Three.js Cheatsheet
Meshes and Groups
Use this Three.js reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Mesh
const mesh = new THREE.Mesh(geometry, material); scene.add(mesh); // Multiple materials per geometry (one per group) const mesh = new THREE.Mesh(geometry, [mat0, mat1, mat2]); // Geometry groups map faces to material indices geo.addGroup(start, count, materialIndex);
Object3D — The Base Class
Every visible and invisible object (Mesh, Group, Light, Camera, Bone…) extends Object3D.
Position, Rotation, Scale
// Position mesh.position.set(x, y, z); mesh.position.x = 1; mesh.position.copy(otherMesh.position); mesh.position.add(new THREE.Vector3(0, 1, 0)); // Rotation (Euler, radians, default order 'XYZ') mesh.rotation.set(rx, ry, rz); mesh.rotation.y = Math.PI / 4; mesh.rotation.reorder('YXZ'); // change application order // Quaternion (alternative to Euler — no gimbal lock) mesh.quaternion.setFromEuler(new THREE.Euler(rx, ry, rz)); mesh.quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2); mesh.quaternion.slerp(targetQuat, 0.1); // smooth interpolation // Scale mesh.scale.set(2, 2, 2); mesh.scale.multiplyScalar(0.5);
Hierarchy & Scene Graph
parent.add(child); // add child; child inherits parent transform parent.remove(child); // detach child child.removeFromParent(); // detach self (r133+) mesh.parent; // direct parent (null if root) mesh.children; // array of direct children // Traverse entire subtree mesh.traverse((node) => { if (node.isMesh) node.castShadow = true; }); // Traverse only visible nodes mesh.traverseVisible((node) => { /* ... */ }); // Find descendants mesh.getObjectByName('Wheel_FL'); mesh.getObjectByProperty('type', 'PointLight');
World vs Local Transforms
// Get world position (accounts for all parent transforms) const worldPos = new THREE.Vector3(); mesh.getWorldPosition(worldPos); const worldQuat = new THREE.Quaternion(); mesh.getWorldQuaternion(worldQuat); const worldScale = new THREE.Vector3(); mesh.getWorldScale(worldScale); const worldDir = new THREE.Vector3(); mesh.getWorldDirection(worldDir); // -Z direction in world space // Convert between spaces const localPt = mesh.worldToLocal(worldPoint.clone()); const worldPt = mesh.localToWorld(localPoint.clone());
lookAt
mesh.lookAt(new THREE.Vector3(0, 0, 0)); // point +Z toward target mesh.lookAt(targetMesh.position); // lookAt uses world coordinates; call after setting position
Matrix
mesh.updateMatrix(); // recompute local matrix from position/rotation/scale mesh.updateMatrixWorld(true); // recompute world matrix recursively mesh.matrix; // local transform Matrix4 mesh.matrixWorld; // world transform Matrix4 // Lock auto-update if you set matrix manually mesh.matrixAutoUpdate = false; mesh.matrix.compose(position, quaternion, scale); mesh.matrix.decompose(position, quaternion, scale);
Identity and Naming
mesh.name = 'PlayerBody'; mesh.uuid; // auto-generated unique ID mesh.userData = { hp: 100 }; // arbitrary data storage, not used by Three.js mesh.visible = false; mesh.renderOrder = 1; // higher = drawn later (useful for transparency sort) mesh.layers.set(1); // visibility layer (default 0) camera.layers.enable(1); // camera must see the same layer
Groups
const group = new THREE.Group(); group.add(meshA); group.add(meshB); scene.add(group); // Transform entire group together group.position.set(5, 0, 0); group.rotation.y = Math.PI; group.scale.setScalar(2); // Groups are Object3D — all methods apply group.traverse((child) => { /* ... */ });
Pivot Offset Pattern
// Rotate around an arbitrary pivot by nesting const pivot = new THREE.Group(); pivot.position.set(pivotX, pivotY, pivotZ); pivot.add(mesh); mesh.position.set(-pivotX, -pivotY, -pivotZ); // offset so pivot is at pivot point scene.add(pivot); pivot.rotation.y += 0.01; // orbits around the pivot
Instanced Mesh
Use InstancedMesh to render thousands of identical geometry+material pairs in a single draw call.
const count = 10000; const iMesh = new THREE.InstancedMesh(geometry, material, count); iMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // if updated per frame const dummy = new THREE.Object3D(); for (let i = 0; i < count; i++) { dummy.position.set( (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20 ); dummy.rotation.set( Math.random() * Math.PI, Math.random() * Math.PI, 0 ); dummy.scale.setScalar(Math.random() * 0.5 + 0.5); dummy.updateMatrix(); iMesh.setMatrixAt(i, dummy.matrix); } iMesh.instanceMatrix.needsUpdate = true; scene.add(iMesh); // Per-instance color iMesh.setColorAt(i, new THREE.Color(Math.random(), Math.random(), Math.random())); iMesh.instanceColor.needsUpdate = true; // Update one instance later dummy.position.y = 5; dummy.updateMatrix(); iMesh.setMatrixAt(targetIndex, dummy.matrix); iMesh.instanceMatrix.needsUpdate = true; // Raycasting works automatically // Reduce visible count without rebuilding iMesh.count = 500;
Lines and Points
// Line (two points) const geo = new THREE.BufferGeometry().setFromPoints([ new THREE.Vector3(0, 0, 0), new THREE.Vector3(1, 1, 0), ]); const line = new THREE.Line(geo, new THREE.LineBasicMaterial({ color: 0xffffff })); // LineLoop — closed const loop = new THREE.LineLoop(geo, mat); // LineSegments — pairs of points (no join) const segs = new THREE.LineSegments(geo, mat); // Points / particles const points = new THREE.Points(geo, new THREE.PointsMaterial({ size: 0.05 }));
Shadows
// Renderer renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Light dirLight.castShadow = true; dirLight.shadow.mapSize.width = 2048; dirLight.shadow.mapSize.height = 2048; dirLight.shadow.camera.near = 0.5; dirLight.shadow.camera.far = 50; dirLight.shadow.camera.left = -10; // ortho frustum for directional dirLight.shadow.camera.right = 10; dirLight.shadow.camera.top = 10; dirLight.shadow.camera.bottom = -10; dirLight.shadow.bias = -0.001; // fixes shadow acne dirLight.shadow.normalBias = 0.02; // alternative to bias // Objects mesh.castShadow = true; // casts a shadow mesh.receiveShadow = true; // receives shadows from others ground.receiveShadow = true; // Shadow camera helper (debug) scene.add(new THREE.CameraHelper(dirLight.shadow.camera));
Useful Object3D Methods Reference
| Method | Description |
|---|---|
.add(...objects) | Attach children |
.remove(...objects) | Detach children |
.removeFromParent() | Detach from parent |
.clear() | Remove all children |
.clone(recursive) | Deep copy |
.copy(source, recursive) | Copy properties from source |
.lookAt(v) | Orient +Z toward world point |
.traverse(cb) | Visit all descendants |
.traverseVisible(cb) | Visit only visible descendants |
.getObjectById(id) | Find descendant by id |
.getObjectByName(name) | Find descendant by name |
.getWorldPosition(v) | Write world position to v |
.getWorldQuaternion(q) | Write world quaternion to q |
.getWorldScale(v) | Write world scale to v |
.getWorldDirection(v) | Write world -Z direction to v |
.localToWorld(v) | Transform point local→world (mutates v) |
.worldToLocal(v) | Transform point world→local (mutates v) |
.applyMatrix4(m) | Apply a Matrix4 transform |
.applyQuaternion(q) | Rotate by quaternion |
.translateOnAxis(axis, dist) | Translate along a local axis |
.rotateOnAxis(axis, angle) | Rotate around a local axis |
.rotateOnWorldAxis(axis, angle) | Rotate around a world axis |
Cloning and Disposal
// Clone a mesh (geometry and material are shared by default) const clone = mesh.clone(); // Deep clone with independent geometry/material const deepClone = mesh.clone(); deepClone.geometry = mesh.geometry.clone(); deepClone.material = mesh.material.clone(); // Dispose function disposeMesh(mesh) { mesh.geometry.dispose(); if (Array.isArray(mesh.material)) { mesh.material.forEach(m => m.dispose()); } else { mesh.material.dispose(); } scene.remove(mesh); }