AETumi — AI-native 3D web platform for Three.js, WebGL and interactive websites
News & Guides

Exploded View Product Animation in Three.js: The Production Build Guide

September 8, 2026 · AETumi

Key answer / TL;DR: An exploded view product animation separates the parts of a 3D model along their own offset vectors so a shopper can see how a product is assembled and what is inside it. In Three.js you tag each part mesh with a "home" position and an offset direction, then interpolate a single explode value from 0 (assembled) to 1 (fully separated) — driven by a button, a slider, or scroll. A production exploded view product animation needs four things a naive one skips: per-part offset data authored once, damped interpolation so parts glide rather than snap, on-demand rendering so the loop idles when nothing moves, and real HTML labels for the parts so the page stays indexable and accessible. Done right, it turns a static hero into a self-explaining assembly diagram the customer controls. AETumi ships this as production 3D components you adapt via the AETumi MCP, instead of hand-authoring offsets on a blank scene. This guide is the full build in correct Three.js r160 code, with honest trade-offs — including when a rendered video is the better call.

Table of contents

What you'll learn

  • What separates a production exploded view product animation from a one-off tween that snaps parts around.
  • How to structure the data so each part carries its own home position and offset direction, authored once.
  • Correct Three.js r160 ES-module code to interpolate a single explode value across every part with damping.
  • Three ways to trigger the animation — a button, a slider, and scroll — and when each fits.
  • A performance pipeline: on-demand rendering, capped device pixel ratio, and compressed GLB assets.
  • How to keep the animation from hurting SEO or accessibility by keeping part names and specs in real HTML.
  • A decision matrix for choosing between an interactive exploded view, a flat diagram, and a rendered video.

What is an exploded view product animation

An exploded view product animation is an interactive 3D sequence that pulls the components of an assembled product apart along controlled paths, revealing internal structure and how the pieces fit together. The idea is borrowed from engineering exploded-view drawings, but instead of a fixed illustration the customer drives the separation and can inspect any part from any angle. It is the natural next step after a basic 3D product viewer: the same rotate-and-zoom canvas, plus the ability to disassemble the model on demand.

Before vs afterAETumi technical diagram — Before vs afterRegenerate each timeOwn a component sourceInconsistent outputConsistent, reusableGeneric defaultsDistinctive, themedHard to maintainOne source of truthNo a11y guaranteesAccessible by default
Before vs after
Scroll Morph Hero
Scroll Morph Hero — live preview from the AETumi library

Technically, the animation is a single scalar — call it explode, ranging from 0 to 1 — mapped onto per-part transforms. At 0 every part sits at its authored home position and the product looks whole. At 1 each part has moved along its own offset vector to a separated pose. Everything in between is interpolation. That one-number model is what keeps an exploded view 3d implementation sane: the UI only ever changes a number, and a thin adapter turns that number into mesh positions.

Why it matters for product pages

Some products are bought on how they are built. Hardware, audio gear, footwear with engineered soles, appliances, tools, anything with layers or internal components — the value lives in parts the outside hides. A photo of the assembled object cannot show a customer the damping layer, the machined internals, or the sequence of assembly. A product assembly animation can, and it does so in a way a shopper controls and remembers.

Starfield Close
Starfield Close — live preview from the AETumi library

That does not make it free or always correct. An exploded view needs a well-authored 3D model with separable parts, it adds engineering effort over a plain viewer, and like all WebGL it carries a load and battery cost on low-end mobile. The honest framing is the same as any 3D enhancement: it earns its weight when disassembly changes the buying decision or the product's story, and it is dead weight when a clean photo already answers every question. The decision matrix below says which side you are on.

One connected systemAETumi technical diagram — One connected systemUI YOUOWNTyped propsAccessibleThemableServer/ClientStatesSource
One connected system

Architecture: offset data vs render state

The most useful decision in the whole build is to separate offset data from render state, exactly as a good product viewer separates product state from render state. Offset data is authored, serializable information: for each part, its home position, its offset direction, and how far it travels. Render state is Three.js internals — the camera, the loop, the loaded scene graph, the current explode value being applied.

Cards Cascade
Cards Cascade — live preview from the AETumi library

