Matrices

A transformation matrix is nothing but its columns: where the basis vectors land. Read the columns and you've read the transform — rotation, scale, and shear are just different column placements, and composing them is where order starts to matter.

Core Idea

A transformation matrix stores exactly one thing: where the basis vectors land. The first column is the new home of x̂, the second column the new home of ŷ — drag either column above and the entire grid, and everything living in it, follows. That’s the whole trick:

[ Xx  Yx  Zx ]   column 1 → where x̂ goes
[ Xy  Yy  Zy ]   column 2 → where ŷ goes
[ Xz  Yz  Zz ]   column 3 → where ẑ goes

The identity matrix is just every basis vector still at home — ones on the diagonal, nothing moved.

Rotation, Scale, Shear: Column Placements

Press the presets above and watch the columns, not the grid: rotation swings both columns around the origin at length 1; scale stretches them along their own axes (the length of a column is that axis’s scale factor); shear tilts one column while the other stays. There is no separate machinery for each transform — only different places to put the columns.

The gold parallelogram is the image of the unit square, and its area is the determinant. Drag a column until the grid folds through itself: det < 0 means the space is mirrored (winding flips — the same flip that turns a front-face into a back-face), and det = 0 means the plane collapsed to a line, a transform that cannot be undone.

Multiplying Is Just Dot Products

Transforming a vector is one dot product per output component — each row against the vector:

out.x = dot(row0, v)
out.y = dot(row1, v)
out.z = dot(row2, v)

Matrix × matrix is the same idea tiled: element [i][j] is row i of the first dotted with column j of the second. Equivalently — and this is the readable version — the product’s columns are the first matrix applied to the second matrix’s columns.

Order Matters

Multiplication chains transforms, and it reads right-to-left: in T · R · S · v the vector is scaled first, rotated second, translated last. Chains don’t commute — the same two matrices in opposite order produce genuinely different transforms:

Rotate-then-scale squashes the rotated shape against the world axes and shears its angles; scale-then-rotate squashes first and rotates the result rigidly. This is the classic bug: scaling after translating multiplies the position too, and an object placed at (10, 0, 0) scaled by 2 teleports to (20, 0, 0). Scale while centred at the origin, then rotate, then translate — see transformations for the full TRS story.

16 Floats for a Million Vertices

The pipeline’s economy rests on this: the CPU composes Model, View, and Projection into one 4×4 and uploads 16 floats as a uniform, and the GPU applies them to every vertex in parallel:

gl.uniformMatrix4fv(u_mvp, false, mvp)   // 16 floats, once
gl.drawArrays(gl.TRIANGLES, 0, count)    // mvp × position, per vertex

Whether the mesh has 3 vertices or 3 million, the transform costs the same to send. (mat4 in GLSL, float4x4 in HLSL.)

What a 3×3 Can’t Do

Every transform above fixes the origin — dot products of rows with (0,0,0) are always zero — so pure matrices can rotate, scale, and shear but never translate. Graphics fixes this with a fourth coordinate: see homogeneous coordinates for how w smuggles translation (and later perspective) into matrix multiplication.

Connections

Multiplying by a matrix doesn’t move geometry — it re-expresses it in a new frame, which is the central insight of coordinate spaces; the Model, View, and Projection matrices are the three hops of that journey, and projection is the strange one whose matrix only stages a division. How translate, rotate, and scale compose per-frame into a model matrix lives in transformations, and the reason those 4×4s work at all is homogeneous coordinates.