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>
4.7 KiB
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.jsreference (recordgod) — procedural Web Audio "fwip/thunk"; reuse the synth approach for smash SFX (mirror Godot'sJuice.gdmaterial 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 localweb/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_aabbapproach). - 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 eachchunk_*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
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.