Skip to content
back to selected work

Interlock

TypeScriptReact.NET 10Azure App ServiceAzure SQLBicepPlaywright

Warehouse load simulator · event-sourced underneath

LIVE

Interlock is a simulator, and getting there meant admitting what it wasn't. It began as an animation: a scrollytelling piece, a box traveling down a conveyor belt, one package's journey told in three acts. Watching that single box move made me want to see a whole floor of them at once, so I built the floor: a workflow engine where packages move between stations under a configurable definition, every move is an event, and the board is computed from that log rather than a status column anyone updates.

For a while I entertained it as an operations dashboard. Then I admitted what it actually was, a simulation, and the logical thing was to make it a simulator: hand over the controls and see what the flow does under load. That is where the inflow knob came from, and the valves, the recirculation belt, and the redirection belt. Something I learned was that the queue forms one stage behind whatever is constrained, so the station under strain is never the one that can fix it.

▶ play walkthrough
~1:00 through the live app. The self test is a real round trip: it replays the log and times it. Then the inflow goes up: the load rack fills left to right, belts open when the loops run out of road, and one loop is opened to show what is going round. A station is locked out and released, and the queue behind it drains on its own. Click to pause.
~/architecture
Takeaway the log is the record · the board and the timeline are the same computation at a different t, which is why the scrubber cannot disagree with the board: there is nothing for it to disagree with