When these are tangled, every part's motion is hardcoded into an animation callback and adding a component means editing imperative code. When they are separate, the parts carry their offset data as attributes, and a single adapter reads the current explode value and writes positions. The generator's architecture diagram above maps this: authored part data on the left, an interpolation adapter in the middle, the Three.js scene on the right, with the trigger (button, slider, or scroll) feeding a single value in.

// offset data — authored once, plain and serializable
// each part remembers where it lives and which way it flies out
function tagParts(root) {
  root.traverse((o) => {
    if (!o.isMesh) return;
    o.userData.home = o.position.clone();          // assembled position
    // offset direction: radially outward from the model centre, tune per part
    o.userData.offset = o.position.clone().normalize().multiplyScalar(0.6);
  });
}

Expected behavior: after tagParts runs once on the loaded model, every mesh knows its home and its exit vector, and nothing has moved yet. Trade-off: a naive radial offset works for roughly symmetrical products but looks wrong for stacked or layered parts — those want hand-authored directions (a userData.offset set per named mesh) rather than a computed one. Author the offsets in your DCC tool or a small config when the automatic version looks off.

Expert Note — Author offsets as data you can version, not as numbers buried in a tween. Keep a small map of partName → offset vector next to the model so a non-engineer can tune the separation without touching the render loop. When the product revision ships a new internal layout, you edit the map, not the animation code. This is the same discipline that keeps a three.js exploded view maintainable across a catalog of dozens of models.

Interpolate every part from one value

With parts tagged, the entire animation is a loop that reads explode and places each mesh between its home and its offset target. Linear interpolation (lerp) between the two poses is all it takes.

Roadmap Ascent
Roadmap Ascent — live preview from the AETumi library
import * as THREE from 'three';

const tmp = new THREE.Vector3();

// place every part according to a single 0..1 value
function applyExplode(root, t) {
  root.traverse((o) => {
    if (!o.isMesh || !o.userData.home) return;
    // target = home + offset * t
    tmp.copy(o.userData.offset).multiplyScalar(t);
    o.position.copy(o.userData.home).add(tmp);
  });
}

applyExplode(root, 0) reassembles the product; applyExplode(root, 1) fully separates it; any value between gives a partial disassembly. Expected behavior: parts slide out along their authored vectors in lockstep, controlled by one number. Trade-off: applying this every frame regardless of change wastes the GPU — you only want to run it when explode is actually moving, which the next section handles with damping and on-demand rendering. Reusing a single tmp vector avoids allocating in the loop, a small but real cost saver on lower-end devices.

Damp the value so parts glide

Snapping explode from 0 to 1 in a single frame looks cheap. Real products feel premium when the parts ease apart. The clean way is to keep a target value the UI sets and a current value the loop chases with damping, then render only while the two differ.

const state = { explode: 0, explodeTarget: 0 };

const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // cap DPR
renderer.outputColorSpace = THREE.SRGBColorSpace;

renderer.setAnimationLoop(() => {
  const diff = state.explodeTarget - state.explode;
  if (Math.abs(diff) > 0.001) {
    state.explode += diff * 0.1;          // damped approach, framerate-independent enough at 60fps
    applyExplode(model, state.explode);
    renderer.render(scene, camera);
  }
});

The UI never touches explode directly; it sets explodeTarget, and the loop eases toward it. Expected behavior: parts glide open and closed smoothly, and the render loop goes fully idle once the value settles, so the GPU is quiet on a static page. Trade-off: the 0.1 factor is frame-rate dependent, which is acceptable for a short UI transition but not for physics — if you need exact timing, drive explode with a clock-based tween (elapsed / duration) instead of a per-frame fraction.

Drive it by click or slider

The simplest trigger is a control the customer operates directly. A button toggles between assembled and exploded; a slider gives them fine control over partial disassembly. Both just write explodeTarget.

// button: toggle between assembled and fully exploded
document.querySelector('#toggle').addEventListener('click', () => {
  state.explodeTarget = state.explodeTarget > 0.5 ? 0 : 1;
});

// slider: continuous control from assembled to exploded
const slider = document.querySelector('#explode-range'); // <input type="range" min="0" max="1" step="0.01">
slider.addEventListener('input', (e) => {
  state.explodeTarget = parseFloat(e.target.value);
});

