Add parallel-lane execution specs for Opus 4.8
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 <noreply@anthropic.com>
This commit is contained in:
parent
5852322606
commit
c03bb85c9f
36
LANES/KICKOFF.md
Normal file
36
LANES/KICKOFF.md
Normal file
@ -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.
|
||||
87
LANES/LANE1-godot-record-ritual.md
Normal file
87
LANES/LANE1-godot-record-ritual.md
Normal file
@ -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`.
|
||||
74
LANES/LANE2-asset-pipeline-fracture.md
Normal file
74
LANES/LANE2-asset-pipeline-fracture.md
Normal file
@ -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 <script> -- <args>`,
|
||||
parses a `FINISH_RESULT:{json}` line from stdout. Finishing does join→solidify (watertight!)
|
||||
→decimate→brighten→normalize→export GLB.
|
||||
- `meshgod/batch.py` — resumable manifest runner (`python3 -m meshgod.batch manifest <f.json>
|
||||
--out <dir>`, content-hashed IDs, checkpoints, `--workers`).
|
||||
- `meshgod/pipeline.py`, `config.py` — the OpenRouter→fal.ai→finish flow. **Cost is real**
|
||||
(~$0.10–0.55/asset); fal key in gitignored `open.txt`. Check remaining credit before a big batch.
|
||||
- 3GOD push: `MESHGOD/scripts/test_3god_push.py` (on M1) guards the depot auth/slug contract;
|
||||
find/mirror the actual push helper meshgod uses to POST a finished GLB to digalot.fyi/3god.
|
||||
|
||||
## Deliverables
|
||||
|
||||
### 1. `meshgod/scripts/fracture_glb.py` — headless Blender cell-fracture
|
||||
Mirror `finish_glb.py`'s structure exactly (arg parsing, `FRACTURE_RESULT:{json}` stdout line).
|
||||
- Input: a finished watertight GLB + `--chunks N` (default 12) + `--out <path>`.
|
||||
- Enable the **Cell Fracture** addon (`bpy.ops.preferences.addon_enable(module="object_fracture_cell")`)
|
||||
and run `bpy.ops.object.add_fracture_cell_objects(source_limit=N, ...)` on the imported mesh.
|
||||
(Blender 5.1 — verify the addon module name; if renamed/removed, fall back to a Voronoi
|
||||
geometry-nodes or `boolean`-based split, but Cell Fracture is preferred.)
|
||||
- Each chunk: recenter its origin to its own bounds center (so it can become a rigid body),
|
||||
keep the parent's material.
|
||||
- Export **all chunks as a single `<name>.fractured.glb`** whose root's direct children are the
|
||||
chunk meshes named `chunk_00…chunk_NN` (SHARED-CONTRACT #2 in PLAN.md). Report chunk count +
|
||||
whether any chunk is non-manifold.
|
||||
|
||||
### 2. `meshgod/fracture.py` (module) + CLI
|
||||
`python3 -m meshgod.fracture <in.glb> --chunks 12 --out <out.fractured.glb>` — thin wrapper
|
||||
that subprocess-launches the script (same pattern as `finish.py`). Optionally add a
|
||||
`--fracture` flag to `batch.py` so a manifest entry can request `"fracture": {"chunks": 12}`
|
||||
and get both `<name>.glb` + `<name>.fractured.glb` out.
|
||||
|
||||
### 3. `meshgod/manifests/destroyulator.json` — the prop batch
|
||||
Workplace hero props, real-metre `height_m` + tri budgets. Include at least:
|
||||
office **printer** (the boss!), office desk, monitor/CRT, desk phone, filing cabinet,
|
||||
water cooler, office chair, ceiling fluorescent light, coffee mug, potted plant, wall clock,
|
||||
cardboard box; record-store extras: turntable, amp/speaker, cash register, wall shelf.
|
||||
Each entry: `{name, prompt, height_m, tris, fracture:{chunks}}`. ~16 assets ≈ $3–8, ~30 min.
|
||||
**Confirm the fal budget covers it before running; if low, do the top 6 first.**
|
||||
|
||||
### 4. Push finished + fractured GLBs to 3GOD
|
||||
Use meshgod's existing depot-push path. Land both the intact and `.fractured.glb` on the
|
||||
digalot.fyi/3god shelf so Lanes 1 & 3 can pull them by slug.
|
||||
|
||||
## Acceptance
|
||||
- `fracture_glb.py` on one finished GLB (e.g. `outputs/robot_game.glb`) yields a
|
||||
`.fractured.glb` with ≥8 chunk children named `chunk_*`; verify by loading it in Blender
|
||||
headless and printing child count + names.
|
||||
- The manifest runs (or a 2-asset subset does) end-to-end: intact + fractured GLBs on disk,
|
||||
watertight, correct scale, pushed to 3GOD (`GET /api/list` shows the new slugs).
|
||||
|
||||
## Gotchas
|
||||
- Cell Fracture needs the mesh to be a single manifold object; run it AFTER finish's solidify.
|
||||
- fal costs money per asset and the key is shared/rotating — read `open.txt`, don't hardcode,
|
||||
and cap batch size to the remaining credit.
|
||||
- Keep chunk counts modest (8–16). Hundreds of chunks tank the consuming physics engines.
|
||||
|
||||
## Definition of done
|
||||
Fracture stage works and is documented; `destroyulator.json` (or its top-6 subset) generated,
|
||||
finished, fractured, and pushed to 3GOD; committed + pushed to meshgod's own remote.
|
||||
Post the list of produced slugs so Lanes 1 & 3 can consume them.
|
||||
75
LANES/LANE3-web-smash-toy.md
Normal file
75
LANES/LANE3-web-smash-toy.md
Normal file
@ -0,0 +1,75 @@
|
||||
# LANE 3 — Web smash toy: thriftgod-based FP demo, 3GOD props, Rapier physics
|
||||
|
||||
**Owns:** `web/` (new dir in the destroyulator monorepo). **For:** an Opus 4.8 session.
|
||||
**Runs on:** M3 Ultra (serve locally); deploy target later is the digalot.fyi VPS.
|
||||
|
||||
## Objective
|
||||
|
||||
A **shareable, instant-link web toy** — not a port of the Godot game, a different product in
|
||||
the same universe. Walk around a room first-person, grab records, and smash the place, in the
|
||||
browser. Built on thriftgod's proven FP-interior code, physics via Rapier (WASM), props pulled
|
||||
live from the 3GOD depot. This is the streamer-bait / "try it in one click" front door.
|
||||
|
||||
## What already exists (study, then fork — DON'T edit thriftgod)
|
||||
|
||||
- `~/Documents/thriftgod` (local) — LIVE Three.js first-person game (digalot.fyi). Copy the
|
||||
patterns, don't modify it. Reusable pieces:
|
||||
- `web/index.html` (~129k) — pointer-lock WASD FP controller, seeded procedural interior,
|
||||
3D pickup/inspect interaction, **GLTFLoader + DRACOLoader** wiring (~line 1233, fixture
|
||||
kind `'glb'`). This is your movement + loading foundation.
|
||||
- `web/dig.js`, `web/cards.js` — interaction + item UI patterns.
|
||||
- Three.js r0.175 via unpkg importmap, no build step (keep this — zero-tooling is a feature).
|
||||
- `~/Documents/Destroyulater/game/scripts/dig.js` reference (recordgod) — procedural Web Audio
|
||||
"fwip/thunk"; reuse the synth approach for smash SFX (mirror Godot's `Juice.gd` material voices).
|
||||
- 3GOD depot: `https://digalot.fyi/3god`, `GET /api/list` → shelf JSON; GLBs by slug. **Read-only.**
|
||||
|
||||
## Deliverables (all under `web/`)
|
||||
|
||||
### 1. `web/index.html` + `web/main.js` — the app
|
||||
- Fork thriftgod's pointer-lock FP controller + a simple room (floor, walls, a couple of racks).
|
||||
- Load props from 3GOD by slug via GLTFLoader (start with `record`, `crate`, `milk-crate-stack`,
|
||||
`vintage-cash-register`, and the Lane-2 printer once it lands). Fallback to a local
|
||||
`web/assets/` copy if the depot is unreachable, so the demo never hard-fails offline.
|
||||
|
||||
### 2. `web/physics.js` — Rapier (WASM) destruction
|
||||
- Use `@dimforge/rapier3d-compat` (or `-simd`) via CDN/ESM. One rigid body per smashable prop,
|
||||
colliders auto-sized from the GLB bounding box (mirror Godot's `_body_local_aabb` approach).
|
||||
- **Support-graph cascade** — port the Godot idea: frozen (fixed) bodies hold up dynamic ones;
|
||||
destroying a support switches its dependents to dynamic. Same "knock the legs, it pancakes" feel.
|
||||
- **Pre-fractured swap:** when a prop has a `.fractured.glb` (Lane 2 contract #2), on smash hide
|
||||
the intact mesh and spawn each `chunk_*` as a short-lived dynamic body inheriting velocity.
|
||||
Brittle kinds (vinyl/glass) also shatter on hard impact. Pool + despawn debris (JS GC is the
|
||||
ceiling — cap active bodies, sleep/remove settled ones).
|
||||
|
||||
### 3. `web/juice.js` — feel layer
|
||||
- Screenshake (camera trauma), a brief hitstop (scale the physics step / freeze a few frames),
|
||||
per-material particle bursts (Points or instanced quads), and **procedural Web Audio** smash
|
||||
SFX per material (wood crunch, cardboard rip, vinyl crack+warble, glass tinkle, steel ring) —
|
||||
same recipe as Godot `Juice.gd::_synth`. Combo counter in the DOM HUD.
|
||||
|
||||
### 4. Record ritual (lite) + share hook
|
||||
- A simplified version of Lane 1's ritual: click a record to pull it (drag to slide the disc
|
||||
out), then throw/smash. Keep it snappy for web.
|
||||
- A "share your mess" button: screenshot the canvas (`toDataURL`) + a smash-count caption.
|
||||
|
||||
## Serve + acceptance
|
||||
```sh
|
||||
cd web && python3 -m http.server 8099 # then open http://localhost:8099
|
||||
```
|
||||
- Loads with no console errors; FP movement + pointer lock work; at least one 3GOD prop loads
|
||||
and smashes with particles + sound; holds ~60fps with a roomful of props on the M3 (test in
|
||||
Chrome AND Safari — Safari is the weakest WASM/WebGPU target).
|
||||
- Cross-origin note: fetching GLBs from digalot.fyi needs CORS on 3GOD; if blocked, mirror the
|
||||
handful of props into `web/assets/` and load locally for now (flag it for the depot owner).
|
||||
|
||||
## Gotchas
|
||||
- Don't import a bundler unless necessary — thriftgod's no-build importmap approach is the norm here.
|
||||
- Rapier is WASM: `await RAPIER.init()` before creating the world; keep physics off the render
|
||||
thread if it janks (Web Worker + SharedArrayBuffer needs COOP/COEP headers — only if needed).
|
||||
- The 3GOD SSRF/open-mode issue (see PLAN.md) is a WRITE-side problem; this lane only reads, so
|
||||
it's unaffected — but don't add any write calls to the depot from the web client.
|
||||
|
||||
## Definition of done
|
||||
A playable `web/` smash toy: walk, grab a record, smash props (fractured where available) with
|
||||
juice, in Chrome + Safari, props from 3GOD (or local mirror). Committed + pushed to `origin main`
|
||||
under `web/`. Post a localhost screenshot/gif.
|
||||
59
LANES/PLAN.md
Normal file
59
LANES/PLAN.md
Normal file
@ -0,0 +1,59 @@
|
||||
# DESTROYULATOR — Build Plan & Lane Specs
|
||||
|
||||
*Fable's review + plan, 2026-07-08. Three parallel lanes over one shared asset pipeline.*
|
||||
|
||||
## The verdict
|
||||
|
||||
Destroyulator plugs into the **GODVERSE pipeline you already have**, it does not reinvent it:
|
||||
|
||||
```
|
||||
meshgod ──makes──▶ 3GOD depot ──serves──▶ { Godot game, web toy }
|
||||
(text→GLB) (digalot.fyi/3god) (two front-ends, one universe)
|
||||
```
|
||||
|
||||
- **Engine question, settled:** Godot stays the shippable game (native Apple Silicon,
|
||||
Jolt, exports Win/Mac/Linux off the M3). Three.js is NOT a port of the same game —
|
||||
it's a **separate, shareable web toy** built on thriftgod's live first-person interior
|
||||
code, wired to the same props. Different product, same universe. Both consume the
|
||||
same pipeline, so the expensive part (assets) is built once.
|
||||
- **Assets are hybrid-cloud, not free:** meshgod = OpenRouter + fal.ai (~$0.10–0.55/asset,
|
||||
1–2 min). Budget per batch; don't assume infinite regeneration.
|
||||
|
||||
## The three lanes (fire in parallel)
|
||||
|
||||
| Lane | Repo / dir it OWNS | Deliverable | Depends on |
|
||||
|---|---|---|---|
|
||||
| **1 — Godot: record ritual** | `game/` (this repo) | Grab→lift→slide-disc→smash mechanic + "find the misfiled disc" mode | nothing (starts now) |
|
||||
| **2 — Asset pipeline** | `~/Documents/meshgod` (separate repo) | Cell-fracture stage + Destroyulator prop manifest → 3GOD | nothing (starts now) |
|
||||
| **3 — Web smash toy** | `web/` (this repo, new dir) | thriftgod-based FP smash demo, 3GOD props, Rapier physics | 3GOD (read-only) |
|
||||
|
||||
**Scope rule (prevents collisions):** each lane writes ONLY inside the dir it owns.
|
||||
Lane 2 delivers assets to 3GOD + meshgod outputs; Lane 1 *pulls approved GLBs into
|
||||
`game/assets/`* itself (Lane 2 never writes `game/`). Lane 3 fetches from 3GOD at runtime.
|
||||
|
||||
## Shared contracts (every lane obeys these)
|
||||
|
||||
1. **GLB convention:** glTF **Y-up, 1 unit = 1 m, origin at floor-center**, textures
|
||||
embedded, decimated to tri budget. (meshgod already emits this.)
|
||||
2. **Fracture format:** an intact `<name>.glb` PLUS a sibling `<name>.fractured.glb`
|
||||
whose root's direct children are the chunk meshes (each a `MeshInstance`/mesh node
|
||||
named `chunk_00…chunk_NN`, origin at its own centroid, in the intact model's local
|
||||
space). Consumers instance it and turn each chunk into a rigid body. Defined by Lane 2,
|
||||
consumed by Lanes 1 & 3.
|
||||
3. **Depot:** 3GOD at `https://digalot.fyi/3god` — `GET /api/list` returns the shelf;
|
||||
GLBs fetchable by slug. Web lane reads live; game lane commits offline copies.
|
||||
|
||||
## ⚠️ Pre-req / ops risk (owner's call — NOT auto-fixed)
|
||||
|
||||
The review of 3GOD found the **public digalot.fyi/3god instance running in open mode
|
||||
(`GOD3_OPEN=1`)** — write endpoints (upload/delete/fetch) are reachable **unauthenticated**,
|
||||
plus an **SSRF hole in `/api/fetch`** (`server.py:173`, reads `file://` + cloud metadata).
|
||||
Lane 3 only *reads* the depot, so it's not blocked — but before leaning on 3GOD as public
|
||||
game infrastructure, close open-mode + allow-list `/api/fetch` schemes/hosts. This is a
|
||||
production box; flagged for you to action, not silently changed.
|
||||
|
||||
## Sequencing note
|
||||
|
||||
All three start immediately. Lane 2's fracture output *upgrades* Lanes 1 & 3 (real
|
||||
shard-by-shard destruction) but neither is blocked waiting for it — both already work
|
||||
with primitive/auto-collider fallbacks. Integrate fractured assets when they land.
|
||||
Loading…
Reference in New Issue
Block a user