Render Matter.js Bodies with PixiJS Graphics
Pairing Matter.js with PixiJS allows developers to replace the
default Canvas 2D debug renderer with high-performance WebGL rendering.
By decoupling the physics calculation loop from the visual presentation,
you can simulate thousands of rigid bodies while maintaining a
consistent 60 frames per second. This article explains how to set up the
dual-engine pipeline, translate Matter.js geometry into
PIXI.Graphics objects, and synchronize transform data
efficiently to maximize WebGL throughput.
Decoupling Physics and Rendering
Matter.js includes a built-in Matter.Render module, but
it relies on the CPU-bound Canvas 2D context. To achieve higher
throughput, omit Matter.Render entirely. Instead, manage a
headless physics simulation with Matter.Engine and sync the
resulting transform data (positions and angles) directly to a
PIXI.Application stage running on WebGL.
Initialization
First, instantiate both engines independently. Ensure the PixiJS canvas matches the dimensions of your physics world boundaries.
import * as PIXI from 'pixi.js';
import Matter from 'matter-js';
// 1. Initialize PixiJS
const app = new PIXI.Application();
await app.init({ width: 800, height: 600, backgroundColor: 0x1099bb });
document.body.appendChild(app.canvas);
// 2. Initialize Matter.js
const engine = Matter.Engine.create();
const world = engine.world;Creating Graphics from Matter.js Bodies
A common performance pitfall is clearing and redrawing vector shapes
inside the animation loop via graphics.clear(). Doing this
forces the GPU to rebuild vertex buffers every frame, nullifying WebGL
benefits.
Instead, draw the local geometry of the Matter.js body to a
PIXI.Graphics object once during initialization. Center the
geometry at local coordinate (0, 0), and attach the graphic
to the physics body object for quick reference.
function createPhysicsGraphic(body, color = 0xffffff) {
const graphic = new PIXI.Graphics();
// Draw geometry based on vertices relative to the body center
graphic.fill(color);
const vertices = body.vertices;
graphic.moveTo(vertices[0].x - body.position.x, vertices[0].y - body.position.y);
for (let i = 1; i < vertices.length; i++) {
graphic.lineTo(vertices[i].x - body.position.x, vertices[i].y - body.position.y);
}
graphic.closePath();
graphic.fill();
// Map body to graphic
body.pixiGraphic = graphic;
app.stage.addChild(graphic);
return graphic;
}Spawning Bodies
When creating bodies with Matter.js, instantiate their physics representation, generate their visual representation, and push them to their respective containers.
// Create a dynamic box
const box = Matter.Bodies.rectangle(400, 200, 80, 80);
createPhysicsGraphic(box, 0xff0044);
// Create a static ground body
const ground = Matter.Bodies.rectangle(400, 580, 810, 40, { isStatic: true });
createPhysicsGraphic(ground, 0x222222);
// Add bodies to the Matter world
Matter.Composite.add(world, [box, ground]);The Synchronization Render Loop
To achieve optimal throughput, use the PixiJS ticker to step the
physics engine and update the hardware-accelerated transform properties
(position and rotation) of each corresponding
PIXI.Graphics object.
const bodies = Matter.Composite.allBodies(world);
app.ticker.add((ticker) => {
// 1. Step the physics engine forward by delta time
Matter.Engine.update(engine, ticker.deltaMS);
// 2. Update graphic transforms
for (let i = 0; i < bodies.length; i++) {
const body = bodies[i];
if (body.pixiGraphic) {
body.pixiGraphic.position.set(body.position.x, body.position.y);
body.pixiGraphic.rotation = body.angle;
}
}
});Key Optimization Strategies
- Disable Auto-Density Calculation: When creating massive amounts of bodies, set explicit inertia and mass values to skip expensive geometric calculations in Matter.js.
- Sleeping Bodies: Enable sleeping via
engine.enableSleeping = true. This prevents Matter.js from recalculating non-moving bodies, allowing you to conditionally skip transform updates on resting Graphics objects. - Avoid Complex Concave Polygons: Matter.js decomposes concave shapes into convex sets using vertices. For PixiJS rendering, triangulate or trace only the outer hull to minimize primitive drawing operations.