LLearnCode
Academy/graphics/The rendered world

intermediate · 27 minute study

Local transforms compose into a world

A model that orbits instead of turning, a child that jumps, or a lit object that goes dark often reflects a misunderstanding of coordinate space or ownership.

Loading progressEvidence grows with practice
Useful preparation · 1 prerequisite

Use this as a map, not a lock. If these ideas are familiar, continue.

First, build a mental model

Each node describes its transform relative to its parent. Following the ancestors composes those local transforms into world space. A light then interacts with surface orientation and material properties in that world. The final pixels depend on the entire chain.

  1. Position, rotation and scale are local to the parent. A group can act as a pivot: move the group to relocate its children together, or rotate it to move offset children around the group's origin.
  2. Transform order matters. Rotating a translated offset around a parent origin is different from rotating a mesh around its own origin. Draw the hierarchy and identify the pivot before compensating with arbitrary coordinate changes.
  3. Three.js Euler rotation values use radians; the perspective camera's field-of-view parameter uses degrees. Quaternion rotations can avoid some Euler interpolation problems, but they still require a deliberate coordinate convention.
  4. Surface normals describe orientation used by lighting. Wrong normals, an unexpected back face, a light pointing elsewhere or a metal-like material without useful environmental illumination can all produce surprising dark regions.
  5. Directional, point and ambient illumination answer different visual needs. Shadows require additional setup and work; enabling a light does not automatically guarantee shadows. Build a readable light setup before spending the frame budget on expensive effects.
Read the codejavascript · educational example
import * as THREE from "three";
const pivot = new THREE.Group();
pivot.position.set(10, 0, 0);
const child = new THREE.Object3D();
child.position.set(2, 0, 0);
pivot.add(child);
pivot.updateMatrixWorld(true);
const before = child.getWorldPosition(new THREE.Vector3());
console.log(before.toArray()); // [12, 0, 0]
pivot.rotation.y = Math.PI / 2; // 90 degrees, expressed in radians
pivot.updateMatrixWorld(true);
const after = child.getWorldPosition(new THREE.Vector3());
console.log(after.toArray()); // approximately [10, 0, -2]
console.log(child.position.toArray()); // still [2, 0, 0]
// These are transform calculations; attach visible meshes to inspect them.
  1. Local

    The child stores an offset of two units along its parent's positive X axis. It does not store the value 12 in its local position.

  2. World before rotation

    With no rotation or scale, the parent's translation 10 and the child's offset 2 compose to world X = 12.

  3. World after rotation

    The parent's positive Y rotation turns that local X offset toward negative world Z. The child remains locally at (2, 0, 0), while the world position becomes approximately (10, 0, -2).

Production thinking

Take this beyond the example.

Keep gameplay coordinates, imported asset transforms and presentation offsets explicit. A decorative animation should not quietly change authoritative collision data. Validate rotated and scaled assets in the actual scene; nonuniform scale, parent transforms, face orientation and shadow settings can expose defects a neutral preview hides.

Sources and further reading

Your evidence

unseen is a local learning signal, not a credential or proof of production competence.

Explain the mental model, then explicitly acknowledge it. Opening a page is not evidence.

Supported retries can complete this lesson. Independent evidence and delayed review determine the skill stage.

Next lesson · A texture is data with a meaning and a budget →