three.js is the library that put 3D on the open web. It wraps the raw complexity of WebGL in a friendly API — so a spinning object, an orbitable product, or the particle field behind this very page is a few dozen lines, not a graphics project.
Browsers can draw hardware-accelerated 3D through WebGL, but WebGL on its own is famously low-level — you manage shaders, buffers and matrices by hand. three.js is the library that sits on top of it. It hands you friendly building blocks — meshes, cameras, lights, materials — and does the maths, so you can think "a glowing shape here, a camera looking at it" instead of GPU plumbing. It runs in a plain <canvas>, with no plugins, on every modern browser.
Every three.js project is built from the same trio: a scene (the world), a camera (your viewpoint), and a renderer (which draws the scene from the camera onto the canvas each frame).
import * as THREE from 'three';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
70, innerWidth / innerHeight, 0.1, 100
);
camera.position.z = 4;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
Objects on screen are meshes: a geometry (the shape) wrapped in a material (how it looks). Add a light so the material has something to react to, and drop both into the scene.
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0xd97757 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
const light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(2, 3, 4);
scene.add(light);
Animation is just re-drawing the scene many times a second, nudging something between frames. three.js calls your function before every repaint via setAnimationLoop — the modern replacement for a hand-rolled requestAnimationFrame loop, and the one that behaves correctly when the tab is hidden.
function animate() {
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);
That's a spinning cube in about twenty lines. Swap the geometry for a sphere, a loaded model, or tens of thousands of points and the shape of the code barely changes.
A few habits separate a demo from something you'd ship on a real site:
renderer.setPixelRatio(Math.min(devicePixelRatio, 2)) so retina screens don't render 4× the pixels for no visible gain.prefers-reduced-motion — render a single still frame for visitors who ask for less motion.IntersectionObserver, so a background effect isn't draining battery while someone reads further down.addEventListener('resize', () => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});
const still = matchMedia('(prefers-reduced-motion: reduce)').matches;
if (still) renderer.render(scene, camera); // one static frame
else renderer.setAnimationLoop(animate);
No build step required. The tidy modern way is an import map pointing at a CDN, then an ES module — the same approach that loads the starfield at the top of this page:
<script type="importmap">
{ "imports": { "three": "https://cdn.jsdelivr.net/npm/three@0.171.0/build/three.module.js" } }
</script>
<script type="module">
import * as THREE from 'three';
// ...your scene here
</script>
The jump from "spinning cube" to "tasteful hero animation" is mostly restraint: subtle motion, brand colours, and the performance habits above. The animated field behind this article's title is a three.js point cloud lit by a few coloured lights — a small effect that gives a flat page depth without shouting.
With Claude CMS you don't have to wire any of this by hand. Ask Claude to "add a three.js particle hero" or "make the header shape rotate," and it writes the module, drops it into your page, and matches your accent colour — the same way this site itself was built.
Here's a three.js scene running right here in the page — an SVG turned into a bevelled, lit 3D mesh. Drag to rotate, scroll to zoom, switch materials (chrome, glass, gold…), press Emboss → flat, or drop in your own .svg.
Built with three.js (WebGL) plus the SVGLoader and OrbitControls add-ons. Open the demo full-screen →