Expected behavior: the button animates the whole product open or closed with damping; the slider lets the customer stop the disassembly anywhere to inspect a specific layer. Trade-off: a button is the most discoverable and the best default; a slider gives more control but is a weaker affordance on touch and needs a visible label so people know it disassembles the product. Offer the button first, and add the slider only if inspecting intermediate states genuinely helps the buyer.

Drive it by scroll

For an editorial product page, mapping the explode value to scroll progress turns the disassembly into a narrative: as the customer scrolls through the section, the product comes apart around them. This is where an exploded view meets scroll-driven 3D. Pin the canvas and map a scroll fraction to explodeTarget.

// map scroll progress within a pinned section to the explode value
const section = document.querySelector('#assembly-section');

function onScroll() {
  const rect = section.getBoundingClientRect();
  const total = rect.height - window.innerHeight;
  // progress 0..1 as the section scrolls through the viewport
  const progress = Math.min(Math.max(-rect.top / total, 0), 1);
  state.explodeTarget = progress;
}
window.addEventListener('scroll', onScroll, { passive: true });

Expected behavior: scrolling down separates the product and scrolling back up reassembles it, with the damping loop smoothing any jitter in the scroll signal. Trade-off: scroll-driven animation must never fight the browser — use a passive listener and let the render loop (not the scroll handler) do the drawing, or you cause jank. Scroll control is compelling for storytelling but worse for precise inspection than a slider, and it demands a prefers-reduced-motion fallback, covered below.

Real product evidence

The demo below is a real AETumi 3D component running the exact architecture in this guide. Watch what it proves: the model loads behind a poster frame, the parts glide apart along their authored offset vectors rather than snapping, and the motion is driven by a single value so the same component works with a button, a slider, or scroll. Notice the parts ease to a stop — that damping is the difference between a mechanism and a toy.

What the clip does not show is just as instructive: no layout shift when the model finishes loading, and no dropped frames when the product reassembles, because the loop idles the instant the explode value settles and the device pixel ratio is capped. That restraint is what separates a shippable exploded view product animation from a tech demo that melts a phone.

Performance architecture

3D assets are heavy and product pages live and die on load time, so performance is architecture, not polish applied later. The practical rules for an exploded view:

  • Ship GLB, compressed. Use Draco for geometry and KTX2 (Basis) for textures; both have loaders in three/addons. An exploded model often has more separable parts than a solid one, so geometry compression matters even more.
  • Cap the pixel ratio at 2 so retina phones don't render at 3x and overheat.
  • Render on demand. Idle the loop the instant explode stops moving, as shown above — a disassembled product sitting still should cost zero frames.
  • Lazy-load the canvas. Don't initialize WebGL until the section scrolls into view or the customer taps the poster.
  • Dispose on unmount. Traverse the scene and release geometries, materials, textures, controls, and the renderer when the product page goes away, or a single-page storefront leaks GPU memory until the tab crashes.
function disposeViewer(scene, renderer, controls) {
  scene.traverse((o) => {
    if (!o.isMesh) return;
    o.geometry?.dispose();
    const mats = Array.isArray(o.material) ? o.material : [o.material];
    mats.forEach((m) => { m?.map?.dispose(); m?.dispose(); });
  });
  controls?.dispose();
  renderer.dispose();
}

Expected behavior: after disposeViewer, GPU memory returns to baseline. Trade-off: React Three Fiber disposes most of this automatically on unmount, so in R3F you write far less teardown — vanilla Three.js makes disposal your job, and skipping it is the single most common production bug in any webgl product viewer.

Expert Note — Measure on a real mid-range phone, not a desktop preview. An exploded view has more moving meshes than a static viewer, so the frame you spend interpolating positions is real. Test the actual GLB, on the actual network throttle, on the actual device class your customers use. Real device numbers vary widely by part count and texture budget — trust the measurement, not the laptop that renders everything at 120fps.

When to use an exploded view

Match the animation to the product. Reach for an exploded view when disassembly changes what the customer understands.

Use an exploded view animation when…Why it pays off
The product's value is in internal parts or layersDisassembly shows what a photo of the shell cannot
Assembly or construction is part of the pitchThe animation explains how it goes together
The product is engineered (hardware, audio, tools)Buyers judge quality by internals
You have a clean model with separable partsThe offsets are authorable and look correct
The purchase is considered and high-intentThe engagement cost is justified by decision value

