Listen up. If you're building modern applications, understanding Introduction to WebGL & Three.js is non-negotiable. This is where simple logic turns into intelligent behavior.
1Why Three.js Replaced Raw WebGL
Welcome to the world of 3D on the Web! Before Three.js, building 3D scenes meant writing hundreds of lines of complex WebGL code ā manually compiling GLSL shaders, managing vertex buffers, and hand-rolling matrix math just to draw a single triangle.
Three.js wraps that low-level WebGL API in a JavaScript-friendly object model: instead of shader boilerplate, you work with THREE.Mesh, THREE.Geometry, and THREE.Material objects that read like plain JavaScript. This doesn't remove WebGL ā it's still running underneath ā but it turns weeks of graphics-programming setup into a few readable lines of code you can iterate on quickly.
// Vanilla WebGL requires insane amounts of math
// Three.js makes it as easy as building with Lego bricks!3D Scene rendered. Objects: 4, Draw Calls: Optimized.
2The Holy Trinity: Scene, Camera, Renderer
At its core, a 3D application needs 3 things: A Scene (the universe), a Camera (your eyes), and a Renderer (the projector). We call this the Holy Trinity.
The Scene is a container that holds every object, light, and group you add to it ā think of it as the 3D equivalent of the DOM tree. The Camera defines the viewpoint and field of view used to project that 3D world onto a 2D screen. The Renderer takes the Scene and Camera together and actually draws the pixels, frame after frame, using the GPU via WebGL. None of the three is optional ā remove any one of them and there's nothing to render.
import * as THREE from 'three';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera();
const renderer = new THREE.WebGLRenderer();3D Scene rendered. Objects: 4, Draw Calls: Optimized.
3How the Trinity Works Together at Render Time
Every animation frame, the renderer asks: given this camera's position and this scene's contents, what should appear on screen? It calculates which objects are visible, applies lighting and materials, and rasterizes the result into the canvas element.
This loop typically runs inside requestAnimationFrame, redrawing up to 60 times per second. Understanding this cycle matters because anything you change on the scene or camera before the next frame ā a rotation, a new mesh, a moved light ā will be reflected in the very next render, which is what makes real-time 3D interactivity possible.
scene, camera, and ???3D Scene rendered. Objects: 4, Draw Calls: Optimized.
4Enter React Three Fiber (R3F)
In modern React apps, we use a wrapper called 'React Three Fiber' (R3F). It takes care of the Holy Trinity for us by just using a Canvas component ā no manual new THREE.Scene() or renderer setup required.
R3F isn't a reimplementation of Three.js; it's a React reconciler that lets you describe a Three.js scene declaratively, the same way you'd describe a DOM tree with JSX. Under the hood it still creates real Three.js objects and drives the same render loop ā it just manages their lifecycle (creation, updates, disposal) for you as your component tree changes.
import { Canvas } from '@react-three/fiber';
function App() {
return (
<Canvas>
{/* 3D Objects go here */}
</Canvas>
);
}3D Scene rendered. Objects: 4, Draw Calls: Optimized.
5Rendering Your First Mesh
Let's actually render something! Let's put a rotating cube inside our Canvas and watch the 3D preview update in real time.
A mesh in R3F pairs a geometry (the shape, here boxGeometry) with a material (the surface appearance, here meshStandardMaterial), exactly like Three.js's new THREE.Mesh(geometry, material). The useFrame hook runs on every animation frame, letting you mutate the mesh's rotation values directly ā this is how you animate objects without manually managing a render loop yourself.
const Cube = () => {
const meshRef = React.useRef();
useFrame((state, delta) => {
meshRef.current.rotation.x += delta;
meshRef.current.rotation.y += delta;
});
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshStandardMaterial color="hotpink" />
</mesh>
);
};
render(
<Canvas>
<ambientLight intensity={0.5} />
<directionalLight position={[2, 5, 2]} />
<Cube />
</Canvas>
);3D Scene rendered. Objects: 4, Draw Calls: Optimized.
6The Canvas Component
In React Three Fiber, the Canvas component automatically creates the Scene, Camera, and Renderer for you and mounts a real canvas DOM element in its place.
Everything you nest inside Canvas ā lights, meshes, groups ā becomes part of that scene graph automatically. This is why R3F code looks so much shorter than vanilla Three.js: the imperative setup (new THREE.Scene(), new THREE.WebGLRenderer(), appending the canvas to the DOM) all happens implicitly the moment you render a Canvas component.
<??? />3D Scene rendered. Objects: 4, Draw Calls: Optimized.
7Lowercase Tags Map to Three.js Classes
Notice how we used mesh, boxGeometry, and meshStandardMaterial? In R3F, all Three.js classes are available as lowercase HTML-like tags, generated automatically from the THREE namespace.
The naming convention is mechanical: THREE.BoxGeometry becomes boxGeometry, THREE.MeshStandardMaterial becomes meshStandardMaterial, and so on for every class Three.js exports. This means you rarely need to look up R3F-specific documentation for basic primitives ā if you know the Three.js class name, you already know its JSX tag.
// THREE.BoxGeometry -> <boxGeometry />
// THREE.MeshStandardMaterial -> <meshStandardMaterial />3D Scene rendered. Objects: 4, Draw Calls: Optimized.
8Passing Props Like Constructor Arguments
You can pass properties to these tags just like React props. To set the color, we use the color prop, exactly as you would pass a parameter to new THREE.MeshStandardMaterial({ color: '#00FF00' }) in vanilla Three.js.
Most Three.js constructor options map directly to JSX props this way. For properties that take multiple arguments (like a geometry's width, height, and depth), R3F uses an args array prop instead ā boxGeometry args={[1, 1, 1]} ā since JSX props can only pass one value each.
<meshStandardMaterial color="#00FF00" />3D Scene rendered. Objects: 4, Draw Calls: Optimized.
9Building Other Primitive Geometries
The same tag-mapping rule applies to every geometry Three.js ships with, including THREE.SphereGeometry, which becomes sphereGeometry in React Three Fiber.
Each primitive geometry accepts its own args ā a sphere takes radius and segment counts, a box takes width/height/depth, a cylinder takes top/bottom radius and height. Checking the Three.js documentation for a class's constructor signature tells you exactly what to pass in the args array.
<??? />3D Scene rendered. Objects: 4, Draw Calls: Optimized.
10Swapping in a Rotating Sphere
Let's change our cube into a rotating green sphere! Swapping the shape is as simple as swapping the geometry tag ā the mesh, material, and animation logic barely need to change.
The args={[1.5, 32, 32]} here set the sphere's radius to 1.5 and its width/height segment counts to 32 each, controlling how smooth the sphere looks. Higher segment counts produce a rounder sphere at the cost of more triangles to render ā a tradeoff worth remembering once you start optimizing scenes with many objects.
const Sphere = () => {
const meshRef = React.useRef();
useFrame((state, delta) => {
meshRef.current.rotation.y -= delta;
});
return (
<mesh ref={meshRef}>
<sphereGeometry args={[1.5, 32, 32]} />
<meshStandardMaterial color="#CCFF00" wireframe />
</mesh>
);
};
render(
<Canvas>
<ambientLight intensity={1} />
<Sphere />
</Canvas>
);3D Scene rendered. Objects: 4, Draw Calls: Optimized.
11What You've Built and What's Next
Awesome! You've just built your first interactive 3D scenes. In the next lessons, we'll dive deeper into the Scene graph and Camera types (perspective vs. orthographic).
The pattern you just learned ā geometry and material combined inside a mesh, animated via a frame hook ā is the foundation for almost everything else in Three.js and R3F, from complex character models to particle systems. Every advanced technique you'll see later is built on this same core loop.
// š Level 1 Complete!3D Scene rendered. Objects: 4, Draw Calls: Optimized.
12Step-by-Step Breakdown
Welcome to the world of 3D on the Web! Before Three.js, building 3D scenes meant writing hundreds of lines of complex WebGL code. Three.js changed everything.
At its core, a 3D application needs 3 things: A Scene (the universe), a Camera (your eyes), and a Renderer (the projector). We call this the Holy Trinity.
What are the three fundamental components required to render anything in Three.js?
- āgeometry
- ārenderer
- āmesh
In modern React apps, we use a wrapper called 'React Three Fiber' (R3F). It takes care of the Holy Trinity for us by just using a <Canvas> component!
Let's actually render something! Let's put a rotating cube inside our Canvas. Look at the 3D preview!
In React Three Fiber, what component automatically creates the Scene, Camera, and Renderer?
- āScene
- āCanvas
- āWebGL
Notice how we used <mesh>, <boxGeometry>, and <meshStandardMaterial>? In R3F, all Three.js classes are available as lowercase HTML-like tags.
You can pass properties to these tags just like React props. To set the color, we use the color prop.
How would you write a THREE.SphereGeometry in React Three Fiber?
- āSphereGeometry
- āsphere
- āsphereGeometry
Let's change our cube into a rotating green sphere!
Awesome! You've just built your first interactive 3D scenes. In the next lessons, we'll dive deeper into the Scene and Cameras.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Provide a Text Alternative for Canvas-Rendered 3D Content
A WebGL canvas is a single opaque bitmap to assistive technology ā screen readers cannot inspect meshes, lights, or geometry inside it. Always wrap the Canvas with an aria-label or adjacent visually-hidden text describing what the scene shows, so the experience isn't entirely invisible to non-sighted users.
<div role="img" aria-label="3D rotating cube demo"><Canvas>...</Canvas></div>SEO Implications
- 1
3D Canvas Content Is Invisible to Search Crawlers
Everything rendered inside a WebGL canvas is pixels, not indexable text or DOM structure ā a page's SEO value for Three.js content comes entirely from the surrounding text, headings, and code samples on the page, not from anything happening inside the canvas element itself.
Best Practices
Always Dispose of Geometries, Materials, and Textures When Removing Objects
Three.js resources allocate GPU memory that JavaScript's garbage collector cannot reclaim on its own. Call .dispose() on any geometry, material, or texture before removing its mesh from the scene, especially in single-page apps where components mount and unmount repeatedly.
Reuse Geometries and Materials Across Multiple Meshes Where Possible
If you're rendering many similar objects (like a field of trees), share one geometry and material instance across all of them via instancing or simple reuse, rather than constructing a new one per mesh ā this dramatically reduces memory use and draw calls.
Frequent Bugs
Adding lights and geometry to a scene but seeing nothing render because the camera is positioned at the same coordinates as the object (0,0,0) or facing the wrong direction.
Always explicitly set the camera's position away from the origin (e.g., camera.position.set(0, 0, 5)) and confirm it's pointed at your objects ā R3F's default camera position is not guaranteed to frame arbitrary scene content correctly.
Real-World Examples
Product Configurators for E-Commerce
Furniture and sneaker brands use Three.js/R3F to let shoppers rotate, zoom, and recolor a 3D product model directly in the browser ā built on exactly the Scene/Camera/Renderer trinity and mesh/geometry/material pattern covered in this lesson, just with more detailed imported models instead of a basic cube.
<Canvas camera={{ position: [0, 0, 5] }}>
<ProductModel color={selectedColor} />
<OrbitControls />
</Canvas>