TURNCRAFT/docs/INTEGRATION_NOTES.md
jing f88be60e60 Integrate all five lanes: wire main.ts, fix record height contract, verify live
- 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>
2026-07-13 21:11:10 +10:00

83 lines
4.7 KiB
Markdown
Raw 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.

# 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, faceTopYdepth+1 … faceTopY1, 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, 19/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 / maxX18, 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.