Start with a budget, not a profiler panic
WebGL performance problems often appear late because the scene starts simple and becomes expensive one feature at a time. A small site should have a budget before the visual polish begins. Decide how many objects, draw calls, lights, texture sizes, and postprocessing passes are acceptable for the page's purpose.
A hero scene, a product viewer, and a full-screen tool deserve different budgets. A hero scene shares attention with text, navigation, and scrolling. A tool can justify more GPU work because interaction is the main experience. Write this down so every new effect has to earn its cost.
Watch draw calls and materials
Many small meshes with unique materials can cost more than one larger mesh with shared material. Imported models may contain dozens of nodes from the authoring tool. Inspect `renderer.info.render.calls`, mesh count, and material count. These numbers explain why a scene feels heavy even when the triangle count looks reasonable.
When possible, merge static geometry, reuse materials, and remove hidden authoring leftovers. If a viewer is intended for arbitrary uploaded models, expose these metrics rather than silently accepting every asset as production-ready.
Texture size is a content problem
Huge textures are easy to miss because the model still loads. A 4096 pixel texture may be fine for a close-up product render but excessive for a small card preview. Compression and resizing often deliver more improvement than rewriting code. If the page targets mobile users, texture memory matters as much as JavaScript size.
Use the smallest texture that survives the intended camera distance. For many web previews, 1024 or 2048 pixel maps are enough. Save 4K maps for scenes where the user can zoom close enough to benefit.
Stop rendering when nothing changes
The simplest render loop redraws every frame forever. That is fine for animated scenes, but wasteful for static viewers. If the object is still, render on controls change, resize, or UI updates. If the scene is below the fold, pause animation with IntersectionObserver. If reduced motion is enabled, remove nonessential loops.
Performance is part of trust. A site that makes a laptop fan spin for a decorative hero scene feels careless. Keep the WebGL work proportional to the user's benefit.
When this guide is the right tool
Use this guide when the problem is specific enough that a broad Three.js tutorial would waste time. The focus here is performance in a real browser page: what to check first, what to measure, and what to avoid before the scene becomes harder to reason about.
The practical rule is simple: Measure draw calls, triangles, texture sizes, and frame time early. If that sentence describes the scene in front of you, treat the article as a checklist. Read the explanation, copy the smallest useful code pattern, then test the result in a narrow mobile viewport and a wide desktop viewport before adding more polish.
Common mistake to avoid
The common mistake is treating A practical Three.js performance budget for small sites as a visual tweak instead of a scene-system decision. Three.js problems often look like one broken line of code, but the actual issue is usually a chain: asset assumptions, renderer settings, camera math, material setup, interaction state, and page layout all meet inside the canvas.
That is why the safest fix is incremental. Start from a known-good scene, change one variable, and keep a visible diagnostic while testing. Clamp pixel ratio and avoid postprocessing until the base scene is stable. When the scene works, remove temporary helpers and leave behind only the checks that make sense for users.
Publishing check
Before publishing, run the scene through three questions. Does the page remain useful if WebGL fails or the asset loads slowly? Does the same scene still read clearly on a phone? Can another developer understand the important settings without reverse-engineering the whole file?
The last pass should be boring on purpose: verify canvas size, console errors, mobile performance, source links, internal links, and the related guide path. Pause or reduce animation for offscreen scenes and reduced-motion users. If any answer is fuzzy, fix that before introducing a new effect or a larger asset.
Basic render metrics
function logRenderInfo(renderer) {
const { render, memory } = renderer.info;
console.table({
calls: render.calls,
triangles: render.triangles,
geometries: memory.geometries,
textures: memory.textures
});
}
setInterval(() => logRenderInfo(renderer), 2000);
FAQ
When should I use A practical Three.js performance budget for small sites?
Use it when your Three.js scene has a focused performance problem and you need a practical checklist before adding more visual polish.
Is the code snippet production-ready?
Treat the snippet as a clear starting point. Test it in your scene, adapt naming and paths, and verify behavior on mobile hardware before publishing.
What should I check after applying this guide?
Run the scene through mobile sizing, console errors, loading states, source links, and related guide paths so the page remains useful even when assets or WebGL fail.