Core Idea
Every object in a scene carries a Transform: a scale, a rotation, a translation. They are stored as three separate values, and every frame the engine multiplies them into one model matrix:
M = T · R · S (read right-to-left: scale, then rotate, then translate)
The order is not a convention you may reshuffle — it’s the recipe that keeps each ingredient honest. Scale first, while the object is still centred on its origin, so stretching can’t smear its position. Rotate second, still at the origin, where rotation lives. Translate last, carrying the finished object to its place. Run it in another order and the earlier transforms contaminate the later ones — the matrices page’s order demo shows the damage.
Rotate Around Any Point
Rotation (and scale) only ever happen around the origin — that’s the one move a linear matrix knows. So how does a door swing on its hinge, a moon orbit a planet, a shape spin around its grabbed corner? You sandwich it:
M = T(p) · R(θ) · T(−p)
Carry the pivot to the origin, rotate, carry it back — play the three beats above and watch each matrix take its turn. The pivot p is free: drag it off the shape entirely and rotation becomes orbit, the same three matrices doing celestial work. (The carrying is translation, which needs the fourth coordinate — that story lives in homogeneous coordinates.)
Hierarchies: Transforms All the Way Up
A scene graph is transforms containing transforms. Each node stores only its local pose relative to its parent; its world matrix is the running product down the chain:
M_world = M_parent_world · M_local
Drag the first joint and watch the readout: one local angle changes, the children’s locals stay untouched — yet every link downstream swings, because each world matrix is rebuilt through its parent. This is why animating a wave of the hand doesn’t require computing where the hand is in the room: rotate one joint in its own local space and the chain does the bookkeeping. Sun → planet → moon works identically, just with orbits instead of elbows.
The pivot sandwich and the hierarchy are secretly the same trick: an orbit rig is just an empty parent node placed at the pivot with the camera as its child — rotate the parent, the camera orbits.
What the Engine Does Every Frame
In Three.js the three ingredients are the properties you already use — composed for you, per frame:
mesh.position.set(4, 0, -2) // T
mesh.rotation.y = 0.6 // R
mesh.scale.setScalar(2) // S
// → mesh.matrix = T·R·S, rebuilt when needed
// → mesh.matrixWorld = parent.matrixWorld · mesh.matrix
The geometry buffer never changes. “Motion” is a new matrix each frame re-addressing the same vertices — the flipbook-of-frames idea that coordinate spaces develops in full.
Connections
Each of T, R and S is a matrix whose columns say where the basis vectors land; the sin/cos entries of R come from trigonometry. Translation joins the multiplication only thanks to homogeneous coordinates. And the model matrix built here is the first hop of the vertex’s journey through coordinate spaces — the M in MVP.