Log Lane E landing and PLAN3D asset-path corrections

PLAN3D §2's inventory was verified against the M1 Ultra, but we build on the
M3 Ultra, where several of those libraries are absent or moved. Records the
real paths and flags the gaps that block Lanes A and D, plus the node/anchor
contracts other lanes consume.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-07-16 21:32:42 +10:00
parent 3815055678
commit 219dd55716

View File

@ -87,3 +87,64 @@ Format: `[lane letter] YYYY-MM-DD — note`
§0's clone path is what people are actually using. If the four missing libraries above live on that
other machine, this isn't a path fix, it's a decision about where lanes run. Flagging rather than
guessing.
[E] 2026-07-16 — ✅ **A's §2 correction independently confirmed** — I hit the same wall from the asset side
before M0 landed: `3D-STORE` is at `~/Documents/Destroyulater/3D-STORE/`, and `character_kit` / `FBX` /
`3D=models` / `mixamo-fetch` exist nowhere on this box. My inputs were relocated, not missing, so §5-E
is unblocked and done — Lane D's §5-D genuinely isn't. Two lanes hitting this independently is probably
the answer to A's open question.
[E] 2026-07-16 — **§5-E LANDED: 16 GLBs + grass atlas, all from one script.**
`blender -b -P tools/blender/build_yard_assets.py` (flags: `--only <name>` / `--no-verify` /
`--no-debris`). Proven rather than asserted: 17/17 outputs are byte-identical across two runs; every
GLB is re-imported from disk and checked for dims-in-range, tri budget and node-name survival;
`contact_sheet.png` renders each beside the 1.7 m ref capsule. Heaviest is garden_bed at 2,580 tris —
everything far under the 15 k budget. Machine-readable manifest: `tools/blender/asset_report.json`.
[E] 2026-07-16 — **NODE CONTRACTS — the names your code queries.** Every empty survives the export;
verified in three.js, not just Blender.
· trees: `trunk` (trunk+branches, rigid) + `canopy_01..03` as SEPARATE nodes — Lane A, sway the
canopies only. `branch_anchor_01..03` empties carry `anchor_type="tree"` + `rating_hint` (thicker
limb = higher) for `world.anchors`.
· `house_yardside`: `fascia_anchor_01..03` carry `rating_hint=0.35` + `collateral="gutter"`, and the
`gutter` node carries `collateral_of="fascia"` — DESIGN.md's "the fascia board is a lie" wired as
data, so ripping it takes the gutter with it. Facade only, 9.20 × 1.05 × 2.90 m, no interior.
· `sail_post`: exported VERTICAL, `rake_pivot` at the footing, `top_anchor` at the head. Rake is a
player decision (DESIGN.md: rake away from the load), so it's a runtime rotation, never baked.
**Lane A — this is exactly your 8° rake:** rotate about `rake_pivot` and the footing stays put.
· hardware: `shackle`/`carabiner`/`turnbuckle` each keep their failure part as its own node — `pin`
(unscrews then shears), `gate` (flutters open), `body` (thread strips) — with `failure_mode`
stamped as a custom prop, so a break anim moves just that piece.
· `shed_table``pickup_anchor` · `ladder_01``ladder_base`/`ladder_top` · `gate``hinge_axis`.
[E] 2026-07-16 — `garden_bed` ships all 3 damage states in ONE glb as sibling nodes `plants_full` /
`plants_tattered` / `plants_dead` (full visible, rest `hide_render`). Lane A: toggle `.visible`, don't
reload — instant swap, no pop-in. Tuft positions are identical across states, so the bed wilts instead
of rearranging itself.
[E] 2026-07-16 — debris in `web/world/models/debris/`, copied verbatim (§0 copies rule) and scale-checked:
BlueCrate_v2 0.36×0.36×0.29 · BlackTub_v2 + WhiteTub_v2 0.36×0.54×0.20 · WoodenBin_v2 0.35×0.36×0.31 m
— all plausible real-world sizes. Plus `tramp_01_v1.glb` (2.96×2.96×0.78, `mass_hint` 45), because every
Australian storm produces exactly one airborne trampoline. **Lane C: glob the dir, don't hardcode
names** — §0's `*_v1.glb` rule beats §5-E's "tramp_01.glb" spelling. Grass is a texture, not geometry
(§5-E item 9): `models/textures/grass_atlas.png`, 512², 2×2 tufts, alpha — instance billboards off it.
[E] 2026-07-16 — ⚠️ **LANE A + LANE C, BOUNDING BOXES.** `THREE.Box3.setFromObject(obj)` expands each mesh's
LOCAL box by the world matrix, so a node carrying a rotation reports an inflated box — and that box is
what three frustum-culls against. Blender's `obj.bound_box` has the identical trap; it cost me an hour
chasing phantom failures. Fixed at source: `join_group()` now bakes rotation into the vertices so every
local box is axis-aligned and tight. Before the fix, three reported `tramp_01` as 3.29 × 1.27 m against
a true 2.96 × 0.78. Default `Box3` is safe on these assets now — but if you ever measure geometry
yourself, measure VERTICES, not `bound_box` corners.
[E] 2026-07-16 — filled in `js/tests/e.test.js` (thanks for the pre-created stub — that was a good call)
and landed `tools/assetcheck/` as a standalone version. Loads every GLB through the vendored
GLTFLoader and asserts Y-up, scale sanity and node survival. It exists because the Blender round-trip
**cannot** catch an axis bug: it exports Z-up→Y-up and imports Y-up→Z-up, so a broken `export_yup`
flips back and passes green. Only a native glTF reader can prove it. Green: 16/16, with
`branch_anchor_01` at (-0.96, 3.64, -1.46) — height correctly on +Y.
[E] 2026-07-16 — ❓ open q for Lane A: your yard puts house fascia anchors at y=2.6, but `house_yardside`'s
fascia sits at 2.80 (2.90 m ridge), and the facade is 9.20 m against a 30 m north edge. Want me to
re-cut it to your numbers, or will you read `fascia_anchor_*` off the GLB when you swap the graybox?
Either way it's one constant for me — the script regenerates everything.