destroyulator/LANES/LANE3-web-smash-toy.md
Monster Robot Party c03bb85c9f Add parallel-lane execution specs for Opus 4.8
LANES/PLAN.md         — verdict, GODVERSE pipeline architecture, shared contracts, 3GOD security note
LANES/LANE1-*.md      — Godot: grab/slide/smash record ritual + find-the-misfiled-disc mode (owns game/)
LANES/LANE2-*.md      — meshgod cell-fracture stage + Destroyulator prop batch -> 3GOD (owns ~/meshgod)
LANES/LANE3-*.md      — thriftgod-based web smash toy, Rapier physics, 3GOD props (owns web/)
LANES/KICKOFF.md      — per-lane opening prompts + collision-safety rules

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 16:47:47 +10:00

76 lines
4.7 KiB
Markdown

# LANE 3 — Web smash toy: thriftgod-based FP demo, 3GOD props, Rapier physics
**Owns:** `web/` (new dir in the destroyulator monorepo). **For:** an Opus 4.8 session.
**Runs on:** M3 Ultra (serve locally); deploy target later is the digalot.fyi VPS.
## Objective
A **shareable, instant-link web toy** — not a port of the Godot game, a different product in
the same universe. Walk around a room first-person, grab records, and smash the place, in the
browser. Built on thriftgod's proven FP-interior code, physics via Rapier (WASM), props pulled
live from the 3GOD depot. This is the streamer-bait / "try it in one click" front door.
## What already exists (study, then fork — DON'T edit thriftgod)
- `~/Documents/thriftgod` (local) — LIVE Three.js first-person game (digalot.fyi). Copy the
patterns, don't modify it. Reusable pieces:
- `web/index.html` (~129k) — pointer-lock WASD FP controller, seeded procedural interior,
3D pickup/inspect interaction, **GLTFLoader + DRACOLoader** wiring (~line 1233, fixture
kind `'glb'`). This is your movement + loading foundation.
- `web/dig.js`, `web/cards.js` — interaction + item UI patterns.
- Three.js r0.175 via unpkg importmap, no build step (keep this — zero-tooling is a feature).
- `~/Documents/Destroyulater/game/scripts/dig.js` reference (recordgod) — procedural Web Audio
"fwip/thunk"; reuse the synth approach for smash SFX (mirror Godot's `Juice.gd` material voices).
- 3GOD depot: `https://digalot.fyi/3god`, `GET /api/list` → shelf JSON; GLBs by slug. **Read-only.**
## Deliverables (all under `web/`)
### 1. `web/index.html` + `web/main.js` — the app
- Fork thriftgod's pointer-lock FP controller + a simple room (floor, walls, a couple of racks).
- Load props from 3GOD by slug via GLTFLoader (start with `record`, `crate`, `milk-crate-stack`,
`vintage-cash-register`, and the Lane-2 printer once it lands). Fallback to a local
`web/assets/` copy if the depot is unreachable, so the demo never hard-fails offline.
### 2. `web/physics.js` — Rapier (WASM) destruction
- Use `@dimforge/rapier3d-compat` (or `-simd`) via CDN/ESM. One rigid body per smashable prop,
colliders auto-sized from the GLB bounding box (mirror Godot's `_body_local_aabb` approach).
- **Support-graph cascade** — port the Godot idea: frozen (fixed) bodies hold up dynamic ones;
destroying a support switches its dependents to dynamic. Same "knock the legs, it pancakes" feel.
- **Pre-fractured swap:** when a prop has a `.fractured.glb` (Lane 2 contract #2), on smash hide
the intact mesh and spawn each `chunk_*` as a short-lived dynamic body inheriting velocity.
Brittle kinds (vinyl/glass) also shatter on hard impact. Pool + despawn debris (JS GC is the
ceiling — cap active bodies, sleep/remove settled ones).
### 3. `web/juice.js` — feel layer
- Screenshake (camera trauma), a brief hitstop (scale the physics step / freeze a few frames),
per-material particle bursts (Points or instanced quads), and **procedural Web Audio** smash
SFX per material (wood crunch, cardboard rip, vinyl crack+warble, glass tinkle, steel ring) —
same recipe as Godot `Juice.gd::_synth`. Combo counter in the DOM HUD.
### 4. Record ritual (lite) + share hook
- A simplified version of Lane 1's ritual: click a record to pull it (drag to slide the disc
out), then throw/smash. Keep it snappy for web.
- A "share your mess" button: screenshot the canvas (`toDataURL`) + a smash-count caption.
## Serve + acceptance
```sh
cd web && python3 -m http.server 8099 # then open http://localhost:8099
```
- Loads with no console errors; FP movement + pointer lock work; at least one 3GOD prop loads
and smashes with particles + sound; holds ~60fps with a roomful of props on the M3 (test in
Chrome AND Safari — Safari is the weakest WASM/WebGPU target).
- Cross-origin note: fetching GLBs from digalot.fyi needs CORS on 3GOD; if blocked, mirror the
handful of props into `web/assets/` and load locally for now (flag it for the depot owner).
## Gotchas
- Don't import a bundler unless necessary — thriftgod's no-build importmap approach is the norm here.
- Rapier is WASM: `await RAPIER.init()` before creating the world; keep physics off the render
thread if it janks (Web Worker + SharedArrayBuffer needs COOP/COEP headers — only if needed).
- The 3GOD SSRF/open-mode issue (see PLAN.md) is a WRITE-side problem; this lane only reads, so
it's unaffected — but don't add any write calls to the depot from the web client.
## Definition of done
A playable `web/` smash toy: walk, grab a record, smash props (fractured where available) with
juice, in Chrome + Safari, props from 3GOD (or local mirror). Committed + pushed to `origin main`
under `web/`. Post a localhost screenshot/gif.