Three.js Tutorial: Getting Started in 2026
Build your first 3D web experience with Three.js
Start Building with Hypereal
Access Kling, Flux, Sora, Veo & more through a single API. Free credits to start, scale to millions.
No credit card required • 100k+ developers • Enterprise ready
Three.js Tutorial: Getting Started in 2026
Three.js is the most popular JavaScript library for creating 3D graphics on the web. It abstracts WebGL's complexity into an approachable API that lets you build interactive 3D scenes, product configurators, data visualizations, games, and immersive experiences directly in the browser.
This tutorial takes you from zero to a working 3D scene with lighting, materials, animation, and user interaction. No prior 3D programming experience is required.
What You Will Build
By the end of this tutorial, you will have a 3D scene with:
- A rotating, textured cube
- Ambient and directional lighting
- Camera controls for orbiting the scene
- Responsive canvas that adapts to window size
Prerequisites
| Requirement | Version |
|---|---|
| Node.js | 18+ |
| npm or yarn | Latest |
| Modern browser | Chrome, Firefox, Safari, or Edge |
| Code editor | VS Code recommended |
Basic JavaScript knowledge is required. Familiarity with ES modules (import/export) is helpful.
Step 1: Project Setup
Create a new project with Vite, which provides a fast dev server with hot module replacement:
npm create vite@latest threejs-tutorial -- --template vanilla
cd threejs-tutorial
npm install three
npm run dev
Your project structure should look like this:
threejs-tutorial/
index.html
main.js
style.css
package.json
Replace the contents of style.css:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
overflow: hidden;
}
canvas {
display: block;
}
Replace index.html with a minimal structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Three.js Tutorial</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<script type="module" src="/main.js"></script>
</body>
</html>
Step 2: Create a Basic Scene
Every Three.js application needs three things: a scene, a camera, and a renderer. Replace the contents of main.js:
import * as THREE from 'three';
// 1. Create the scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
// 2. Create a camera
const camera = new THREE.PerspectiveCamera(
75, // Field of view (degrees)
window.innerWidth / window.innerHeight, // Aspect ratio
0.1, // Near clipping plane
1000 // Far clipping plane
);
camera.position.z = 5;
// 3. Create the renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
// 4. Add a cube
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff88 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 5. Animation loop
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
Open your browser and you should see a green cube rotating against a dark background. That is your first Three.js scene.
Understanding the Core Concepts
| Concept | What It Does |
|---|---|
| Scene | The container for all 3D objects, lights, and cameras |
| Camera | Defines the viewpoint. PerspectiveCamera simulates human vision |
| Renderer | Converts the 3D scene into 2D pixels on the canvas |
| Geometry | The shape of an object (box, sphere, plane, etc.) |
| Material | The surface appearance (color, texture, shininess) |
| Mesh | A combination of geometry + material = a visible object |
Step 3: Add Lighting
The MeshBasicMaterial ignores lighting. To make objects respond to light, use a different material:
// Replace the material and add lighting
// Remove the old material line and replace with:
const material = new THREE.MeshStandardMaterial({
color: 0x00ff88,
roughness: 0.4,
metalness: 0.3,
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Add ambient light (soft, overall illumination)
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// Add directional light (like sunlight)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);
// Add a point light (like a light bulb)
const pointLight = new THREE.PointLight(0xff6b6b, 1, 100);
pointLight.position.set(-3, 2, 4);
scene.add(pointLight);
Light Types Comparison
| Light Type | Description | Performance Cost |
|---|---|---|
| AmbientLight | Uniform light from all directions | Lowest |
| DirectionalLight | Parallel rays (like sunlight) | Low |
| PointLight | Emits in all directions from a point | Medium |
| SpotLight | Cone-shaped beam | Medium-High |
| HemisphereLight | Sky/ground gradient light | Low |
| RectAreaLight | Light from a rectangular surface | High |
Step 4: Add Camera Controls
Install the orbit controls to let users rotate, zoom, and pan the camera:
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// After creating the renderer:
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 2;
controls.maxDistance = 20;
// Update the animation loop:
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
controls.update(); // Required when damping is enabled
renderer.render(scene, camera);
}
Now you can click and drag to orbit, scroll to zoom, and right-click to pan.
Step 5: Add Textures
Load an image texture onto the cube:
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('/textures/brick.jpg');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
const material = new THREE.MeshStandardMaterial({
map: texture,
roughness: 0.7,
metalness: 0.1,
});
You can also generate textures programmatically or use the built-in textures for prototyping.
Loading Multiple Textures (PBR Materials)
For photorealistic materials, use Physically Based Rendering (PBR) textures:
const loader = new THREE.TextureLoader();
const material = new THREE.MeshStandardMaterial({
map: loader.load('/textures/albedo.jpg'), // Color
normalMap: loader.load('/textures/normal.jpg'), // Surface detail
roughnessMap: loader.load('/textures/roughness.jpg'), // Shininess
metalnessMap: loader.load('/textures/metalness.jpg'), // Metal areas
aoMap: loader.load('/textures/ao.jpg'), // Ambient occlusion
});
Step 6: Add More Objects
Create a scene with multiple objects:
// Ground plane
const planeGeometry = new THREE.PlaneGeometry(20, 20);
const planeMaterial = new THREE.MeshStandardMaterial({
color: 0x333344,
roughness: 0.8,
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -1;
scene.add(plane);
// Sphere
const sphereGeometry = new THREE.SphereGeometry(0.7, 32, 32);
const sphereMaterial = new THREE.MeshStandardMaterial({
color: 0xff6b6b,
roughness: 0.2,
metalness: 0.8,
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.x = -2;
scene.add(sphere);
// Torus
const torusGeometry = new THREE.TorusGeometry(0.5, 0.2, 16, 100);
const torusMaterial = new THREE.MeshStandardMaterial({
color: 0x4ecdc4,
roughness: 0.3,
metalness: 0.6,
});
const torus = new THREE.Mesh(torusGeometry, torusMaterial);
torus.position.x = 2;
scene.add(torus);
Step 7: Make It Responsive
Handle window resizing so the scene adapts to any screen size:
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
Step 8: Load 3D Models
Most real projects use pre-made 3D models. The GLTF format is the standard for web 3D:
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const gltfLoader = new GLTFLoader();
gltfLoader.load(
'/models/robot.glb',
(gltf) => {
const model = gltf.scene;
model.scale.set(0.5, 0.5, 0.5);
model.position.set(0, -1, 0);
scene.add(model);
},
(progress) => {
console.log(`Loading: ${(progress.loaded / progress.total * 100).toFixed(1)}%`);
},
(error) => {
console.error('Failed to load model:', error);
}
);
Where to Find Free 3D Models
| Source | Format | License |
|---|---|---|
| Sketchfab | GLTF, FBX, OBJ | Varies (many CC) |
| poly.pizza | GLTF | CC0 |
| Kenney.nl | GLTF | CC0 |
| Three.js examples | GLTF | MIT |
| Quaternius | GLTF | CC0 |
Step 9: Add Post-Processing
Add visual effects like bloom, which creates a glow around bright areas:
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.5, // Strength
0.4, // Radius
0.85 // Threshold
);
composer.addPass(bloomPass);
// In your animation loop, replace renderer.render() with:
function animate() {
requestAnimationFrame(animate);
controls.update();
composer.render(); // Use composer instead of renderer
}
Complete Example
Here is the full main.js combining everything:
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
// Camera
const camera = new THREE.PerspectiveCamera(
75, window.innerWidth / window.innerHeight, 0.1, 1000
);
camera.position.set(3, 3, 5);
// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// Controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// Lights
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 5, 5);
dirLight.castShadow = true;
scene.add(dirLight);
// Objects
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0x00ff88, roughness: 0.4 })
);
cube.castShadow = true;
scene.add(cube);
const plane = new THREE.Mesh(
new THREE.PlaneGeometry(20, 20),
new THREE.MeshStandardMaterial({ color: 0x333344 })
);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -1;
plane.receiveShadow = true;
scene.add(plane);
// Resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
controls.update();
renderer.render(scene, camera);
}
animate();
Performance Tips
| Tip | Impact |
|---|---|
| Limit pixel ratio to 2 | Prevents rendering at 3x on high-DPI screens |
| Use BufferGeometry (default in modern Three.js) | Much faster than legacy Geometry |
| Dispose of unused textures and geometries | Prevents memory leaks |
| Use instancing for repeated objects | Draw thousands of objects in one draw call |
| Enable frustum culling (on by default) | Skip objects outside the camera view |
| Use compressed textures (KTX2/Basis) | Smaller file size and faster GPU upload |
Wrapping Up
Three.js opens up the world of 3D web development with an approachable API that scales from simple visualizations to complex interactive experiences. Start with the basics covered in this tutorial, then explore advanced topics like shaders, physics engines, and VR/AR integration.
If you are building 3D experiences that incorporate AI-generated content, such as textures, character faces, or video backgrounds, Hypereal AI offers APIs for AI image generation, video creation, and more that can feed directly into your Three.js pipeline.
Related Articles
Start Building Today
Get 35 free credits on signup. No credit card required. Generate your first image in under 5 minutes.
