TURNCRAFT/docs/SIDEB_W_handoff.md
type-two 33232fdeba SIDE B: the crate worlds — three dive-in pockets, stamps, golden slipmat
Three records in the under-table crate are pressed with whole scenes. E beside
one dives you into its pocket above the booth walls; complete its sound-first
quest to press a STAMP; all three raise the golden slipmat + a permanent bonus
percussion stem. Dust bunnies move in under the table.

- Worlds (Lane W): ACID WAREHOUSE / DUB CHAMBER / DISCO LOFT — sealed themed
  pockets, portal rings, exit pads; deterministic, zero light leaks (incl. the
  flythrough path), meshes unchanged at 469, build ~760 ms.
- Machines (Lane M): portal dive/exit/safety (membership-based escape catch),
  tune-the-303 hold-sweep pedestals, carry-the-charge wobbling spring bridge,
  beat-Simon dance floor with glow tiles; stamps store + relay {t:'stamp'}
  (default-closed, persisted, join snapshot, fuzzed); golden slipmat; stamps
  survive the reset ritual.
- Ambience (Lane S): dust bunnies (wander/flee, zero steady-state allocs),
  vinyl-warp portal iris, HUD stamp tray, stamp confetti + golden shimmer.
- Audio (Lane E2): per-world grooves (acid 303 w/ fader-driven bands, dub
  feedback-echo + spring, disco pentatonic tiles) over a boothGain
  duck-and-handback that can never restore stale state; portal/stamp/golden
  SFX; bonus stem.

Post-integration review (2 seam finders, 10 findings, all fixed + verified):
stamp events carry origin (local/remote/replay) so consumers celebrate
proportionately instead of wall-clock guessing — kills phantom join
celebrations, first-person confetti for peers' wins, and audio/visual grace
mismatches; reconnect re-uploads locally-won stamps the server missed;
relay saveState survives disk errors; pocket escape via mined floor counts as
a real exit at any altitude; exit-pad speed gate + dwell stops mid-quest
yank-outs; dive cooldown stops exit/re-dive ping-pong; locked acid bands
need deliberate holds (tap-spam dead); disco foot band excludes jump apex.

Verified: whole-tree typecheck + build clean; per-lane live verification
(27/27 worldgen assertions, relay fuzz, 18-phase audio matrix, fps unchanged);
integrated smoke: dive/exit/safety/stamps/golden + all origin paths live.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 16:22:11 +10:00

