The game had no room. Props sat on a grey disc in a black void, which quietly broke
the premise: a game about wrecking your workplace needs a workplace.
Office.gd — LEVEL 01
- Open-plan office laid out after The Office (US) floor plan: bullpen of facing desk
pairs behind cubicle partitions, reception, glass-walled manager's office, conference
room, break room with vending machines, copier alcove, warehouse roller door.
- Drop ceiling on a T-bar grid with fluorescent troffers that ARE the light sources
(the old scene lit an interior with one outdoor directional lamp, which is exactly
why it read as "props on a plane"), window wall with blinds, magnolia and carpet.
- Office owns the shell + static fittings; Main._populate() owns everything smashable
and asks Office where things go. Walls/desks/counters are boxes because they ARE
boxes; chairs, vending machines, microwave and plant come from a new Blender
generator (tools/gen_office_props.py) because a box reads as wrong for those.
The level no longer falls over on its own
- Records were stacked 3 cm apart vertically while being 30 cm TALL, so Jolt resolved
27 cm of interpenetration explosively on frame one and shoved the furniture over
before the player touched anything. They now stand side by side.
- Per-material mass (MASSES): everything was 1 kg, so a thrown record could tip a
filing cabinet.
- Spawn guard: placing ~40 props by formula guarantees an occasional overlap, and
depenetration is violent (a chair left the building at 500 m/s). Dynamic bodies are
speed-limited for 0.75 s, and each offender is named once with the position it was
PLACED at, so the cause stays visible instead of being papered over. It then found
the real bug: bullpen rows 3.6 m apart left the two rows' chairs meeting
back-to-back with 3 cm to spare. Rows are now 4.8 m apart.
- dev/DemoDriver.gd act 0 touches nothing for 5 s and prints total body speed. Now
reads 0.00 m/s with zero spawn warnings.
Two real melee bugs found while testing the level
- The hit test was a SPHERE parked at `reach`, so anything CLOSER than the weapon's
reach fell in front of it and was missed — you could stand against the printer with
a sledgehammer and swing straight through it. Now a capsule swept from the camera.
- Swings started at eye height (1.6 m), so a carton on the floor was ~1.5 m away even
standing over it and short-reach weapons could never touch anything on the ground.
Swings now originate at hand height.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
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>