Skip to content

Build1 publisher3 min readPublished

Reading the texture-geometry split first got a sneaker configurator from 16.7 MB to 2.4 MB

A dev.to write-up runs gltf-transform inspect before compressing anything, because Draco only shrinks geometry and this model's textures were the large majority of its weight. The KTX2 step pays off on the GPU as well as the wire.

The Engineer · Build desk

Illustration accompanying Reading the texture-geometry split first got a sneaker configurator from 16.7 MB to 2.4 MB

What happened

  • Optimising the glTF took a browser sneaker configurator's model from 16.7 MB to 2.4 MB, removing 14.3 MB, about 86 percent of the original bytes.
  • The author says the 16.7 MB version is a two second wait on a laptop on office wifi, and on a mid-range Android phone on mobile data the user leaves before the first frame.
  • He ran npx gltf-transform inspect before touching anything, and the size table showed textures as the large majority of the file with geometry smaller than he expected.
  • The Draco pass quantised positions at 14 bits, normals at 10, texture coordinates at 12 and colour at 8, chosen per attribute rather than left at the tool's defaults.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • decision The inspect table decides which tool is worth reaching for at all: where textures hold most of the file, a Draco pipeline and its client-side decoder buy a fraction of the weight.
  • constraint A configurator's camera rig caps achievable detail: no pixel ever samples the extra bytes in a map authored above the resolution its maximum zoom can resolve.
  • cost Most of this saving was paid in asset authoring time, not in a build flag, because the maps had to be regenerated at sizes matched to the viewing distance.
  • exposure A team that signs off on download size is blind to the failure that hits mid-range phones, where the decoded texture sitting in video memory is what ends the session.

Four bytes a pixel is what the GPU asks for. The write-up puts a 2048x2048 texture at 16 MB in GPU memory no matter how small the JPEG was, because it has to be decoded to raw RGBA before the GPU can use it [19]. Multiply it out: 2048 x 2048 x 4 bytes is 16.78 MB, so the quoted figure is the uncompressed buffer, not an estimate [21]. KTX2 with Basis Universal stays compressed on the GPU, and the author says that on a mid-range phone, where GPU memory is the actual ceiling, this is often the difference between running and crashing [20].

The quantisation numbers are the part least likely to transfer. The command runs position at 14 bits, normals at 10, texture coordinates at 12 and colour at 8 [9]. At 10 bits the author reports he could not see a difference on curved surfaces under moving light [10]. That is one pair of eyes on one model at one orbit distance, and the post says as much: the defaults are conservative, the right values depend on your model's scale and how close the camera gets, and the method is to walk each value down until the damage is visible and then step back one [12]. Getting texture coordinates wrong has a signature, texture swimming at the seams [11].

The texture saving came out of the source assets. Every map had been authored at the resolution you would want if the camera could get arbitrarily close, and a configurator has a defined orbit distance and a maximum zoom that bound how much detail can ever reach a pixel [16]. Base colour is the map the eye judges and kept the most resolution; normals need resolution but tolerate compression artefacts poorly; roughness, metalness and ambient occlusion went dramatically smaller because they drive shading response and not perceived detail [17]. The KTX2 encode is one gltf-transform uastc call at level 4, rdo-quality 4 and zstd 18 [18].

Draco also moves cost to the client. DRACOLoader is pointed at a path with setDecoderPath('/draco/') and setDecoderConfig({ type: 'js' }) before the GLTFLoader gets it [13]. The author's warning is that the decoder is itself a download, so serve it yourself and make sure it is cached, or you have traded model bytes for decoder bytes on every cold load [14].

The second half of the story is an assertion. Once the file was small enough, swapping a colourway made the shoe look wrong [22], and the introduction promises that the obvious way to recolour a 3D model destroys the thing you built it to show [23]. The text as published breaks off mid-sentence at "The obvious implementation is" [24]. So the diagnosis-first argument is documented end to end, with commands and parameters, and the material bug is a symptom with no code under it.

What to watch

  • Whether the rest of the write-up publishes the recolouring implementation and names the material property it destroyed.
  • Whether the author reports measured load times or crash rates on the mid-range Android hardware the byte cuts were aimed at.
  • Whether the quoted gltf-transform uastc settings of level 4, rdo-quality 4 and zstd 18 survive the tool's next default change.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories