Pixijs Math

pixijs/pixijs-skills/skills/pixijs-math

作者 pixijs83760c6f5346MIT347 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫7 天前更新

Use this skill when working with coordinates, vectors, matrices, shapes, hit testing, or layout rectangles in PixiJS v8. Covers Point/ObservablePoint, Matrix (2D affine, decompose (including mirrored/negative-scale matrices), apply, applyInverse), shapes (Rectangle, Circle, Ellipse, Polygon, RoundedRectangle, Triangle), Rectangle layout helpers (pad, fit, enlarge, ceil, scale, getBounds), strokeContains hit tests, Polygon isClockwise/containsPolygon, toGlobal/toLocal, PointData/PointLike/Size types, DEG_TO_RAD, and pixi.js/math-extras vector and intersection helpers. Triggers on: Point, ObservablePoint, Matrix, Rectangle, Circle, Polygon, Triangle, RoundedRectangle, toGlobal, toLocal, hitArea, strokeContains, pad, fit, enlarge, ceil, getBounds, containsRect, intersects, isClockwise, math-extras, lineIntersection, segmentIntersection, DEG_TO_RAD, PointData, decompose, mirror, flip, negative scale, setFromMatrix.

AI 產生的概覽

PixiJS v8 數學基礎參考:點、矩陣、形狀、命中測試與矩形版面配置。

功能
此技能提供 PixiJS v8 數學基礎型別的參考說明與程式碼範例,涵蓋 Point 與 ObservablePoint、二維仿射矩陣 Matrix、Rectangle、Circle、Ellipse、Polygon、RoundedRectangle、Triangle 等形狀類別,以及 toGlobal、toLocal 座標轉換。內容說明了以 contains 與 strokeContains 進行命中測試、Rectangle 的 pad、fit、enlarge、ceil、getBounds 等版面配置輔助方法,以及選用的 pixi.js/math-extras 向量與相交輔助函式。文件也列出常見錯誤,例如從 @pixi/math 匯入或保存共用暫存物件的參考,並附上 API 參考連結。
適用情境
在撰寫涉及座標、向量、矩陣、形狀、命中測試或版面配置矩形的 PixiJS v8 程式碼時使用。也適合用來排查變換分解、鏡像或負縮放矩陣,以及 math-extras 方法缺失等問題。
執行需求
需要以 PixiJS v8 作為目標函式庫;此技能未附帶指令碼,僅為說明文件。只有在開啟所連結的 API 文件頁面時才需要網路存取。

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.

Quick Start

ts
const parent = new Container();parent.position.set(100, 100);parent.scale.set(2);app.stage.addChild(parent);
const child = new Container();child.position.set(50, 50);parent.addChild(child);
const globalPt = child.toGlobal(new Point(0, 0));
const m = new Matrix()  .translate(100, 50)  .rotate(Math.PI / 4)  .scale(2, 2);const world = m.apply(new Point(10, 20));
const hitArea = new Rectangle(0, 0, 200, 100);console.log(hitArea.contains(50, 50));

Related skills: pixijs-scene-container (transform properties), pixijs-events (hitArea usage), pixijs-scene-core-concepts (culling with Rectangle).

Core Patterns

Point and ObservablePoint

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.

ts
import { Point } from "pixi.js";
const p = new Point(10, 20);p.set(30, 40); // set bothp.set(50); // x=50, y=50
const clone = p.clone();console.log(p.equals(clone)); // true
p.copyFrom({ x: 1, y: 2 }); // accepts any PointData
// Point.shared: temporary point, reset to (0,0) on each accessconst temp = Point.shared;temp.set(100, 200);// do not store a reference to Point.shared

Container properties like position, scale, pivot, origin, and skew are ObservablePoints. Setting .x or .y on them triggers transform recalculation automatically.

ts
import { Container } from "pixi.js";
const obj = new Container();obj.position.set(100, 200); // triggers observer -> marks transform dirtyobj.position.x = 150; // also triggers observer

Matrix (2D affine transform)

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.

