Reference

Three.js API Quick Reference

A copy-paste lookup for the Three.js (r160) API surface you touch every day: renderer and scene setup, geometries, materials, lights, the scene graph, loaders, the animation loop, and raycasting.

Core: Renderer, Scene, Camera

Every Three.js app needs exactly three top-level objects: a WebGLRenderer that draws pixels, a Scene that holds the graph, and a Camera that defines the view. Set these up once, then reuse them for the app's lifetime.

import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.160/build/three.module.js';

// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);

// Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a0a0a);
scene.fog = new THREE.Fog(0x0a0a0a, 10, 60);

// Perspective camera: fov, aspect, near, far
const camera = new THREE.PerspectiveCamera(
  60,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.set(0, 5, 10);
camera.lookAt(0, 0, 0);

// Orthographic camera (for 2D-style / isometric views)
const frustumSize = 10;
const aspect = window.innerWidth / window.innerHeight;
const orthoCam = new THREE.OrthographicCamera(
  (-frustumSize * aspect) / 2, (frustumSize * aspect) / 2,
  frustumSize / 2, -frustumSize / 2,
  0.1, 1000
);
Renderer property Purpose
setPixelRatio() Match device DPR; cap at 2 to avoid GPU overload on retina displays
outputColorSpace THREE.SRGBColorSpace for correct gamma on final output
toneMapping ACESFilmic or Reinhard for HDR-lit PBR scenes
shadowMap.type PCFSoftShadowMap for soft edges; BasicShadowMap is cheapest
setClearColor(color, alpha) Background colour when scene.background is unset

Geometries

Geometries are BufferGeometry instances describing vertex positions, normals, and UVs. Built-in constructors cover the common primitives.

Constructor Key arguments
BoxGeometry width, height, depth, widthSeg, heightSeg, depthSeg
SphereGeometry radius, widthSegments, heightSegments
PlaneGeometry width, height, widthSeg, heightSeg
CylinderGeometry radiusTop, radiusBottom, height, radialSegments
TorusGeometry radius, tube, radialSegments, tubularSegments
ConeGeometry radius, height, radialSegments
IcosahedronGeometry radius, detail (0 = flat-shaded low-poly)
ExtrudeGeometry Shape + { depth, bevelEnabled, steps }
// Custom BufferGeometry from raw vertex data
const geo = new THREE.BufferGeometry();
const positions = new Float32Array([
  -1, -1, 0,
   1, -1, 0,
   0,  1, 0,
]);
geo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geo.computeVertexNormals();
geo.computeBoundingSphere(); // required for correct frustum culling

// Merge multiple geometries into one draw call
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
const merged = mergeGeometries([geoA, geoB, geoC]);

Materials

Materials define how a surface responds to light. MeshStandardMaterial and MeshPhysicalMaterial are physically-based (PBR) and the default choice for realistic lighting.

Material Lighting model Use case
MeshBasicMaterial None (unlit) UI overlays, wireframes, emissive-only shapes
MeshLambertMaterial Diffuse only Cheap matte surfaces, mobile
MeshPhongMaterial Diffuse + specular Shiny plastics without full PBR cost
MeshStandardMaterial PBR metallic/roughness Default for realistic scenes
MeshPhysicalMaterial PBR + clearcoat/transmission Glass, car paint, coated surfaces
ShaderMaterial Custom GLSL Full control — custom vertex/fragment shaders
const mat = new THREE.MeshStandardMaterial({
  color: 0x3388ff,
  metalness: 0.2,
  roughness: 0.6,
  map: colorTexture,          // albedo
  normalMap: normalTexture,
  roughnessMap: roughTexture,
  envMapIntensity: 1.0,
  transparent: true,
  opacity: 0.9,
  side: THREE.DoubleSide,     // FrontSide | BackSide | DoubleSide
});

// Custom shader material
const shaderMat = new THREE.ShaderMaterial({
  uniforms: {
    uTime:  { value: 0 },
    uColor: { value: new THREE.Color(0xff5500) },
  },
  vertexShader: /* glsl */ `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: /* glsl */ `
    uniform float uTime;
    uniform vec3 uColor;
    varying vec2 vUv;
    void main() {
      gl_FragColor = vec4(uColor * (0.5 + 0.5 * sin(uTime + vUv.x * 6.28)), 1.0);
    }
  `,
});

Lights

Light Behaviour Cost
AmbientLight Uniform light, no direction, no shadows Free
HemisphereLight Sky/ground gradient — cheap approximation of outdoor light Free
DirectionalLight Parallel rays (sun); casts shadows via orthographic frustum Cheap
PointLight Radiates from a point; shadow uses a cube map (6 passes) Expensive with shadows
SpotLight Cone of light with angle + penumbra Moderate
RectAreaLight Soft light from a rectangular panel (no shadows) Moderate, needs LTC textures init
const ambient = new THREE.AmbientLight(0xffffff, 0.4);

const sun = new THREE.DirectionalLight(0xffffff, 3);
sun.position.set(5, 10, 5);
sun.castShadow = true;
sun.shadow.mapSize.set(2048, 2048);
sun.shadow.camera.left   = -10;
sun.shadow.camera.right  =  10;
sun.shadow.camera.top    =  10;
sun.shadow.camera.bottom = -10;
sun.shadow.bias = -0.0005; // reduce shadow acne

const spot = new THREE.SpotLight(0xffaa33, 5, 20, Math.PI / 6, 0.3);
spot.position.set(0, 8, 0);

scene.add(ambient, sun, spot);
Only DirectionalLight, PointLight, and SpotLight can cast shadows. Every mesh that should cast or receive a shadow needs mesh.castShadow = true / mesh.receiveShadow = true set explicitly — renderer-level shadowMap.enabled alone is not enough.

Objects & Scene Graph

Object3D is the base class for everything placeable in a scene — meshes, groups, cameras, and lights all inherit its transform (position, rotation/quaternion, scale) and parenting.

const mesh = new THREE.Mesh(geo, mat);
mesh.position.set(0, 1, 0);
mesh.rotation.set(0, Math.PI / 4, 0);   // Euler, radians
mesh.scale.setScalar(1.5);
mesh.castShadow = true;
mesh.receiveShadow = true;

// Group objects to transform them together
const group = new THREE.Group();
group.add(mesh, otherMesh);
group.position.y = 2;
scene.add(group);

// Traverse the whole graph
scene.traverse((obj) => {
  if (obj.isMesh) obj.material.needsUpdate = true;
});

// World-space transforms (accounting for parents)
const worldPos = new THREE.Vector3();
mesh.getWorldPosition(worldPos);

// InstancedMesh for thousands of identical objects in one draw call
const instanced = new THREE.InstancedMesh(geo, mat, 5000);
const m4 = new THREE.Matrix4();
for (let i = 0; i < 5000; i++) {
  m4.makeTranslation(Math.random() * 20 - 10, 0, Math.random() * 20 - 10);
  instanced.setMatrixAt(i, m4);
}
instanced.instanceMatrix.needsUpdate = true;
scene.add(instanced);

Controls

Control Typical use
OrbitControls Orbit/zoom/pan around a target — the default for demos and editors
PointerLockControls First-person mouse-look, locks the cursor
TrackballControls Free rotation with no fixed up-vector
TransformControls Move/rotate/scale gizmo for editing tools
FlyControls Free-flight camera (spacecraft-style)
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 2;
controls.maxDistance = 50;
controls.maxPolarAngle = Math.PI / 2; // prevent camera going below ground

// Must be called every frame when damping is enabled
function tick() {
  controls.update();
  renderer.render(scene, camera);
}

Loaders

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';

// GLTF/GLB models, optionally Draco-compressed
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');

const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
gltfLoader.load('model.glb', (gltf) => {
  scene.add(gltf.scene);
  gltf.animations; // AnimationClip[]
});

// Textures
const texLoader = new THREE.TextureLoader();
const colorMap = texLoader.load('albedo.jpg');
colorMap.colorSpace = THREE.SRGBColorSpace; // color textures need sRGB
colorMap.wrapS = colorMap.wrapT = THREE.RepeatWrapping;
colorMap.anisotropy = renderer.capabilities.getMaxAnisotropy();

// HDR environment maps
new RGBELoader().load('studio.hdr', (hdrTexture) => {
  hdrTexture.mapping = THREE.EquirectangularReflectionMapping;
  scene.environment = hdrTexture; // image-based lighting for PBR materials
  scene.background = hdrTexture;
});
All loaders are async and callback- or Promise-based. Use LoadingManager to track overall progress across many assets, and always handle the onError callback — failed asset loads should degrade gracefully, not crash the scene.

Animation Loop

const clock = new THREE.Clock();

function tick() {
  const dt = clock.getDelta();       // seconds since last frame
  const elapsed = clock.getElapsedTime();

  mesh.rotation.y += dt * 0.5;
  shaderMat.uniforms.uTime.value = elapsed;
  controls.update();

  renderer.render(scene, camera);
}

// WebXR-compatible animation loop (preferred over requestAnimationFrame)
renderer.setAnimationLoop(tick);

// Stop the loop
// renderer.setAnimationLoop(null);

// Resize handling
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

Raycasting & Interaction

Raycaster casts a ray from the camera through a normalised pointer position and reports intersections — the standard way to click, hover, or select 3D objects.

const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();

window.addEventListener('pointermove', (event) => {
  // Convert to Normalised Device Coordinates: -1 to +1
  pointer.x =  (event.clientX / window.innerWidth)  * 2 - 1;
  pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
});

window.addEventListener('click', () => {
  raycaster.setFromCamera(pointer, camera);

  // true = check descendants recursively (needed for groups)
  const hits = raycaster.intersectObjects(scene.children, true);

  if (hits.length > 0) {
    const { object, point, distance, face } = hits[0];
    object.material.color.set(0xff0000);
    console.log('Hit point:', point, 'distance:', distance);
  }
});
Raycasting against thousands of objects every frame is expensive. Restrict the candidate list (pass a specific array, not scene.children), or use a spatial index (octree/BVH via three-mesh-bvh) for large static scenes.

Math Types

Type Common methods
Vector3 .set(), .add(), .sub(), .multiplyScalar(), .normalize(), .length(), .lerp(), .cross(), .dot(), .applyQuaternion()
Quaternion .setFromAxisAngle(), .setFromEuler(), .slerp(), .multiply(), .invert()
Euler x, y, z (radians) + rotation order, e.g. 'XYZ'
Matrix4 .compose(), .decompose(), .makeTranslation(), .multiplyMatrices(), .invert()
Box3 .setFromObject(), .containsPoint(), .intersectsBox(), .getCenter()
MathUtils .degToRad(), .radToDeg(), .clamp(), .lerp(), .randFloatSpread(), .smoothstep()
// All temporaries should be pre-allocated outside hot loops to avoid GC churn
const _v = new THREE.Vector3();
const _q = new THREE.Quaternion();

_q.setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);
_v.set(1, 0, 0).applyQuaternion(_q); // rotate a vector by a quaternion

// Decompose a world matrix into position/quaternion/scale
const pos = new THREE.Vector3();
const quat = new THREE.Quaternion();
const scale = new THREE.Vector3();
mesh.matrixWorld.decompose(pos, quat, scale);
Prefer quaternions over Euler angles for interpolation and composition — Euler angles suffer from gimbal lock and do not interpolate linearly along the shortest path. Use Euler only for authoring/reading human-friendly rotations.