Three.js Fundamentals
Quick Start
javascript
import * as THREE from "three";
// Create scene, camera, rendererconst scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000,);const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));document.body.appendChild(renderer.domElement);
// Add a meshconst geometry = new THREE.BoxGeometry(1, 1, 1);const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });const cube = new THREE.Mesh(geometry, material);scene.add(cube);
// Add lightscene.add(new THREE.AmbientLight(0xffffff, 0.5));const dirLight = new THREE.DirectionalLight(0xffffff, 1);dirLight.position.set(5, 5, 5);scene.add(dirLight);
camera.position.z = 5;
// Animation loopfunction animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera);}animate();
// Handle resizewindow.addEventListener("resize", () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight);});Core Classes
Scene
Container for all 3D objects, lights, and cameras.
javascript
const scene = new THREE.Scene();scene.background = new THREE.Color(0x000000); // Solid colorscene.background = texture; // Skybox texturescene.background = cubeTexture; // Cubemapscene.environment = envMap; // Environment map for PBRscene.fog = new THREE.Fog(0xffffff, 1, 100); // Linear fogscene.fog = new THREE.FogExp2(0xffffff, 0.02); // Exponential fogCameras
PerspectiveCamera - Most common, simulates human eye.
javascript
// PerspectiveCamera(fov, aspect, near, far)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.set(0, 5, 10);camera.lookAt(0, 0, 0);camera.updateProjectionMatrix(); // Call after changing fov, aspect, near, farOrthographicCamera - No perspective distortion, good for 2D/isometric.
javascript
// OrthographicCamera(left, right, top, bottom, near, far)const aspect = window.innerWidth / window.innerHeight;const frustumSize = 10;const camera = new THREE.OrthographicCamera( (frustumSize * aspect) / -2, (frustumSize * aspect) / 2, frustumSize / 2, frustumSize / -2, 0.1, 1000,);ArrayCamera - Multiple viewports with sub-cameras.
javascript
const cameras = [];for (let i = 0; i < 4; i++) { const subcamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100); subcamera.viewport = new THREE.Vector4( Math.floor(i % 2) * 0.5, Math.floor(i / 2) * 0.5, 0.5, 0.5, ); cameras.push(subcamera);}const arrayCamera = new THREE.ArrayCamera(cameras);CubeCamera - Renders environment maps for reflections.
javascript
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256);const cubeCamera = new THREE.CubeCamera(0.1, 1000, cubeRenderTarget);scene.add(cubeCamera);
// Use for reflectionsmaterial.envMap = cubeRenderTarget.texture;
// Update each frame (expensive!)cubeCamera.position.copy(reflectiveMesh.position);cubeCamera.update(renderer, scene);WebGLRenderer
javascript
const renderer = new THREE.WebGLRenderer({ canvas: document.querySelector("#canvas"), // Optional existing canvas antialias: true, // Smooth edges alpha: true, // Transparent background powerPreference: "high-performance", // GPU hint preserveDrawingBuffer: true, // For screenshots});
renderer.setSize(width, height);renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// Tone mappingrenderer.toneMapping = THREE.ACESFilmicToneMapping;renderer.toneMappingExposure = 1.0;
// Color space (Three.js r152+)renderer.outputColorSpace = THREE.SRGBColorSpace;
// Shadowsrenderer.shadowMap.enabled = true;renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Clear colorrenderer.setClearColor(0x000000, 1);
// Renderrenderer.render(scene, camera);Object3D
Base class for all 3D objects. Mesh, Group, Light, Camera all extend Object3D.
javascript
const obj = new THREE.Object3D();
// Transformobj.position.set(x, y, z);obj.rotation.set(x, y, z); // Euler angles (radians)obj.quaternion.set(x, y, z, w); // Quaternion rotationobj.scale.set(x, y, z);
// Local vs World transformsobj.getWorldPosition(targetVector);obj.getWorldQuaternion(targetQuaternion);obj.getWorldDirection(targetVector);
// Hierarchyobj.add(child);obj.remove(child);obj.parent;obj.children;
// Visibilityobj.visible = false;
// Layers (for selective rendering/raycasting)obj.layers.set(1);obj.layers.enable(2);obj.layers.disable(0);
// Traverse hierarchyobj.traverse((child) => { if (child.isMesh) child.material.color.set(0xff0000);});
// Matrix updatesobj.matrixAutoUpdate = true; // Default: auto-update matricesobj.updateMatrix(); // Manual matrix updateobj.updateMatrixWorld(true); // Update world matrix recursivelyGroup
Empty container for organizing objects.
javascript
const group = new THREE.Group();group.add(mesh1);group.add(mesh2);scene.add(group);
// Transform entire groupgroup.position.x = 5;group.rotation.y = Math.PI / 4;Mesh
Combines geometry and material.
javascript
const mesh = new THREE.Mesh(geometry, material);
// Multiple materials (one per geometry group)const mesh = new THREE.Mesh(geometry, [material1, material2]);
// Useful propertiesmesh.geometry;mesh.material;mesh.castShadow = true;mesh.receiveShadow = true;
// Frustum cullingmesh.frustumCulled = true; // Default: skip if outside camera view
// Render ordermesh.renderOrder = 10; // Higher = rendered laterCoordinate System
Three.js uses a right-handed coordinate system:
- +X points right
- +Y points up
- +Z points toward viewer (out of screen)
javascript
// Axes helperconst axesHelper = new THREE.AxesHelper(5);scene.add(axesHelper); // Red=X, Green=Y, Blue=ZMath Utilities
Vector3
javascript
const v = new THREE.Vector3(x, y, z);v.set(x, y, z);v.copy(otherVector);v.clone();
// Operations (modify in place)v.add(v2);v.sub(v2);v.multiply(v2);v.multiplyScalar(2);v.divideScalar(2);v.normalize();v.negate();v.clamp(min, max);v.lerp(target, alpha);
// Calculations (return new value)v.length();v.lengthSq(); // Faster than length()v.distanceTo(v2);v.dot(v2);v.cross(v2); // Modifies vv.angleTo(v2);
// Transformv.applyMatrix4(matrix);v.applyQuaternion(q);v.project(camera); // World to NDCv.unproject(camera); // NDC to worldMatrix4
javascript
const m = new THREE.Matrix4();m.identity();m.copy(other);m.clone();
// Build transformsm.makeTranslation(x, y, z);m.makeRotationX(theta);m.makeRotationY(theta);m.makeRotationZ(theta);m.makeRotationFromQuaternion(q);m.makeScale(x, y, z);
// Compose/decomposem.compose(position, quaternion, scale);m.decompose(position, quaternion, scale);
// Operationsm.multiply(m2); // m = m * m2m.premultiply(m2); // m = m2 * mm.invert();m.transpose();
// Camera matricesm.makePerspective(left, right, top, bottom, near, far);m.makeOrthographic(left, right, top, bottom, near, far);m.lookAt(eye, target, up);Quaternion
javascript
const q = new THREE.Quaternion();q.setFromEuler(euler);q.setFromAxisAngle(axis, angle);q.setFromRotationMatrix(matrix);
q.multiply(q2);q.slerp(target, t); // Spherical interpolationq.normalize();q.invert();Euler
javascript
const euler = new THREE.Euler(x, y, z, "XYZ"); // Order matters!euler.setFromQuaternion(q);euler.setFromRotationMatrix(m);
// Rotation orders: 'XYZ', 'YXZ', 'ZXY', 'XZY', 'YZX', 'ZYX'Color
javascript
const color = new THREE.Color(0xff0000);const color = new THREE.Color("red");const color = new THREE.Color("rgb(255, 0, 0)");const color = new THREE.Color("#ff0000");
color.setHex(0x00ff00);color.setRGB(r, g, b); // 0-1 rangecolor.setHSL(h, s, l); // 0-1 range
color.lerp(otherColor, alpha);color.multiply(otherColor);color.multiplyScalar(2);MathUtils
javascript
THREE.MathUtils.clamp(value, min, max);THREE.MathUtils.lerp(start, end, alpha);THREE.MathUtils.mapLinear(value, inMin, inMax, outMin, outMax);THREE.MathUtils.degToRad(degrees);THREE.MathUtils.radToDeg(radians);THREE.MathUtils.randFloat(min, max);THREE.MathUtils.randInt(min, max);THREE.MathUtils.smoothstep(x, min, max);THREE.MathUtils.smootherstep(x, min, max);Common Patterns
Proper Cleanup
javascript
function dispose() { // Dispose geometries mesh.geometry.dispose();
// Dispose materials if (Array.isArray(mesh.material)) { mesh.material.forEach((m) => m.dispose()); } else { mesh.material.dispose(); }
// Dispose textures texture.dispose();
// Remove from scene scene.remove(mesh);
// Dispose renderer renderer.dispose();}Clock for Animation
javascript
const clock = new THREE.Clock();
function animate() { const delta = clock.getDelta(); // Time since last frame (seconds) const elapsed = clock.getElapsedTime(); // Total time (seconds)
mesh.rotation.y += delta * 0.5; // Consistent speed regardless of framerate
requestAnimationFrame(animate); renderer.render(scene, camera);}Responsive Canvas
javascript
function onWindowResize() { const width = window.innerWidth; const height = window.innerHeight;
camera.aspect = width / height; camera.updateProjectionMatrix();
renderer.setSize(width, height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));}window.addEventListener("resize", onWindowResize);Loading Manager
javascript
const manager = new THREE.LoadingManager();
manager.onStart = (url, loaded, total) => console.log("Started loading");manager.onLoad = () => console.log("All loaded");manager.onProgress = (url, loaded, total) => console.log(`${loaded}/${total}`);manager.onError = (url) => console.error(`Error loading ${url}`);
const textureLoader = new THREE.TextureLoader(manager);const gltfLoader = new GLTFLoader(manager);Performance Tips
- Limit draw calls: Merge geometries, use instancing, atlas textures
- Frustum culling: Enabled by default, ensure bounding boxes are correct
- LOD (Level of Detail): Use
THREE.LODfor distance-based mesh switching - Object pooling: Reuse objects instead of creating/destroying
- Avoid
getWorldPositionin loops: Cache results
javascript
// Merge static geometriesimport { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";const merged = mergeGeometries([geo1, geo2, geo3]);
// LODconst lod = new THREE.LOD();lod.addLevel(highDetailMesh, 0);lod.addLevel(medDetailMesh, 50);lod.addLevel(lowDetailMesh, 100);scene.add(lod);See Also
threejs-geometry- Geometry creation and manipulationthreejs-materials- Material types and propertiesthreejs-lighting- Light types and shadows


