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

Claude Code + Three.js: Building 3D Scenes and Components

September 7, 2026 · AETumi

Key answer: Claude Code Three.js work goes well when you prompt with structure — name the scene graph, camera, lighting, materials, interaction, and a performance budget, then change one variable at a time. Claude Code is fast at setup, wiring, and refactors; you direct the look and review the output, because an agent will confidently produce plausible-but-wrong 3D code (invented APIs, outdated methods) if you don't check it against the current docs. Start it from a real reference — AETumi's Three.js assets, installable via MCP — rather than a blank scene, and the first draft lands close to shippable. The prompting-patterns checklist below is the practical core.

Three.js is the most popular way to put real-time 3D on the web, and Claude Code is an agent that can assemble and refactor exactly the kind of multi-part code a scene requires. Paired well, they compress hours of renderer plumbing into a reviewable loop. Paired carelessly, you get a generic spinning cube and a subtle memory leak. This article is about pairing them well: the failure modes to expect, a reusable checklist, correct baseline code, how to iterate on shaders and motion, and when a real reference beats a blank prompt.

From idea to productionAETumi technical diagram — From idea to productionBrief & art directionPrompt the agentBuild from owned sourceReview & refineShip production
From idea to production

Table of contents

What you will learn

  • The two failure modes of Claude Code Three.js work — generic demos and outdated APIs — and how to defeat both.
  • An eleven-point prompting checklist to hand the agent before any scene.
  • A minimal, correct r160 ES-module baseline you can ask the agent to extend.
  • How to iterate on shaders and motion by exposing uniforms instead of regenerating.
  • The disposal and reduced-motion habits that keep scenes leak-free and accessible.
  • A clear decision framework for React Three Fiber vs. vanilla Three.js.

Why Three.js is a good fit for an agent

Three.js is a well-documented, widely used library with stable, composable concepts: a scene, a camera, a renderer, meshes made of geometry and material, lights, and a render loop. That structure is exactly what an agent like Claude Code handles well — clear building blocks it can assemble, wire, and refactor across files. It is also why Claude Code Three.js work rewards a little structure up front: the pieces are predictable, so precise constraints steer the output reliably.

Lens Refraction
Lens Refraction — live preview from the AETumi library

Two failure modes are worth naming up front. Without direction, an agent produces the canonical spinning-cube demo — technically correct, visually generic. And because Three.js has evolved (examples moved to ES modules, some helpers were renamed or removed), an agent may reach for an API that no longer exists or a pattern from an old tutorial. Both are solvable: brief it with structure and a real reference for the look, and verify the code runs against the version in your project rather than assuming it's right. Treat the agent as a fast, literal collaborator you direct and review, not an oracle.

AETumi live WebGL scene — real-time Three.js rendered in your browser, not a video.

Why this matters for shipping 3D

The reason to get the Claude Code Three.js loop right is that 3D fails visibly. A misremembered string method degrades gracefully; a misremembered Three.js API leaves a black canvas or throws in the console. A scene that forgets to dispose resources does not error at all — it just leaks GPU memory until a long session stutters. These are bugs that are cheap to prevent with structure and expensive to chase after the fact.

One connected systemAETumi technical diagram — One connected systemAETUMIBUILDAI promptThree.jsNext.jsComponents3D scenesShip
One connected system

The upside is equally real: when you brief the agent well and start from a correct reference, it removes the tedious, error-prone plumbing — renderer config, resize handling, the animation loop, disposal — and lets you spend your attention on the look and the motion, which is where the value actually is. That trade — agent does the mechanics, you do the art direction and review — is why the workflow is worth the discipline.

The Three.js prompting patterns checklist

This checklist is the unique, reusable asset here. Run through it whenever you ask Claude Code for a Three.js scene or component.

  • [ ] State the scene graph. List objects explicitly: "one hero mesh, a ground plane, a particle field." Ambiguity invites filler.
  • [ ] Fix the camera. Type (perspective/orthographic), position, and behavior (orbit, fixed, scroll-driven). Say the starting framing.
  • [ ] Specify lighting. e.g., "key + rim light, soft ambient." Name the mood, not just the lights.
  • [ ] Choose materials precisely. PBR metal, glass, matte; roughness/metalness intent. Add "no cheap drop shadows."
  • [ ] Define interaction. Scroll scrub, pointer parallax, hover state — and keep it restrained.
  • [ ] Set a performance budget. Target framerate, texture compression, geometry disposal, pause loop offscreen.
  • [ ] Demand a reduced-motion fallback. A static, accessible state for users who prefer reduced motion.
  • [ ] Pin the version. Tell it which Three.js version you're on so it doesn't mix old and new APIs.
  • [ ] Ask for one component, runnable. A self-contained file plus notes on where assets go.
  • [ ] Iterate one variable at a time. Change the material, or the camera path — not both — so you can judge the effect.
  • [ ] Request cleanup. Dispose geometries/materials and remove listeners on unmount to avoid leaks.