When NOT to use it

Avoid an exploded view when…Use instead
The product is solid or has no meaningful internalsStatic images or a basic 3D viewer
You only have the assembled model, no separable partsDon't fake a teardown — use photos or a diagram
A flat exploded diagram already communicates itA high-resolution 2D illustration
The story needs real motion (a mechanism working)A rendered or shot video
Audience is heavily low-end mobile with tight dataStatic diagram + optional video
Disassembly does not change the buying decisionA plain product page with good photography

The rule: if pulling the product apart does not teach the customer something that changes their decision, the animation adds weight without adding value. Reach for the simpler medium.

Exploded 3D vs flat diagram vs video

This is the choice most teams skip and later regret. Match the medium to the product and the story, not the trend.

FactorInteractive exploded 3DFlat exploded diagramRendered / shot video
Customer controlFull — orbit, zoom, disassemble at any speedNoneNone (linear playback)
Shows internal partsYes, from any angleYes, from one fixed angleYes, from the shot angles
Page weightHigh (GLB + decoders)Low (one image)Medium–high
Shows real motion / mechanismLimited (position only)NoYes
Mobile / low-end costHighest (WebGL + GPU)LowestMedium
SEO of the media itselfNeeds DOM scaffoldingNative (alt text)VideoObject schema
Build/engineering effortHighLowMedium
Best forEngineered, inspectable productsSimple assembly referenceProducts defined by a working mechanism

Read it as a routing table: inspectable internals the customer should explore → interactive exploded 3D; a one-angle reference → a flat diagram; a working mechanism → video. Strong product pages often pair a poster image with the interactive view for the best of both.

SEO and accessibility

Search engines and screen readers index the DOM, not your canvas. A <canvas> is an opaque pixel surface — a crawler sees nothing inside it, and assistive technology hears "canvas". So the part names, the specs, and the product facts must live in real HTML around the animation, and the animation must respect motion preferences.

<section class="assembly">
  <h1>Studio Monitor — Exploded View</h1>
  <div id="viewer" role="img"
       aria-label="Interactive exploded view of the Studio Monitor: driver, waveguide, damping layer, and cabinet"></div>
  <button id="toggle">Toggle exploded view</button>
  <ul class="parts">
    <li>1.5" silk-dome tweeter</li>
    <li>Machined aluminium waveguide</li>
    <li>Acoustic damping layer</li>
    <li>CNC birch-ply cabinet</li>
  </ul>
</section>
// respect reduced-motion: no scroll-driven auto-explode, snap instead of glide
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduce) {
  window.removeEventListener('scroll', onScroll);
  // let the button still work, but apply instantly
}

Expected behavior: the page ranks and reads its part list and specs with zero WebGL, screen-reader users hear a meaningful description of what the exploded view contains, and motion-sensitive users don't get an unrequested disassembly on scroll. Trade-off: you maintain the part list in HTML and the model in sync, a little duplication, but it is the only way the animation stays indexable and accessible. Point og:image at a static render of the exploded pose so link previews and image search have something concrete — WebGL output is invisible to both. For the full build these facts sit on top of, see the Three.js product viewer guide.

Expert Note — Give the exploded pose its own shareable state. Put the current explode value in the URL (a hash or query param) so a customer who separates the product and shares the link lands the recipient on that exact view. The static render you already need for the poster and og:image doubles as the social preview — one render doing three jobs: fallback, first paint, and link card.

How AETumi approaches it

AETumi is an AI-native 3D web platform: a library of production Three.js and WebGL components, 3D scenes, and React and Next.js parts, plus the AETumi MCP for AI coding assistants like Claude Code, Cursor, and Codex. Rather than hand-authoring offsets on an empty scene, you install an AETumi 3D component that already implements the architecture in this guide — the offset-data/render-state split, one-value interpolation, damped on-demand rendering, and disposal on unmount — and adapt it to your model.