ts
import { Matrix, Point } from "pixi.js";
// Build a transformconst m = new Matrix()  .translate(100, 50)  .rotate(Math.PI / 4)  .scale(2, 2);
// Transform a point (local -> parent space)const local = new Point(10, 20);const world = m.apply(local);
// Inverse transform (parent -> local space)const backToLocal = m.applyInverse(world);
// Combine matricesconst a = new Matrix().translate(50, 0);const b = new Matrix().rotate(Math.PI / 2);a.append(b); // a = a * b
// Decompose into position/scale/rotation/skewconst transform = {  position: new Point(),  scale: new Point(),  pivot: new Point(),  skew: new Point(),  rotation: 0,};m.decompose(transform);console.log(transform.rotation); // ~0.785 (PI/4)
// A mirrored matrix (one axis flipped, axes still perpendicular) decomposes into// rotation + negative scale.x with zero skew. scale.y is never negative: a y-axis// flip comes back as scale.x = -1 plus a half turn. Either way the parts rebuild the matrix.const mirrored = new Matrix().rotate(Math.PI / 6).scale(-1, 1);mirrored.decompose(transform);transform.scale.x; // -1transform.skew.x; // 0
// Shared temporary matrix (reset on each access)const temp = Matrix.shared;// IDENTITY is read-only referenceconst isDefault = m.equals(Matrix.IDENTITY);

Coordinate transforms via Container

Containers provide toGlobal, toLocal, and getGlobalPosition for coordinate conversion.

ts
import { Container, Point } from "pixi.js";
const parent = new Container();parent.position.set(100, 100);parent.scale.set(2);
const child = new Container();child.position.set(50, 50);parent.addChild(child);
// Local point in child's space -> global (world) spaceconst globalPt = child.toGlobal(new Point(0, 0));// globalPt = { x: 200, y: 200 } (100 + 50*2, 100 + 50*2)
// Global point -> child's local spaceconst localPt = child.toLocal(new Point(200, 200));// localPt = { x: 0, y: 0 }
// Convert between two containersconst other = new Container();other.position.set(300, 300);const ptInOther = child.toLocal(new Point(10, 10), other);

Shapes and hit testing

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?) (Triangle ignores alignment and always tests a centered stroke). They can be used as hitArea on containers for custom interaction regions.

ts
import { Rectangle, Circle, Ellipse, Polygon, Container } from "pixi.js";
const rect = new Rectangle(0, 0, 200, 100);rect.contains(50, 50); // truerect.contains(300, 50); // falserect.left; // 0rect.right; // 200rect.top; // 0rect.bottom; // 100rect.isEmpty(); // false (Rectangle.EMPTY returns a fresh empty rect)
// Native Rectangle-to-Rectangle methods (no math-extras needed)const other = new Rectangle(50, 50, 100, 100);rect.containsRect(other); // true if `other` is fully inside `rect`rect.containsRect(new Rectangle(100, 0, 100, 100)); // true: a flush right edge countsrect.containsRect(rect.clone()); // true: identical rects contain each otherrect.intersects(other); // boolean: do they overlap at all?rect.intersects(other, matrix); // overlap after transforming `other`
// Stroke hit testing (alignment: 1 = inner, 0.5 = centered, 0 = outer)rect.strokeContains(0, 50, 4); // true if (0,50) lies on a 4px centered strokeconst circle = new Circle(100, 100, 50);circle.strokeContains(150, 100, 4, 1); // inner-aligned stroke check// A stroke that reaches past the shape's centre covers the whole interior; there is no holenew Ellipse(0, 0, 10, 10).strokeContains(0, 0, 40, 1); // true
// getBounds works on every shape (returns a Rectangle, accepts an out param)const bounds = circle.getBounds();const reused = new Rectangle();new Polygon([0, 0, 100, 0, 50, 100]).getBounds(reused);
// Use as hit area for interactionconst button = new Container();button.hitArea = new Rectangle(0, 0, 200, 50);button.eventMode = "static";button.on("pointerdown", () => {  /* clicked */});

Do not confuse native Rectangle.intersects(other) (returns boolean) with math-extras intersection(other) (returns a Rectangle describing the overlap area).

Rectangle layout helpers

Rectangle ships with mutating helpers used heavily in UI/layout, bounds aggregation, and pixel snapping. All return this for chaining.