Feed these as constraints up front and the first draft lands far closer to right.

A minimal, correct scene as a baseline

A short, correct vanilla Three.js starting point (r160, ES modules) you can ask the agent to extend. Keep versions current in your own project.

import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  50, window.innerWidth / window.innerHeight, 0.1, 100
);
camera.position.set(0, 0, 4);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const mesh = new THREE.Mesh(
  new THREE.IcosahedronGeometry(1, 0),
  new THREE.MeshStandardMaterial({ metalness: 0.6, roughness: 0.3 })
);
scene.add(mesh);

const key = new THREE.DirectionalLight(0xffffff, 2);
key.position.set(3, 2, 5);
scene.add(key);
scene.add(new THREE.AmbientLight(0xffffff, 0.4));

renderer.setAnimationLoop(() => {
  mesh.rotation.y += 0.005;
  renderer.render(scene, camera);
});

Expected behavior: a PBR icosahedron turns slowly under a key and ambient light, at capped pixel ratio. Production trade-off: this omits a resize handler and disposal for brevity — both are non-negotiable in a shipped component, so name them when you ask the agent to extend this. From here, direct the agent: "swap to a glass material," "make the camera scroll-driven," "add a subtle particle field." One change at a time.

Iterating on shaders and motion

Shaders and motion are where iteration pays off — and where a vague prompt burns the most time. The pattern that works is to describe intent, expose the knobs, and refine visually rather than asking for a finished effect in one shot.

  • Describe the look, not the math. "Fresnel rim glow, subtle, cool tint" gives the agent a target; refine the numbers after you see it. Asking for a specific GLSL formula up front usually gets you something rigid you then have to unpick.
  • Ask for uniforms you can tune. Request exposed parameters — uIntensity, uSpeed, uColor — wired as material.uniforms, so you adjust values live without regenerating the whole shader. This one habit turns shader work from "regenerate and hope" into a tuning session.
  • Give the agent the update hook. Tell it to advance a uTime uniform in the animation loop and drive motion from that, not from Date.now() scattered through the code, so timing stays centralized and pausable.
  • Motion in physical terms. "Ease the camera along a path over the first two viewport scrolls, then hold." Then tune the easing curve once you can feel it.
  • Guard performance while iterating. Ask it to keep draw calls low, reuse Vector3/Color instances instead of allocating per frame, and avoid rebuilding geometry on every change. Per-frame new is the quiet killer of a smooth shader.

Here is the shape of an exposed-uniform material the agent should produce, so you can tune it live:

const material = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0 },
    uIntensity: { value: 0.8 },
    uColor: { value: new THREE.Color('#66ccff') },
  },
  vertexShader: /* glsl */`
    varying vec3 vNormal;
    void main() {
      vNormal = normalize(normalMatrix * normal);
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }`,
  fragmentShader: /* glsl */`
    uniform float uIntensity;
    uniform vec3 uColor;
    varying vec3 vNormal;
    void main() {
      float fresnel = pow(1.0 - abs(vNormal.z), 3.0) * uIntensity;
      gl_FragColor = vec4(uColor * fresnel, fresnel);
    }`,
  transparent: true,
});

Expected behavior: a view-dependent Fresnel rim glow whose strength and tint you change by setting material.uniforms.uIntensity.value or .uColor.value — no shader recompile. Trade-off: this simple Fresnel uses vNormal.z as a cheap approximation; a physically accurate rim needs the view vector, which costs a little more. Start cheap, upgrade only if the look demands it. Then drive time from one place in the loop:

const clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
  material.uniforms.uTime.value = clock.getElapsedTime();
  renderer.render(scene, camera);
});

Expected behavior: motion advances from a single uTime source, so pausing the loop pauses everything and timing stays consistent. Trade-off: getElapsedTime keeps counting even while off-screen, so pair this with pausing the loop when the canvas is not visible.

Cleanup, disposal, and reduced motion

The two things an improvised scene most often skips are disposal and reduced-motion — both cheap to add, both real problems in production. Ask the agent for them explicitly. Disposal releases GPU resources when a scene unmounts:

function dispose(scene, renderer) {
  scene.traverse((obj) => {
    obj.geometry?.dispose();
    const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
    mats.forEach((m) => m?.dispose());
  });
  renderer.dispose();
}

