- Records are stepped groove amphitheaters (3 vinyl tiers + 4-tier spindle tower, stacked rotating cylinder colliders) - you climb a spinning staircase. Tonearm clearances raised to match. - Player physics: cylinder contacts resolve by minimum penetration (fixes a latent radial-slingshot bug), collider lips auto-step like voxel ledges, rim-standing radius grace. - Well seam ring raised (was a 7-deep inescapable trench, now a 1-step Technics seam). - Plywood ceiling with amber lamp panels + warm point lights; brighter warm lighting rig; colorful mixer knob caps; rim-crumble debris. - window.TURNCRAFT_CINE camera override for screenshots/trailers. Verified live: rim->plateau spiral climb at 33rpm, tower climb 83->87, seam escape, quest/win chain, 121 fps. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
113 lines
6.6 KiB
Markdown
113 lines
6.6 KiB
Markdown
# TURNCRAFT — Integration Notes (what the integrator changed and why)
|
||
|
||
Integration performed per [INTEGRATION.md](./INTEGRATION.md) after all five
|
||
lanes landed. Every cross-lane glue decision is listed here.
|
||
|
||
## Contract changes (core is integrator-owned)
|
||
|
||
1. **`Y_RECORD_TOP`: 85 → 81** (`src/core/constants.ts`). At 85 the vinyl
|
||
surface was a 5-voxel cliff above the plinth (jump height ≈ 1.3 — the
|
||
record was unreachable), and Lane D's platter stack floated on the plinth
|
||
top, ignoring the 6-deep well Lane C carved. Now the record sits 1 proud of
|
||
the plinth (auto-steppable, like a real 1200) and the platter body fills
|
||
the well. Everything downstream (tonearm heights, audio panner positions,
|
||
FX rim sparkle, D's quest defaults) derives from the constant and moved
|
||
automatically. Added `PLATTER.wellDepth = 6` alongside.
|
||
2. Lane B's requested `velocityAt` out-param overload was NOT taken: Lane D
|
||
already returns a reused per-collider scratch array (no allocation), which
|
||
satisfies the hot-path concern with no contract change.
|
||
|
||
## Cross-lane glue (in `src/main.ts`)
|
||
|
||
- **QuestPositions adapter**: Lane C's nested `QUEST_POS` is mapped to Lane
|
||
D's flat `QuestPositions`; the crossfader slot span is derived from C's
|
||
`MIXER` anchors (centerX ± halfLen, faceTopY−depth+1 … faceTopY−1, z −1…+2)
|
||
so D's slide gate covers exactly the tram volume C carved.
|
||
- **`machines.attachPlayer(player)`** called after the player is built
|
||
(Lane D's added step "6.5") — enables walk-push faders and walk-press plates.
|
||
- **Hotbar**: D's `Hotbar` structurally satisfies E's `HotbarModel`; passed
|
||
directly as `getHotbar`, with `hotbar.onChange(() => hud.refreshHotbar())`.
|
||
- **Input wiring**: LMB hold = mine, RMB = place, E = use, 1–9/wheel = hotbar,
|
||
all gated on pointer lock (matching Lane B's own key gating). Start splash
|
||
click → `audio.init()` + pointer lock; resume click → re-lock only.
|
||
- **Fixed-step loop**: machines → player → interaction → fx at `FIXED_DT`,
|
||
with `MAX_SUBSTEPS` catch-up and an accumulator clamp so a backgrounded tab
|
||
doesn't spiral; `audio.updateListener` + `chunks.update()` + render per frame.
|
||
- Debug handle `window.TURNCRAFT` (world/player/machines/quest/hotbar/audio/
|
||
fx/hud/chunks/interaction) — used by the smoke tests, harmless in play.
|
||
|
||
## Lane-file adjustments (documented per CONTRACTS "integrator resolves")
|
||
|
||
- `src/machines/platter.ts` — platter body now spans the well floor to 1
|
||
below the vinyl (visuals) and its collider spans well floor → `Y_RECORD_TOP`
|
||
so the spinning body also pushes the player out of the well's 2-voxel gap
|
||
ring (which is now a real, intentional fall-in hazard).
|
||
- `src/fx/layout.ts` — VU overlay sprites aligned to Lane C's physical LED
|
||
towers (x = mixer minX+18 / maxX−18, 12 segments, in front of the open
|
||
casing face) per Lane E's friction note #5.
|
||
- `src/interact/interaction.ts` — per-material break times (soft 0.12 s,
|
||
glass 0.25 s, default 0.4 s). The crossfader jam is ~240 dust blocks; at a
|
||
flat 0.4 s it was a 96-second chore.
|
||
- `docs/DESIGN.md` — elevation table updated for the Y_RECORD_TOP change.
|
||
|
||
## Deviations accepted as-is
|
||
|
||
- **45 speed available pre-win** (D's reading; DESIGN's "45 unlocked at win"
|
||
treated as flavor). `Platter.unlocked45` exists if we ever gate it.
|
||
- **`fader_cross` does not drive audio** (E maps pitch + channel digits only);
|
||
crossfader is quest/physical-only in v1.
|
||
- **Both deck pitch faders drive the one global mix pitch** (E has a single
|
||
transport; fine until per-deck stems exist).
|
||
- **Tonearm pedestal (C's voxels) vs D's arm pivot** are ~11 voxels apart —
|
||
cosmetic misalignment, queued for polish, gameplay unaffected.
|
||
|
||
## Verified at integration (live browser, real code paths)
|
||
|
||
- Boot: booth builds + meshes in ~670 ms dev / 46 modules build in 0.5 s;
|
||
fillBox fast path ENABLED; **120 fps**; zero console errors all session.
|
||
- Ride: standing on the record at 33 → clean circle, r drift 20.00→20.02 over
|
||
4 s, y = 81 exactly, spin-up ramp visible; at 45 near the rim → 10.7 v/s
|
||
(= ω×r), jump lands back on the moving disc.
|
||
- Mining: real DDA aim → dust breaks into hotbar; crossfader stays gated
|
||
while dust remains.
|
||
- Quest chain: stems stack 0→5 per `signal:repair`, power switch arms exactly
|
||
after the 4th repair, real button press → `game:win` once, both platters
|
||
auto-start, HUD banner + tracker 5/5, AudioContext running.
|
||
- The platter-well gap ring behaves as a trench (collider pushes, no clipping).
|
||
|
||
## Concept-art pass (post-integration, from John's Gemini mockup)
|
||
|
||
- **Terraced records**: the flat disc became a stepped "groove amphitheater" —
|
||
3 vinyl tiers rising 1 voxel each to the label plateau, then a 4-tier
|
||
stepped spindle tower with an amber lamp (all in `TIERS`, `platter.ts`).
|
||
Each tier is its own stacked kinematic cylinder; you walk/spiral up a
|
||
SPINNING staircase. Tonearm raised (`HEAD_Y` +2.6) and `R_INNER` pulled to
|
||
16 so the needle clears the terraces and never hits the tower.
|
||
- **Player physics upgrades this required** (`PlayerController.ts`):
|
||
cylinder contacts now resolve by minimum penetration (up vs radial), which
|
||
fixes a latent slingshot bug (feet dipping below a disc's top while deep
|
||
inside its footprint used to teleport the player radially to the rim);
|
||
1-voxel collider lips auto-step like voxel ledges; cylinder tops have a
|
||
half-foot radius grace so you can stand on rims.
|
||
- **Well seam**: the platter well's outer ring was a 7-deep inescapable
|
||
trench; floor raised to 1 below the plinth top (worldgen) — now a Technics
|
||
seam you step out of.
|
||
- **Room feel**: plywood ceiling with six recessed amber lamp panels
|
||
(worldgen) + matching warm PointLights (main.ts), warmer/brighter
|
||
hemi/ambient/fog (renderer.ts).
|
||
- **Mixer color pop**: knob caps get a deterministic palette scatter (red/
|
||
white/gold/LED) in `buildMixer`. **Rim crumble**: vinyl chips/dust/screws
|
||
scattered around the well mouths in `buildDeck`.
|
||
- Dev nicety: `window.TURNCRAFT_CINE = { pos, look }` detaches the camera
|
||
for screenshots/trailers; `window.TURNCRAFT` exposes camera/render too.
|
||
- Verified: walk-in from the rim spirals up to the label plateau at 33 rpm
|
||
(fighting the spin is intentional physics — stop the deck for an easy
|
||
climb); tower fully climbable (83→87 by walking); seam escape 1-step;
|
||
121 fps with ceiling + lights; quest/win chain re-verified end-to-end.
|
||
|
||
## Not yet done (deploy phase)
|
||
|
||
Run `/ship-check` before exposing anything publicly; deploy per deploy-map
|
||
conventions (static `dist/` — 156 KB gzipped). Cloudflare/host wiring is a
|
||
separate step, to be done with the token holder present.
|