How to Convert Open SVG Paths to Matter.js Bodies

Converting non-closed SVG paths into Matter.js rigid bodies requires transforming zero-area open lines into collidable geometry, as physics engines require defined mass and volume to calculate collisions. This article explains why open paths fail in standard conversion pipelines and outlines three practical solutions: expanding strokes into polygonal outlines, auto-closing the path geometry, and breaking open paths into chained compound bodies.

Why Non-Closed SVG Paths Fail in Matter.js

Matter.js relies on closed, non-intersecting polygons to calculate mass, center of mass, inertia, and collision bounds. When using utilities like Matter.Svg.pathToVertices(), the engine samples points along the vector path to generate a vertex array, which is then passed to Matter.Bodies.fromVertices().

If an SVG path is open (such as a simple line, an arc, or an unclosed bezier curve), the resulting vertex array does not form a complete boundary. Passing an open set of points to the vertex decomposition algorithm (such as poly-decomp.js, which Matter.js uses under the hood) causes the triangulation to fail, producing inverted polygons, missing collision bounds, or completely collapsed bodies with zero mass.

The most reliable way to convert an open path with visible thickness into a solid body is to convert its stroke into a closed boundary polygon before passing it to Matter.js.

  1. Calculate the Stroke Offset: Instead of using the raw path centerline, offset the path outward by half the stroke width on both sides (+strokeWidth / 2 and -strokeWidth / 2).
  2. Cap the Ends: Connect the parallel edges at the endpoints using either a flat cap (butt) or a series of rounded points (round cap).
  3. Generate a Closed Polygon: Join the offset edges into a continuous, clockwise-oriented loop.

You can automate this in JavaScript using vector libraries such as Paper.js (path.strokeBounds or path expansion tools) or ClipperLib. Once the path has an enclosed area, Matter.Bodies.fromVertices() will accurately generate the physical shape.

Method 2: Segment Chaining via Compound Bodies

If you are dealing with thin walls, terrain, or open tracks where stroke expansion creates unnecessary vertices, you can decompose the open path into a chain of overlapping convex rectangles.

  1. Sample Points Along the Path: Use the SVG DOM method SVGPathElement.getPointAtLength() to sample points at regular intervals along the open path.
  2. Generate Segment Bodies: Iterate through the sampled points. For every pair of adjacent points \((P_1, P_2)\):
    • Calculate the distance \(d\) between them: \(\sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}\).
    • Calculate the angle: \(\text{atan2}(y_2 - y_1, x_2 - x_1)\).
    • Create a thin rectangle using Matter.Bodies.rectangle(midX, midY, d, thickness, { angle }).
  3. Group into a Compound Body: Assemble all segment rectangles into a single rigid structure using Matter.Body.create({ parts: [rect1, rect2, ...] }).

This approach ensures smooth collisions without requiring third-party vector-offsetting algorithms, making it ideal for procedural tracks and irregular static boundaries.

Method 3: Direct Path Closure (For Quasi-Closed Shapes)

If the SVG path was intended to be a solid shape but simply omitted the terminal Z or z segment in its d attribute, you can manually force closure:

Handling Concavity and Polygon Decomposition

Regardless of the method used, the resulting closed vertex list will almost certainly be concave. Matter.js cannot handle concave shapes natively and requires the poly-decomp library to break shapes down into convex hulls.

Ensure the decomposition library is registered to your environment before creating bodies:

// Provide poly-decomp to Matter.js
Matter.Common.setDecomp(require('poly-decomp'));

// Generate the rigid body from the closed vertices
const body = Matter.Bodies.fromVertices(x, y, vertexSets, {
    isStatic: true
});

By ensuring every open path is either expanded into a boundary with area, chained into discrete segments, or cleanly closed with a terminal segment, you avoid degenerate physics states and achieve consistent collision detection.