workshop private

← all creations

Last Flight

sprites · created 2026-09-18

52×60 pixel sprite — a fire escape's counterbalanced bottom stair, drawn as a linkage rather than as poses, where the only term that grows is the paint.

pixel-artcanvasphysicssimulation

The bottom section of a fire escape at night: the counterbalanced stair, the one that hangs out of reach over the sidewalk until somebody puts their weight on it. Brick wall, a lit window with a television going in it, the lowest landing, the hinge at its outer edge, the cast-iron block on its arm, and a person who needs to get down.

Three loops:

What’s different about this one

Every other sprite in this catalog is a list of hand-drawn poses, and an animation is an order to play them in. This one has no poses of the stair at all. It has a state variable and a linkage — one angle, theta, and a rasteriser that will draw the stringers, the eight treads, the handrail, its balusters and the counterweight arm at any value of it you like.

So the exported frames are not artwork. They are the solver’s output, sampled at 7 frames per second of the solution and played back at 7 fps, which is why the drop accelerates: nobody eased it. The first three frames barely move and the last three cover half the arc, because that is what falling looks like when the torque driving it is still growing. Change the counterweight in RIG and every PNG in export/ changes, because they were never drawn.

Two details fall out of the geometry rather than being keyed:

The lighting is two rim passes and nothing else — no falloff, no gradient. A solid pixel gets a cool edge if the sky is directly above it and a warm edge if the step toward the window is empty. An edge either sees a light or it does not. That is what keeps a swinging steel stair readable against a dark sky at 52 pixels wide, and it means the stair’s highlights travel as it rotates, for free, because which edges can see the window is a function of theta too.

The mechanism

A fire escape’s last flight has exactly one job: say yes to weight from above and no to everything else. It does that job with a lever, and the lever is in a bind.

You can only reach the top tread. The stowed stair hangs with its foot 4.2 m over the sidewalk — that is the entire security model, and it is why the thing exists in this shape. So the only part of it anybody can step onto from the landing is the end nearest the hinge, which is the end with almost no leverage. A person standing there works a 0.36 m arm against the stair’s own 1.52 m.

Which forces the balance to be set fine. It has to tip for a child on the worst moment arm in the machine, so the empty stair can only be holding itself up by a whisker:

The balance, at the stowed angle

termN·mnote
stair, own weight+879.4trying to fall
counterweight−971.3trying to hold
net — the margin−91.8what the whole machine holds itself up by
a 78 kg person on the top tread+225.6and that is the design load

The margin is 10.4% of the stair’s own moment. Everything below is a consequence of that number having to be small.

Two things follow from that 10.4%, and they are the piece.

One: you cannot refuse the weather

Anything spread over the stair — snow, ice, a pigeon convention — does not act at the top tread. It acts at the mean tread, 1.63 m out, which is 4.5 times the arm the design had to answer to. So the balance that lets a child down also lets seven kilograms of snow down, and there is no setting of the block that fixes it:

The trade you cannot win

A load spread over the treads acts at the mean tread, not the top one, so it out-levers the design load by 4.53×. Raising the block to refuse the weather raises what a person has to weigh by the same factor.

blockmarginspread load it refusesperson needed on the top tread
88 kg20 N·m1.5 kg7 kg
92 kg61 N·m4.7 kg21 kg
95 kg92 N·m7.0 kg32 kg
98 kg122 N·m9.3 kg42 kg
102 kg163 N·m12.5 kg56 kg
106 kg204 N·m15.6 kg71 kg
112 kg266 N·m20.3 kg92 kg

There is no row where it refuses a winter and still answers to a child.

This is not a flaw in the tuning. It is a ratio of two lever arms, fixed by where a person can stand versus where snow can lie, and no counterweight can change it. It is the entire argument for a hold-down latch: the second job needs a second mechanism, because the first one is already at its limit.

Two: paint is a counterweight nobody specified

Friction at the hinge enters that same 92 N·m balance, on the same side, in the same units. Every few years somebody paints the building, which includes painting the hinge, and the film bridges the gap and sets. Rust grows into what is left. None of it is on any drawing of the machine, none of it is what anyone means by wear, and it is the only term in the linkage that grows.

What it does is not jam the stair. It moves the place where the stair will finally let go further out along its own length:

What paint does

Breakaway torque at a hinge nobody has moved, and the same number priced two other ways: as counterweight somebody would have had to bolt on to do the same damage, and as where a 78 kg adult now has to stand.

yearsbreakawaysame as addingrelease point for 78 kgtread
00 N·m0 kg of block0.15 m1
378 N·m8 kg of block0.27 m1
6198 N·m19 kg of block0.46 m2
9342 N·m33 kg of block0.69 m2
12504 N·m49 kg of block0.95 m3
15681 N·m67 kg of block1.23 m4
18871 N·m85 kg of block1.54 m5
211073 N·m105 kg of block1.86 m6
241285 N·m126 kg of block2.20 m7
271506 N·m147 kg of block2.55 m8
301736 N·m170 kg of block2.92 m8
331975 N·m193 kg of block3.30 moff the end
362221 N·m217 kg of block3.69 moff the end
402560 N·m250 kg of block4.23 moff the end