Expected behavior: geometries, materials, and the renderer's GPU context are freed; skip this in a single-page app and memory climbs every time a scene mounts. Trade-off: in vanilla Three.js you must call this yourself at the right lifecycle moment, which is easy to forget — one reason React Three Fiber, which disposes on unmount, is attractive for app-integrated 3D.

For accessibility, gate motion on the user's preference:

const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
renderer.setAnimationLoop(reduce ? null : () => {
  mesh.rotation.y += 0.005;
  renderer.render(scene, camera);
});
if (reduce) renderer.render(scene, camera); // render one static frame

Expected behavior: users who prefer reduced motion see a still, correctly-lit frame instead of continuous animation. Trade-off: a single static frame may look less impressive, but it is the accessible and honest default — motion should be an enhancement, not a requirement to use the page.

Performance budget

State performance as an explicit budget in the prompt rather than hoping the agent adds it, because a first draft usually will not. The high-leverage items: cap device pixel ratio at 2 so you are not rendering 3x fragments on a phone for no visible gain; keep draw calls low by merging geometry and reusing materials; avoid allocating new Vector3 or Color objects inside the animation loop, since per-frame garbage collection causes visible hitching; compress textures and size them to what the screen actually shows; and pause the render loop when the canvas scrolls off-screen. None of these are exotic — they are the difference between a scene that holds 60fps and one that stutters, and an agent will include them reliably only if you ask. Making a performance budget part of every Claude Code Three.js prompt is the cheapest quality gate you have.

React Three Fiber vs. vanilla Three.js

The choice isn't about which is "better" — it's about which paradigm fits your stack, because mixing them mid-project produces the worst agent output. Decide first, then tell Claude Code explicitly.

FactorVanilla Three.jsReact Three Fiber
Mental modelImperative scene graphDeclarative components
Fits your stackAny / no frameworkReact / Next.js
Agent ergonomicsExplicit, easy to traceComposable, reusable
State & UI wiringManualNatural via React hooks
Lifecycle & cleanupYou manage disposalR3F disposes on unmount
Best forStandalone scenes, demosApp-integrated 3D

Vanilla keeps everything explicit: one file, a clear render loop, easy to trace when you're debugging what the agent wrote. It's the right call for a standalone hero scene or a widget dropped into a non-React page.

React Three Fiber expresses the scene as JSX components and reconciles it like the rest of your UI. If your site is React or Next.js, it usually keeps the agent's output cleaner and more reusable, and it handles disposal on unmount for you — one less leak to police. The tradeoff is an extra abstraction layer to understand when something goes wrong. See the React Three Fiber collection for components built this way. Whichever you pick, say so in the prompt — an unspecified choice is how you end up with imperative scene.add() calls tangled inside a React render.

When to use an agent for Three.js

SituationWhy it fits
Standing up scene plumbing (renderer, loop, resize)Agent is fast and reliable at boilerplate
Refactoring or restructuring an existing sceneTraces and edits multi-file code well
Iterating on shaders via exposed uniformsTune live instead of regenerating
Adapting a reviewed reference componentStrong, predictable starting point
Wiring 3D into a React/Next.js appR3F output composes cleanly

When NOT to use one

SituationBetter choice
A flat decorative visual with no interactionStatic image or CSS — no WebGL at all
A simple 2D animationCSS transitions or a small canvas 2D loop
Bleeding-edge or novel rendering researchHand-write it; the agent's training lags
Hard low-end mobile budget, heavy sceneReconsider 3D; ship a lighter asset
You can't verify the output against docsSlow down — unreviewed 3D ships bugs

Expert notes

Expert Note — Pin your Three.js version in the prompt, every time. The single most common Claude Code Three.js bug is an API that was renamed or removed between versions. The model's memory blends releases, so it may reach for a helper that no longer exists. Telling it "we're on r160, ES modules" scopes its choices to reality and eliminates a whole category of "it looked right but throws" errors before they happen.

Expert Note — Expose uniforms instead of regenerating shaders. When a shader is close but not right, the instinct is to ask for a new one. Don't. Ask the agent to wire the tunable values as material.uniforms up front, then adjust .value live. This turns shader work from a slot machine into a tuning knob, and it is the difference between landing a look in three tries and thirty.

Expert Note — Start from a reviewed reference, not a blank scene. A blank prompt gives the agent no anchor, so it defaults to the generic demo. Handing it a real, working scene — like an AETumi Three.js component installed via MCP — gives it a correct baseline to adapt, so the first draft is close to shippable instead of close to a tutorial. The reference does more to control quality than any single prompt instruction.

Using AETumi assets via MCP

AETumi (aetumi.app) is an AI-native 3D web platform: a library of production Three.js scenes, WebGL sites, and React components, plus an MCP integration for AI coding assistants. It is purpose-built for Claude Code Three.js work, giving the agent a reviewed starting point instead of a blank file. Instead of asking Claude Code to build a hero from nothing, have it install an asset and adapt it — a stronger, more predictable starting point than a blank scene.

