workshop private

← all creations

Pitch

sprites · created 2026-09-28

184×126 pixel vending shelf in elevation with four loops. The coil turns exactly once, every time, in every case — including the ones where nothing came out. What decides it is an angle nobody prints on anything, 180 × depth / pitch, and the margin it leaves is one millimetre.

physicssimulationpixel-artcanvas

A spiral vending shelf is a helix of wire lying on a flat tray with a gearmotor behind it. The turns divide the tray into pockets, one product per pocket. The motor turns the helix, the helix pushes everything forward by exactly one pitch per revolution, and the frontmost product falls off the lip into the delivery bin.

That is the whole machine. It has no idea what any of that looked like.

The angle that matters is not the one the motor counts

The product tips when its centre of mass passes the lip, and not before. So the question was never “does the coil move it far enough” — it always moves it exactly one pitch — it is how far round the coil has gone by the time the centre of mass gets there. Load a shelf the way anyone loads a shelf, with the front product’s face flush at the lip, and its centre of mass starts half its own depth behind:

release angle = 360 × (d/2) / p = 180 × d / p

A 34 mm bag on a 38 mm coil leaves at 161°, with a half turn to spare. A 74 mm box on the same coil leaves at 350°. Same coil, same motor, same one revolution, and one of them has nine degrees left — against a topple that takes 62° of coil to finish. It lands, correctly, after the sale has closed.

The motor stops at 360°, because it is homed by a cam switch on its own output shaft. That switch is the machine’s entire sense of what happened. It closes once per revolution in every case on this page, including the ones where nothing came out, and the controller is not lying when it prints THANK YOU — it is reporting the only thing it can see.

media/06-the-same-coil-four-products.png is one shelf at one moment with four products in it: 161°, 284°, 351°, 388°. Nothing about the machine changes across those four frames.

Which makes the margin a length

Release needs 180 d / p ≤ 360, so no product deeper than 2p can ever come out in one revolution, and the slack either side of that is

margin = p − d/2        millimetres of loading error

21 mm for the 34 mm bag. 1.0 mm for the 74 mm box. That is the number an operator should be handed and never is: not will this vend, but how accurately does this shelf have to be filled, by hand, in a corridor, by someone with forty more machines to do today. Load the 74 mm box two millimetres shy of the lip and it needs 369°, and 369 is not a number the motor has. media/07-one-millimetre-of-loading.png is that boundary walked across by shoving the stack — −2, 0, +1, +3 mm giving 332°, 351°, 360°, 379°. The third one releases on the exact degree the cam cuts and gets out on the last fraction of the last degree, which is not a tolerance, it is a coin toss.

Past 2p it does not jam, which is worse

The first vend moves the product one pitch and stops with the centre of mass still behind the lip, so nothing falls. The second vend finishes the job and delivers it. From then on every vend delivers an item, and the item is the one the previous customer paid for. The machine is one purchase behind for the whole life of the load, it never reports an error, and it is right not to: a cam switch on a motor shaft cannot tell this from working.

The release angle is also a fixed point. Whatever it is on the first vend, the leftover rotation leaves the next product in exactly the same place, so it is the same angle on every vend until someone reloads. A shelf filled wrong is wrong until it is empty.

And a second failure that has nothing to do with the coil

A product released over the lip pivots about it, and while it pivots its far corner swings out into the chute. The furthest any part of it ever reaches is

r = hypot(d/2, h)

and if that exceeds the gap between the lip and the front glass, the product does not fall. It turns until the corner touches the glass and stops there, wedged between the tray lip, the coil and the door. A 44 × 66 mm box in a 62 mm chute reaches 69.6 mm and hangs at 44.6°. This is the one everybody has seen, and note what it is not about: that box releases comfortably at 208° with 16 mm of slack. The pitch was fine. The chute was the constraint, and the chute is not on any planogram.

media/08-the-corner-that-does-not-fit.png is the same 44 mm box getting taller until the corner stops clearing.

Nothing here stalls the motor, which is why none of it registers

A coil is a screw. A 1.5 N·m gearmotor on a 38 mm pitch puts

F = 2πT / p = 248 N

along the tray, and the 44 × 66 box weighs 0.38 N. The coil has 660 times the force the job needs, so it pushes a wedged box into the glass with exactly as much complaint as it makes dropping a free one, which is none. There is no current spike to alarm on. The mechanism is too strong to be an instrument.

The fix is in the bin, and it has a clock on it

You cannot sense this at the coil. The bin is the only place in the machine where “did it fall” is observable at all, which is why every modern machine has an optical beam across the delivery chute and re-vends when it stays unbroken.

Then that fix gets its own trap, and it is the 74 mm box: it finishes toppling after the motor has stopped, so a detection window shorter than its topple declares the vend a failure, refunds the customer, and then delivers the product anyway. media/09-what-the-beam-can-see.png is the beam against all three failures — two rescued, one refunded, because a beam can see an empty bin but cannot see why.

The kicker is that the coil which works holds more

Pitch is chosen to fit facings on the tray, and a bigger pitch looks like fewer of them. On a 430 mm tray, though, the 82 mm product on the 38 mm coil takes three pockets each — 114 mm of tray per item, 3 facings, and it never vends. Move it to a 45 mm coil: two pockets, 90 mm per item, 4 facings, and it leaves at 328° with 4 mm of slack, inside one revolution. (It still finishes toppling after the cam cuts — 32° of motor left against 62° of topple — but landing late is a different thing from never landing.) The coil chosen to squeeze more product onto the shelf fits less of it and does not deliver it.

Four loops

Reading the frame

The demo

demo/ runs the shelf live with every input on a slider, because the whole point is that these are inputs and the machine treats them as facts. pitch is the coil, depth and height are the product, chute is the gap to the glass, and loading is where a human left the front face. drop beam fits the sensor; buy adds another customer at whatever moment you are looking at, which is how you watch the one-behind shelf stay one behind.

The setting worth finding by hand: leave the 74 mm preset alone and walk loading from −2 to +2 mm. The shelf works, works, works, and then quietly stops delivering, and nothing on the machine’s side of the panel changes at all.

Reuse

Both need Playwright from site/node_modules.

What is modelled and what is drawn

Worth saying, because the numbers above are only as good as this: