Three.js Best Practices
Comprehensive performance optimization guide for Three.js applications. Contains 100+ rules across 17 categories, prioritized by impact.
Based on official guidelines from Three.js llms branch maintained by mrdoob.
When to Apply
Reference these guidelines when:
Setting up a new Three.js project Writing or reviewing Three.js code Optimizing performance or fixing memory leaks Working with custom shaders (GLSL or TSL) Implementing WebGPU features Building VR/AR experiences with WebXR Integrating physics engines Optimizing for mobile devices Rule Categories by Priority Priority Category Impact Prefix 0 Modern Setup & Imports FUNDAMENTAL setup- 1 Memory Management & Dispose CRITICAL memory- 2 Render Loop Optimization CRITICAL render- 3 Geometry & Buffer Management HIGH geometry- 4 Material & Texture Optimization HIGH material- 5 Lighting & Shadows MEDIUM-HIGH lighting- 6 Scene Graph Organization MEDIUM scene- 7 Shader Best Practices (GLSL) MEDIUM shader- 8 TSL (Three.js Shading Language) MEDIUM tsl- 9 Loading & Assets MEDIUM loading- 10 Camera & Controls LOW-MEDIUM camera- 11 Animation System MEDIUM animation- 12 Physics Integration MEDIUM physics- 13 WebXR / VR / AR MEDIUM webxr- 14 Audio LOW-MEDIUM audio- 15 Mobile Optimization HIGH mobile- 16 Production HIGH error-, migration- 17 Debug & DevTools LOW debug- Quick Reference 0. Modern Setup (FUNDAMENTAL) setup-use-import-maps - Use Import Maps, not old CDN scripts setup-choose-renderer - WebGLRenderer (default) vs WebGPURenderer (TSL/compute) setup-animation-loop - Use renderer.setAnimationLoop() not manual RAF setup-basic-scene-template - Complete modern scene template 1. Memory Management (CRITICAL) memory-dispose-geometry - Always dispose geometries memory-dispose-material - Always dispose materials and textures memory-dispose-textures - Dispose dynamically created textures memory-dispose-render-targets - Always dispose WebGLRenderTarget memory-dispose-recursive - Use recursive disposal for hierarchies memory-dispose-on-unmount - Dispose in React cleanup/unmount memory-renderer-dispose - Dispose renderer when destroying view memory-reuse-objects - Reuse geometries and materials 2. Render Loop (CRITICAL) render-single-raf - Single requestAnimationFrame loop render-conditional - Render on demand for static scenes render-delta-time - Use delta time for animations render-avoid-allocations - Never allocate in render loop render-cache-computations - Cache expensive computations render-frustum-culling - Enable frustum culling render-update-matrix-manual - Disable auto matrix updates for static objects render-pixel-ratio - Limit pixel ratio to 2 render-antialias-wisely - Use antialiasing judiciously 3. Geometry (HIGH) geometry-buffer-geometry - Always use BufferGeometry geometry-merge-static - Merge static geometries geometry-instanced-mesh - Use InstancedMesh for identical objects geometry-lod - Use Level of Detail for complex models geometry-index-buffer - Use indexed geometry geometry-vertex-count - Minimize vertex count geometry-attributes-typed - Use appropriate typed arrays geometry-interleaved - Consider interleaved buffers 4. Materials & Textures (HIGH) material-reuse - Reuse materials across meshes material-simplest-sufficient - Use simplest material that works material-texture-size-power-of-two - Power-of-two texture dimensions material-texture-compression - Use compressed textures (KTX2/Basis) material-texture-mipmaps - Enable mipmaps appropriately material-texture-anisotropy - Use anisotropic filtering for floors material-texture-atlas - Use texture atlases material-avoid-transparency - Minimize transparent materials material-onbeforecompile - Use onBeforeCompile for shader mods (or TSL) 5. Lighting & Shadows (MEDIUM-HIGH) lighting-limit-lights - Minimize dynamic lights lighting-bake-static - Bake lighting for static scenes lighting-shadow-camera-tight - Fit shadow camera tightly lighting-shadow-map-size - Choose appropriate shadow resolution lighting-shadow-selective - Enable shadows selectively lighting-shadow-cascade - Use CSM for large scenes lighting-probe - Use Light Probes 6. Scene Graph (MEDIUM) scene-group-objects - Use Groups for organization scene-layers - Use Layers for selective rendering scene-visible-toggle - Use visible flag, not add/remove scene-flatten-static - Flatten static hierarchies scene-name-objects - Name objects for debugging scene-object-pooling - Use object pooling 7. Shaders GLSL (MEDIUM) shader-precision - Use appropriate precision shader-avoid-branching - Minimize branching shader-precompute-cpu - Precompute on CPU shader-avoid-discard - Avoid discard, use alphaTest shader-texture-lod - Use textureLod for known mip levels shader-uniform-arrays - Prefer uniform arrays shader-varying-interpolation - Use flat when appropriate shader-chunk-injection - Use Three.js shader chunks 8. TSL - Three.js Shading Language (MEDIUM) tsl-why-use - Use TSL instead of onBeforeCompile tsl-setup-webgpu - WebGPU setup for TSL tsl-complete-reference - Full TSL type system and functions tsl-material-slots - Material node properties reference tsl-node-materials - Use NodeMaterial classes tsl-basic-operations - Types, operations, swizzling tsl-functions - Creating TSL functions with Fn() tsl-conditionals - If, select, loops in TSL tsl-textures - Textures and triplanar mapping tsl-post-processing - bloom, blur, dof, ao tsl-compute-shaders - GPGPU and compute operations tsl-glsl-to-tsl - GLSL to TSL translation 9. Loading & Assets (MEDIUM) loading-draco-compression - Use Draco for large meshes loading-gltf-preferred - Use glTF format gltf-loading-optimization - Full loader setup with DRACO/Meshopt/KTX2 loading-progress-feedback - Show loading progress loading-async-await - Use async/await for loading loading-lazy - Lazy load non-critical assets loading-cache-assets - Enable caching loading-dispose-unused - Unload unused assets 10. Camera & Controls (LOW-MEDIUM) camera-near-far - Set tight near/far planes camera-fov - Choose appropriate FOV camera-controls-damping - Use damping for smooth controls camera-resize-handler - Handle resize properly camera-orbit-limits - Set orbit control limits 11. Animation (MEDIUM) animation-system - AnimationMixer, blending, morph targets, skeletal 12. Physics (MEDIUM) physics-integration - Rapier, Cannon-es integration patterns 13. WebXR (MEDIUM) webxr-setup - VR/AR buttons, controllers, hit testing 14. Audio (LOW-MEDIUM) audio-spatial - PositionalAudio, HRTF, spatial sound 15. Optimization (HIGH) mobile-optimization - Mobile-specific optimizations and checklist raycasting-optimization - BVH, layers, GPU picking 16. Production (HIGH) error-handling-recovery - WebGL context loss and recovery migration-checklist - Breaking changes by version 17. Debug (LOW) debug-stats - Use Stats.js debug-helpers - Use built-in helpers debug-gui - Use lil-gui for tweaking debug-renderer-info - Check renderer.info debug-conditional - Remove debug code in production How to Use
Read individual rule files for detailed explanations and code examples:
rules/setup-use-import-maps.md rules/memory-dispose-geometry.md rules/tsl-complete-reference.md rules/mobile-optimization.md
Each rule file contains:
Brief explanation of why it matters BAD code example with explanation GOOD code example with explanation Additional context and references Key Patterns Modern Import Maps
Proper Disposal function disposeObject(obj) { if (obj.geometry) obj.geometry.dispose(); if (obj.material) { if (Array.isArray(obj.material)) { obj.material.forEach(m => m.dispose()); } else { obj.material.dispose(); } } }
TSL Basic Usage import { texture, uv, color, time, sin } from 'three/tsl';
const material = new THREE.MeshStandardNodeMaterial(); material.colorNode = texture(map).mul(color(0xff0000)); material.colorNode = color(0x00ff00).mul(sin(time).mul(0.5).add(0.5));
Mobile Detection const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent); renderer.setPixelRatio(Math.min(window.devicePixelRatio, isMobile ? 1.5 : 2));