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

9.5 KiB
Raw Permalink Blame History

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 r≈3 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.