The 3D Asset Optimization Pipeline is an automated system that optimizes GLB model files for runtime performance and load times. It applies geometry transforms, mesh compression, texture resizing, and generates LOD (Level of Detail) variants.
- ✅ Geometry Optimization: Prune, dedup, weld, and quantize vertex data
- ✅ Mesh Compression: Draco compression for smaller file sizes
- ✅ Texture Processing: Automatic power-of-two resizing with max dimension caps
- ✅ LOD Generation: Multiple quality levels for distance-based rendering
- ✅ Smart Caching: Skip reprocessing when files and config are unchanged
- ✅ Detailed Reporting: Size reduction and triangle count statistics
# Optimize all models
yarn optimize
# Force re-optimization (ignore cache)
yarn optimize:force
# Optimize as part of build
yarn buildThe pipeline runs automatically during:
yarn dev- Silent background optimizationyarn build- Pre-build optimization
Edit .model-optimization.config.json in the project root:
{
"pipelineVersion": 1,
"geometry": {
"quantize": {
"position": 14,
"normal": 10,
"texcoord": 12,
"color": 8,
"generic": 12
},
"simplify": {
"enabled": true,
"ratio": 0.6,
"error": 0.001
}
},
"compression": {
"method": "draco",
"draco": {
"encodeSpeed": 5,
"decodeSpeed": 5
},
"meshopt": {
"level": "medium"
}
},
"textures": {
"resize": {
"enabled": true,
"max": 2048,
"powerOfTwo": true
},
"ktx2": {
"enabled": false,
"mode": "ETC1S",
"quality": 128,
"uastcZstandard": 18
}
},
"lod": {
"enabled": true,
"ratios": [1.0, 0.5, 0.25]
}
}-
quantize: Precision bits for vertex attributes (lower = smaller file)
position: 14 bits (default) - Good balance for most modelsnormal: 10 bits - Sufficient for smooth shadingtexcoord: 12 bits - High precision UVscolor: 8 bits - Standard color precisiongeneric: 12 bits - Other vertex attributes
-
simplify: Polygon reduction settings
enabled: Enable/disable simplificationratio: Keep N% of triangles (0.6 = 60%)error: Maximum visual deviation (0.001 = 0.1%)
-
method:
"draco"|"meshopt"|"both"draco: Better compression, slower decodemeshopt: Faster decode, web-optimizedboth: Apply both (not recommended)
-
draco: Draco-specific settings
encodeSpeed: 1-10 (10 = fastest, lower quality)decodeSpeed: 1-10 (10 = fastest decode)
-
resize: Texture sizing options
enabled: Enable automatic resizingmax: Maximum dimension (e.g., 2048)powerOfTwo: Force power-of-two dimensions
-
ktx2: KTX2/Basis Universal compression
enabled: Enable KTX2 compression (requirestoktxbinary)mode:"ETC1S"(smaller) or"UASTC"(higher quality)quality: 1-255 (higher = better quality)
- enabled: Enable LOD generation
- ratios: Array of simplification ratios
- First value (1.0) is always the base model
- Additional values generate LOD variants (e.g., [1.0, 0.5, 0.25])
The pipeline organizes models as follows:
public/assets/models/
└── <ModelName>/
├── model.glb # Original source file
├── glb/
│ └── model.glb # Optimized base (LOD0)
└── lod/
├── model.lod1.glb # 50% triangle count
└── model.lod2.glb # 25% triangle count
Important:
- Source
.glbfiles should be placed directly in<ModelName>/directories glb/andlod/subdirectories are auto-generated and should be in.gitignore- The pipeline skips
glb/andlod/directories to avoid recursive optimization
The .model-optimization-manifest.json tracks optimization state:
{
"optimized": {
"public/assets/models/FarmHouse/farm_house_basic_shaded.glb": {
"fileHash": "sha256:...",
"configHash": "sha256:...",
"outputs": {
"lod0": { "path": "...", "size": 123456 },
"lod1": { "path": "...", "size": 65432 },
"lod2": { "path": "...", "size": 32100 }
},
"timestamp": 1730000000000
}
}
}- fileHash: SHA-256 of source file content
- configHash: SHA-256 of pipeline configuration
- Models are re-optimized when either hash changes
Typical results from optimizing farm assets:
📊 Summary:
✅ Optimized: 3
💾 Total size: 19,133KB → 9,282KB (-51.5%)
🔺 Total triangles: 297,709 → 291,286 (-2.2%)
- Draco Compression: 40-60% reduction
- Geometry Simplification: 5-15% reduction
- Texture Resizing: 20-40% (when textures are oversized)
- Quantization: 10-20% reduction
- Place source
.glbfile inpublic/assets/models/<ModelName>/ - Run
yarn optimizeor let build scripts handle it - Commit source files only; generated
glb/andlod/are ephemeral
For high-quality hero assets:
{
"geometry": { "simplify": { "ratio": 0.8 } },
"compression": { "draco": { "encodeSpeed": 3 } }
}For background/distant objects:
{
"geometry": { "simplify": { "ratio": 0.4 } },
"compression": { "draco": { "encodeSpeed": 8 } }
}Models not optimizing:
- Check file is
.glb(not.gltf) - Verify file is in correct directory (not in
glb/orlod/) - Run with
--forceto ignore cache
Visual artifacts:
- Increase
geometry.simplify.ratio - Reduce
geometry.simplify.error - Increase quantization bits
Large file sizes:
- Enable texture resizing
- Lower
textures.resize.max - Enable KTX2 compression (requires
toktx)
The pipeline integrates seamlessly with build processes:
{
"build": "... && node scripts/optimize-models.js --silent && tsc && vite build"
}Silent mode suppresses output except errors, ideal for CI logs.
@gltf-transform/core- glTF document manipulation@gltf-transform/functions- Optimization transformsdraco3dgltf- Draco compression codecmeshoptimizer- Meshopt simplificationsharp- Image resizing (Node native)
Optional:
toktx- KTX2/Basis Universal compression (external binary)
To override settings for specific models, modify scripts/optimize-models.js:
const modelConfig = {
'FarmHouse/farm_house_basic_shaded.glb': {
geometry: { simplify: { ratio: 0.8 } },
},
};For issues or questions:
- Check manifest for error details
- Run
yarn optimizewith verbose output - Review optimization logs for specific models
- Consult PRD edge cases section