NavTech Solution is currently accepting new Next.js and AI development projects.Get in touch

Web DesignJuly 10, 2026 · 3 min read

When (and When Not) to Add a Three.js Scene to Your Website

3D web visuals can genuinely help a product page or hurt your Core Web Vitals badly — the difference comes down to a handful of implementation decisions.

By NavTech Solution

A 3D hero visual can make a product page feel considerably more polished, and it can also tank your Largest Contentful Paint if it's built without discipline. The technology isn't the risk — the implementation is.

Ask what the 3D scene is actually for

Before writing any Three.js code, be specific about the job the scene is doing. "Looks impressive" isn't a strong enough reason on its own; it needs to either communicate something a flat image can't (a product's actual geometry, an interactive configurator, data that genuinely has three dimensions) or serve a clear brand/attention goal on a page where performance cost is acceptable. If a static image or a CSS animation would communicate the same thing, that's usually the better default — it's cheaper to build, cheaper to maintain, and has zero WebGL performance cost.

Never let it block first paint

The most common mistake: importing Three.js directly into a page component, so its entire bundle ships as part of the initial JavaScript the browser has to parse before anything renders. Three.js is not small. Load it lazily, client-side only, after the rest of the page has already rendered:

"use client";
import dynamic from "next/dynamic";

const HeroScene = dynamic(() => import("./hero-scene"), { ssr: false });

And always render a real fallback underneath — a gradient, a static image, a CSS pattern — not a blank div or a spinner. If the 3D scene never mounts (slow connection, low-end device, JavaScript error), the page should still look intentional, not broken.

Gate it behind device capability and motion preference

Not every device can render a WebGL scene at an acceptable frame rate, and some users have explicitly told their OS they don't want motion:

function canRenderScene() {
  if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return false;
  if (navigator.hardwareConcurrency && navigator.hardwareConcurrency < 4) return false;
  if (window.innerWidth < 640) return false;
  return true;
}

Respecting prefers-reduced-motion isn't optional politeness — for some users it's the difference between a comfortable page and a genuinely disorienting one. Combine it with a coarse capability check (core count, screen size) so low-power devices get the static fallback instead of a scene that renders at an unusable frame rate.

Keep the scene itself lightweight

A few habits that keep a 3D scene's runtime cost proportional to what it's actually doing:

  • Dispose everything on unmount. Geometries, materials, and the renderer itself all hold GPU memory that won't release on its own — clean them up in your component's cleanup function, every time.
  • Cap pixel ratio. renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) — rendering at a phone's native 3x pixel density for a decorative hero visual burns GPU budget for a difference most users won't perceive.
  • Pause when off-screen. Stop the render loop when the tab isn't visible (document.visibilityState) or the scene has scrolled out of the viewport — there's no reason to keep animating something nobody's looking at.
  • Prefer vanilla Three.js for simple scenes. React Three Fiber's scene-graph abstraction is genuinely useful for complex, deeply interactive 3D applications, but for a single hero visual it's often extra abstraction over a scene simple enough to manage directly.

The honest tradeoff

Even built well, a 3D scene adds JavaScript weight and GPU cost that a static hero doesn't have. The question isn't "can we make it fast enough to not matter" — with lazy-loading and capability gating, you usually can — it's "does what this scene communicates justify that cost on this specific page." For a product with genuinely three-dimensional value (hardware, spatial data, a configurator), the answer is often yes. For a generic marketing site that wants "a 3D thing" because a competitor has one, a well-designed static or CSS-animated hero usually communicates just as much, for a fraction of the cost.

We build these gated, lazy-loaded, and disposed correctly by default as part of Three.js development, and the same lazy-loading and fallback discipline applies to how we think about Core Web Vitals on every page, 3D or not.

Three.jsWebGLPerformance