Upload the model behind your scene to find what's tanking your frame rate.
Drop a 3D model to grade it
or click to browse — GLB or glTF, up to 300 MB. It's graded in your browser; the file never leaves your device.
When an R3F scene stutters, the model is usually the cause: too many draw calls, dense geometry, or textures that exhaust GPU memory. The analyzer surfaces these instantly so you stop guessing in the profiler.
Draw calls are the classic bottleneck — every separate material and mesh adds CPU overhead. Merging geometry that shares a material and using texture atlases is often the biggest single win.
After that it's geometry density and texture memory. The analyzer estimates draw calls and reports both, so you know where to focus before touching code.
Most R3F performance work is asset work, not code. Get the model lean — fewer draw calls, compressed textures, sensible triangle counts — and instancing, frustum culling and the rest of your tuning suddenly pays off.
We'll rework the heavy assets in your Three.js / R3F project — draw calls, geometry, textures — so the scene hits its frame-rate target. Free review and quote.
Draco/Meshopt geometry, KTX2 textures and clean decimation — without visible quality loss.
Optimized to load fast and render smoothly on phones, not just high-end desktops.
We protect silhouettes, UVs and materials so the model still looks like your model.
When a ThreeJS scene drops frames or performs poorly on mobile, the root cause is almost always the loaded model, not the render loop. Three.js and R3F are efficient renderers; they struggle when the assets they are given are too heavy. Before reaching for profiler counters or useFrame optimizations, inspect the model itself.
Draw calls are the first thing to measure. Every mesh with its own material generates a separate draw call — a CPU-to-GPU command with non-trivial overhead per frame. A single model exported from CAD or a sculpting tool can contain hundreds of meshes with individual materials, producing hundreds of draw calls per frame. On mobile, draw calls above ~50 become a significant CPU bottleneck regardless of GPU speed. Merge geometries that share a material using mergeGeometries from three-stdlib, and consider InstancedMesh for repeating objects to collapse many draw calls into one.
Uncompressed textures are the second lever. A PNG or JPEG texture must be fully decoded into GPU memory before it can be used. A single 4096×4096 RGBA texture consumes ~64 MB of VRAM — before mipmaps. Three or four maps of that size exhaust the VRAM budget on most mobile devices, causing texture loss, frame drops, or tab crashes. KTX2 (Basis Universal) solves this: the texture stays compressed natively on the GPU, reducing VRAM by 4–6×. Three.js ships a KTX2Loader that handles format transcoding automatically.
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const ktx2Loader = new KTX2Loader()
.setTranscoderPath('/basis/')
.detectSupport(renderer);
const loader = new GLTFLoader();
loader.setKTX2Loader(ktx2Loader);If the GLB uses Draco geometry compression — which it should, for any production asset — you need to configure the DRACOLoader on the GLTFLoader. Without it, Three.js cannot parse Draco-compressed meshes at all. With it, geometry that was 20 MB on disk loads as 3 MB and parses significantly faster.
The MeshGrade analyzer reports whether Draco and KTX2 compression are present in your GLB. If they are not, that is almost always the highest-impact change available. A model that goes from uncompressed to Draco + KTX2 typically drops from 20–40 MB to 2–5 MB with no visible quality change.
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');
const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);Before writing any of the above, run your model through the free MeshGrade analyzer. It reports the exact draw call count, triangle and vertex totals, every texture's resolution and estimated VRAM cost, and whether Draco and KTX2 compression are present. A five-second grade tells you whether the bottleneck is draw calls, texture memory, or geometry density — so you invest your optimization time in the right place and skip changes that won't move the needle.
Most often the loaded model: high draw calls, too many triangles, or large uncompressed textures. The analyzer measures all three from your GLB.
For smooth mobile rendering, keep it under ~50 where you can. Hundreds of draw calls will bottleneck the CPU regardless of how fast your GPU is.