Extract Vertices from PNG for Matter.js Bodies
Extracting vertices from a PNG image allows you to generate accurate,
custom physics hitboxes for complex 2D sprites in Matter.js instead of
relying on basic geometric primitives. This process involves drawing the
PNG onto an offscreen HTML5 canvas, reading its alpha channel to
identify the outline using a contour-tracing algorithm, simplifying
those points into an ordered coordinate path, and passing the resulting
vertex array into Matter.js's Bodies.fromVertices
method.
1. Enable Concave Decomposition
Matter.js supports concave polygon bodies through an external library
called poly-decomp.js. Because auto-traced image outlines
are almost always concave, this dependency must be loaded and registered
before creating bodies from vertex sets:
// Provide poly-decomp to Matter.js
window.decomp = require('poly-decomp'); // or include via <script> tag2. Read Image Data with an Offscreen Canvas
To detect the shape of the sprite, load the image and draw it onto an
invisible HTML5 canvas element. This provides raw access to the RGBA
values of each pixel via getImageData.
function getPixelData(image) {
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
return ctx.getImageData(0, 0, image.width, image.height);
}3. Trace the Alpha Outline
The boundary of the PNG is defined by the transition between fully transparent pixels (alpha = 0) and opaque pixels (alpha > threshold). To turn this boundary into an ordered sequence of coordinates:
- Thresholding: Iterate through the image pixels and
create a 2D binary grid where
1represents an opaque pixel and0represents empty space. - Contour Extraction: Run a boundary-following
algorithm such as the Marching Squares or Moore-Neighbor tracing
algorithm over the binary grid. This produces an ordered loop of
{ x, y }points defining the perimeter.
Third-party utilities like marching-squares or SVG
vectorizers can be used to handle this step efficiently.
4. Reduce and Optimize the Vertex Count
Raw contour tracing often generates hundreds or thousands of individual vertices—one for every edge pixel. Passing too many vertices into a physics engine creates severe performance bottlenecks.
Pass the traced points through a polyline simplification algorithm, such as the Ramer-Douglas-Peucker (RDP) algorithm. This eliminates redundant points along straight edges and curves while preserving the essential silhouette of the object, reducing the vertex count to a manageable number (typically 20 to 50 points).
5. Generate the Matter.js Body
Once you have a simplified array of coordinates in clockwise or
counter-clockwise order, pass the array to
Matter.Bodies.fromVertices.
// vertices: Array of points [{ x: 10, y: 0 }, { x: 30, y: 20 }, ...]
const vertices = getSimplifiedVertices(image);
const body = Matter.Bodies.fromVertices(spawnX, spawnY, vertices, {
render: {
sprite: {
texture: 'path/to/sprite.png'
}
}
}, true);
Matter.Composite.add(engine.world, body);The fourth parameter is an options object, and the optional boolean
parameter (true) enables internal vertex correction and
automated hull decomposition. Matter.js automatically recalculates the
center of mass, repositions the vertices relative to that center, and
splits concave geometries into a compound body composed of convex
sub-polygons.