- src/main.ts: full wiring per docs/INTEGRATION.md (renderer/world/booth/ chunks/machines/player/interaction/audio/fx/hud + fixed-step loop), QuestPositions adapter (Lane C nested -> Lane D flat), attachPlayer step, pointer-lock-gated input, debug handle for smoke tests. - core/constants: Y_RECORD_TOP 85 -> 81 (record was an unclimbable 5-voxel cliff; now 1 proud of the plinth, auto-steppable) + PLATTER.wellDepth. - machines/platter: body + collider now fill Lane C's well down to y=74. - fx/layout: VU sprites aligned to Lane C's physical LED towers. - interact: per-material break times (dust 0.12s) so the crossfader jam isn't a 96-second mine. - docs/INTEGRATION_NOTES.md: every glue decision + live verification results (120 fps, ride/mine/quest/win all green, zero console errors). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
83 lines
4.7 KiB
Markdown
83 lines
4.7 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).
|
||
|
||
## 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.
|