What the numbers are
| build | file | render verts | upload verts | textures | normals | glass |
|---|---|---|---|---|---|---|
| source | 41.0 MB | 4,497,216 | 417,028 | 2048 px JPEG | f32 | correct |
| this pass | 12.8 MB | 4,497,216 | 567,860 | 1536 px JPEG | f32 | correct |
| Khronos reference | 11.5 MB | 4,497,216 | 266,184 | KTX2 / ETC1S | f32 | correct |
| aggressive variant | 7.0 MB | 2,945,184 | 317,187 | 1024 px JPEG | i8 | broken |
Two places where this pass is beaten, and they belong here rather than in
a footnote. The reference build ships GPU-compressed KTX2 textures, so it wins on video
memory at a similar file size. And its upload vertex count is 266,184 against my
567,860 — the join step traded shared geometry for fewer draw calls, which
costs GPU memory. On a phone that trade can go the wrong way. Which build is right depends
on whether the bottleneck is bandwidth, VRAM or draw calls — that is a decision to make per
project, not a default to copy.
The part that cost a rebuild
The first pass came out at 7.0 MB — smaller than the official build. It was wrong.
Meshopt encodes normals as 8-bit octahedral, and that quietly destroys smooth
KHR_materials_transmission glass: the transparent spheres on the pawns turned
into dark faceted blobs. File size said success; the render said otherwise.
Draco keeps normals at f32 and the glass survives. The lesson is not
"use Draco" — it is that a size number alone cannot tell you whether an optimization worked.
Every pass here was checked by rendering both versions side by side, not by reading a report.
The pass, in full
gltf-transform optimize src.glb raw.glb \
--compress false --texture-compress false --simplify false # dedup, join, prune only
gltf-transform copy raw.glb un/scene.gltf # externalise textures
# textures: cap at 1536 px, re-encode (q92 for normal/AO maps, q88 for albedo)
gltf-transform copy un/scene.gltf packed.glb
gltf-transform draco packed.glb out.glb --quantize-normal 12 --quantize-position 14
Texture pass: 18.05 MB → 9.81 MB. Geometry and buffers carry the rest. Total wall-clock, start to finish: under a minute on a laptop.
What this does not claim
This is one scene, measured once, on a desktop connection. A real project needs its own numbers: your texture budget, your target device, and whether transmission, skinning or morph targets are in play — each of them changes which steps are safe. The scene here is ABeautifulGame from the Khronos sample assets, CC-BY 4.0, chosen because it is heavy, public, and ships with an official optimized build to check against.