Model Cache System
The Model Cache system provides efficient loading and caching of 3D models (GLB/GLTF files) with automatic material setup, LOD generation, and persistent IndexedDB storage.Model cache code lives in
packages/shared/src/utils/rendering/ModelCache.ts.Overview
The cache prevents loading the same GLB file multiple times by:- In-memory caching: Loaded models are cached and cloned for new instances
- Material sharing: All instances of a model share the same materials (reduces draw calls)
- IndexedDB persistence: Processed models are stored in IndexedDB to skip GLTF parsing on subsequent sessions
- Automatic LOD generation: Optional decimated meshes and octahedral impostors for distant rendering
Basic Usage
Processed Model Cache (IndexedDB)
The cache stores processed models in IndexedDB to skip expensive GLTF parsing on subsequent loads.What Gets Cached
Geometry Data:- Vertex positions, normals, UVs, colors
- Index buffers
- Skinning data (weights, indices)
- Colors (base, emissive)
- PBR values (roughness, metalness)
- Texture pixel data (RGBA arrays)
- Transparency, alpha test, side
- Node tree structure
- Mesh-to-node mapping
- Bone hierarchy (for skinned meshes)
- Keyframe tracks (position, rotation, scale)
- Track timing and interpolation
- Collision data from GLB extras
- Cache version and timestamp
Cache Version
The cache uses version3 (as of Feb 2026). When the version changes, all cached entries are automatically invalidated.
- v1: Initial implementation
- v2: Added texture caching
- v3: Fixed missing objects bug (identity-based mesh mapping) and texture restoration bug (DataTexture pixel extraction)
Cache Invalidation
Cached models are invalidated when:- Cache version changes (code update)
- Source GLB file size changes (asset update)
- IndexedDB is cleared by browser
Bug Fixes (PR #935)
Missing Objects Bug
Issue: Models with duplicate mesh names (e.g., multiple meshes named “Cube”) had missing objects after cache restoration. Only the last mesh with each name appeared in the scene. Root Cause:serializeNode() used findIndex-by-name to map hierarchy nodes to mesh data. When multiple meshes shared the same name, they all resolved to the same index. During deserialization, Three.js add() auto-removes children from their previous parent, so only the last reference survived.
Fix: Use object-identity mapping instead of name-based lookup:
Lost Textures Bug
Issue: Textures appeared white or wrong colors after browser restart. Models loaded correctly on first load but lost textures when restored from IndexedDB cache. Root Cause: Textures were serialized as ephemeralblob: URLs but never reloaded during deserialization. The blob URLs became invalid after page refresh.
Fix: Extract raw RGBA pixel data synchronously and restore as DataTexture:
- Synchronous restoration (no async loading race conditions)
- No network requests for cached textures
- Textures persist across browser restarts
Grey Tree Materials Bug
Issue: Trees appeared grey in WebGPU builds after cache restoration. Root Cause:createDissolveMaterial() used instanceof MeshStandardMaterial which fails for MeshStandardNodeMaterial in WebGPU builds (separate classes).
Fix: Duck-type property check instead of instanceof:
Disabling the Cache
For debugging or testing, you can disable the processed model cache:Error Handling
The cache includes comprehensive error logging:- IndexedDB unavailable → Falls back to GLTF parsing
- Deserialization error → Clears cache entry and retries
- Corrupted cache entry → Automatically invalidated on version mismatch
Performance
Cache Hit Benefits:- Skips GLTF binary parsing (~20-100ms per model)
- Skips texture decoding (already in RGBA format)
- Immediate geometry reconstruction from typed arrays
- No network requests for textures
- Small models (items): 20-40ms
- Medium models (NPCs): 40-80ms
- Large models (buildings): 80-150ms
Material Sharing
By default, all instances of a model share the same materials:- Reduces draw calls (GPU can batch instances)
- Lower memory usage (one material per model type)
- Faster cloning (no material creation)
- Custom per-instance colors
- Dynamic material properties
- Instance-specific textures
LOD Integration
The cache integrates with the LOD system for automatic level-of-detail generation:Cache Statistics
Cache Management
Preloading
Preload multiple models in parallel for faster initial load:WebGPU Compatibility
All cached materials are converted toMeshStandardNodeMaterial for WebGPU/TSL support:
- Proper PBR lighting with sun/moon
- WebGPU-native TSL dissolve effects
- Consistent material behavior across renderers
Collision Data
Models can embed collision data in GLB extras (injected byinject-model-collision.ts):
Related Documentation
- LOD System - Level-of-detail generation and management
- Client Loader - Asset loading and priority system
- Three.js Integration - Three.js setup and WebGPU compatibility