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>
176 lines
9.5 KiB
Markdown
176 lines
9.5 KiB
Markdown
# 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 19–29 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 ~760–780 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.
|