Three.js From Zero · Article s6-05
S6-05 gltf-transform
Season 6 · Article 05
gltf-transform — the CLI your pipeline needs
One tool. Lints, optimizes, compresses, splits, merges, inspects glTF files. Composable commands. Your 100MB artist dump becomes a 3MB shippable in one script.
1. Install
npm install --global @gltf-transform/cli
# Verify
gltf-transform --version
2. The commands you'll use most
| Command | Purpose |
|---|---|
inspect | Dump file structure, sizes, extensions |
validate | Run Khronos validator, catch errors |
draco | Compress geometry with Draco |
meshopt | Optimize + compress with Meshopt |
uastc / etc1s | Compress textures with Basis/KTX2 |
optimize | Bundle of safe optimizations (recommended) |
dedup | Deduplicate repeated meshes/materials/textures |
prune | Remove unused nodes/materials/textures |
weld | Merge near-identical vertices |
simplify | Quadric-error-metric mesh simplification |
resize | Shrink oversized textures |
3. The "big shrink" recipe
gltf-transform optimize input.glb output.glb \
--compress meshopt \
--texture-compress uastc \
--simplify 0.5
# Plus if needed:
gltf-transform resize output.glb output.glb --size 2048 2048
optimize runs prune + dedup + weld + compressors in one go. Usually 5-10× smaller output.
4. Before/after: a real asset
| Step | Size | Notes |
|---|---|---|
| Raw FBX from Mixamo | 11 MB | |
| → glTF export (Blender) | 8.2 MB | Default settings |
→ gltf-transform optimize | 2.1 MB | Prune, dedup, weld |
→ + draco | 720 KB | Geometry compressed |
→ + uastc | 420 KB | Textures compressed |
5. Programmatic API
CLI is built on a JS API you can script:
import { NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import { weld, dedup, prune, draco } from '@gltf-transform/functions';
const io = new NodeIO().registerExtensions(ALL_EXTENSIONS);
const doc = await io.read('input.glb');
await doc.transform(weld(), dedup(), prune(), draco());
await io.write('output.glb', doc);
Drop into a Node build. CI-friendly.
6. Inspection
gltf-transform inspect model.glb
┌ INFO ─────────────────────────────┐ │ version: 2.0 │ │ generator: Khronos Blender exp... │ │ scenes: 1 nodes: 12 meshes: │ │ 8 materials: 5 textures: 14 │ └───────────────────────────────────┘ ┌ MESHES ───────────────────────────┐ │ # name primitives verts │ │ 0 chair 1 2104 │ │ 1 table 1 5012 │ ...
7. Authoring reminders
- Always
validatebefore committing. - Run
prune— artists ship orphaned materials constantly. dedupif multiple meshes share a texture — it'll ref once instead of duplicate.weldbefore simplify — removes near-coincident vertices.
8. CI integration
# package.json
"scripts": {
"assets:build": "gltf-transform optimize raw/*.glb public/assets/ \
--compress meshopt --texture-compress uastc"
}
# GitHub Actions
- run: npm ci
- run: npm run assets:build
- uses: actions/upload-artifact@v4
with: { path: public/assets }
9. Live demo — comparison
Loads DamagedHelmet in .gltf and .glb form. Same asset, different packaging. Check Network tab for transfer sizes.
–
10. Takeaways
- gltf-transform is THE glTF Swiss Army knife.
- One command:
optimizeruns prune + dedup + weld + compress. 90% of the win. - Programmatic API for CI.
- Always inspect + validate before ship.
- Stack with Draco/KTX2/Meshopt for final size.