Commit Graph

4 Commits

Author SHA1 Message Date
61757d24bc LANE6: rigged FPS viewmodel, weapon loadout + material matrix, 4 HUD styles
Hands/POV
- Cut a real first-person arms rig out of the GODVERSE modular character kit
  (tools/gen_fps_arms.py): ch01 hands + per-side sleeves on the full 65-bone
  mixamorig skeleton, so all 20 finger bones per hand are poseable at runtime.
  Textures shrunk to 1k; 4.2 MB.
- ViewModel.gd instances that rig ONCE PER HAND and places each instance so its
  own hand bone lands on the grip — no IK. Grip orientation is measured off the
  rig at load (pinky->index knuckle = bore axis, elbow->hand = forearm dir), so
  it survives re-tuning grip_rest_rot instead of needing new euler angles.
- Motion layers: look-sway with spring-back, walk bob scaled by speed and weapon
  heft, idle breathe, landing dip, weapon lower/raise on swap.
- Sleeve material overridden (donor asset is a fantasy leather bracer); hand
  material forced non-metallic (its spec/gloss maps rendered skin as bronze).

Weapons
- Weapon.gd replaces MeleeAttack: 6 weapons, 4 swing archetypes, and the
  weapon-vs-material matrix from the founding chat.
- Smashable moves from binary hits_to_break to hp/toughness, giving three
  outcomes: break, dent, or futile (dead clank, no score, HUD nudge). The box
  cutter genuinely shreds cardboard and genuinely cannot hurt a filing cabinet.
- The hit lands at Weapon.contact THROUGH the swing, not on the click — that
  delay is most of why the sledge feels different from the cutter.
- Slots on 1-6 / wheel / Q; game modes moved to M, HUD cycle to H.

HUD
- Hud.gd: Arcade, Minimal, Work Order (a corporate destruction docket that fills
  in line items) and Dev, over one shared data feed. Scoring + combo multipliers.

Dev harness (not shipped)
- macOS screen-recording perms aren't available to the CLI, so the game records
  itself: dev/demo.tscn + DemoDriver.gd drive a scripted tour for --write-movie,
  and dev/probe_*.gd print rig/scale/placement numbers.

Fix: tools/gen_viewmodel.py box() scaled by size/2 on top of primitive_cube_add's
already-unit side length, halving every box — which detached the bat's blade.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 16:34:00 +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
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
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