Data spine: - Schema v1 ratified (TECH.md, C-owned). Additive over v0: schema/par/next, segment name, cross-section placement (theta/rho as a FRACTION of safe radius), spread, span, pickup+gate event types, hazard params. STUB_LEVEL synced (that const only, per ROUND1 §Lane C.1) — world.hash() unchanged (1bdf001), geometry provably untouched. - levels/index.js: registry + loader (node+browser, no THREE), real schema selfcheck (qa's --selfcheck hook is now live) and a pacing simulator (--sim). Consumes the other lanes' contracts live rather than restating them: A's biomes.js for ids and wave.amp+breathe, A's SKIN, B's tuning.js hull radius, B's balance.js for scores. - levels/enemies.js (fiction id -> archetype join table), levels/difficulty.js. L2_esophagus — the vertical slice, complete: 3600 units, 7 beats, 47 events, 65 enemies, 10 checkpoints, 3 samples, reflux-surge finale. L1/L3 skeletons (shape only). Anatomy is the level designer: the three real esophageal constrictions are the three setpieces, and all three enemies are real esophageal pathology (bolus chunk, eosinophilic esophagitis, candida esophagitis). Measured (node web/js/levels/index.js --selfcheck|--sim; qa GREEN): - selfcheck 3/3 valid, exit 0. - pressure curve 0.27 -> 2.14 -> 4.35 -> 0.69 -> 4.53 -> 6.35 -> 4.40 (breather/pressure/ spike/breather/pressure/peak/finale). - par 3:30 vs measured 2:47 speedrun / 3:19 par-pace / 4:22 timid; par.score 9000 of a 9400 kill budget (95%), computed from B's scores. - all 10 checkpoint gaps within the <=30s death-cost law (max 28.8s); min clearance 2.73. Two contract collisions found and resolved (LANE_C_NOTES): - Biome ids: authored mouth/pharynx/cardia/pylorus; A's registry has six canonical ids and rejected all four. A is right — biome = look, segments[].name = anatomy. Conformed. - Balance: my first enemies.js restated hp/size/speed/score that B owns in balance.js. Cut to a join table; index.js reads B's scores via scoreFor(). Caught live: A raised esophagus wave.amp 0.9 -> 1.4 mid-session, making the diaphragmatic hiatus unflyable (2.33 vs the 2.5 floor). Widened 6.5 -> 6.8. The invariant also failed my own aortic constriction's first draft (radius 7, symmetric squeeze) -> radius 9, directional. No in-engine flythrough: ?stub=1&lvl= does not compose (snippet offered to F) and the stub is single-segment, so it could only render beat 1. The pacing evidence is a kinematic model, not a playtest — it proves L2 is flyable, paced and survivable, not that it feels good. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.5 KiB
Lane C (Levels & Encounters) — progress
2026-07-16 — Round 1: the data spine + the vertical slice
Landed:
- Schema v1 ratified (TECH.md §Level data schema, C-owned from here). Additive over F's
v0:
schema,par,next, segmentname, cross-section placement (theta/rho, rho as a fraction of the safe radius), groupspread, zonespan,pickup/gateevent types, hazard params. STUB_LEVEL synced to v1 (only that const in F's file, per ROUND1 §Lane C.1). levels/index.js— registry + loader (node + browser, no THREE), schema selfcheck (real; qa.sh's--selfcheckhook is now live) and a pacing simulator (--sim). The selfcheck consumes the other lanes' contracts live: A'sworld/biomes.jsfor biome ids andwave.amp + wave.breathe, A'sSKIN, B'sflight/tuning.jshull radius, B'scombat/balance.jsfor scores. C's registry owns composition and mirrors nothing.levels/enemies.js— enemy catalogue (fiction id → archetype) + pickup/hazard vocab.levels/difficulty.js— the single difficulty table +applyDifficulty()(authored, not yet validated against play).L2_esophagus.json— the vertical slice, complete: 3600 units, 7 beats, 47 events, 65 enemies, 10 checkpoints, 3 samples, reflux-surge finale.L1_mouth/L3_stomachskeletons (shape only, flagged SKELETON — the selfcheck downgrades content laws for them).- GDD refined in place (bannered): per-level time targets replacing a flat "6–10 min", esophagus roster, L2's three real constrictions as its setpieces.
- Boss specs (Guardian / Tapeworm / Blockage) as one-pagers in NOTES — phases, telegraphs, windows, failure pressure. Deliberately three different pressures: coat race, distance race, hull attrition + doom timer.
Verification (measured, node web/js/levels/index.js --selfcheck|--sim; qa.sh GREEN):
- selfcheck 3/3 valid, exit 0; 6 warnings, all expected (skeletons undesigned, L4 not yet registered).
- L2 pressure curve 0.27 → 2.14 → 4.35 → 0.69 → 4.53 → 6.35 → 4.40 (breather → pressure → spike → breather → pressure → peak → finale).
- L2 par 3:30 against a measured 2:47 speedrun / 3:19 par-pace / 4:22 timid run; par.score 9000 of a 9400 kill budget (95%), computed from B's scores.
- All 10 checkpoint gaps within the ≤30 s death-cost law (max 28.8 s). Min clearance 2.73 at the hiatus, against C's 2.5 floor.
- Booted
?stub=1&dbg=1after the STUB_LEVEL edit: tube renders, zero console errors, and the v1 module builds a valid world (length 400,wallRho(0,0) = 8.5, centre-line collidenull).world.hash()is byte-identical before and after my edit (1bdf001) — the sync adds data fields only and provably does not move the geometry, so F's round-0 shot still stands. No screenshot committed: it would be pixel-identical to round 0's, and per charter a data lane's evidence is the pacing report, not a picture of an unchanged tube. (No fps claim: the preview pane throttles rAF in the background —rafTicks: 0— so framerate is unmeasurable here. Not a code fault; the render path is fine.)
Two contract collisions found and resolved (detail in NOTES):
- Biome ids — I had authored
mouth/pharynx/cardia/pylorus; A's registry has six canonical ids and rejected all four. A is right: biome = look,segments[].name= anatomy. Conformed, and the constraint paid for itself (the cardia keeping the esophagus palette is why the acid sea reveals itself in colour). - Balance ownership — my first
enemies.jsrestated hp/size/speed/score that B already owns incombat/balance.js. Cut to a join table;index.jsreads B's scores instead.
Caught live: A raised esophagus wave.amp 0.9 → 1.4 mid-session, which made the
diaphragmatic hiatus unflyable (2.33 free radius vs the 2.5 floor). Widened 6.5 → 6.8. The
invariant did its job on my own level twice — the aortic constriction also failed its first
draft (radius 7, symmetric squeeze) and became radius 9 with a directional squeeze.
Not done / next round: no in-engine flythrough — ?stub=1&lvl= does not compose yet (snippet
offered to F) and the stub is single-segment, so it could only ever render beat 1. L2's
pacing evidence is a kinematic model, not a playtest: it proves the level is flyable,
paced and survivable; it cannot prove the hiatus feels good. That needs A's world + B's
controller in round 2 — and if one thing gets playtested, it should be s 2600–3000.