ts
import { Rectangle } from "pixi.js";
const r = new Rectangle(10, 10, 100, 50);
r.pad(5); // grow on all sides: x=5, y=5, w=110, h=60r.pad(10, 4); // separate horizontal/vertical paddingr.scale(2); // multiply x, y, width, height by 2
// fit shrinks `this` to lie inside another rect (clipping)const viewport = new Rectangle(0, 0, 200, 200);new Rectangle(150, 150, 200, 200).fit(viewport); // -> 150, 150, 50, 50
// enlarge expands `this` to include another rect (bounds aggregation)const total = new Rectangle();items.forEach((item) =>  total.enlarge(new Rectangle().copyFromBounds(item.getBounds())),);
// ceil snaps to a pixel grid (resolution: 1 = whole pixels, 2 = half pixels)new Rectangle(10.2, 10.6, 100.8, 100.4).ceil();
// copy a Container/Mesh bounds object straight into a Rectanglenew Rectangle().copyFromBounds(container.getBounds());

Polygon

Polygon accepts four constructor formats: a flat number array, an array of point-like objects, or either passed as spread arguments.

ts
import { Polygon, Point } from "pixi.js";
new Polygon([0, 0, 100, 0, 50, 100]); // flat numbersnew Polygon([new Point(0, 0), new Point(100, 0), new Point(50, 100)]); // PointData[]new Polygon(0, 0, 100, 0, 50, 100); // spread numbersnew Polygon(new Point(0, 0), new Point(100, 0), new Point(50, 100)); // spread points
const poly = new Polygon([0, 0, 100, 0, 100, 100, 0, 100]);poly.points; // [0, 0, 100, 0, 100, 100, 0, 100] (mutable flat array)poly.closePath; // true by default; false produces an open pathpoly.startX; // 0  - first vertexpoly.lastX; // 0  - last vertex (lastY for y)poly.isClockwise(); // shoelace winding test (useful for SVG hole detection)
// Polygon-in-polygon containment for hole detectionconst outer = new Polygon([0, 0, 100, 0, 100, 100, 0, 100]);const hole = new Polygon([25, 25, 75, 25, 75, 75, 25, 75]);outer.containsPolygon(hole); // true
// Stroke hit test follows the drawn stroke: alignment 1 = inside, 0.5 = centered,// 0 = outside, independent of winding orderouter.strokeContains(-5, 50, 20); // true (centered stroke extends 10px outward)outer.strokeContains(-5, 50, 20, 1); // false (inner stroke stays inside)outer.strokeContains(5, 50, 20, 0); // false (outer stroke stays outside)

Constants

ts
import { DEG_TO_RAD, RAD_TO_DEG, PI_2 } from "pixi.js";
const angle = 45 * DEG_TO_RAD; // 0.785...const degrees = angle * RAD_TO_DEG; // 45const fullCircle = PI_2; // Math.PI * 2

Types

  • PointData - minimal {x, y} interface accepted by most APIs. Use it when typing parameters that only need to read coordinates.
  • PointLike - extends PointData with set(), copyFrom(), copyTo(), equals(). Implemented by both Point and ObservablePoint.
  • Size - { width, height } interface used by renderer/canvas APIs.
  • SHAPE_PRIMITIVE - string literal union: 'rectangle' | 'circle' | 'ellipse' | 'polygon' | 'roundedRectangle' | 'triangle'. Every shape exposes type so you can branch without instanceof.
ts
import type { PointData } from "pixi.js";
function distance(a: PointData, b: PointData): number {  const dx = a.x - b.x;  const dy = a.y - b.y;  return Math.sqrt(dx * dx + dy * dy);}

math-extras (side-effect import)

import 'pixi.js/math-extras' adds methods to Point, ObservablePoint, and Rectangle via prototype extension. Not included in the default bundle.

ts
import "pixi.js/math-extras";import { Point } from "pixi.js";
Point / ObservablePoint vector methods

All methods accept an optional out parameter to avoid allocations. Without out, a new Point is returned.

ts
const a = new Point(3, 4);const b = new Point(1, 2);
// Arithmeticconst sum = a.add(b); // Point(4, 6)const diff = a.subtract(b); // Point(2, 2)const prod = a.multiply(b); // Point(3, 8) - component-wiseconst scaled = a.multiplyScalar(2); // Point(6, 8)
// Dot and cross productconst dot = a.dot(b); // 11const cross = a.cross(b); // 2 (z-component of 3D cross)
// Lengthconst len = a.magnitude(); // 5const lenSq = a.magnitudeSquared(); // 25 (faster for comparisons)
// Normalize to unit vectorconst unit = a.normalize(); // Point(0.6, 0.8)
// Projection and reflectionconst proj = a.project(b); // project a onto bconst refl = a.reflect(new Point(0, 1)); // reflect across normal
// Rotationconst rotated = a.rotate(Math.PI / 2); // rotate 90 degrees
// Reuse existing point to avoid allocationconst out = new Point();a.add(b, out); // result written to out
Rectangle extended methods

