destroyulator/game
Monster Robot Party e5f4e8c5e4 LANE7: the Gauntlet, four modes, two more provocations, and ambient attrition
THE GAUNTLET (Gauntlet.gd + Cabinet.gd)
Five identical cabinets, each with its alphabetical range on a Label3D. The brief names
a CLIENT, never a cabinet, so working out that HENDERSON lives in F-J is the puzzle —
no waypoint, nothing glows. Destruction is granular on purpose: pull a drawer, it
slides out on a spring and goes live, and the folders inside become individual
smashables. Doing that by hand inside the clock isn't really possible.

The perfect tool: every site hides a SHREDDER that eats a whole open drawer at once,
and the game never says so. Noticing it and working out what it's for IS the level.
Getting it wrong isn't fatal, just slow — the right shape for a secret, since it
rewards the observant without hard-failing everyone else.

Each site nominates its own records area in its spec. Building the bank 3.4 m in front
of wherever the player happened to be standing put it through walls.

MODES (Modes.gd, M cycles)
  CUBICLE HELL       the main loop
  THE GAUNTLET       above
  TOTAL DESTRUCTION  no job, no pay, clear the site, scored on time
  AGAINST THE CLOCK  fixed timer, maximise damage VALUE — the exact inverse of Cubicle
                     Hell, where expensive things become the goal rather than the
                     mistake. Same level, opposite instinct.
Entering a mode arms only what that mode needs; Cubicle Hell and the Gauntlet are
mutually exclusive, because you cannot be doing your job and shredding the Henderson
file at the same time.

TWO MORE PROVOCATIONS (Tasks.gd)
  STAPLES     SPACE lifts a staple, then it must be pulled the way it's bent — and it's
              bent differently each time. Dither and the sheet tears, bundle reprints.
  GUILLOTINE  align to a mark and cut. The guide has a PERMANENT offset and nothing on
              screen admits it. Once you work out the error it's easy, which is the
              joke: you have to learn to distrust the equipment.
Desks now alternate spreadsheet/staples so "a desk" isn't always the same minigame.

AMBIENCE (Ambience.gd) — the attrition you can't play around. The tube above your desk
flickers, and actually flickers the real lights. Fish in the microwave. A phone ringing
four desks away. Reply-all, forty-one recipients, "thanks!". Small periodic ticks with
no interaction at all; it's what makes the room hostile rather than merely beige.

Fixes: the payslip was rendering over the Gauntlet (it belongs to Cubicle Hell, and only
once the shift has actually ended); gauntlet drawer reach was 2.0 m when the true
distance from standing-at-a-cabinet to a bottom drawer is over 2 m.

dev/probe_gauntlet.gd drives a whole run headlessly — mode switch, labels, open every
drawer, shred, win — because that catches the failure that matters: a run you can't
finish because the files never become destroyable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 18:12:20 +10:00
..
assets LANE7: four workplaces, built from data 2026-07-31 17:58:41 +10:00
dev LANE7: the Gauntlet, four modes, two more provocations, and ambient attrition 2026-07-31 18:12:20 +10:00
scripts LANE7: the Gauntlet, four modes, two more provocations, and ambient attrition 2026-07-31 18:12:20 +10:00
.gitignore Restructure into monorepo: game/ is the Godot lane 2026-07-14 15:33:13 +10:00
main.tscn Restructure into monorepo: game/ is the Godot lane 2026-07-14 15:33:13 +10:00
project.godot Restructure into monorepo: game/ is the Godot lane 2026-07-14 15:33:13 +10:00
README.md LANE7: the Gauntlet, four modes, two more provocations, and ambient attrition 2026-07-31 18:12:20 +10:00

Destroyulator — the game

Mac-first (Apple Silicon / Metal), Godot 4.7, Jolt physics.

Run it

Editor: open /Applications/Godot.app, import this folder (game/), press F5 / ▶.

CLI:

/Applications/Godot.app/Contents/MacOS/Godot --path /Users/m3ultra/Documents/Destroyulater/game

Controls

