Skip to content

v0.3.0

Choose a tag to compare

@stoatworks-labs stoatworks-labs released this 06 Aug 22:12
· 12 commits to main since this release

A fourteenth game, and the cheapest one yet.

Flapper — one button against gravity, through the gaps in a wall that scrolls past. It joins the other thirteen in the same dropdown, in the same two bundles, and it cost no new cell type and no new parameter: the columns are Wall, which already meant "the thing you die on", and the flier is Head.

The press sets the vertical velocity rather than adding to it, so every flap is the same arc from wherever it was pressed. That is what makes it readable — you are timing one thing, not managing a throttle.

Termination had to be built in, again

Skill only works on a game you can misjudge, and this is not one: holding a single axis between two horizontal edges is an easier control problem than Stacker or Duel, and a competent flier at a fixed difficulty simply never dies. A layer that never changes is the thing the respawn delay exists to prevent.

So difficulty here is a ramp rather than a setting. Every column passed narrows the gap, speeds the scroll, pulls the columns closer and widens how far the next hole may sit from the last — until the hole is further away than the flier can travel between two columns. That is arithmetic on the ramp's own floors, and coinoptest does the arithmetic rather than trusting the comment above it.

Two faults that every check passed straight through

Both are worth naming, because neither was visible to a harness that asserts on state.

The first autopilot never passed a single column, on any seed, while satisfying every assertion in the file — dying in bounds having touched nothing is a legal way to play. It projected free fall forward and so settled a braking distance above the hole it was aiming at; aiming at row 12 it hovered at row 7 and clipped the top of every column. A damped position error fixed it, and Score() > 0 is now a check.

The playfield then scrolled in from the right over about two seconds, and because losing a life cleared the columns it did it again on every death — three black stretches a game. An empty playfield is a legal playfield, so nothing caught it until the opening seconds were rendered out and looked at. The field is now built full, with a runway ahead of the flier.

That is the third time in this repo a real fault has survived the whole suite and been found only by looking at the picture. AGENTS.md now says so plainly.

Verification

coinoptest 243 → 268 checks, coinopgl 31 → 33. The browser demo carries all fourteen, each held to the C++ byte for byte by demo/tools/check_sim.mjs — and Flapper is the first port that did not match on its first run. The cause was the one that file had warned about in the abstract: 0.12f + 0.10f * 0.5f is 0.169999998 as a float and 0.17 as a double. The other thirteen get away with doubles because they re-quantise to whole cells constantly; Flapper never puts its floats down.

Still not verified

It has never been loaded into Resolume. The FFGL parameter and clock plumbing is the part no harness here reaches — check it in your own rig before trusting it in a show.

Full Changelog: v0.2.0...v0.3.0