Commit Graph

12 Commits

Author SHA1 Message Date
9dd6824c14 LANE4 (web): catalog Lane 2 batch, printer boss, 404 fix, drag-to-look
Consume Lane 2's props + close the review gaps in the browser toy.

props.js: all 16 depot slugs added to CATALOG (material/kind per prop; printer is the
boss). loadFractured() now (a) caches its result per id — including the null miss — so a
prop with no fractured sibling stops re-fetching + 404-ing on EVERY spawn (the record.
fractured.glb spam), and (b) returns the real chunk container (the fractured_root wrapper
Blender exports), so physics.js's direct-children chunk swap actually fires.

main.js: loadHeroProps() places the printer BOSS + office set dressing (desk, crt-monitor,
filing-cabinet, water-cooler) with their fractured templates. The boss soaks 4 hits then
bursts into its 16 GLB chunks (kept non-shatterable so a topple can't break it early).

Pointer-lock fallback (shareability fix): if the lock request is refused — iframes/embedded
hosts, where the toy used to dead-end on the title screen — we fall back to DRAG-TO-LOOK
(hold-drag rotates, a tap still smashes) so the shareable link always plays.

Assets: office-printer / crt-monitor / filing-cabinet mirrored into web/assets/ (offline
fallback); record/crate/rack.fractured.glb generated + mirrored so the record ritual smashes
into real chunks. The three store fractured GLBs were also pushed to the 3GOD shelf.

Verified in-browser via ?debug: printer aimSmash→"printer" then 16 chunks; thrown record →
8 chunks; debris drains 16→0; record.fractured.glb serves 200 (no 404); drag-look rotates
the camera when pointer lock is unavailable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:28:25 +10:00
51210215e2 LANE4 (Godot): real fractured-chunk destruction + printer boss
Consume Lane 2's pre-fractured props in the Godot game. Smashable.shatter() now prefers
a <name>.fractured.glb sibling: it instances the fractured template and turns each
chunk_00…chunk_NN mesh into its own debris RigidBody3D that inherits the intact body's
velocity + the smash impulse (box collider per chunk, debris group so the HUD count +
Juice keep working), falling back to primitive shards when no fractured sibling exists.
_glb_piece auto-wires the sibling, so every GLB prop upgrades for free.

Smashable gains hits_to_break + is_boss: the office PRINTER is the level boss — it sits on
a desk, soaks 5 hits (rocking with each), then bursts in a bigger juice cloud into its 16
GLB chunks. Six more Lane 2 props (crt-monitor, filing-cabinet, water-cooler, cardboard-box,
turntable, office-desk) are scattered as smashable furniture; the store crate/rack also pick
up real 8-chunk shatter from their mirrored fractured GLBs.

Assets pulled into game/assets/store/ (intact + .fractured.glb): office-printer, office-desk,
crt-monitor, filing-cabinet, water-cooler, cardboard-box, turntable + record/crate/rack
fractured siblings (generated via meshgod's Voronoi fracture CLI).

Verified headless: smoke test clean (0 script errors), printer boss soaks 4 hits then
spawns 16 chunk bodies, a crate spawns 8 — both real GLB chunks, not primitive shards.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:27:50 +10:00
1d282d4b3b LANE4 spec: integrate Lane 2's fractured props into game/ + web/, pointer-lock fallback
Review of the three lanes (2026-07-14): all shipped and verified — Lane 1 smoke test
clean, Lane 2's 16 props (intact+fractured) live on 3GOD with the chunk_* contract,
Lane 3 play-tested via its ?debug handle (smash, rack cascade, record ritual, debris
pool all work). LANE4 closes the integration gap the parallel run left open, plus two
review findings: record.fractured.glb 404 spam and no pointer-lock fallback in
embedded browsers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 21:48:17 +10:00
ca8b22c3c0 Lane 3: browser smash toy in web/ — FP record store, Rapier destruction, 3GOD props
A shareable one-click web toy (not a port of the Godot game): walk a record store
first-person, pull a record, and wreck the place in the browser. Built on
thriftgod's pointer-lock FP-interior patterns, zero build step (three r0.175 +
@dimforge/rapier3d-compat over an importmap).

- physics.js: Rapier WASM world, one body per prop, support-graph cascade
  (smash a rack → its crates pancake), pre-fractured swap (chunk_* bodies) with
  generative-shard fallback until Lane 2 ships fractured GLBs, capped debris pool.
- props.js: GLTFLoader/DRACOLoader; loads props live from the 3GOD depot
  (/a/<file>, CORS-open) with a local web/assets/ mirror fallback so it never
  hard-fails offline. Read-only against the depot.
- juice.js: camera-trauma screenshake, hitstop, per-material particle bursts and
  procedural Web-Audio smash voices (wood/cardboard/vinyl/glass/steel), combo HUD.
- main.js: FP controller, record-store room, grab/smash raycasting, record ritual
  (pull → held → throw → shatter), "share your mess" canvas screenshot.

Assets mirrored offline: record/crate/rack (from the Godot lane) + cashbot/
council-bin (from 3GOD). Verified in-browser: props load, smashing spawns shards +
particles + combo, rack cascade pancakes its crates, record ritual and share work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 20:14:32 +10:00
ad0ca62f3e LANE1: record-destruction ritual + Find-the-Misfiled-Disc mode
Turn records from one-hit props into the store's signature dexterity ritual,
and add the first game mode on top of it.

Record.gd (class_name Record extends Smashable): a cardboard SLEEVE that hides a
vinyl DISC. Splits record.glb's Sleeve_Mesh / Vinyl_Disc nodes at runtime — the
sleeve stays on the body, the disc becomes its own frozen-kinematic vinyl Smashable
that follows the sleeve until freed. State machine IN_CRATE -> HELD -> EXTRACTING
-> DISC_FREE. set_extract() slides the disc up and out of the mouth; release_disc()
arms it as a live brittle throwable; shatter() spills the disc first so brute-force
smashing still spills it. Genre tints on disc label / sleeve spine make a misfiled
disc read at a glance.

GrabController.gd (under Player): hold point on the camera, E grabs the Record under
the crosshair (fat-sphere query, Record-filtered), horizontal mouse drag pulls the
disc (~600px = full), LMB throws the freed disc then trashes the empty sleeve, G
drops. On-screen pull meter.

GameMode.gd (class_name GameMode, owned by Main): FreePlay (default) + FindMisfiled —
plants exactly one disc_genre != sleeve_genre, 60s timer, win by extracting it and
pressing F while holding it, scores the mess (bodies smashed) + records disturbed.
Prints the plant on start.

Wiring: Player creates the GrabController and routes E/G/LMB/drag (yaw suspended
mid-pull, Esc untouched); Main._build_rack spawns Record instances on the crates
(keeps supports cascade + sleeve-art skinning + per-record genres), forwards smashes
to the mode, and adds keys 1/2 (modes) and F (report).

Headless smoke test clean (0 script errors / 0 warnings, 15 records); a runtime
harness exercised grab/extract/throw/drop/shatter-spill/mode-switch/reset — all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:40:52 +10:00
d0cbe7267d Fix stale dig.js path in LANE3 spec (lives in thriftgod/web, not game/scripts)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 18:13:48 +10:00
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
5852322606 Restructure into monorepo: game/ is the Godot lane
Repo root moves up from game/ to the project folder. Lanes live as top-level
dirs (game/ now, web/ planned); LANES/ will hold parallel-session specs.
3D-STORE asset vault stays out of git. History preserved as renames.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 15:33:13 +10:00
b78ea04183 Records wear real sleeves: Nano Banana art atlases + UV-tile skinning
- assets/art/sleeves_{a,b}.jpg: two 3x3 sheets of ORIGINAL fictional album
  covers (18 total — dub, techno, metal, jazz, punk, synthwave, hip-hop,
  psych, ambient, northern soul, krautrock, disco, white-label, bossa,
  UKG, country, noise) generated with Gemini gemini-3-pro-image. No real
  artists/albums — copyright-clean destructible content.
- assets/art/keyart.jpg: DESTROYULATOR title key art ("CLOCK OUT. SMASH
  EVERYTHING.") for a future title screen.
- Main.gd _skin_record(): records duplicate their M_Sleeve_Front/Back
  materials and window one random atlas tile via uv1_scale/uv1_offset —
  one texture in VRAM serves nine covers, every record looks different.
- Verified headless: boots clean, "[art] records skinned: 15" (all of
  them). The two dummy-renderer "material is null" prints are headless-
  only (override materials have no RID in the dummy backend). Eyeball a
  sleeve in the editor — if the art renders rotated, flip uv1 here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:24:11 +10:00
7c88e8371d Bring in real store art: Monster Robot Party racks, crates, records
- game/assets/store/{rack,crate,record}.glb from the 3D-STORE library
- _glb_piece(): instances a GLB as a Smashable's visual, auto-fits a box
  collider to the mesh AABB, and drops it flush to the floor (no hardcoded dims)
- _build_rack now assembles two smashable racks + crates of records on the floor
- cascade preserved: smashing a crate spills the records stacked on it

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 00:39:46 +10:00
cc5b118d71 Add juice layer: hitstop, screenshake, particles, procedural audio, combos
Juice.gd — the feel system, driven off Smashable.smashed (purely additive):
- Hitstop freeze-frame on every impact (time_scale dip, released in real time)
- Screenshake with quadratic trauma falloff, scaled by shard count
- Per-material GPU particle bursts, colored from the PROFILES table
- Procedural impact audio synthesized in code per material — no sound files,
  the dig.js trick: wood crunch, cardboard rip, vinyl crack+warble, glass tinkle, steel ring
- Combo counter on the HUD

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 00:29:17 +10:00
a8b735f79e Destroyulator prototype: first-person cascade smasher (Godot 4.7)
Mac-native (Apple Silicon / Metal), Jolt physics.
- First-person controller + semi-opaque viewmodel hands
- Punch (L-click) / kick (R-click) via a swappable MeleeAttack resource
- Structural support-graph cascade: knock the legs -> the rack pancakes
- Brittle vinyl records shatter on hard impact
- Day-0 stress gate (B: rain 500) — holds 60fps on the M3 Ultra

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 00:25:35 +10:00