arcade2d
Class

Matrix

geometry/matrix.ts:58

A 2D affine transform — the engine's representation of a fully-resolved world transform. Where a WorldObject stores its transform as a human-friendly decomposed triple (position, rotation, scale), a Matrix is the composed form those three collapse into, and it is the only form that survives an object hierarchy intact.

Why a matrix, and not just position/rotation/scale

As long as everything is flat, "position + rotation + scale" is a perfect description of where a thing is. The moment you nest one object under another, that stops being true: a child's world transform is its parent's world transform composed with its own local one, and once a rotation meets a non-uniform scale somewhere up that chain, the result contains shear — a skew that no single (rotation, scale) pair can represent. A matrix represents it exactly. This is why WorldObject.worldMatrix is a Matrix and not three numbers, and why graphics push the matrix straight to the renderer rather than a decomposed transform.

Representation

The transform is stored as the six significant entries of a 3×3 affine matrix, in the same a, b, c, d, tx, ty layout the underlying renderer (PIXI) uses, so handing one to the renderer is a field-for-field copy:

| a  c  tx |     x' = a·x + c·y + tx
| b  d  ty |     y' = b·x + d·y + ty
| 0  0  1  |

a/b/c/d are the linear part (rotation + scale + shear); tx/ty are the translation. The default-constructed matrix is the identity.

Mutation style

Like Point, the in-place operations (Matrix.append, Matrix.invert) mutate this matrix and return this for chaining, while Matrix.clone and Matrix.apply never mutate. Compose a fresh matrix with the static Matrix.compose; tear one back apart with Matrix.decompose.

Example

// The world transform of a child = parent's world × child's local.
const world = parent.worldMatrix.append(
  Matrix.compose(child.position, child.rotation, child.scale),
);

// Project the child's local origin into world space.
const worldOrigin = world.apply({ x: 0, y: 0 });

Constructors

#
constructor(a: number, b: number, c: number, d: number, tx: number, ty: number): Matrix

Creates a new matrix from its six affine entries. Defaults to the identity matrix.

Parameters

  • a number
  • b number
  • c number
  • d number
  • tx number
  • ty number

Properties

#
a: number

Row-0 x-axis factor (cosine·scaleX for a pure TRS transform).

#
b: number

Row-1 x-axis factor (sine·scaleX).

#
c: number

Row-0 y-axis factor (−sine·scaleY).

#
d: number

Row-1 y-axis factor (cosine·scaleY).

#
tx: number

Translation along x.

#
ty: number

Translation along y.

Methods

#
append(other: Matrix): this

Post-multiplies this matrix by other in place — this = this × other — and returns this. "Post-multiply" means other is applied to a point first: this.append(other).apply(p) equals this.apply(other.apply(p)).

This is the operation that walks an object hierarchy: starting from a parent's world matrix and appending a child's local matrix yields the child's world matrix.

Parameters

Returns

this

This matrix, for chaining.

#
apply(point: PointPrimitive): Point

Transforms a point by this matrix, returning the result as a fresh Point (this matrix and the input are left untouched). Equivalent to (a·x + c·y + tx, b·x + d·y + ty).

Parameters

Returns

Point

A new Point holding the transformed coordinates.

#
clone(): Matrix

Returns an independent copy of this matrix. Use before a mutating operation (Matrix.append, Matrix.invert) when the original must be preserved.

Returns

Matrix
#
decompose(): DecomposedTransform

Recovers an approximate translate/rotate/scale triple from this matrix — the lossy inverse of Matrix.compose. Round-trips exactly for any matrix built from a TRS chain with non-negative scale; a matrix carrying shear (rotation composed with non-uniform scale, as can happen deep in an object hierarchy) is approximated, because shear has no TRS representation.

Translation is read directly from tx/ty; the x-scale and y-scale are the lengths of the two basis vectors; rotation is the angle of the first basis vector. See DecomposedTransform for the per-field contract.

Returns

DecomposedTransform

The recovered DecomposedTransform.

#
invert(): this

Inverts this matrix in place and returns this, so that applying the result undoes the original transform. Used when reparenting an object "in place": the new local transform is the new parent's inverse world matrix appended with the object's current world matrix.

A matrix with a zero determinant (one that collapses space — e.g. a zero scale on an axis) has no inverse; rather than producing Infinity/NaN entries, this resets the matrix to the identity. The collapse is already information-losing, so identity is the least surprising degenerate result.

Returns

this

This matrix, for chaining.

static #
compose(position: PointPrimitive, rotation: number, scale: PointPrimitive): Matrix

Composes a translate → rotate → scale chain into a single matrix, in that application order: a point is first scaled, then rotated, then translated. This is the exact transform a WorldObject applies to map a point from its own local space into its parent's space, so it is the building block WorldObject.worldMatrix is assembled from.

Parameters

Returns

Matrix

A new Matrix representing the composed transform.

static #
identity(): Matrix

Creates a fresh identity matrix — the transform that leaves every point unchanged. Equivalent to new Matrix(), but reads as intent at a call site that needs a neutral starting transform.

Returns

Matrix
ESC