Every game project eventually accumulates a folder of GLBs nobody has audited: oversized textures, duplicate accessors, uncompressed vertex data, untrimmed animations. glTF-Transform is the CLI and Node.js library that lets you fix all of it in one automated pass — no DCC tool, no manual re-export.
What glTF-Transform does — and why game pipelines need it
glTF-Transform is an open-source JavaScript library and CLI for reading, modifying, and writing glTF 2.0 and GLB files. Unlike Blender or Substance, it operates purely on the glTF document model: accessors, buffer views, meshes, materials, and extensions. That makes it lightweight, fast, and scriptable.
![]()
The key difference from other mesh optimizers: glTF-Transform is non-destructive to source files. It reads one GLB in, writes an optimized copy out. Run it against every asset at build time and keep clean source files in version control.
Core operations it covers:
- Draco mesh compression — reduce geometry transfer size by 60–90%
- KTX2 / Basis Universal texture compression — GPU-native formats for Unity, UE5, and Godot 4
- Dedup — strip duplicate accessors and buffer views (common in Blender multi-object exports)
- Prune — remove unused nodes, skins, animations, and materials
- Flatten — collapse scene hierarchy to reduce draw call overhead
- Resample — remove redundant animation keyframes without affecting playback
- Weld — merge nearby vertices below a threshold, useful before LOD generation
Installing and running the CLI on your asset folder
```bash
npm install -g @gltf-transform/cli
gltf-transform --version
# 4.x.x
```
Single-file optimization pass:
```bash
gltf-transform optimize input.glb output.glb \
--texture-compress ktx2 \
--texture-size 2048
```
Batch processing an entire folder:
```bash
for f in assets/raw/*.glb; do
out="assets/optimized/$(basename "$f")"
gltf-transform optimize "$f" "$out" \
--texture-compress ktx2 \
--texture-size 1024 \
--draco
echo "✓ $f → $out"
done
```
> Tip: Always set `--texture-size`. Blender exports at full resolution by default — a 4096 albedo on a prop that never fills 256 px on screen is pure waste.
Key transforms every game dev should know
| Transform | CLI flag | What it does | When to use it |
|---|---|---|---|
| Draco | `--draco` | Compress geometry with Draco | Web and mobile targets |
| KTX2 | `--texture-compress ktx2` | Basis Universal GPU textures | Unity, UE5, Godot 4 |
| Dedup | built into `optimize` | Remove duplicate accessors | All multi-mesh Blender exports |
| Prune | built into `optimize` | Strip unused scene data | After animation retargeting |
| Flatten | `--flatten` | Collapse node hierarchy | Static props, instanced meshes |
| Weld | `--weld` | Merge nearby vertices | LOD generation prep |
| Resample | `--resample` | Drop redundant keyframes | All rigged characters |
Engine-specific notes:
- Godot 4: skip Draco — Godot's built-in GLB importer does not support `KHR_draco_mesh_compression` at runtime. Use `--texture-compress ktx2` only, or leave textures uncompressed and let Godot's import pipeline handle it.
- Unreal Engine 5: UE5 strips KTX2 and re-compresses textures internally. Run with `--texture-compress none` when targeting UE5; the `dedup`, `prune`, and `flatten` passes still reduce import time and version-control file sizes.
- Unity URP/HDRP: full support for both Draco and KTX2 via the Unity glTFast importer.
Automating GLB optimization in a CI/CD pipeline
For teams on GitHub Actions or any Node-based build, glTF-Transform installs as a dev dependency and integrates before the engine build step.
```bash
npm install --save-dev @gltf-transform/core @gltf-transform/extensions @gltf-transform/functions
npm install --save-dev draco3dgltf sharp
```
Minimal batch optimization script (`scripts/optimize-assets.mjs`):
```js
import { NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import { dedup, prune, resample, textureCompress } from '@gltf-transform/functions';
import draco3d from 'draco3dgltf';
import sharp from 'sharp';
import { glob } from 'glob';
import path from 'path';
const io = new NodeIO()
.registerExtensions(ALL_EXTENSIONS)
.registerDependencies({
'draco3d.encoder': await draco3d.createEncoderModule(),
'sharp': sharp,
});
for (const src of await glob('assets/raw/**/*.glb')) {
const dest = src.replace('assets/raw', 'assets/optimized');
const doc = await io.read(src);
await doc.transform(
dedup(),
prune(),
resample(),
textureCompress({ encoder: sharp, targetFormat: 'webp', resize: [1024, 1024] }),
);
await io.write(dest, doc);
console.log(`✓ ${path.basename(src)}`);
}
```
GitHub Actions step:
```yaml
- name: Optimize GLB assets
run: node scripts/optimize-assets.mjs
```
![]()
Structure the repo so `assets/raw/` holds artist-authored files and `assets/optimized/` is a generated output never committed to git. Add `assets/optimized/` to `.gitignore` and let CI regenerate it on every build. Artists push source GLBs freely; the pipeline handles optimization on every merge.
Verify the size reduction after a run:
```bash
du -sh assets/raw/ assets/optimized/
# assets/raw/ 420M
# assets/optimized/ 148M
```
Typical reduction on a mixed prop set: 40–70%, with no visible quality loss at in-game distances.
Start with production-ready GLBs from BitSoul's marketplace and run this pipeline on download. Every asset ships in GLB format — one `gltf-transform optimize` pass gives you engine-ready files with compressed geometry and GPU-native textures in seconds.
---
*This post is part of the Ultimate Guide to Free 3D Game Assets — BitSoul's complete reference for formats, texturing, rigging, optimization, and engine integration.*