The three that stopped a pack shipping:
- a mesh-less GLB (armature-only export) fired onSwap anyway, hiding the
primitive and adding nothing — an invisible prop with a live collider.
Mesh count is now checked BEFORE the scene is touched, in one guard that
covers every consumer including slotObject/blob.face.
- the fulfilment path had no try/catch, so a throw became an unhandled
rejection. Split in two: a build failure bails out before onSwap can hide
anything; an onSwap failure keeps the replacement parented, because
consumers hide their primitive on onSwap's first line and removing the fit
node there would manufacture the one forbidden state.
- preload() awaited every url forever. Each is now raced against a 10s
deadline with allSettled semantics: a stalled host costs one warning and a
fallback prop, not a game that never boots.
Also:
- instantiate/instanceSync never throw — createBlob's call site is frozen and
unguarded, so a throw there is a black screen.
- ghost and blob share fitBodyToRadius(); a borrowed blob.body was rendering
the ghost 2.17x oversized with the farm mesh.
- skinned blob.body is rejected loudly instead of silently half-working; the
idle-clip mixer is gone (it animated an orphaned skeleton in the fixed step).
- paintableInfo counts UV islands: blobbo-base.glb passes every other check
and still paints wrong at 1140 charts. Warning, not rejection.
- slots.ts gains cannon.base, course.finish, course.tunnel, course.tramp, all
hooked except tramp (built in frozen game.ts).
- manifest ignores _-prefixed metadata keys instead of calling them typos.
Empty-manifest parity verified byte-for-byte: scripts/sacred-parity.check.ts
fingerprints the built scene and reports 49df4f20 on main and on this branch.
Custom-GLB drop-in system: manifest/registry with procedural fallbacks,
IndexedDB override layer for zero-deploy playtesting, and a three-panel
in-browser fitting editor. Physics/visual decoupling makes every mesh
swappable; blob.body is the one paintable special case (UV requirements).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Driven by the live fresh-eyes finding: a naive racer finishes with 0% paint —
the core mechanic is currently skippable. G makes paint route-guaranteed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixed-step world runtime, event bus wire protocol between lanes, integration
seam (game.ts) with placeholder ball. Lanes A/B/C own disjoint dirs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>