About Shunt
Shunt is a conveyor-routing puzzle. Boxes arrive at the top of the board and ride the belts. You click the switches that direct them to their destinations. The browser only runs the clock; the C core owns the rules.
It's a tribute to Global Player, a mid-2000s Flash game for logistics company Dachser, where you sorted colour-coded parcels onto the right trucks, trains, and planes. Finished, Shunt will be ten levels of rising difficulty.
Why C
Not for performance, for the constraint. A game engine would handle most of this easily. Without one, all the challenges come straight to me. Even the rendering is work - instead of a grid of pixels, I have a straight list of bytes, and calculate every pixel position. I also need a separate model and screen view to represent the game, since the game is on a simple grid but the view is dimetric. If you start look at screen position instead of a model position, things get messy very quickly.
I use good tools most of the time, which make it easier than ever to skip the hard parts. This game is an exercise in deliberate practice. I'm doing it for the same reason people go to the gym, now that machinery does most of our heavy lifting.
What's been hard
I've been caught out by little things continually: 8-bit integers overflowing, forgetting that the buffer uses 32 bits per pixel, unexpected behaviour from negative modulo. I've had to refactor things as my model and view became coupled together. I've also made some pragmatic choices, like putting sufficient capacity arrays on the stack instead of allocating memory. These are the little things that a language without guardrails throws at you constantly, and there's nowhere to hide.