Because the platform exposes a Model Context Protocol server, Claude Code can pull assets and components directly into your project — no manual download, no path guessing. The workflow:

1. Pick a Three.js scene or 3D component that matches your concept. 2. Connect via MCP. 3. Ask the agent to install it, then apply the prompting-patterns checklist to customize. 4. Iterate on shaders and motion using the tips above.

This pairs naturally with a broader agent-driven build. If you're standing up a whole site this way, see how to build a website with Claude Code for the end-to-end flow. Plans are buy once, own for life: Standard $19, Pro $39, Premium $99, and Full Stack $129. Full source code and the MCP integration are included in Full Stack — the natural pick for agent-driven Three.js work, since it's what lets Claude Code install and modify components directly.

How AETumi approaches it

The stance behind AETumi is that an agent produces its best 3D when it starts from correct, reviewed source rather than its own memory. So the platform ships full source for its Three.js scenes and React components, and exposes them to agents through an MCP server, so Claude Code can install a real component and adapt it with the checklist above. The components already handle the parts an improvised scene fumbles — capped pixel ratio, a centralized uTime, disposal on unmount, a reduced-motion path — so what the agent hands you is close to shippable. The division of labor is deliberate: the library supplies the correct baseline, the agent supplies the adaptation, you supply the art direction and the review.

GitHub and technical proof

A minimal reference implementation lives in the open-source AETumi claude-code-threejs repository. It shows the r160 ES-module setup, a tunable-uniform material, and the disposal and reduced-motion patterns discussed here — a real example rather than a wall of prose. Reading it is also how you see the limits: it is a compact reference, not a full site, and it pins a specific Three.js version, so treat the version and API choices there as a snapshot to verify against your own project rather than an evergreen guarantee. The point of the repo is a correct, inspectable baseline the agent can extend — the same principle this article argues for.

How it works, step by stepAETumi technical diagram — How it works, step by stepFull source (Three.js / React / Next.js)AI build promptCompressed assets (Draco / KTX2)Poster + reduced-motion fallback
How it works, step by step

FAQ

Can Claude Code write Three.js code correctly? Often, yes — especially for standard scene setup, wiring, and refactors, which are structured tasks it handles reliably. But it can also produce plausible code that uses an outdated or invented API, because its memory blends library versions. Pin your version in the prompt, verify the result runs in your project, and direct-and-review rather than assuming the first draft is right. Treated that way, it is a fast collaborator; treated as an oracle, it ships subtle bugs.

How do I stop it from producing a generic demo? Use the prompting-patterns checklist: explicit objects, a fixed camera, a named lighting mood, precise materials, defined interaction, and a performance budget. The single biggest lever, though, is a real reference — hand the agent a working scene to adapt instead of a blank prompt, and it starts from something specific rather than defaulting to the canonical spinning cube. Structure plus a reference beats either alone.

Should I use React Three Fiber or vanilla Three.js? Use React Three Fiber if your site is React or Next.js, since it composes with your UI and disposes on unmount for you; use vanilla for standalone scenes or non-React pages, where an explicit single-file loop is easy to trace. Decide before you prompt and tell the agent which one. The failure to avoid is leaving it unspecified, which is how you end up with imperative scene.add() calls tangled inside a React render.

How does AETumi help with Three.js specifically? It provides production Three.js scenes and components the agent can install via MCP, so you customize proven code — with capped pixel ratio, disposal, and reduced-motion already handled — instead of building from scratch. That reviewed baseline is what makes the agent's first draft close to shippable. A minimal reference implementation lives in the claude-code-threejs repo.

How do I keep 3D performant with an AI agent? State an explicit budget in the prompt: compress textures, cap the pixel ratio at 2, minimize draw calls, avoid per-frame allocations, dispose unused resources, and pause the loop off-screen. An agent includes these reliably only when asked, so make them a named constraint rather than a hope. These few habits are the difference between a scene that holds 60fps and one that stutters on a mid-range phone.

Related resources

Conclusion

Claude Code is a capable Three.js collaborator when you prompt with structure, pin your version, iterate one variable at a time, and review its output instead of trusting it blindly. Use the prompting-patterns checklist to keep results production-grade, expose uniforms so shader work becomes tuning rather than guessing, choose vanilla or React Three Fiber deliberately, and start from a real reference rather than a blank scene. AETumi's Three.js assets install straight into your project via MCP, giving the agent the strong baseline it needs. Connect from aetumi.app/pricing, hand Claude Code the checklist, and build.

More from the AETumi library

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

Browse all Three.js assets →