Custom Shapes in Matter.js Using Matter.Vertices

This guide explains how to define and render custom rigid bodies using the Matter.Vertices module in Matter.js. You will learn how to create shapes using coordinate arrays, parse SVG paths into physics bodies, handle concave geometry with polygon decomposition, and properly account for the physics engine's automatic center-of-mass calculations.


1. Defining Vertices Manually

In Matter.js, vertices are represented as an array of 2D vector objects, where each point has an x and y property. Points must be defined in clockwise order to form a valid, closed polygon boundary.

const starCoords = [
  { x: 50, y: 0 },
  { x: 63, y: 38 },
  { x: 100, y: 38 },
  { x: 69, y: 59 },
  { x: 82, y: 100 },
  { x: 50, y: 75 },
  { x: 18, y: 100 },
  { x: 31, y: 59 },
  { x: 0, y: 38 },
  { x: 37, y: 38 }
];

2. Creating a Body with Bodies.fromVertices

Once you have defined your coordinates, pass them to Matter.Bodies.fromVertices to instantiate a physics body.

const { Bodies, Composite } = Matter;

const x = 400; // X position in the world
const y = 300; // Y position in the world

const customBody = Bodies.fromVertices(x, y, [starCoords], {
  isStatic: false,
  render: {
    fillStyle: '#e74c3c',
    strokeStyle: '#c0392b',
    lineWidth: 1
  }
});

Composite.add(engine.world, customBody);

The third parameter must be an array of vertex sets (an array containing your coordinate array), allowing multiple paths to define compound shapes.


3. Parsing Shapes from SVG Paths

Instead of manually typing coordinates, you can use Matter.Vertices.fromPath to convert standard SVG path strings directly into vertices:

const { Vertices, Bodies, Composite } = Matter;

// Standard SVG path definition
const pathData = "M 0 0 L 100 0 L 50 100 Z";

// Parse path into vertex set
const pathVertices = Vertices.fromPath(pathData);

const shape = Bodies.fromVertices(200, 200, [pathVertices], {
  restitution: 0.8
});

Composite.add(engine.world, shape);

4. Handling Concave Shapes with poly-decomp

Matter.js collision algorithms require convex polygons. If you pass a concave shape to Bodies.fromVertices, Matter.js automatically splits it into multiple convex sub-bodies.

To enable this, you must install and expose the poly-decomp library to the window or engine context before creating the body:

<!-- Load poly-decomp before Matter.js -->
<script src="https://cdn.jsdelivr.net/npm/poly-decomp@0.3.0/build/decomp.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>

In modular environments (Node.js/Webpack/Vite):

import Matter from 'matter-js';
import decomp from 'poly-decomp';

// Assign poly-decomp to Matter.Common
Matter.Common.setDecomp(decomp);

If poly-decomp is omitted, concave shapes will either fail to render accurately or will revert to an approximated convex hull.


5. Utility Methods in Matter.Vertices

The Matter.Vertices module provides functions to manipulate coordinate sets before generating bodies:

Example of pre-processing vertices:

// Rotate 45 degrees and scale up by 1.5x before creating the body
Matter.Vertices.rotate(starCoords, Math.PI / 4, { x: 50, y: 50 });
Matter.Vertices.scale(starCoords, 1.5, 1.5, { x: 50, y: 50 });

6. Center-of-Mass Positioning Caveat

When Bodies.fromVertices builds a shape, it shifts the origin of the vertices to the polygon's calculated center of mass. This means the (x, y) arguments supplied to Bodies.fromVertices dictate where the center of mass will be placed in the simulation, not the top-left coordinate (0, 0) of your original vertex data.