$npx -y skills add pixijs/pixijs-skills --skill pixijs-mathUse this skill when working with coordinates, vectors, matrices, shapes, hit testing, or layout rectangles in PixiJS v8. Covers Point/ObservablePoint, Matrix (2D affine, decompose, apply, applyInverse), shapes (Rectangle, Circle, Ellipse, Polygon, RoundedRectangle, Triangle), Rec
| 1 | PixiJS exposes lightweight math primitives (Point, Matrix, shape classes) used throughout the library for transforms, hit testing, and coordinate conversion. Import `pixi.js/math-extras` to add vector operations (add, dot, magnitude, reflect) and Rectangle intersection/union helpers. |
| 2 | |
| 3 | ## Quick Start |
| 4 | |
| 5 | ```ts |
| 6 | const parent = new Container(); |
| 7 | parent.position.set(100, 100); |
| 8 | parent.scale.set(2); |
| 9 | app.stage.addChild(parent); |
| 10 | |
| 11 | const child = new Container(); |
| 12 | child.position.set(50, 50); |
| 13 | parent.addChild(child); |
| 14 | |
| 15 | const globalPt = child.toGlobal(new Point(0, 0)); |
| 16 | |
| 17 | const m = new Matrix() |
| 18 | .translate(100, 50) |
| 19 | .rotate(Math.PI / 4) |
| 20 | .scale(2, 2); |
| 21 | const world = m.apply(new Point(10, 20)); |
| 22 | |
| 23 | const hitArea = new Rectangle(0, 0, 200, 100); |
| 24 | console.log(hitArea.contains(50, 50)); |
| 25 | ``` |
| 26 | |
| 27 | **Related skills:** `pixijs-scene-container` (transform properties), `pixijs-events` (hitArea usage), `pixijs-scene-core-concepts` (culling with Rectangle). |
| 28 | |
| 29 | ## Core Patterns |
| 30 | |
| 31 | ### Point and ObservablePoint |
| 32 | |
| 33 | Point is a simple {x, y} value type. ObservablePoint fires a callback when x or y changes; it is used internally by Container's position, scale, pivot, origin, and skew. |
| 34 | |
| 35 | ```ts |
| 36 | import { Point } from "pixi.js"; |
| 37 | |
| 38 | const p = new Point(10, 20); |
| 39 | p.set(30, 40); // set both |
| 40 | p.set(50); // x=50, y=50 |
| 41 | |
| 42 | const clone = p.clone(); |
| 43 | console.log(p.equals(clone)); // true |
| 44 | |
| 45 | p.copyFrom({ x: 1, y: 2 }); // accepts any PointData |
| 46 | |
| 47 | // Point.shared: temporary point, reset to (0,0) on each access |
| 48 | const temp = Point.shared; |
| 49 | temp.set(100, 200); |
| 50 | // do not store a reference to Point.shared |
| 51 | ``` |
| 52 | |
| 53 | Container properties like `position`, `scale`, `pivot`, `origin`, and `skew` are ObservablePoints. Setting `.x` or `.y` on them triggers transform recalculation automatically. |
| 54 | |
| 55 | ```ts |
| 56 | import { Container } from "pixi.js"; |
| 57 | |
| 58 | const obj = new Container(); |
| 59 | obj.position.set(100, 200); // triggers observer -> marks transform dirty |
| 60 | obj.position.x = 150; // also triggers observer |
| 61 | ``` |
| 62 | |
| 63 | ### Matrix (2D affine transform) |
| 64 | |
| 65 | Matrix represents a 3x3 affine transform: `| a c tx | b d ty | 0 0 1 |`. It supports translate, scale, rotate, append, prepend, invert, and decompose. |
| 66 | |
| 67 | ```ts |
| 68 | import { Matrix, Point } from "pixi.js"; |
| 69 | |
| 70 | // Build a transform |
| 71 | const m = new Matrix() |
| 72 | .translate(100, 50) |
| 73 | .rotate(Math.PI / 4) |
| 74 | .scale(2, 2); |
| 75 | |
| 76 | // Transform a point (local -> parent space) |
| 77 | const local = new Point(10, 20); |
| 78 | const world = m.apply(local); |
| 79 | |
| 80 | // Inverse transform (parent -> local space) |
| 81 | const backToLocal = m.applyInverse(world); |
| 82 | |
| 83 | // Combine matrices |
| 84 | const a = new Matrix().translate(50, 0); |
| 85 | const b = new Matrix().rotate(Math.PI / 2); |
| 86 | a.append(b); // a = a * b |
| 87 | |
| 88 | // Decompose into position/scale/rotation/skew |
| 89 | const transform = { |
| 90 | position: new Point(), |
| 91 | scale: new Point(), |
| 92 | pivot: new Point(), |
| 93 | skew: new Point(), |
| 94 | rotation: 0, |
| 95 | }; |
| 96 | m.decompose(transform); |
| 97 | console.log(transform.rotation); // ~0.785 (PI/4) |
| 98 | |
| 99 | // Shared temporary matrix (reset on each access) |
| 100 | const temp = Matrix.shared; |
| 101 | // IDENTITY is read-only reference |
| 102 | const isDefault = m.equals(Matrix.IDENTITY); |
| 103 | ``` |
| 104 | |
| 105 | ### Coordinate transforms via Container |
| 106 | |
| 107 | Containers provide `toGlobal`, `toLocal`, and `getGlobalPosition` for coordinate conversion. |
| 108 | |
| 109 | ```ts |
| 110 | import { Container, Point } from "pixi.js"; |
| 111 | |
| 112 | const parent = new Container(); |
| 113 | parent.position.set(100, 100); |
| 114 | parent.scale.set(2); |
| 115 | |
| 116 | const child = new Container(); |
| 117 | child.position.set(50, 50); |
| 118 | parent.addChild(child); |
| 119 | |
| 120 | // Local point in child's space -> global (world) space |
| 121 | const globalPt = child.toGlobal(new Point(0, 0)); |
| 122 | // globalPt = { x: 200, y: 200 } (100 + 50*2, 100 + 50*2) |
| 123 | |
| 124 | // Global point -> child's local space |
| 125 | const localPt = child.toLocal(new Point(200, 200)); |
| 126 | // localPt = { x: 0, y: 0 } |
| 127 | |
| 128 | // Convert between two containers |
| 129 | const other = new Container(); |
| 130 | other.position.set(300, 300); |
| 131 | const ptInOther = child.toLocal(new Point(10, 10), other); |
| 132 | ``` |
| 133 | |
| 134 | ### Shapes and hit testing |
| 135 | |
| 136 | Rectangle, Circle, Ellipse, Polygon, RoundedRectangle, and Triangle all implement `contains(x, y)` for point-in-shape tests, plus `getBounds(out?)` and `strokeContains(x, y, width, alignment?)`. They can be used as `hitArea` on containers for custom interaction regions. |
| 137 | |
| 138 | ```ts |
| 139 | impo |