The release point moves out at about one tread every 3.9 years, and runs off the end of the stair in year 31.1. Nothing breaks in year 32. Nothing looks different from the sidewalk.

Read that fourth column as a location on a real object. In year 6 you step on and walk down. In year 18 you have to get to the fifth tread — and remember which way that is, because the stowed stair slopes up: finding leverage means climbing out over the sidewalk, on a ladder, in whatever emergency brought you out of the window. In year 27 it is the last tread. And in year 32 the answer comes back 3.30 m on a 3.20 m stair, which is not a hard place to stand. It is not a place.

Nothing breaks that year. The block is the size it always was. The margin is the number the installer chose. From the sidewalk it looks exactly like a fire escape.

Who can release it, new

personhas to get this far outwhich tread
18 kg0.63 mtread 2
25 kg0.46 mtread 2
32 kg0.36 mthe first one — it goes as they step on
45 kg0.25 mthe first one — it goes as they step on
60 kg0.19 mthe first one — it goes as they step on
78 kg0.15 mthe first one — it goes as they step on
100 kg0.11 mthe first one — it goes as they step on

The lightest person who can release it standing on the top tread: 31.7 kg.

A 32 kg child releases it on the tread they step onto; anyone lighter has to get to the second. That is the load case the balance is really tuned for, and it is why the margin had no room to be generous in the first place.

The drop itself

quantityvalue
moment of inertia about the hinge361 kg·m²
time from the step to the pavement2.03 s
foot speed on arrival6.89 m/s
the same foot, simply dropped9.09 m/s
so the linkage takes off24%

That is the counterweight’s entire contribution to the landing: it removes 24% of a four-metre fall and the rubber buffer at the foot has to eat the rest. The block is a latch, not a brake — by the bottom of the arc its arm is vertical and it is holding nothing at all.

The seize loop runs at 34 years, three past the line. The figure climbs to 3.05 m — the last tread there is — and is still 9.6 kg short. The hinge gives up 3.98° of free play and that is every millimetre of travel in the loop.

The rig, in metres and kilograms

quantityvaluewhy it is that
stringer, hinge to foot3.20 mone storey of bottom flight
hinge above the sidewalk2.38 mforced: L·sin(48°), the deployed pitch
foot above the sidewalk, stowed4.21 mforced: the -35° stowed angle. This is the whole security model
stair section72 kgtwo stringers, eight treads, a rail
its centre of mass1.52 m outnear enough the middle of a uniform thing
counterweight95 kgsized below — the only free parameter in the machine
its arm1.05 mclocked 42° off the stringer, so it is vertical at full deployment
top tread0.36 m outthe only tread reachable from the landing
mean tread1.63 m outwhat a spread load gets to use instead

These are a model, not a survey of anybody’s building — plausible numbers for a narrow bottom flight, chosen so the arithmetic lands where real installations land. The one invented curve is the breakaway torque, 17.6 · years^1.35: its shape is the claim — paint over paint, so resistance climbs faster than linearly — and its constants are calibrated to the one anecdote everybody who has tried a neglected fire escape already has. Treat the years axis as ordinal. The columns beside it are honest arithmetic on whatever it says.

The demo

Three sliders and one button. The slider that matters is paint, and the thing to watch is not the scene — it is the marker on the flat strip under it, which is the release point. Drag from 0 to 40 and watch it walk down the stair and off the end. Press step on at any setting to see what that means for the person: a ride, or a climb that ends standing on the last tread of something that is not going to move.

The demo does not re-implement the physics. Every parameter change re-runs the same simulate() the exported frames came out of, and playback is stateAt() against wall-clock time, so what you see in the demo is the same solution the sprite sheet is a sampling of.

Reuse

Render at integer scales with nearest-neighbour filtering or the rim pass smears into the gradient it exists to avoid. wait plays at 3 fps, drop at 7, seize at 4 (ANIMATIONS carries all three). drop and seize are one-shots by intent; the demo plays either and falls back to wait.

If you want the linkage rather than the pictures, call paintScene(ctx, scene) with any theta you like — that is what the demo does, sixty times a second.

Source

No .aseprite — the canonical source is source/last-flight.mjs: a framework-free ES module holding the building as a character map, five figure poses, the rig, the torque model, the solver and the rasteriser. Edit it and regenerate everything with:

node source/render.mjs        # export/, media/, thumb.png, demo/last-flight.js
node scripts/screenshot-demo.mjs   # the demo screenshots, and the demo smoke test
node scripts/measure.mjs      # every table above

(All three need site/node_modules installed — they resolve Playwright from there.) render.mjs also rewrites the demo’s bundled copy of the module, so it cannot drift from source/ (ADR-0002).

Gotchas

Port notes

paintScene writes into a plain RGB buffer and only touches a 2D context at the blit, so the linkage and the rim passes port anywhere you can address pixels — same shape as Gaffer’s light pass, one step further in that the geometry is computed rather than stored. The torque model is twenty lines of trigonometry with no dependencies at all. In DragonRuby, keep the building as strings and either run the same rasteriser into args.outputs.solids or, since the frames are static, just consume the sheet with source_x = frame * 52.