diff --git a/E-progress.md b/E-progress.md index 5b1fe06..329b246 100644 --- a/E-progress.md +++ b/E-progress.md @@ -4,6 +4,33 @@ Reviewed against `docs/LANES/LANE_E_ASSETS.md` + `docs/LANES/ROUND3_INSTRUCTIONS.md`. Nothing in other lanes' files was touched.* +## Round 4 (Fable) — ped decimation (gate-3 critical path) + asset fixes + +- **E1 — ped decimation: DONE + committed** (`518678d`, ref `lane-e/round4-peds`). The 19 ped rigs + in `web/models/peds/` were **924k tris total** (31k–56k each) — the gate-3 blocker. Decimated to + **≤3k each** (1564–2805; fleet **924k→46.5k**, ~2.45k avg) via `gltf-transform weld → simplify + --ratio 0.05 --error 0.12` (meshoptimizer — works on these manifold skinned meshes, unlike R3 + TRELLIS shell-soup). **Skinning + skeleton fully preserved** (65 joints intact, `walk`/`idle` + untouched); contact sheet `docs/shots/laneE/peds_decimated.png` clean at street distance. Originals + gitignored in `pipeline/.peds_orig/`; per-ped in `pipeline/_peds_decim.json`. → **Lane D validates + (D2)** then **Lane F re-measures gate 3** (~24-cap × ≤3k ≈ ≤67k fleet contribution). +- **E2a — `record_crate` FIXED, verified + published.** Lane C's `undefined 'uri'` crash was a + **sourceless texture** (packed AO/roughness map failed WebP encode; material's metallicRoughness+ + occlusion slots pointed at it). New tool `pipeline/fix_glb_textures.py` strips those slots (three.js + loads textures lazily → no crash). **Verified it loads in the real vendored `GLTFLoader`** (meshes=1, + tris=5000). **Re-published to the depot** (the fixed version is live, tex refs all-sourced). +- **E2b — counter-with-till (~2 m): LIVE.** New `counter_till` fitting + (`procity_fit_counter_till_01.glb`, **1.61 × 0.64 m, 1.15 m tall**, 32k tris) — timber counter + + cabinet doors + period till. Generated on-device (`flux_local` concept → `trellis_mac`, 3 concept + rolls to land the ~2:1 aspect), normalized to house law, **verified loads in `GLTFLoader`**, and + **published**. Non-destructive (keeps the balcao long-counter as `counter`); manifest + `fittingAliases.counter` → `counter_till`; Lane C re-maps kind `counter` → `counter_till` in `glb.js`. +- **Publish: DONE** (John approved). Both re-exports live; **manifest `validate --depot` GREEN + (0 err, 23 GLBs live)**. `publish.py` gained an `--only ` filter + tailnet-passwordless + detection (`GOD3_DEPOT=http://100.94.195.115:8788`, decision #4). +- **Not doing** (per Fable decisions): fal.ai spend (glass-case/bus-shelter parked); hero-prop + bake-to-lowpoly. + ## Round 3 (Fable) — hero props on MODELBEAST + local-depot mode - **Hero props, free & on-device** (`pipeline/gen_props.py`): `flux_local` concept image → `trellis_mac` diff --git a/docs/LANES/LANE_E_NOTES.md b/docs/LANES/LANE_E_NOTES.md new file mode 100644 index 0000000..a5a1542 --- /dev/null +++ b/docs/LANES/LANE_E_NOTES.md @@ -0,0 +1,49 @@ +# LANE E — cross-lane notes (round 4) + +## → Lane D (task D2): decimated peds ready to validate + +The 19 ped rigs in `web/models/peds/` are decimated and staged (committed `518678d`, ref +`lane-e/round4-peds`). Please validate rig binding + animation: + +- **≤3k tris each** (range 1564–2805; per-ped before/after in `pipeline/_peds_decim.json`). + Fleet total **924k → 46.5k tris** (48.6k → 2.45k avg). At the 24-rig near cap ≈ **≤67k**. +- **Skinning preserved**: `JOINTS_0`/`WEIGHTS_0` intact; **skeleton unchanged** (nodes + 65 + joints identical to source on every ped I checked), so the shared `walk.glb`/`idle.glb` + clips retarget unchanged. **`walk.glb`/`idle.glb` were NOT touched.** +- Method: `gltf-transform weld` → `simplify --ratio 0.05 --error 0.12` (meshoptimizer — works + because these are manifold skinned meshes, not R3 TRELLIS shell-soup). Contact sheet: + `docs/shots/laneE/peds_decimated.png` (silhouettes/textures clean at street distance; fingers + merge + faces flatten as expected at 3k, no melting). +- Originals backed up (gitignored) at `pipeline/.peds_orig/` if you need a before/after diff. + +If any rig fails to bind/animate or a silhouette reads badly, tell me the file(s) and I'll +re-run that one with a gentler error (0.08 keeps ~50% more tris but still <5k). Then F re-measures +gate 3 after your sign-off. + +## → Lane C: E2 asset re-exports + +1. **`procity_fit_record_crate_01.glb` — FIXED.** Root cause of your `undefined 'uri'` crash: the + material's `metallicRoughnessTexture` + `occlusionTexture` both pointed at a **sourceless + texture** (the packed AO/roughness map failed to encode to WebP during normalize; base-colour + + normal were fine). Fix: `pipeline/fix_glb_textures.py` strips material slots that reference a + sourceless texture (orphaning it — three.js loads textures lazily, so no crash). **Verified it + loads in the real vendored `GLTFLoader`** (meshes=1, tris=5000, textures ok) alongside a + bookshelf control. Re-published to the depot — re-map `record_crate`/`recordBin` in `glb.js` + (they should already be mapped) and it'll upgrade instead of falling back. +2. **counter-with-till — LIVE.** New fitting `counter_till` (`procity_fit_counter_till_01.glb`): + **1.61 × 0.64 m footprint, 1.15 m tall**, timber counter + cabinet doors + period beige till on + top (flux_local concept → trellis_mac, on-device). Fixes the R3 4 m till-less counter that + squashed. **Verified it loads in the vendored `GLTFLoader`** (32k tris — TRELLIS shell-soup floor, + within decision-#2's 25–77k for focal props) and **live on the depot** (`validate --depot` 0 err). + → **In `glb.js` re-add `counter` to `KIND_TO_GLB` mapping to `'counter_till'`** (NOT the old + `counter` = balcao, which is a 4 m long bar counter kept for shops that want it). The manifest + `fittingAliases.counter` → `counter_till` too. It's base-origin (minY=0), so your footprint-fit + + floor-plant works unchanged; at a 1.4–2.0 m counter slot it scales to a believable ~1.0–1.4 m + tall counter. + +## → Fable: status + +- **E1 (gate-3 critical path): DONE.** Peds ≤3k, committed + pinned. Unblocks D2 → F3. +- **E2a record_crate: DONE + verified** (loads in vendored GLTFLoader). Re-published. +- **E2b counter: in progress** (local, on-device — no fal spend per decision #3). +- Not doing: fal.ai spend (glass-case/bus-shelter stay parked), hero-prop bake-to-lowpoly. diff --git a/docs/shots/laneE/counter_till.png b/docs/shots/laneE/counter_till.png new file mode 100644 index 0000000..f3b0804 Binary files /dev/null and b/docs/shots/laneE/counter_till.png differ diff --git a/pipeline/AUDIT.md b/pipeline/AUDIT.md index 519d80a..dfc00d5 100644 --- a/pipeline/AUDIT.md +++ b/pipeline/AUDIT.md @@ -179,3 +179,18 @@ intact, skeleton unchanged (nodes + 65 joints identical to source), so the share (fine for street distance). Originals backed up (gitignored) at `pipeline/.peds_orig/`; per-ped before/after in `pipeline/_peds_decim.json`. Lane D validates rig binding + anims (task D2); Lane F re-measures gate 3 (~24-rig near cap × ≤3k ≈ ≤67k fleet contribution). + +## Round 4 — E2 asset re-exports (published) + +- **`procity_fit_record_crate_01.glb` re-export (fixed).** The R3 normalize left a **sourceless + texture** (packed AO/roughness map didn't survive the WebP export; the material's + `metallicRoughnessTexture` + `occlusionTexture` pointed at it), which crashed three.js GLTFLoader + with `undefined 'uri'`. `pipeline/fix_glb_textures.py` strips material slots that reference a + sourceless texture (base-colour + normal kept; the orphan is never loaded). Verified it loads in + the vendored `GLTFLoader` (5000 tris, textures ok); re-published to the depot. +- **`procity_fit_counter_till_01.glb` (new).** ~2 m timber shop counter with a period beige till — + `flux_local` concept (3 rolls for the ~2:1 aspect) → `trellis_mac` mesh → `normalize.py`. 1.61 × + 0.64 m, 1.15 m tall, 32k tris (TRELLIS shell-soup floor, within decision-#2's 25–77k for focal + props). **Provenance: 100% synthetic/on-device** (FLUX.2-klein-4B + TRELLIS.2 on the M3 Ultra), no + third-party source — cleanest licence zone. Replaces the R3 4 m till-less counter for the interior + counter slot (Lane C maps `counter` → `counter_till`); the balcao 4 m `counter` stays for long-bar use. diff --git a/pipeline/_props_results.json b/pipeline/_props_results.json index 060e85b..6494623 100644 --- a/pipeline/_props_results.json +++ b/pipeline/_props_results.json @@ -84,6 +84,23 @@ 1.91, 0.93 ] + }, + { + "src": "/Users/m3ultra/Documents/procity/pipeline/.genprops/_m_counter3/trellis2_counter_till_v3.glb", + "file": "procity_fit_counter_till_01.glb", + "out": "/tmp/counter_norm/procity_fit_counter_till_01.glb", + "thumb": "web/assets/thumbs/procity_fit_counter_till_01.png", + "tri_before": 195285, + "tri_after": 32234, + "size_m": [ + 1.609, + 1.15, + 0.642 + ], + "footprint": [ + 1.61, + 0.64 + ] } ], "errors": [] diff --git a/pipeline/_published.json b/pipeline/_published.json index c4bac4a..deb267e 100644 --- a/pipeline/_published.json +++ b/pipeline/_published.json @@ -5,6 +5,7 @@ "procity_fit_clothes_rack_01.glb", "procity_fit_coffee_table_01.glb", "procity_fit_counter_01.glb", + "procity_fit_counter_till_01.glb", "procity_fit_cube_shelf_wide_01.glb", "procity_fit_drinks_fridge_01.glb", "procity_fit_listening_booth_01.glb", @@ -19,6 +20,5 @@ "procity_street_longbench_01.glb", "procity_street_novelty_record_01.glb", "procity_street_park_bench_01.glb", - "procity_street_streetlight_01.glb", - "vintage-cash-register.glb" + "procity_street_streetlight_01.glb" ] \ No newline at end of file diff --git a/pipeline/batch_counter.json b/pipeline/batch_counter.json new file mode 100644 index 0000000..c75893e --- /dev/null +++ b/pipeline/batch_counter.json @@ -0,0 +1,3 @@ +[ + {"src": "/Users/m3ultra/Documents/procity/pipeline/.genprops/_m_counter3/trellis2_counter_till_v3.glb", "id": "counter_till", "category": "fit", "height_m": 1.15, "tris": 8000} +] diff --git a/pipeline/build_manifest.py b/pipeline/build_manifest.py index 757d8b8..4e6c789 100644 --- a/pipeline/build_manifest.py +++ b/pipeline/build_manifest.py @@ -168,7 +168,8 @@ def build(): # stay primitives — see MESHGOD_BATCH.md). Lets a consumer that iterates registry SHOP_TYPES.fittings # resolve to a GLB. Lane C's glb.js already maps its own kinds straight to the physical ids below. fitting_aliases = { - "record_bins": "record_crate", "crates": "box_crate", "counter": "counter", + # registry 'counter' → the ~2m counter-with-till (counter_till), NOT the 4m balcao 'counter' + "record_bins": "record_crate", "crates": "box_crate", "counter": "counter_till", "clothes_racks": "clothes_rack", "bricabrac_shelving": "wire_shelf", "book_wall": "bookshelf", "cube_shelves": "cube_shelf_wide", "display_tables": "coffee_table", "bookshelves": "bookshelf", "vhs_shelving": "wire_shelf", "trestle_tables": "work_table", diff --git a/pipeline/fix_glb_textures.py b/pipeline/fix_glb_textures.py new file mode 100644 index 0000000..809222e --- /dev/null +++ b/pipeline/fix_glb_textures.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +"""Repair a GLB whose material references a texture with no image source. + +Blender's WebP glTF export occasionally emits a texture slot whose image failed to encode +(no `source`, no `EXT_texture_webp.source`) — e.g. a packed metallic-roughness/AO map. three.js +GLTFLoader then throws `Cannot read properties of undefined (reading 'uri')` when a material points +at it. This strips every material texture-slot that points at a sourceless texture (base-colour / +normal are kept; the orphaned texture is never loaded because GLTFLoader loads textures lazily), +then repacks the GLB (BIN chunk untouched). + + python3 fix_glb_textures.py in.glb out.glb +""" +import json, struct, sys + +SLOTS = ("baseColorTexture", "metallicRoughnessTexture", "normalTexture", + "occlusionTexture", "emissiveTexture") + + +def read_glb(path): + d = open(path, "rb").read() + off, gltf, chunks = 12, None, [] + while off < len(d): + clen, ctype = struct.unpack("