All 27 shipped GLBs run through gltf-transform (meshopt + webp + 1024 textures).
Measured per-asset, no failures: 27,304 KB -> 7,132 KB (74% off) with PBR intact.
The biggest wins are the wave-1/wave-2 assets that shipped raw (artifact-bottler
1453->329, chroma-keyer 1928->301, mv-extractor 1376->190); the six baked through
the new farm script were already lean and barely moved, which is the check that
the farm-side step is doing its job.
tools/optimize-assets.mjs: idempotent gate wired into deploy.sh BEFORE vite build.
Skips anything already carrying EXT_meshopt_compression (so it costs ~0s when
nothing is new) and FAILS THE BUILD on any asset over 900 KB — a farm regression
that emits trellis2-dense meshes now stops the deploy instead of shipping 36 MB.
deploy.sh verify gap closed: it tested exactly one .js file, so a deploy that
shipped ZERO models would have reported success. Now checks the JS bundle, a real
GLB endpoint, and asserts live model count == built model count.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The new farm stack changes the economics of every asset in the game. Measured,
same machine, same concept:
current (flux -> sf3d, albedo only) 1135 KB 27k tris no PBR
hunyuan3d_mlx raw 7408 KB 60k tris PBR
hunyuan3d_mlx + gltf-transform 418 KB 18k tris PBR <-- ships
trellis2_mlx raw 36087 KB 487k tris PBR
trellis2_mlx + gltf-transform 4147 KB 273k tris PBR (too heavy)
So the optimized Hunyuan path is 2.7x SMALLER than what ships today and adds real
metallic-roughness maps. 30 machines would be ~13 MB against today's 31 MB.
Enabling change: GLTFLoader.setMeshoptDecoder (three bundles the decoder).
EXT_texture_webp + KHR_mesh_quantization are native. Uncompressed GLBs unaffected.
Verified in the live showroom: served 428068 bytes, webp textures, 1 PBR-mapped
material, zero console errors.
mosh-reactor.glb replaced with the pilot output (LoRA-directed concept: rainbow
melt in the porthole, recovered anchor slab glowing in the airlock).
Also fixed on the farm, not in this repo: the FLUX LoRA library lived in ComfyUI's
models/loras, which flux_local does not search, on a queue that load-balances to a
second node that had none of them - every LoRA call failed with 'LoRA not found'
depending on which machine caught the job. Both nodes now carry the same set.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
flux_local -> sf3d on the m3ultra, same pipeline as wave 1. demuxer, demosaicer,
dct-press, subsampler, mv-extractor, p-caster, gop-assembler, bloom-duplicator,
field-loom, telecine-puller, hex-splicer, shipper, asic-cooler, roto-bench,
matte-bath, optical-printer, neural-keyer. 27 of 30 machines now carry real GLBs
(belt + lane-splitter + buffer-tank stay procedural by design - the shader belts
carry the flow-field chevrons a baked mesh would lose). ~31MB total, served as
static runtime fetches - none of it in the JS bundle.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ASSETS: 10 GLBs generated end-to-end on the local farm (flux_local concept ->
sf3d image-to-GLB on the m3ultra, ~2min/asset, zero cloud spend) and installed
into public/assets/models/: mosh-reactor, quantizer, seam-extractor, muxer,
archaeology-lab, software-decoder, decode-asic, mosquito-trap, chroma-keyer,
artifact-bottler. Hot-swap verified in showroom + demo world. Known gap, ordered:
GLBs carry no emissive accent so they read dark at game zoom - RENDER round 6.
Contracts v8: WildlifeState/'wildlife' event gain 'parity-mite'; new 'repaired'
SimEvent (a mite corrected your work); speaker adapter gains listStations()
passthrough (MHz) for dial tick marks. ui/voice.ts widened for the new kind
(placeholder copy; UI owns the real lines).
Round 6 orders in all lane docs - THE CORRECTION walks: parity mites (SIM),
GLB legibility pass (RENDER), mite surfacing + dial ticks + credits (UI),
repair stamps + sterile creep on the sky (SCREEN), firewall machine + numbers
decoy drift fix + accents for the GLB'd ten (DATA).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>