Input Does
WASD / Space move / jump
mouse look (Esc releases the cursor, click recaptures)
LMB swing the equipped weapon
16 · wheel · Q pick a weapon · cycle · swap to previous
H cycle HUD style (Arcade / Minimal / Work Order / Dev)
M cycle game mode (Cubicle Hell / Gauntlet / Total Destruction / Against the Clock)
L cycle site (Scranton / Pawnee / The Incubator / Sub-level 4)
G restart a Gauntlet run
F report the disc in hand (Find-the-Misfiled-Disc)
E work at the station you're standing at (locks you in place); otherwise grab a record
drag ←→ · LMB · G with a record held: slide the disc out · throw it · drop
digits · arrows · ENTER while working: type · move cell · commit
B · R rain 500 bodies (stress gate) · reset the office

The four sites

scripts/Floorplan.gd builds a workplace from a data spec; scripts/Levels.gd holds four of them. A site is a Dictionary — bounds, palette, walls with doors and glazing, window runs, ceiling style, light grid and style, slabs, props, desk clusters, chairs, smashables, gauntlet records-area and spawn — so a new one is authorable in minutes and a generator can later emit the same structure.

palette / light what makes it different
SCRANTON BRANCH magnolia, grey carpet, troffers the baseline office
PAWNEE CITY HALL civic beige, blue-grey a public counter, pinboards, over-partitioned
THE INCUBATOR timber, white, 3 m, pendants nobody has a desk; they work at a dining table
SUB-LEVEL 4 concrete, green strip lights no windows, exposed services, a wall of servers

dev/probe_levels.gd builds every one and reports residual motion after a full second. All four must read 0.00 m/s.

The four modes

scripts/Modes.gd, cycled with M.

  • CUBICLE HELL — the main one, below.
  • THE GAUNTLETscripts/Gauntlet.gd + scripts/Cabinet.gd. Five identical cabinets, each labelled with an alphabetical range. The brief names a client, never a cabinet, so working out that HENDERSON lives in FJ is the puzzle — nothing glows. Destruction is granular: pull a drawer, it slides out and goes live, and the folders inside become individual smashables. Doing that by hand inside the clock isn't really possible — every site hides a shredder that eats a whole open drawer at once, and the game never says so. Noticing it is the level.
  • TOTAL DESTRUCTION — no job, no pay. Clear the whole site, scored on time.
  • AGAINST THE CLOCK — fixed timer, maximise damage value. The exact inverse of Cubicle Hell: here the expensive things are the goal rather than the mistake.

CUBICLE HELL

The mode the game is about. See ../LANES/LANE7-cubicle-hell.md for the full design.

Rage.gd is the tilt meter: work provokes it, clean work drains it slightly, and at 100% you SNAP into a forced destruction window that stalls if you stop destroying. RageOverlay.gd is the blood vessel — a vignette that closes in, procedural veins that creep further into frame, and a heartbeat that goes 62 → 172 BPM. All of it generated in code; no textures, no shader files, no audio assets.

Tasks.gd is the job — four stations, each with one designed way of wasting your time:

  • SPREADSHEET — the selected cell silently drifts one cell partway through entry. No sound, no animation. Commit without noticing and the figure is in the wrong cell.
  • PHOTOCOPIER — jams, and wants the right tray out of 1, 2, 2A, 3, 3B.
  • STAPLES — SPACE lifts a staple, then it must be pulled the way it's bent. Dither and the sheet tears and the bundle reprints.
  • GUILLOTINE — align to a mark and cut. The guide has a permanent offset and nothing on screen admits it; you have to learn to distrust the equipment.

Ambience.gd is the attrition you can't play around: the tube above your desk flickers (and actually flickers, on the real lights), someone puts fish in the microwave, a phone rings four desks away, reply-all to forty-one recipients. No interaction, just a periodic tick on the meter — it's what makes the room hostile rather than merely beige.

CubicleHell.gd scores it as a payslip: wages damages. Rage drains a flat amount per object but each object bills at its own value, so the meltdown decision is smash a lot of cheap things fast versus one expensive swing.

The weapon-vs-material matrix

This is the decision the game is built on. A swing deals Weapon.power × Weapon.vs[material] against that material's hp, and there are three outcomes: it breaks, it dents (knockback + a chip of damage), or it's futile — a dead clank, no score, no combo, and a HUD nudge to switch tools.

cardboard paper vinyl glass wood steel
Bare Hands ok good ok ok poor useless
Box Cutter shreds shreds good poor useless useless
Cricket Bat good poor great great ok poor
Crowbar ok poor ok good good great
Sledgehammer ok poor ok great great great
Fire Extinguisher ok poor ok great good good

