7.9 KiB
7.9 KiB
SPRINT 2 — ASSEMBLY (instructions for Opus 4.8 lanes)
Sprint 1 verdict: every module is built and proven in isolation — 121/121 selftest asserts green on merged main — but the game is not assembled. main.js still drives the M0 placeholder capsule and stub wind. Sprint 2 is one thing: wire the proven modules into one playable storm. Read THREADS.md from your last entry down before starting; the integrator [I] entry lists what changed under you.
Decisions (made — stop waiting on them)
- Lanes run on m3ultra. Lane D's recommendation is adopted: the M1 Ultra
(
johnking@100.91.239.7) is an asset-build box you SSH to; GLBs get committed; the game never needs it at runtime. PLAN3D §0 is amended by this line. - Sail-area problem (B's 70–192 m² finding): fix the yard, not the physics.
Lane A: move p1/p2 in to roughly (−4.5, 5.5) and (4.0, 6.0), add a third post
p3 near (0, 7), and register the trees'
branch_anchor_*empties (E shipped them withrating_hint) as anchors. Target: at least three pickable quads in the 18–45 m² range that can shade the garden bed, verified by a new a.test assert that enumerates quad areas. The huge quads stay possible — the load bars teaching "you cannot span the whole yard" is design working as intended. - Flat-horizontal loophole: Lane C closes it with vertical gust structure. Real gusts aren't horizontal; add a per-gust vertical component (downdraft fraction in storm JSON, default ~0.25 of gust power, validated) so a horizontal plate carries real load. Lane B adds the assert: over 8 directions in storm_02 wind, flat-horizontal peak load ≥ 60% of flat-pitched peak (i.e. no longer a free lunch). Ponding stays out of scope (M4 water spike).
- repair/trim seam: Lane B conforms to Lane D's call sites (D landed first,
duck-typed): add
repair(i)(→ repairCorner with the spare's hw),trim(i, delta)(→ trimCorner) andcornerPos(i) -> Vector3(live world position, fresh vector) to the rig object. Contract entries + b.test asserts. - debris↔sail seam: option (b) — Lane B reads
debris.pieces({x,y,z,vx,vy,vz,r,mass}) insidesail.step()and applies impulses; momentum bookkeeping stays in the one integrator. Lane C freezes thepiecesshape. - House GLB: no re-cut. Lane A reads
fascia_anchor_*positions out ofhouse_yardside_v1.glbat load and places anchors there (data wins over the yard constants). E's 2.80 m fascia replaces the 2.6 m graybox number.
Lane A — assemble the game (this is the sprint)
main.js boot(), in order; keep each step behind a small commit:
- Stub wind →
createWind(storm)—storm_01_gentlefor prep/forecast calm,storm_02_wildnightwhen the storm phase starts. Callwind.setSheltersFromTrees(...)after the yard builds, per C's ask. - Placeholder →
await createPlayer(scene, world, cameraRig, {wind, interact})(async boot; D says same first three args). Delete the placeholder factory. - Sail:
const view = await createSailView(rig); scene.add(view); view.update()per frame afterrig.step(dt, wind, t). B's THREADS entry has the exact shape. createSkyFx({scene, camera, wind, sun, hemi})+unlockAudio()on first input;createDebris({heightAt: world.heightAt, onHitPlayer: player.knockdown}),debris.setModels()frommodels/debris/(glob the dir).- Yard dressing: swap graybox house →
house_yardside_v1.glb(decision 6), shed + shed_table (D's spare pickup), sail posts assail_post_v1.glbrotated aboutrake_pivot, fence set, grass billboards offtextures/grass_atlas.png. - Anchor rework per decision 2.
- HUD: loads in kN (B's units note), per-corner bars vs rating, wind meter +
gust telegraph banner, garden % (wire
rig.coverageOver(world.gardenBed)→ HP → E'splants_full/tattered/deadvisibility swap), phase banner, forecast card (storm JSON summary: peak wind, change time), aftermath screen (garden %, corners lost, budget delta). - Phase machine: forecast (show card, Enter) → prep (rigging UI live, budget
$80, optional timer OFF this sprint) → storm (90 s, storm_02) → aftermath.
Acceptance:
python3 server.py→ rig a sail with the mouse, press Enter, watch storm_02 try to kill it, repair a corner mid-storm, see the aftermath screen. 60 fps during the storm on this box. Selftest stays green after every merge.
Lane B — sail in the world
- Decision 4 API (repair/trim/cornerPos) + asserts.
- Decision 5: consume
debris.piecesin step(); assert momentum is conserved within tolerance on a crate-through-sail scenario. - Prep-phase picking adapter: RiggingSession → clicks. Raycast against Lane A's
anchor markers (A exposes
world.anchorMarkersif you need meshes — agree in THREADS), corner cycling + tension dial + spare purchase, HUD summary line fromsummary(). This unblocks A step 8. - Joint tuning session with C (their THREADS ask): retune cloth ρ against real m/s storms; then re-run the §7 gate against REAL wind (current assert used the stub) — flat cheap rig cascades in storm_02, twisted mixed rig + one repair survives. Log tuned constants in THREADS.
- Small fix:
coverageOver()rays start atheightAt(x,z), not y=0 (your nit). - Decision 3 assert (flat-horizontal no longer dominant) once C lands vertical gusts.
Lane C — weather in the game
- Decision 3: vertical gust component in storm JSON + validator + asserts.
- Decision 5: freeze and document
debris.piecesshape in contracts.js. - Rain must react to the sail: cheap occlusion — sample
rig.coverageOvercells or raycast a handful of drops so the garden visibly stays dry under cloth. (Coordinate the API with B; don't ray-test every drop.) - Storm tuning session with B (see B-4).
- skyfx: verify light restoration on
dispose()inside the real main.js scene — A will call you if teardown flickers phase transitions. - Consider retiring weather_demo.html once main.js hosts the storm — your call, it stops earning its place when the game IS the bench.
Lane D — player in the storm
- After A's step 2 swap: verify controls + camera feel in the real yard (slopes,
fence collision against
world.solids), tune walk/run speeds against yard scale, make gust shove + knockdown fire from real wind and real debris hits. - Wire the spare pickup loop end-to-end: shed_table
pickup_anchor→ carrying →repair(i)consumes it (B's decision-4 API). The §7 "one mid-storm repair" scenario must be playable by hand. - Interaction prompts follow
cornerPos(i)live (flogging corner = moving prompt). - Kill dev_player.html only when the main game covers everything it proves.
Lane E — polish targets (small sprint)
- Wind-reactive foliage handles: verify canopy nodes sway cleanly when A drives
them; add
sway_hintcustom props if A needs per-tree tuning. - Sail cloth texture (512² weave/UV-stripe atlas) so the membrane reads as fabric, + a simple tear decal strip for M3.
- Storm dressing set: wheelie bin (debris,
mass_hint), washing line, garden gnome (collateral scoring bait). One script run, same acceptance as before. - Contact-sheet the assembled yard from A's camera for DESIGN.md.
Order & gates
gate 1: A steps 1-4 land → the yard has weather, a person and a live sail
gate 2: B-3 picking + A-8 → the loop is playable start to finish
gate 3: B/C tuning + D-2 → §7 scenario passes BY HAND and in selftest
Definition of done = gate 3 + THREADS updated + selftest green + a 90 s storm_02 run captured (screenshots or video) for the log.
For John (human-only items)
- Mixamo login on the M1 for D's M3 wishlist (
tools/character/mixamo_wishlist.txt— Climbing Ladder, Turning Key, Digging). Not blocking this sprint. - Two dev servers float around: another session holds :8801; this repo's
launch.json now uses :8809. Kill either freely;
server.py --port Nworks.