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>
63 lines
4.5 KiB
Markdown
63 lines
4.5 KiB
Markdown
# 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`, segment `name`, cross-section placement (`theta`/`rho`, rho as
|
||
a *fraction* of the safe radius), group `spread`, zone `span`, `pickup`/`gate` event 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 `--selfcheck` hook is now live) and a **pacing simulator** (`--sim`).
|
||
The selfcheck consumes the other lanes' contracts live: A's `world/biomes.js` for biome ids
|
||
and `wave.amp + wave.breathe`, A's `SKIN`, B's `flight/tuning.js` hull radius, B's
|
||
`combat/balance.js` for 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_stomach`
|
||
skeletons (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=1` after 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 collide
|
||
`null`). **`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.js` restated hp/size/speed/score that B already
|
||
owns in `combat/balance.js`. Cut to a join table; `index.js` reads 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.
|