Tuned in one place: scripts/Weapon.gd (vs tables) and scripts/Smashable.gd (PROFILES[kind].hp). The office printer is the level boss — steel at toughness_scale = 5.0, so it's a real fight with anything but the sledge.

Weapons also differ in when they connect, not just how hard: the hit lands at Weapon.contact through the swing animation, so the sledgehammer commits late and heavy while the box cutter is near-instant.

The viewmodel

scripts/ViewModel.gd. Real rigged hands (mixamorig, all 20 finger bones per hand) holding real weapon meshes.

The arms rig is instanced once per hand and each instance is placed so its own hand bone lands on the grip — no IK solver. That works because in first person you only ever see forearm and hand. Placement solves two aims at once: the fist's bore lines up with the weapon shaft, and the forearm runs back toward where that shoulder would be. Both directions are measured off the rig at load (pinky-knuckle → index-knuckle for the bore, elbow → hand for the forearm), so the grip survives re-tuning grip_rest_rot instead of needing a fresh set of hand-authored euler angles.

Motion is layered on one node: look-sway with spring-back, walk bob scaled by speed and weapon heft, idle breathing, landing dip, and a keyframed swing arc per archetype (overhead / horizontal / jab / thrust).

Assets

Path Source
assets/viewmodel/fps_arms.glb tools/gen_fps_arms.py — cut from the GODVERSE modular character kit
assets/viewmodel/{bat,sledge,crowbar,cutter,extinguisher}.glb tools/gen_viewmodel.py — procedural, grip at origin, shaft +Y
assets/store/*.glb + *.fractured.glb Lane 2 prop batch; the fractured sibling drives real chunk destruction
assets/art/sleeves_*.jpg 3×3 sheets of generated cover art, windowed per record via uv1 offset

Regenerate either set with:

/Applications/Blender.app/Contents/MacOS/Blender --background --python tools/gen_viewmodel.py -- --render

Dev harness

dev/ is not shipped. Because macOS screen-recording permission isn't available to the CLI, the game records itself:

Godot --path game --resolution 1280x720 --write-movie /tmp/cap.avi --quit-after 2250 dev/demo.tscn

dev/DemoDriver.gd drives the player through a scripted tour (every weapon, the material matrix, the boss, all four HUDs) so a change can be eyeballed frame by frame without a human at the keyboard. dev/probe_*.gd print rig/scale/placement numbers — renders are too coarse to tell a 5 cm error from a 50 cm one.

Smoke test before committing

/Applications/Godot.app/Contents/MacOS/Godot --headless --path game --quit-after 300

Zero script errors required. After adding any class_name script, run Godot --path game --editor --quit first — headless Godot won't rescan a stale class cache.

The level

scripts/Office.gd builds LEVEL 01: an open-plan office after the Dunder Mifflin floor plan — bullpen of facing desk pairs behind cubicle partitions, reception, a glass-walled manager's office, conference room, break room with vending machines, a copier alcove for the printer boss, and a warehouse roller door. Drop ceiling, fluorescent troffers (which are the actual light sources), magnolia walls, grey carpet, a window wall with blinds.

Office owns the shell and static fittings; Main._populate() owns everything smashable, and asks Office where things go (desk_spots(), chair_spots(), copier_spot()). Walls, desks and counters are boxes built in code because they are boxes; chairs, vending machines, the microwave and the plant come from tools/gen_office_props.py, because a box reads as obviously wrong for those.

The spawn guard

Placing ~40 props by formula means something will eventually spawn a few centimetres inside something else, and Jolt's depenetration is not gentle — a chair overlapping a desk left the building at 500 m/s on frame one, knocking over the furniture on its way.

Main._physics_process() speed-limits dynamic bodies for the first 0.75 s: enough for a real overlap to push apart calmly, far too little to launch anything. Every offender is named once in a warning with the position it was placed at, so the underlying overlap stays visible and fixable rather than silently papered over.

Verify a level is genuinely at rest with:

/Applications/Godot.app/Contents/MacOS/Godot --headless --path game --quit-after 300 dev/demo.tscn

The demo's first act touches nothing and prints total body speed each second. It must read 0.00 m/s, and no [spawn] warnings should appear.