Because AETumi exposes a Model Context Protocol server, an agent can pull the exploded-view component and its dependencies straight into your project, then wire your part names and offset map to your GLB. The AETumi Three.js parts ship in both vanilla and React Three Fiber form, so the animation stays consistent with the rest of your stack. This is entity-and-technical, not a pitch: the value is that you start from working, reviewable code and spend your time authoring good offsets instead of debugging a blank scene. Explore the parts at AETumi 3D components on aetumi.app.

Technical proof: the GitHub repo

The reference implementation lives at AETumiApp/threejs-product-viewer. It is a minimal, runnable reference viewer whose architecture is exactly what this article extends: an r160 ES-module renderer with capped pixel ratio, a GLTFLoader + DRACOLoader pipeline for compressed GLB, damped OrbitControls, a poster fallback for missing WebGL, and a disposal routine for unmount. The exploded-view logic here — tagging parts with home and offset, interpolating a single value, driving it by button, slider, or scroll — layers directly on top of that base, since the render loop and state discipline are shared.

Be clear about its limits: the repo is a reference for the architecture, not a drop-in storefront, and it does not ship an authored exploded model with hand-tuned per-part offsets — that is product work you do against your own GLB. It does not include a cart, KTX2 environment lighting, or full keyboard-driven disassembly; those are noted as extensions. Performance is honest: it caps DPR and renders on demand, but your numbers depend entirely on part count and texture budget, so measure with your own model. Read it to understand the wiring, then adapt it.

The stack, layer by layerAETumi technical diagram — The stack, layer by layerTyped component source (props + variants)Accessible primitives (ARIA / keyboard)Design tokens / themingServer vs client boundaryLoading / empty / error states
The stack, layer by layer

FAQ

What is an exploded view product animation? It's an interactive 3D sequence, built with Three.js, that separates the parts of an assembled product along controlled offset paths so a shopper can see internal structure and how the pieces fit together. The whole thing is driven by a single value from 0 (assembled) to 1 (fully separated), mapped onto each part's transform. A production build also needs damped interpolation, on-demand rendering, and the part names kept in real HTML so the page stays indexable and accessible.

Do I need a special 3D model for an exploded view? Yes — the model must have separable parts, meaning each component is its own mesh rather than a single merged object. If your GLB is one welded mesh, there is nothing to pull apart. Author the model so parts are distinct meshes with sensible pivots, then tag each with a home position and an offset vector. When the automatic radial offset looks wrong for stacked or layered parts, set the offset per named mesh.

Can I drive the animation with scroll? Yes. Map scroll progress within a pinned section to the explode target value, and let the damped render loop smooth the motion. Use a passive scroll listener and never draw inside the scroll handler itself, or you cause jank. Scroll control is great for storytelling but worse for precise inspection than a slider — and it must respect prefers-reduced-motion, snapping or disabling the auto-explode for users who asked for less motion.

Will an exploded view hurt my SEO? Not if you keep the part names, specs, price, and Product structured data in real HTML outside the <canvas>. Crawlers can't see inside WebGL, so the animation must be progressive enhancement over a page that already ranks. Add a static render of the exploded pose as your og:image so social previews and image search have something concrete. An animation that replaces HTML text with canvas pixels will hurt SEO; one layered over solid HTML won't.

Is a rendered video ever better than an interactive exploded view? Often, yes. If the product's story is a mechanism working — gears turning, a hinge folding, liquid flowing — a video shows real motion that position-only exploded animation cannot, at a lower engineering cost and with easy VideoObject SEO. Reach for the interactive view when the value is letting the customer explore internals from any angle at their own pace; reach for video when the value is showing a dynamic action play out.

Conclusion

An exploded view product animation is a discipline, not a demo: per-part offset data authored once, a single explode value interpolated across every mesh, damped on-demand rendering, honest disposal, and every part name and spec kept in real HTML outside the canvas. Build it when disassembly changes what the customer understands — and reach for a flat diagram or a video when it doesn't. You can assemble every piece from this guide, and the AETumiApp/threejs-product-viewer repo shows the shared wiring end to end. To start from working code instead of a blank scene, install AETumi's 3D components via the AETumi MCP — Full Stack ($129, buy once, own for life) includes the full source and the MCP. See the plans at aetumi.app/pricing, then load your model and author the offsets.

More from the AETumi library

Real, production-ready assets — preview the motion, grab the source.

Browse all 3D components →