From 58523226061786a0427ad1e851018d3eadc8e331 Mon Sep 17 00:00:00 2001 From: Monster Robot Party Date: Tue, 14 Jul 2026 15:33:13 +1000 Subject: [PATCH] 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 --- .gitignore | 13 ++-- README.md | 61 ++++++------------ destroyulater.txt | 43 ++++++++++++ game/.gitignore | 9 +++ game/README.md | 49 ++++++++++++++ {assets => game/assets}/art/keyart.jpg | Bin {assets => game/assets}/art/keyart.jpg.import | 0 {assets => game/assets}/art/sleeves_a.jpg | Bin .../assets}/art/sleeves_a.jpg.import | 0 {assets => game/assets}/art/sleeves_b.jpg | Bin .../assets}/art/sleeves_b.jpg.import | 0 {assets => game/assets}/store/crate.glb | Bin .../assets}/store/crate.glb.import | 0 {assets => game/assets}/store/rack.glb | Bin {assets => game/assets}/store/rack.glb.import | 0 {assets => game/assets}/store/record.glb | Bin .../assets}/store/record.glb.import | 0 main.tscn => game/main.tscn | 0 project.godot => game/project.godot | 0 {scripts => game/scripts}/Juice.gd | 0 {scripts => game/scripts}/Juice.gd.uid | 0 {scripts => game/scripts}/Main.gd | 0 {scripts => game/scripts}/Main.gd.uid | 0 {scripts => game/scripts}/MeleeAttack.gd | 0 {scripts => game/scripts}/MeleeAttack.gd.uid | 0 {scripts => game/scripts}/Player.gd | 0 {scripts => game/scripts}/Player.gd.uid | 0 {scripts => game/scripts}/Smashable.gd | 0 {scripts => game/scripts}/Smashable.gd.uid | 0 29 files changed, 126 insertions(+), 49 deletions(-) create mode 100644 destroyulater.txt create mode 100644 game/.gitignore create mode 100644 game/README.md rename {assets => game/assets}/art/keyart.jpg (100%) rename {assets => game/assets}/art/keyart.jpg.import (100%) rename {assets => game/assets}/art/sleeves_a.jpg (100%) rename {assets => game/assets}/art/sleeves_a.jpg.import (100%) rename {assets => game/assets}/art/sleeves_b.jpg (100%) rename {assets => game/assets}/art/sleeves_b.jpg.import (100%) rename {assets => game/assets}/store/crate.glb (100%) rename {assets => game/assets}/store/crate.glb.import (100%) rename {assets => game/assets}/store/rack.glb (100%) rename {assets => game/assets}/store/rack.glb.import (100%) rename {assets => game/assets}/store/record.glb (100%) rename {assets => game/assets}/store/record.glb.import (100%) rename main.tscn => game/main.tscn (100%) rename project.godot => game/project.godot (100%) rename {scripts => game/scripts}/Juice.gd (100%) rename {scripts => game/scripts}/Juice.gd.uid (100%) rename {scripts => game/scripts}/Main.gd (100%) rename {scripts => game/scripts}/Main.gd.uid (100%) rename {scripts => game/scripts}/MeleeAttack.gd (100%) rename {scripts => game/scripts}/MeleeAttack.gd.uid (100%) rename {scripts => game/scripts}/Player.gd (100%) rename {scripts => game/scripts}/Player.gd.uid (100%) rename {scripts => game/scripts}/Smashable.gd (100%) rename {scripts => game/scripts}/Smashable.gd.uid (100%) diff --git a/.gitignore b/.gitignore index 2625c32..d4fcddd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,8 @@ -# Godot 4 editor cache & reimportable data -.godot/ - -# Godot export output -/build/ -/export/ - # macOS .DS_Store + +# The 700MB source-asset vault (pulled from the M1 Ultra "ultra" node) lives +# outside git — it's Blender/Unreal source material, not repo content. +# Canonical copies: ~/Documents/Destroyulater/3D-STORE (M3) and +# johnking@ultra:~/Documents/3D-STORE (origin). +3D-STORE/ diff --git a/README.md b/README.md index ddf9e7e..5a771d4 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,26 @@ -# Destroyulator — Cascade Prototype +# DESTROYULATOR -Mac-first (Apple Silicon / Metal), **Godot 4.7**, **Jolt** physics. Built to prove two -things on the M3 *before* committing: the destruction feels good, and the frame rate holds. +*Clock out. Smash everything.* -## Run it +A comedic, non-violent, first-person workplace-destruction game from Monster Robot +Party. Level 01 is our actual record store. Nobody gets hurt but the furniture. -**Editor (easiest):** open `/Applications/Godot.app`, import this folder (`game/`), press **F5** / ▶. +## Monorepo layout — one lane per directory -**CLI:** -```sh -/Applications/Godot.app/Contents/MacOS/Godot --path /Users/m3ultra/Documents/Destroyulater/game -``` +| Dir | Lane | What | +|---|---|---| +| `game/` | **Lane 1 — the game** | Godot 4.7 (Jolt physics, Mac-native). The shippable build. | +| `web/` | **Lane 3 — web toy** | Three.js dig-and-destroy demo (planned; thriftgod-adjacent). | +| `LANES/` | coordination | Execution specs for parallel Claude/Opus work sessions. | +| `3D-STORE/` | *not in git* | 700MB Blender/Unreal source-asset vault (see `.gitignore`). | +| `destroyulater.txt` | lore | The founding chat where the idea happened. | -## Controls +Asset generation lives in its own repo: `~/Documents/meshgod` (text→GLB factory). -| Input | Does | -|---|---| -| **Left-click** | Swing the (nerf) hammer at whatever's under the cursor | -| **S** | Rain **500** rigid bodies — the **Day-0 stress gate**. Watch the FPS counter hold. | -| **R** | Reset the rack | +## Rules for parallel work sessions -Top-left HUD shows **FPS · live body count · things smashed**. - -## What it's proving — the cascade - -The rack is nested the same way your store's DB is (`rack → shelf → crate → jacket → record`): - -- **Frame + shelves** start *frozen* (act static, hold everything up). -- Smash a **shelf** → it bursts into shards and vanishes → the **crates** on it fall → - the **cardboard jackets** spill → the **vinyl records** tumble out → -- **records are brittle** (`brittle_speed` in `Smashable.gd`) → they **crack a beat later - when they smack the floor**. A record that lands flat *survives* — there's your comedy/score beat. - -No scripted "release" logic — gravity reads the hierarchy. That's the whole point. - -## Files - -- `scripts/Smashable.gd` — one component for every breakable piece. The `PROFILES` table is - where **material identity** is authored (color · shard count · brittleness · bounce). - Swap `wood/cardboard/vinyl/glass/steel` behaviours here. -- `scripts/Main.gd` — builds the world + rack from primitives, hammer raycast, stress test, HUD. - -## Next step: real art (one function) - -Everything is grey primitives so it runs with zero import deps. To use your actual assets, -change `_piece()` in `Main.gd` to load a GLB instead of building a BoxMesh, e.g. -`load("res://assets/wooden-rack-type-long.glb").instantiate()` for the visual, keep the -convex collider. Your `3D-STORE/clean_glbs/*.glb` are ready to copy into `game/assets/`. +- **A lane session writes ONLY inside its own directory.** Cross-lane contracts + (asset formats, file drops) are specified in `LANES/*.md`. +- Every change to `game/` must pass the headless smoke test before commit: + `Godot --headless --path game --quit-after 180` with zero script errors. +- GLB convention everywhere: glTF Y-up, 1 unit = 1 m, origin at floor-center. diff --git a/destroyulater.txt b/destroyulater.txt new file mode 100644 index 0000000..1df0a69 --- /dev/null +++ b/destroyulater.txt @@ -0,0 +1,43 @@ +Oh, this is absolute gold. Workplace Destroyulator is a spectacular pivot, and honestly, it’s the perfect counterweight to a traditional simulator. +While Record Store Simulator lets you meticulously organize, curate, and obsess over every piece of vinyl, Destroyulator taps into the chaotic, primal urge of anyone who has ever worked a retail or office job and thought, "What if I just took a baseball bat to this printer?" Because you’ve already built the 3D assets for the store in Three.js and are migrating them to Unreal Engine, you are sitting on a goldmine. You have the perfect initial testbed. +Let's break down why this works so well, how Unreal's tech makes it feasible, and how your specific record store assets translate into pure gameplay loop mechanics. +The Core Gameplay Mechanics +For this to be more than just a tech demo, the destruction needs to feel deeply satisfying and arcady. You mentioned different strengths for different materials—this is where the strategy comes in. +1. The Weapon vs. Material Matrix +In Unreal, you can set up physical materials and damage thresholds. +• The Sledgehammer / Cricket Bat: High impact, slow swing. Perfect for shattering heavy wooden record racks, smashing the glass storefront, or obliterating the point-of-sale (POS) counter. +• The Box Cutter: Fast, low impact. Completely useless against a desk, but it shreds cardboard boxes, posters, and wall decals, leaving satisfying hanging ribbons of paper. +• The Projectile (e.g., An old faulty amplifier or a heavy turntable): High risk, high reward. You throw it across the room to trigger a domino effect of falling record crates. +2. The Physics of Vinyl Destruction +Since you have the record and sleeve assets ready, think about how they behave under stress: +• The Sleeves: Light, high-surface-area physics objects. If you smash a crate, 50 sleeves should erupt into the air like a deck of cards thrown in the wind, slowly drifting down. +• The Records: Vinyl is brittle under high impact but flexible under low pressure. In Unreal, you can use the Chaos Destruction system to make records shatter into sharp, jagged shards when hit with a blunt object, or scale a "shrapnel" particle effect. +3. The "Combo" and Triage System +To make it an arcade hit, players shouldn't just mindlessly swing. They need to maximize their score within the time limit: +• Chain Reactions: Smashing the bottom support of a custom-built rack causes the top shelves to collapse, creating a cascade of breaking glass, splintering wood, and flying wax. +• High-Value Targets: The rare wall-gems. Smashing a standard dollar-bin record gives you 10 points. Spotting the rare bootleg on the wall and snapping it in half gives you a 50x Combo Multiplier. +Why Unreal Engine is Perfect for This +Moving from Three.js to Unreal Engine for a destruction game is like upgrading from a bicycle to a monster truck. +Unreal Chaos Physics & Fracturing +Unreal Engine features Chaos Destruction. You don't need to manually animate things breaking. You import your static meshes (your racks, crates, tables), and use the Chaos tool to "fracture" them into hundreds of pieces. You can control: +• Damage Thresholds: How hard a physics object needs to hit the rack before it breaks. +• Connection Fields: Keeping a structure together until a specific structural pillar is destroyed, causing the whole thing to succumb to gravity. +Niagara Particle Systems +To make the destruction feel good (the "juice" of the game), you need visual feedback. +• When wood breaks, Niagara can shoot out splinters and sawdust. +• When a record breaks, you get a burst of shiny black vinyl dust and flying shards. +• Smashing an old CRT monitor or an amp? Cue electrical sparks and popping capacitors. +The "Franchise" Expansion Potential +You hit the nail on the head: the asset pipeline transfers to any workplace. Once you lock down the character controller, the weapon logic, and the scoring system in Unreal, changing the level is just a matter of swapping the static meshes. +• Level 1: The Indie Record Store (Splintering wood, flying cardboard, shattering vinyl, exploding stereo speakers). +• Level 2: The Cubicle Farm Office (Shattering fluorescent lights, exploding PC towers, copy machines spewing paper everywhere). +• Level 3: The Fast Food Kitchen (Denting stainless steel, smashing tile walls, slippery grease mechanics on the floor). +• Level 4: The Trendy Boutique / Hypebeast Store (Shattering glass mannequins, tearing down expensive displays). +How to Build the Foundation Right Now +Since you already have the room, bare racks, empty crates, and a vinyl record with its sleeve in Unreal, your immediate prototyping checklist is incredibly straightforward: +1. Set up a First-Person or Third-Person Character with a basic line-trace or collision volume for a "swing/attack" mechanic. +2. Take your Record Rack mesh into the Chaos Fracture editor. Fracture it into 20–30 chunks. Give it a high damage threshold so it requires a heavy weapon. +3. Take your Vinyl Record mesh, fracture it into 5–6 sharp shards, and set its threshold lower so a light swing snaps it. +4. Scatter 500 records into a few crates using basic rigid body physics, walk up to it with a bat, and see how satisfying it feels to watch them fly. +The beauty of this is that the code and asset optimization you do for Destroyulator (handling hundreds of physics objects on screen at once) will actually help you optimize the Record Store Simulator later if you ever want to build the peaceful version. +Which weapon are you planning to code into the prototype first to test out the physics? \ No newline at end of file diff --git a/game/.gitignore b/game/.gitignore new file mode 100644 index 0000000..2625c32 --- /dev/null +++ b/game/.gitignore @@ -0,0 +1,9 @@ +# Godot 4 editor cache & reimportable data +.godot/ + +# Godot export output +/build/ +/export/ + +# macOS +.DS_Store diff --git a/game/README.md b/game/README.md new file mode 100644 index 0000000..ddf9e7e --- /dev/null +++ b/game/README.md @@ -0,0 +1,49 @@ +# Destroyulator — Cascade Prototype + +Mac-first (Apple Silicon / Metal), **Godot 4.7**, **Jolt** physics. Built to prove two +things on the M3 *before* committing: the destruction feels good, and the frame rate holds. + +## Run it + +**Editor (easiest):** open `/Applications/Godot.app`, import this folder (`game/`), press **F5** / ▶. + +**CLI:** +```sh +/Applications/Godot.app/Contents/MacOS/Godot --path /Users/m3ultra/Documents/Destroyulater/game +``` + +## Controls + +| Input | Does | +|---|---| +| **Left-click** | Swing the (nerf) hammer at whatever's under the cursor | +| **S** | Rain **500** rigid bodies — the **Day-0 stress gate**. Watch the FPS counter hold. | +| **R** | Reset the rack | + +Top-left HUD shows **FPS · live body count · things smashed**. + +## What it's proving — the cascade + +The rack is nested the same way your store's DB is (`rack → shelf → crate → jacket → record`): + +- **Frame + shelves** start *frozen* (act static, hold everything up). +- Smash a **shelf** → it bursts into shards and vanishes → the **crates** on it fall → + the **cardboard jackets** spill → the **vinyl records** tumble out → +- **records are brittle** (`brittle_speed` in `Smashable.gd`) → they **crack a beat later + when they smack the floor**. A record that lands flat *survives* — there's your comedy/score beat. + +No scripted "release" logic — gravity reads the hierarchy. That's the whole point. + +## Files + +- `scripts/Smashable.gd` — one component for every breakable piece. The `PROFILES` table is + where **material identity** is authored (color · shard count · brittleness · bounce). + Swap `wood/cardboard/vinyl/glass/steel` behaviours here. +- `scripts/Main.gd` — builds the world + rack from primitives, hammer raycast, stress test, HUD. + +## Next step: real art (one function) + +Everything is grey primitives so it runs with zero import deps. To use your actual assets, +change `_piece()` in `Main.gd` to load a GLB instead of building a BoxMesh, e.g. +`load("res://assets/wooden-rack-type-long.glb").instantiate()` for the visual, keep the +convex collider. Your `3D-STORE/clean_glbs/*.glb` are ready to copy into `game/assets/`. diff --git a/assets/art/keyart.jpg b/game/assets/art/keyart.jpg similarity index 100% rename from assets/art/keyart.jpg rename to game/assets/art/keyart.jpg diff --git a/assets/art/keyart.jpg.import b/game/assets/art/keyart.jpg.import similarity index 100% rename from assets/art/keyart.jpg.import rename to game/assets/art/keyart.jpg.import diff --git a/assets/art/sleeves_a.jpg b/game/assets/art/sleeves_a.jpg similarity index 100% rename from assets/art/sleeves_a.jpg rename to game/assets/art/sleeves_a.jpg diff --git a/assets/art/sleeves_a.jpg.import b/game/assets/art/sleeves_a.jpg.import similarity index 100% rename from assets/art/sleeves_a.jpg.import rename to game/assets/art/sleeves_a.jpg.import diff --git a/assets/art/sleeves_b.jpg b/game/assets/art/sleeves_b.jpg similarity index 100% rename from assets/art/sleeves_b.jpg rename to game/assets/art/sleeves_b.jpg diff --git a/assets/art/sleeves_b.jpg.import b/game/assets/art/sleeves_b.jpg.import similarity index 100% rename from assets/art/sleeves_b.jpg.import rename to game/assets/art/sleeves_b.jpg.import diff --git a/assets/store/crate.glb b/game/assets/store/crate.glb similarity index 100% rename from assets/store/crate.glb rename to game/assets/store/crate.glb diff --git a/assets/store/crate.glb.import b/game/assets/store/crate.glb.import similarity index 100% rename from assets/store/crate.glb.import rename to game/assets/store/crate.glb.import diff --git a/assets/store/rack.glb b/game/assets/store/rack.glb similarity index 100% rename from assets/store/rack.glb rename to game/assets/store/rack.glb diff --git a/assets/store/rack.glb.import b/game/assets/store/rack.glb.import similarity index 100% rename from assets/store/rack.glb.import rename to game/assets/store/rack.glb.import diff --git a/assets/store/record.glb b/game/assets/store/record.glb similarity index 100% rename from assets/store/record.glb rename to game/assets/store/record.glb diff --git a/assets/store/record.glb.import b/game/assets/store/record.glb.import similarity index 100% rename from assets/store/record.glb.import rename to game/assets/store/record.glb.import diff --git a/main.tscn b/game/main.tscn similarity index 100% rename from main.tscn rename to game/main.tscn diff --git a/project.godot b/game/project.godot similarity index 100% rename from project.godot rename to game/project.godot diff --git a/scripts/Juice.gd b/game/scripts/Juice.gd similarity index 100% rename from scripts/Juice.gd rename to game/scripts/Juice.gd diff --git a/scripts/Juice.gd.uid b/game/scripts/Juice.gd.uid similarity index 100% rename from scripts/Juice.gd.uid rename to game/scripts/Juice.gd.uid diff --git a/scripts/Main.gd b/game/scripts/Main.gd similarity index 100% rename from scripts/Main.gd rename to game/scripts/Main.gd diff --git a/scripts/Main.gd.uid b/game/scripts/Main.gd.uid similarity index 100% rename from scripts/Main.gd.uid rename to game/scripts/Main.gd.uid diff --git a/scripts/MeleeAttack.gd b/game/scripts/MeleeAttack.gd similarity index 100% rename from scripts/MeleeAttack.gd rename to game/scripts/MeleeAttack.gd diff --git a/scripts/MeleeAttack.gd.uid b/game/scripts/MeleeAttack.gd.uid similarity index 100% rename from scripts/MeleeAttack.gd.uid rename to game/scripts/MeleeAttack.gd.uid diff --git a/scripts/Player.gd b/game/scripts/Player.gd similarity index 100% rename from scripts/Player.gd rename to game/scripts/Player.gd diff --git a/scripts/Player.gd.uid b/game/scripts/Player.gd.uid similarity index 100% rename from scripts/Player.gd.uid rename to game/scripts/Player.gd.uid diff --git a/scripts/Smashable.gd b/game/scripts/Smashable.gd similarity index 100% rename from scripts/Smashable.gd rename to game/scripts/Smashable.gd diff --git a/scripts/Smashable.gd.uid b/game/scripts/Smashable.gd.uid similarity index 100% rename from scripts/Smashable.gd.uid rename to game/scripts/Smashable.gd.uid