From c03bb85c9f3ba0e6ed02ac63d40a4c638d43bb21 Mon Sep 17 00:00:00 2001 From: Monster Robot Party Date: Tue, 14 Jul 2026 16:47:47 +1000 Subject: [PATCH] Add parallel-lane execution specs for Opus 4.8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- LANES/KICKOFF.md | 36 +++++++++++ LANES/LANE1-godot-record-ritual.md | 87 ++++++++++++++++++++++++++ LANES/LANE2-asset-pipeline-fracture.md | 74 ++++++++++++++++++++++ LANES/LANE3-web-smash-toy.md | 75 ++++++++++++++++++++++ LANES/PLAN.md | 59 +++++++++++++++++ 5 files changed, 331 insertions(+) create mode 100644 LANES/KICKOFF.md create mode 100644 LANES/LANE1-godot-record-ritual.md create mode 100644 LANES/LANE2-asset-pipeline-fracture.md create mode 100644 LANES/LANE3-web-smash-toy.md create mode 100644 LANES/PLAN.md diff --git a/LANES/KICKOFF.md b/LANES/KICKOFF.md new file mode 100644 index 0000000..a092095 --- /dev/null +++ b/LANES/KICKOFF.md @@ -0,0 +1,36 @@ +# KICKOFF — how to run the three lanes in parallel + +Read `PLAN.md` first (verdict, architecture, shared contracts, the 3GOD security note). +Then start each lane as its own Opus 4.8 session with the one-liner below. Each session's +FIRST job is to read its lane file + `PLAN.md`, then execute. + +## Start each lane (paste as the session's opening prompt) + +**Lane 1 — Godot record ritual** +> Read `~/Documents/Destroyulator/LANES/PLAN.md` then `LANES/LANE1-godot-record-ritual.md` and +> execute it fully. You own `game/` only. Build the grab→slide→smash record ritual + the +> "find the misfiled disc" mode. Pass the headless smoke test before every commit; commit + +> push to `origin main` as you go. + +**Lane 2 — Asset pipeline / fracture** +> Read `~/Documents/Destroyulator/LANES/PLAN.md` then `LANES/LANE2-asset-pipeline-fracture.md` +> and execute it. You own `~/Documents/meshgod` (a separate repo). Add the cell-fracture stage, +> build the Destroyulator prop manifest, generate + fracture + push to 3GOD. CHECK THE fal +> CREDIT before any big batch; do the top-6 props first if it's tight. Commit to meshgod's remote. + +**Lane 3 — Web smash toy** +> Read `~/Documents/Destroyulator/LANES/PLAN.md` then `LANES/LANE3-web-smash-toy.md` and execute +> it. You own `web/` (new dir in the destroyulator monorepo). Fork thriftgod's FP interior into a +> browser smash toy with Rapier physics, 3GOD props, and a juice layer. Do NOT edit thriftgod. +> Commit + push to `origin main` under `web/`. + +## Collision safety +- Lane 1 → writes `game/` only. Lane 3 → writes `web/` only. Lane 2 → writes `~/Documents/meshgod` + only (never `game/`; it delivers assets via 3GOD, and Lane 1 pulls approved GLBs in itself). +- All push to the same remote `ssh://git@100.71.119.27:222/monster/destroyulator.git` (Lanes 1 & 3) + — different top-level dirs, so no merge conflicts. Lane 2 pushes to its own meshgod remote. +- If two lanes ever need the same file, STOP and coordinate through the human — don't guess. + +## Definition of done (whole plan) +Godot game has the record ritual + a playable mode; meshgod can fracture and has shipped the +prop batch to 3GOD; the web toy is playable in-browser. Each lane green on its own acceptance test. diff --git a/LANES/LANE1-godot-record-ritual.md b/LANES/LANE1-godot-record-ritual.md new file mode 100644 index 0000000..a920d13 --- /dev/null +++ b/LANES/LANE1-godot-record-ritual.md @@ -0,0 +1,87 @@ +# LANE 1 — Godot: the record-destruction ritual + "find the misfiled disc" mode + +**Owns:** `game/` only. **Engine:** Godot 4.7 (Jolt). **For:** an Opus 4.8 session. +**Runs on:** M3 Ultra, `/Applications/Godot.app`. + +## Objective + +Turn records from one-hit props into the game's signature **dexterity ritual**: + +> look at a record → **Grab (E)** to lift the sleeve out of the crate → **drag mouse +> left↔right** to slide the black disc out of the sleeve → the freed disc is a throwable +> brittle object (**LMB throw / smash**), and the empty sleeve is separately trashable. + +Then a first game mode on top of it: **"Find the Misfiled Disc"** — one disc is in the +wrong sleeve; find it before the timer, and the frantic search leaves a mess (the point). + +## What already exists (read these first) + +- `game/scripts/Player.gd` — FP `CharacterBody3D`: mouse-look, WASD, `camera`, punch/kick + via `MeleeAttack`. Add the grab controller here (or a child node it owns). +- `game/scripts/Smashable.gd` — `class_name Smashable extends RigidBody3D`; `kind`, + `PROFILES`, `smash(impulse)`, `shatter()`, `supports[]`/`release()` cascade, `smashed` signal. +- `game/scripts/Main.gd` — builds the store (`_glb_piece()` auto-fits colliders, drops to + floor), `_skin_record()` UV-tiles sleeve art, HUD, `B`=rain, `R`=reset. `_on_smashed`→`Juice`. +- `game/scripts/Juice.gd` — hitstop/shake/particles/procedural audio, `impact(kind,pos,shards)`. +- Assets: `game/assets/store/record.glb` (sleeve, carries `M_Sleeve_Front/Back` mats). + Disc-only + sleeve-only source GLBs exist at `~/Documents/Destroyulater/3D-STORE/clean_glbs/` + (`VinylDisc_v4.glb`, `VinylSleeve_v4.glb`) — copy into `game/assets/store/` if you split them. + +## Deliverables + +### 1. `game/scripts/Record.gd` — `class_name Record extends RigidBody3D` +A record = a **cardboard sleeve** (this body, `kind="cardboard"` Smashable-like) that +**contains a hidden vinyl disc**. State machine: `IN_CRATE → HELD → EXTRACTING → DISC_FREE`. +- Exports/fields: `sleeve_genre: String`, `disc_genre: String` (usually equal; the mode + sets one mismatch), `_extract: float` (0→1 pull progress), `_disc: RigidBody3D` (the disc, + starts frozen inside the sleeve at local offset). +- `grab(hold_point: Node3D)`: freeze, reparent-follow the player hold point (kinematic). +- `set_extract(amount: float)`: clamp 0..1, lerp `_disc` local position along the sleeve's + +X (opening) axis by `amount * sleeve_length`; peek the disc label as it emerges. +- At `_extract >= 1.0`: `release_disc()` → unfreeze `_disc`, detach as free brittle vinyl + `Smashable`, keep the now-empty sleeve as a trashable cardboard body. +- The disc + sleeve both reuse `Smashable`'s shatter/juice path (emit `smashed`). + +### 2. `game/scripts/GrabController.gd` — attach under `Player` +- A hold point (`Node3D` child of camera, ~0.5m forward, ~-0.1 down). +- `E` = grab the `Record` under the crosshair (reuse the sphere/ray query pattern from + `MeleeAttack.strike`, but filter for `Record`). Only grabbable within reach (~2m). +- While held: accumulate `InputEventMouseMotion.relative.x` into the held record's + `set_extract()` (tune: ~600px of drag = full pull). Show an on-screen extract meter. +- `LMB` while holding a freed disc = throw (impulse along camera forward, disc is brittle + so it cracks on impact). `G` or `LMB` on the empty sleeve = drop/trash it. +- `Esc` still releases mouse (don't break existing Player input). + +### 3. `game/scripts/GameMode.gd` — `class_name GameMode extends Node`, owned by `Main` +- **FreePlay** (default) and **FindMisfiled**. +- FindMisfiled: on start, pick N records, set exactly ONE to `disc_genre != sleeve_genre` + (e.g. a techno disc in a jazz sleeve). Start a 60s timer (HUD). Win = the player extracts + the misfiled disc and presses **F (report)** while holding it. Track "records disturbed" + and "mess score" (bodies knocked / smashed via `_on_smashed`). Show result on win/lose. +- Key `1` = FreePlay, `2` = start FindMisfiled, on the existing `Main._unhandled_input`. + +### 4. Wire into `Main._build_rack` +- Replace the `_glb_piece(RECORD_GLB, "vinyl", …)` record placement with `Record` instances + (sleeve+disc). Keep them stacked on crates; keep `crate.supports.append(record)`. +- Keep `_skin_record()` for the sleeve art; add a small disc-label tint by `disc_genre`. + +## Acceptance (must pass before each commit) + +```sh +# zero script errors across 180 frames (2 "material is null" lines are benign headless noise) +/Applications/Godot.app/Contents/MacOS/Godot --headless --path game --quit-after 180 2>&1 \ + | grep -E 'SCRIPT ERROR:|Parse Error' | grep -v 'material.*null' # must be empty +``` +Plus a `print()` on mode start confirming the misfiled record was planted (genre A in genre B). +Then eyeball in-editor: grab a record, drag to pull the disc, throw it, trash the sleeve. + +## Gotchas +- Held bodies: set `freeze=true` + move via `global_transform` each `_physics_process`, OR + use a `Generic6DOFJoint3D`/`PinJoint3D` to the hold point — simpler is freeze+follow. +- Don't let the disc's brittle `body_entered` fire while it's still inside the sleeve + (guard: only arm brittleness after `release_disc()`). +- Keep everything in groups `smashable`/`debris` so the HUD body count + `Juice` keep working. + +## Definition of done +Grab/lift/slide/smash works end-to-end; FindMisfiled mode is playable start→win/lose with a +timer and mess score; headless smoke test clean; committed + pushed to `origin main`. diff --git a/LANES/LANE2-asset-pipeline-fracture.md b/LANES/LANE2-asset-pipeline-fracture.md new file mode 100644 index 0000000..c334628 --- /dev/null +++ b/LANES/LANE2-asset-pipeline-fracture.md @@ -0,0 +1,74 @@ +# LANE 2 — Asset pipeline: cell-fracture stage + Destroyulator prop batch + +**Owns:** `~/Documents/meshgod` (SEPARATE repo — not the destroyulator monorepo). +**For:** an Opus 4.8 session. **Runs on:** M3 Ultra; Blender at `/Applications/Blender.app`. + +## Objective + +Give the meshgod factory a **fracture stage** so props arrive pre-shattered for smashing, +then batch-generate Destroyulator's workplace props and push them to 3GOD. This upgrades +Lanes 1 & 3 from "single-box smashable" to real shard-by-shard destruction. + +## What already exists (read first) + +- `meshgod/finish.py` + `scripts/finish_glb.py` — the **headless-Blender subprocess pattern + to copy**: launches `/Applications/Blender.app` `--background --python