176 lines
9.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SIDE B — Lane W handoff (worlds)
**Status: complete.** Whole-tree `npm run typecheck` exits 0. All demo
validation green (27/27 lines incl. the new pocket assertions). Verified live
on port 5212 (launch config `turncraft-laneC-verify`) in both the demo page
and the real game via the cine camera.
## Files touched
- `src/worldgen/worlds/` **(new)** — `index.ts` (`buildWorlds(w, seed)`),
`common.ts` (skin/lining/exit-pad toolkit + accent-led map),
`portalDressing.ts` (W1), `acid.ts`, `dub.ts`, `disco.ts`
- `src/worldgen/buildBooth.ts` — additive only: one import + one
`buildWorlds(w, WORLD_SEED)` call at the end of `buildBooth`
- `src/demo/worldgenDemo.ts` — pocket assertions, three "Pocket:" exterior
view buttons, header notes
- `docs/SIDEB_W_handoff.md` — this file
Nothing else. No `src/core/**` edits, no other lane's directory, no existing
anchor moved, no new block ids (31 still reserved). Portal-ring code lives in
`worlds/portalDressing.ts` and is invoked via `buildWorlds` so the buildBooth
diff stays two lines.
## Determinism & budgets
- **Deterministic:** two full builds byte-identical (asserted headless AND as
a standing demo validation line). All pocket randomness comes from
`mulberry32(WORLD_SEED ^ k)` streams private to this lane — the main
buildBooth rng is never consumed, so every pre-existing booth zone is
byte-identical to before this phase. acid/disco/portal dressing are fully
index-patterned (zero rng); only dub's embers draw randoms.
- **Build time:** buildBooth alone 1929 ms in the array-mock (pockets add
~5 ms; 66,834 pocket voxels). Real game boot log across five boots:
`booth built+meshed in 760 / 769 / 783 / 913 ms` — the 913 outlier was a
vite-reload storm in a background-throttled pane while three other lane
sessions shared the relay; steady state ~760780 ms. Budget < 900 ms.
- **Chunk meshes: 469** (was 469 pre-SIDE B the pockets live in ceiling
chunks that already existed, so the count is unchanged; disco's glass adds
transparent geometry to already-counted chunks). Budget < 700.
- **Console:** zero errors attributable to worldgen. The only error all
session is a `WrongDocumentError` pointer-lock rejection fired by the
browser-pane sandbox when the start splash is clicked (pre-existing
main.ts `requestPointerLock` behaviour inside an embedded pane; does not
occur in a normal tab).
## W1 — portal dressing at the crate
Per world (accent leds: acid=`led_green`, dub=`led_amber`, disco=`led_blue`):
- **Floor ring:** flush 1-voxel ring inlaid in the crate floor (y=2, i.e.
`portalStand.y 1`) around each `portalStand`, radius 3 (16 voxels,
`d² ∈ [7,11]`). Stands: acid (31,3,36), dub (46,3,36), disco (61,3,36).
Matches Lane S's bunny keep-out (`portalStand ±6`).
- **Disc marquee:** 3 accent-led pips riding each portal disc's top rim, at
`(discX, 28, 31)`, `(discX, 27, 27)`, `(discX, 27, 35)` for discX 31/46/61.
Verified glowing in-game (screenshot: three rings green/amber/blue across the
dim crate). No record geometry moved.
## W2 — pocket geometry (everything Lane M needs colliders/anchors for)
Common to all three (contract `src/core/worlds.ts`):
- Shell: 1-voxel `matte_black` skin on all six faces of
`pocketMin..pocketMax` (y 142 base, y 158 roof). Fully sealed entry/exit
is teleport-only. Interior air y 144..157 (≈14 high).
- Themed floor lining at y=143 (= `exitPad.y`); feet stand at 144
(= `entry.y`). Entry voxels verified solid-below + 2-high headroom.
- **Exit pad:** 3×3 `rca_gold` flush at y=143 centred on `exitPad`
(x±1, z 77..79), centre voxel is the world's accent led. 2-high air above
all 9 columns.
### ACID WAREHOUSE (x 20..84, z 20..84)
- **Knob pedestals (quest M2):** three 3×3×3 `matte_black` plinths, centres
x=52, z=44/52/60 footprints x 51..53, y 144..146, z {43..45, 51..53,
59..61}; **top face y=147**; 1-voxel `led_green` pip at (52,147,z).
Exported: `ACID_PEDESTAL_X/Z/TOP_Y` from `src/worldgen/worlds`.
- Floor: steel/alu slab concrete with flush rubber seams. Walls: `ply_edge`
breeze-blocks with shadow slots. 4 pillars 2×2 at x{33,69}×z{35,67}, floor
to ceiling. `led_green` cable runs: wall drops at x=21, z=38/46/62
(y 144..149) + flush floor inlays snaking to each plinth base (all inlays
are walkable floor, no bumps). Strobe rail: `strobe_dot` at (52,157,z) for
z=28..76 step 3.
### DUB CHAMBER (x 192..256, z 20..84)
- Reading of "floor drops 4 at x 210..238": the x-flanks are **raised
shelves** (x 193..209 and 239..255, solid y 144..147, top face 148); the
centre band x 210..238 stays at floor 144 a sunken canyon 4 below the
shelves, holding entry, bridge, and exit on the x=224 axis. (The shell
floor at 142 is inviolable, so the drop is made by raising the sides
entry/exitPad y-values pin the canyon floor to 143/144.)
- **Tank pit:** floor lining carved to the shell over x 212..236, z 41..62
pit walk surface y=143, one step below the canyon (always escapable), four
below the bridge deck. Two chrome reverb-spring coils inside (helices
around (x=217,y=145) and (x=231,y=145), z 43..61, radius 2 clear of the
bridge's x 223..225). **Gold catch pad** x 223..225, y=143, z 51..53.
- **Bridge (your moving deck overlays this):** static chrome deck
**x 223..225, y=146 (walk surface 147), z 40..63** (3×24 exactly), with a
`rca_gold` mouth inlay at **(224,146,52)** the "feed the spring" E-drop
spot, directly over the catch pad. End legs at z=40/63 (y 144..145).
Stairs, 1-voxel steps (auto-step): near z=37 (y144), z=38 (y144..145),
z=39 (y144..146); far z=64 (y144..145), z=65 (y144).
Exported: `DUB_BRIDGE`, `DUB_PIT`.
- **Horn:** stacked `speaker_mesh` rings on the back wall, **centre
(232, 151)** throat plate flush at z=83, rings flaring at z=82/81/80 to
r6; `led_amber` ember at (232,151,82). Exported: `DUB_HORN`.
**Deliberately mounted EAST of the exit axis:** the exit pad (x 223..225,
z 77..79) would otherwise sit between the room and the horn. With the horn
at x=232, a charge anchor near **(232, 147, 79)** is reachable and
carryable to the bridge without ever crossing the pad safe even if you
make exit walk-on. If you'd rather the player never gets close, anchor at
(232,147,75).
- Dressing: vinyl_black everything, ~35 `led_amber` embers in walls/risers,
2 speaker-mesh stacks per shelf (3×3×3 at x 200..202 & 246..248 tops 150).
### DISCO LOFT (x 364..428, z 20..84)
- **Dance tiles (quest M2, your standing-on colliders):** 4×4 grid of 5×5
flush tiles at y=143, tile **centres x {384, 392, 400, 408} ×
z {52, 60, 68, 76}** (pitch 8; each tile spans centre±2; 3-voxel parquet
gaps between tiles). Border ring alternates `label_cream`/`rubber` per
tile (checker), field is the opposite, **centre voxel led_red/led_blue**
(Lane S lights on `disco_cue`). Exported: `DISCO_TILE_CX/CZ/Y`.
The exit pad (x 395..397, z 77..79) sits in the x-gap between tile
columns no overlap.
- **Mirrorball:** chrome/glass checker sphere r3 centred **(396,152,64)**
(over the tile grid), chrome chain at (396,156..157,64). Bottom voxel
y=149 5 clear above heads.
- Dressing: plywood/ply_edge herringbone parquet, plywood walls + ply_edge
skirting, 16 vertical wall-wash strips (led_red/led_blue, y 146..151) on
all four walls.
## Verification performed (all live, port 5212)
Demo (`/demo-worldgen.html`) validation 27/27 green, incl. per-world: skin
sealed matte_black (0 breaches which also proves no emissive/transparent
block anywhere on the skin), entry floor+headroom, exit pad + pip + clear
above, portal ring 16/16 + marquee 3/3, pedestals/bridge/tiles present,
"nothing above y141 outside the pockets (0)", determinism. Build 28.7 ms in
the mock, 0 OOB writes, zero console errors.
Real game (`/`) screenshots via `window.TURNCRAFT_CINE`:
1. Flythrough keyframes from commit caac3da K1 (224,132,26)→(224,60,128),
K2 (330,100,60)→(224,66,100), K3 (140,96,60)→(80,81,96): ceiling in frame
in K2/K3, zero pocket visibility, zero glow.
2. Under-pocket ceiling shots (below acid and dub, lights-off angles): pure
dark ceiling, no leaks.
3. Exterior night, high over the roof from the front: all three pockets read
as faint matte-black slabs, zero emission (two angles).
4. Interiors of all three pockets (front wall room): every listed feature
visible and correct.
5. Crate: the three accent rings glowing round the portal stands.
## Notes / friction for the integrator
1. **`matte_black` is `breakable: true`** in the contract registry, so a
player could in principle mine a hole in a pocket skin (same as the mixer
body). Lane M's out-of-pocket safety teleport (M1) is the net; if we ever
want skins unmineable that's a contract decision, not mine.
2. Dub's "floor drops 4" is implemented as raised side shelves (see above)
the contract's entry/exitPad y-values make a literal 4-deep dig
impossible without piercing the shell. Flagging per CONTRACTS §1 rather
than bending the contract.
3. The pocket skins rest directly on the booth ceiling slab (y 140..141), so
they are strictly invisible from inside the booth; the exterior view only
exists for cine/debug cameras.
4. `worldgen/index.ts` was NOT edited (not in this phase's sanctioned list);
`buildWorlds` is internal to `buildBooth`. Demo imports feature anchors
from `src/worldgen/worlds` directly.
5. Verified while three other lane sessions were live on the same tree/relay
(their WIP caused periodic vite reloads; boot numbers above include that
noise). One environmental console error only see Budgets.