The roster is the alphabet: the sequence is the zombies themselves

Oliver's insight, and it retires a whole subsystem: "we don't need colors at
all! we already have different zombie types.. so the sequence is the zombies
themselves".

The bib and then the ground disc were both inventions bolted on to give a
body an identity it already had. A brute does not look like a runner, the
game is built on reading those silhouettes at speed, and the strip can show
the body's own walk frame instead of a swatch — no legend, no mapping, no new
art ever. It also deletes the accessibility problem outright rather than
deferring it, because a silhouette is not a hue. DRILL_COLS, drawColourRing,
drawBib, PIP_FACES, blip(), drillRingR and drillTones are all gone.

Two rules keep a type unambiguous: the plain shambler is never in the
alphabet (it is what the eaters are, so "not the puzzle" needs no marking),
and one of each type is on court at a time.

The new failure mode this created is instructive. Types move at different
speeds and drill bodies hold their lane, so one in a lane you are not in
walks the whole court and off the back untouched — stranding the sequence
asking for a body that no longer existed, i.e. the un-winnable state the mode
exists to prevent, reintroduced by a change that looked cosmetic. A batch
body crossing your baseline counts as caught now ("GOT PAST YOU"), which is
also just better design, and the speed spread is narrowed to 1.35..0.70 so a
batch stays coherent. Their real difference is HP and that is untouched: a
runner is one shot, a roller is seven.

Verified: 14400 frames of simulation, zero frames where the sequence named a
body that was not on court.

29 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-11 20:24:58 +02:00
1 parent 3379e83efc
commit 5b2f1d55ce
7 files changed
+197 -145

No files matched your search

+10 -12
View File
@@ -345,19 +345,19 @@ export const TUNE = {
barrelRoll: 2.6, // m/s it trundles across the far court — fast enough to have to be led
barrelHp: 1, // anything pops it: ball, pellet, bomb, flame, swish. It is a target, not a body
barrelH: 1.15, // drawn height (a body is 1.8)
// ---- THE COACHING DRILL (src/drill.js) — the cognitive mode. THIRD DESIGN, and the one that
// makes it winnable: a BATCH of bibbed bodies is born on the far side, its combination is called
// off them immediately, and every colour on court is in that combination — no coloured decoys, so
// the strip can never name something you cannot see. Kill the last of a batch and the next walks
// in on the same frame. The danger is a separate channel: unbibbed EATERS on their own clock that
// converge on you the way ordinary shamblers do.
drillBatch: 3, // colours in a batch at the bottom of the ramp...
drillBatchMax: 6, // ...and at the top. Capped by DRILL_COLS — a colour is on court at most once
// ---- THE COACHING DRILL (src/drill.js) — the cognitive mode. THE SEQUENCE IS THE ZOMBIES
// THEMSELVES: a BATCH of distinct roster types is born on the far side and the combination is
// called off them at once, so everything the strip asks for is already in front of you. There are
// no colours, signs or markers anywhere — a brute does not look like a runner, and that is the
// whole point. The danger is a separate channel: plain shambler EATERS on their own clock, never
// in the alphabet, converging on you the way ordinary shamblers do.
drillBatch: 3, // TYPES in a batch at the bottom of the ramp...
drillBatchMax: 6, // ...and at the top. Capped by DRILL_TYPES — one of each type on court at most
drillBatchDepth: 3.0, // m of depth a batch is staggered over. All of it still on the far side,
// which is the promise: you see every colour before you are asked for it
drillSpawnZ: 0.6, // z they enter at (the far baseline is 0)
drillSpread: 3.4, // m either side of the centre line the lanes fan across
drillSpeed: 0.80, // m/s a bibbed body walks at the bottom of the ramp...
drillSpeed: 0.80, // m/s a batch body walks at the bottom of the ramp (x its type's vMul)...
drillSpeedMax: 1.9,// ...and at the top. Stamped per body AT SPAWN, so the ramp shows up as new
// arrivals outpacing the ones already walking, not the court accelerating
// The eaters are RARE on purpose. At every 7 s / 2.2 s they were a second crowd rather than an
@@ -365,13 +365,11 @@ export const TUNE = {
// with only works if breaking off is occasional. They also enter wide of the colour gang
// (spawnEater), because the one body out there that is neither the puzzle nor worth anything has
// no business standing in front of the puzzle.
drillEaterEvery: 12.0, // s between unbibbed eaters at the bottom of the ramp...
drillEaterEvery: 12.0, // s between plain-shambler eaters at the bottom of the ramp...
drillEaterMin: 5.0, // ...and at the top. Still THE difficulty dial, just a slower one
drillEaterMax: 3, // eaters allowed on court at once — past this the puzzle is unreadable
drillEaterSpeed: 1.15,// they walk a touch faster than the batch: the batch is a list, this is a threat
drillRampT: 210, // s to go from the bottom of every curve above to the top
drillRingR: 0.62, // m — radius of the colour disc a bibbed body walks on. Big enough to read at
// the far baseline, which is the whole reason the colour left the chest
drillCaughtBack: 45, // s of ramp handed back when one reaches you. A real setback, not a reset
fps: 60, // frame cap — 30 halves battery/heat but Oliver felt it; smoothness wins (0 = uncapped)
lowPower: 1, // >= 0.5 caps RES at 3 (−44% of pixels painted per frame) — the battery saver,