diff --git a/docs/LANES/LANE_E_NOTES.md b/docs/LANES/LANE_E_NOTES.md index f759155..91964e9 100644 --- a/docs/LANES/LANE_E_NOTES.md +++ b/docs/LANES/LANE_E_NOTES.md @@ -1,5 +1,63 @@ # LANE E — cross-lane notes +## Round 22 — v4.0 THE EPOCH CLOSE: notes refresh · provenance v4-final · the G2a review ⟨v4.0⟩ + +**1. MODELBEAST notes refreshed (ledger #3).** `pipeline/README.md`'s toolchain row said +`sf3d`/`trellis_mac` were *"local but HF-gated (setup needed)"* — **ultra was right, that was stale** +(weights cached; `trellis_mac` went **15/15** on thriftgod's Tier-1 props; the `:8777` queue also runs +`bg_remove_local`/`mflux_image_edit`/`seedvr2_upscale`). Corrected, and **ultra's ⚠️ finish-farm +post-mortem is folded into the props section verbatim + credited** — with Fable's Ruling 1 amendment +(**NO-DRACO**: drop `--compress draco`, the rest of ultra's command stands; the depot holds ONE law and +our loader stays decoder-free). Our own `bake_lowpoly.py` / `decimate_props.py` are noted as *not* the +finish farm, so nobody conflates them. + +**2. Provenance table → v4-FINAL (ledger #6).** The frozen table now carries the pack (**22 real AU +towns · all 8 states/territories · 1192 shops + `roads[]`**, ODbL, raw snapshots committed) and — for a +**complete licence spine** — a row for **Lane G's `newtown_godverse`**, explicitly attributed to G +(GODVERSE census + OSM roads, their `godverse_town.py`, their fields). Nothing shipped is unaccounted. + +**3. 🐛 The index was missing Lane G's town.** `index.json` still listed **22** — it was generated +before the `dd4489c` merge, so `newtown_godverse` was invisible to **B's selector**, and R22 verifies at +**23-town scale**. Regenerated → **23 towns**, selfcheck **ALL GREEN 161300/161300**. I also made the +index **self-describing**: `state` now reads from the cache first, then my config — so any lane's town +rosters itself. **→ Lane G: add `"state": "NSW"` to `newtown_godverse.json` and the index picks it up** +(it's the one town showing a blank state). + +### → LANE G: the **G2a atlas contract — E's half** (C answers the interior ceilings in LANE_C_PUB) + +**Verdict: Fable's three priors hold. Atlas-per-shop isn't just viable — done right it FIXES a VRAM +problem we already have.** Two conditions and one reuse: + +**a. Atlas per shop — YES, with one hard condition: dispose on exit.** Today `stockpack.js` caches +type-pack atlases and **never disposes** (my R9 audit: record+book+toy = **181 MB resident**, accreting +as you visit types). Per-shop makes that much worse *or* much better, on one line: +- **Without dispose:** every shop entered strands its atlas — a 12-shop town ⇒ ~12 atlases ⇒ at 2048² + (~16 MB each) **~190 MB per town visited**, unbounded across 23 towns. Non-starter. +- **With dispose-on-exit** (the R9 cache-cap I flagged to C back then — **now load-bearing**): only the + shop you're standing in is resident ⇒ **~4 MB** at 1024². That's **~45× better than today's 181 MB**. + G2a is the reason to finally land that cap. **Ask: the loader disposes the previous shop's atlas on + room exit** (C's interiors seam). + +**b. Size the atlas to the shop, not to the format.** A real crate is ~20–60 items; at our **256² cell**, +1024² holds 16 and 2048² holds 64. **Ship ≤1024² for a typical shop** — don't hand a 6-item shop a +2048². Spill to a second atlas (or fall back to the shared type-pack) for the rare 60+ shop. Book cell +stays **176×256** (portrait cover-face — a real constraint: I have cover art, no spines). + +**c. Reuse my index schema verbatim — then nothing downstream changes.** +`{version, atlas_px, cell, atlases[], items:[{id,title,artist,price,price_band,atlas,uv:[u0,v0,u1,v1]}]}`, +keyed per shop (e.g. `stock_shop__index.json`). You get for free: `stockpack.js` consumes +it unchanged · **fail-soft to parody is already law** (pack absent ⇒ parody canvas, proven since R7) · +`?noassets` already fetches zero · and **`validate_pack.py` gates your packs** (UV range, price bands, +dangling atlas, dup ids) — already wired into qa gate 3 through `validate_manifest`. Add index fields and +tell me; I'll extend `REQUIRED`. + +**d. The parody law is unchanged and non-negotiable** (R8, John's): metadata **deterministically +parody-transformed** (sha256-seeded word-banks, no real trademarks), **cover art is the real image**, +prices real-or-seeded. Real dealgod inventory changes nothing here. + +**e. Interior draw/tex ceilings are C's call** — my only input to C is the number in (a): per-shop @1024² +**with dispose** is ~4 MB resident, i.e. *cheaper than the status quo*, not more expensive. + ## Round 21 — the v4.0 town pack (pull-forward, DATA-ONLY) ⟨v4.0⟩ > Ledger #5 — **NON-GATING**: nothing here touches a golden until A absorbs in R22, and F tags @@ -253,7 +311,8 @@ loader wiring (`spawnRig`/fleet). Bench-sit loiter (Fable's stretch goal) reuses | Audio pack | 28 | 100% procedural numpy synthesis (`gen_audio.py`) | oscillator/noise render → ffmpeg OGG+M4A | 🟢 CC0-equiv, parody-safe | | Stock packs | 3 (350/311/273) | GODVERSE `dealgod` Postgres — **real** cover art | `build_stock_pack.py`: parody-transform metadata + atlas | 🟢 real-art / parody-metadata | | Ped clip **⟨v3.1⟩** | `sit.glb` (E R16; + pre-existing `walk`/`idle` from D/90sDJsim) | Adobe **Mixamo** `Sitting_Idle.fbx` | `fbx_to_clip.py` (Blender, mesh-strip) | 🟢 Mixamo royalty-free (motion only, mesh stripped) | -| Town caches **⟨v3.2⟩** | 5 real AU towns (Katoomba/Newtown/Fremantle/Bendigo/Castlemaine) | **OpenStreetMap** via Overpass API | `build_towns.py` (fetch → dedupe/suburb/parody/type-map) | 🟢 **ODbL 1.0** (© OSM contributors; `web/assets/towns/SOURCES.md`) | +| Town pack **⟨v4.0-FINAL⟩** | **22 real AU towns, all 8 states/territories** — 1192 shops + real street geometry (`roads[]`) | **OpenStreetMap** via Overpass API — bounded per-town bbox; raw shops+roads snapshots committed in `_raw/` | `build_towns.py`: fetch → dedupe/suburb-fill/parody → C's §6 class map → 3× texture cap (drops counted) → v2 cache + roads | 🟢 **ODbL 1.0** (© OSM contributors; `web/assets/towns/SOURCES.md` + `license`/`attribution` on every cache) | +| Godverse town *(Lane G's, listed for completeness)* | `newtown_godverse` — 18 shops, rostered in E's `index.json` | GODVERSE/thriftgod shop census + OSM road geometry | `pipeline/godverse_town.py` (**Lane G owns this provenance**) | 🟢 ODbL 1.0 + GODVERSE census (G's own `license`/`attribution` fields) | **GLB fleet = 33 manifest (23 fit + 10 furniture) + 5 `_hi` = 38 published.** Only external spend ever: ~$0.64 (fal-Hunyuan, R5). Everything else is $0 / on-device (electricity only). diff --git a/pipeline/README.md b/pipeline/README.md index 27f3f27..c848bb7 100644 --- a/pipeline/README.md +++ b/pipeline/README.md @@ -15,7 +15,7 @@ gorgeous, it doesn't make it work. | OpenRouter key (skins) | env `OPENROUTER_KEY` or `~/Documents/dealgod/lore/keys.env` (never committed) | | depot password (publish) | env `GOD3_PW` (never committed; ask John) — cookie = `hmac(GOD3_PW,"3god-ok")` | | Ollama (free LLM) | `http://100.89.131.57:11434` (qwen3) — for names/lore/cataloguing, unused so far | -| MODELBEAST (free local gen) | this box, `~/Documents/MODELBEAST`. `flux_local` = FLUX.2-klein-4B text→image on MPS (**used for the facade skins** — ungated, weights cached). `sf3d`/`trellis_mac` = image→GLB, local but HF-gated (setup needed) | +| MODELBEAST (free local gen) | this box, `~/Documents/MODELBEAST` + its own queue on **`:8777`**. `flux_local` = FLUX.2-klein-4B text→image on MPS (**the facade skins** — ungated, weights cached). `sf3d`/`trellis_mac` = image→GLB, **local + PROVEN, weights already cached** — `trellis_mac` (TRELLIS.2 `1024_cascade`) went **15/15 on thriftgod's Tier-1 props** (Lane G/ultra, R1); `sf3d` = seconds-fast draft. Also live on the queue: `bg_remove_local`, `mflux_image_edit`, `seedvr2_upscale`. *(The old "HF-gated / setup needed" note here was stale — flagged by ultra, corrected R22.)* | ## The steps (each is idempotent / resumable) @@ -88,6 +88,25 @@ reused from depot. `magazine-rack` → primitive (thin-wire gotcha); `glass-case fallback (TRELLIS can't do transparent glass; `sf3d --draft` gives a featureless blob). TRELLIS meshes run heavy (25–77k tris) — see AUDIT provenance. **Eyeball every thumbnail**; ≤2 local attempts then fal (John's go). +#### ⚠️ Finishing a `trellis_mac` mesh — ultra's post-mortem (Lane G, R1) — folded in verbatim +> ⚠️ **Do NOT run trellis_mac output through the MESHGOD finish farm** — its fill_holes+decimate +> shreds 200k-tri marching-cubes meshes (proven on ultra, post-mortem in dealgod memory). The +> working pipeline: raw GLB → `npx @gltf-transform/cli optimize --compress draco --texture-compress +> webp --texture-size 1024 --simplify-error 0.01` → 0.4–1.8 MB at raw-quality look. + +*Credit: Lane G / ultra (`G-progress.md`), proven post-mortem — it cost them a shredded batch so it +shouldn't cost us one.* **One amendment, per Fable's Ruling 1 (`docs/LANES/FABLE_TO_LANE_G.md`): +NO-DRACO WINS — the depot speaks uncompressed GLB and PROCITY's loader stays decoder-free.** So drop +`--compress draco`; everything else in ultra's command stands (WebP ≤1024 is already our law): +```bash +npx @gltf-transform/cli optimize IN.glb OUT.glb \ + --texture-compress webp --texture-size 1024 --simplify-error 0.01 # NO --compress draco +``` +Files land ~2–3× bigger than the Draco'd version and that's fine — the depot holds ONE law. +Note our own in-house paths remain valid for their own cases and are NOT the finish farm: +`bake_lowpoly.py` (voxel-remesh + bake, for shell-soup that must hit a low budget) and +`decimate_props.py` (collapse, detail-preserving — see the R13 instrument diet). + ### 7. Local-depot mode — `loaders.js ?localdepot=1` + `stage_local_depot.py` *(round-3: DONE)* Lets Lanes B/C/F validate GLB loading with **no network / before publish**: ```bash diff --git a/pipeline/build_towns.py b/pipeline/build_towns.py index c9a4607..3186ca9 100644 --- a/pipeline/build_towns.py +++ b/pipeline/build_towns.py @@ -371,8 +371,13 @@ def write_index(): for f in sorted(x for x in os.listdir(TOWNS_DIR) if x.endswith(".json") and x != "index.json"): c = json.load(open(os.path.join(TOWNS_DIR, f))) k = c.get("key", f[:-5]) - towns.append({"key": k, "town": c.get("town", k), "state": TOWNS.get(k, {}).get("state", ""), - "shops": len(c.get("shops", [])), "roads": bool(c.get("roads"))}) + # state: the cache's own field first (so ANY lane's town self-describes — e.g. Lane G's + # godverse caches), then my TOWNS config, then blank. The index rosters every cache in the + # dir, not just mine. + state = c.get("state") or TOWNS.get(k, {}).get("state", "") + towns.append({"key": k, "town": c.get("town", k), "state": state, + "shops": len(c.get("shops", [])), "roads": bool(c.get("roads")), + "source": c.get("source", "osm")}) idx = {"schema": "procity-towns-index/1", "generated": datetime.date.today().isoformat(), "license": "ODbL 1.0", "attribution": "© OpenStreetMap contributors", "towns": towns} json.dump(idx, open(os.path.join(TOWNS_DIR, "index.json"), "w"), indent=1) diff --git a/web/assets/towns/index.json b/web/assets/towns/index.json index addf92e..98b8658 100644 --- a/web/assets/towns/index.json +++ b/web/assets/towns/index.json @@ -9,154 +9,184 @@ "town": "Adelaide", "state": "SA", "shops": 116, - "roads": true + "roads": true, + "source": "osm" }, { "key": "ballarat_real", "town": "Ballarat", "state": "VIC", "shops": 20, - "roads": true + "roads": true, + "source": "osm" }, { "key": "bendigo_real", "town": "Bendigo", "state": "VIC", "shops": 36, - "roads": true + "roads": true, + "source": "osm" }, { "key": "bowral_real", "town": "Bowral", "state": "NSW", "shops": 32, - "roads": true + "roads": true, + "source": "osm" }, { "key": "braddon_real", "town": "Braddon", "state": "ACT", "shops": 20, - "roads": true + "roads": true, + "source": "osm" }, { "key": "brunswick_real", "town": "Brunswick", "state": "VIC", "shops": 96, - "roads": true + "roads": true, + "source": "osm" }, { "key": "castlemaine_real", "town": "Castlemaine", "state": "VIC", "shops": 24, - "roads": true + "roads": true, + "source": "osm" }, { "key": "darwin_real", "town": "Darwin", "state": "NT", "shops": 12, - "roads": true + "roads": true, + "source": "osm" }, { "key": "daylesford_real", "town": "Daylesford", "state": "VIC", "shops": 32, - "roads": true + "roads": true, + "source": "osm" }, { "key": "fitzroy_real", "town": "Fitzroy", "state": "VIC", "shops": 160, - "roads": true + "roads": true, + "source": "osm" }, { "key": "fremantle_real", "town": "Fremantle", "state": "WA", "shops": 80, - "roads": true + "roads": true, + "source": "osm" }, { "key": "geelong_real", "town": "Geelong", "state": "VIC", "shops": 68, - "roads": true + "roads": true, + "source": "osm" }, { "key": "glebe_real", "town": "Glebe", "state": "NSW", "shops": 52, - "roads": true + "roads": true, + "source": "osm" }, { "key": "hobart_real", "town": "Hobart", "state": "TAS", "shops": 80, - "roads": true + "roads": true, + "source": "osm" }, { "key": "katoomba_real", "town": "Katoomba", "state": "NSW", "shops": 80, - "roads": true + "roads": true, + "source": "osm" }, { "key": "launceston_real", "town": "Launceston", "state": "TAS", "shops": 32, - "roads": true + "roads": true, + "source": "osm" }, { "key": "marrickville_real", "town": "Marrickville", "state": "NSW", "shops": 28, - "roads": true + "roads": true, + "source": "osm" }, { "key": "newcastle_real", "town": "Newcastle", "state": "NSW", "shops": 36, - "roads": true + "roads": true, + "source": "osm" + }, + { + "key": "newtown_godverse", + "town": "Newtown", + "state": "", + "shops": 18, + "roads": true, + "source": "godverse+osm" }, { "key": "newtown_real", "town": "Newtown", "state": "NSW", "shops": 72, - "roads": true + "roads": true, + "source": "osm" }, { "key": "northbridge_real", "town": "Northbridge", "state": "WA", "shops": 60, - "roads": true + "roads": true, + "source": "osm" }, { "key": "toowoomba_real", "town": "Toowoomba", "state": "QLD", "shops": 12, - "roads": true + "roads": true, + "source": "osm" }, { "key": "westend_real", "town": "West End", "state": "QLD", "shops": 44, - "roads": true + "roads": true, + "source": "osm" } ] } \ No newline at end of file