containsRect and intersects are native Rectangle methods (see above). math-extras adds equals, intersection (returns the overlap rect), and union:

ts
import "pixi.js/math-extras";import { Rectangle } from "pixi.js";
const r1 = new Rectangle(0, 0, 100, 100);const r2 = new Rectangle(50, 50, 100, 100);
r1.equals(r2); // false
const overlap = r1.intersection(r2); // Rectangle(50, 50, 50, 50)const envelope = r1.union(r2); // Rectangle(0, 0, 150, 150)
// Optional out parameterconst out = new Rectangle();r1.intersection(r2, out);
Geometry utility functions

These functions are exported from pixi.js/math-extras, not the main pixi.js entry.

ts
import {  floatEqual,  lineIntersection,  segmentIntersection,} from "pixi.js/math-extras";import { Point } from "pixi.js";
// Epsilon-based float comparison (default epsilon: Number.EPSILON)floatEqual(0.1 + 0.2, 0.3, 1e-10); // true with reasonable epsilonfloatEqual(1.0, 1.001, 0.01); // true (custom epsilon)
// Unbounded line intersection (returns {x: NaN, y: NaN} if parallel)const hit = lineIntersection(  new Point(0, 0),  new Point(10, 10), // line A  new Point(10, 0),  new Point(0, 10), // line B); // Point(5, 5)if (isNaN(hit.x)) {  /* lines are parallel */}
// Bounded segment intersection (returns {x: NaN, y: NaN} if segments don't cross)const segHit = segmentIntersection(  new Point(0, 0),  new Point(10, 10),  new Point(10, 0),  new Point(0, 10),); // Point(5, 5)if (isNaN(segHit.x)) {  /* segments don't intersect */}

Common Mistakes

HIGH: Importing from @pixi/math

Wrong:

ts
import { Point } from "@pixi/math";

Correct:

ts
import { Point } from "pixi.js";

v8 uses a single pixi.js package. All sub-packages like @pixi/math, @pixi/core, etc. were removed.

MEDIUM: Mutating ObservablePoint without triggering observer

Wrong:

ts
// Replacing the reference loses observationlet pos = container.position;pos = new Point(100, 200); // container.position unchanged

Correct:

ts
// Mutate in place to trigger the observercontainer.position.set(100, 200);// orcontainer.position.x = 100;container.position.y = 200;// or copy from another pointcontainer.position.copyFrom(new Point(100, 200));

Container's position, scale, pivot, origin, and skew are ObservablePoints. Setting .x or .y on them triggers the container's transform update. Reassigning the variable reference does not modify the container. Always mutate the existing ObservablePoint via .set(), .copyFrom(), or direct property assignment on the original object.

MEDIUM: Not importing math-extras for extended methods

Wrong:

ts
import { Point } from "pixi.js";const p = new Point(1, 2);p.add(new Point(3, 4)); // TypeError: p.add is not a function

Correct:

ts
import "pixi.js/math-extras";import { Point } from "pixi.js";const p = new Point(1, 2);const sum = p.add(new Point(3, 4)); // works

Extended math utilities (add, subtract, multiply, magnitude, normalize, dot, cross, etc. on Point; intersection methods on shapes) require an explicit import 'pixi.js/math-extras'. These are not included in the default bundle.

MEDIUM: Storing references to shared/temporary objects

Wrong:

ts
const myPoint = Point.shared;myPoint.set(100, 200);// ... later ...console.log(myPoint.x); // 0 (reset on next access)

Correct:

ts
const myPoint = new Point();myPoint.copyFrom(Point.shared.set(100, 200));// or justconst myPoint = new Point(100, 200);

Point.shared and Matrix.shared are reset to zero/identity every time they are accessed. They exist for one-off calculations within a single expression. Never store a reference to them.

API Reference

來源與署名

來源:pixijs/pixijs-skills位於skills/pixijs-math提交83760c6

授權條款: MIT

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架