Build a Bridge with Constraints in Matter.js

This guide demonstrates how to construct an interactive, realistic suspension bridge using the Matter.js 2D physics engine. By linking a series of rigid rectangular bodies with elastic constraints and pinning the ends to static anchors, you can simulate realistic tension, sag, and weight-bearing behavior. Below, you will find the conceptual breakdown, step-by-step implementation, and complete code required to generate a functional bridge.

Core Concepts

A dynamic bridge in Matter.js consists of three primary components:

  1. Planks (Bodies): A sequence of dynamic rectangular bodies acting as the bridge deck.
  2. Joints (Constraints): Connections linking adjacent planks together, maintaining distance while allowing rotational flexibility.
  3. Pillars/Anchors: Static bodies or fixed coordinates at both ends that secure the bridge in world space.

Step-by-Step Implementation

1. Initialize the Engine and World

Set up the standard Matter.js modules: Engine, Render, Runner, Bodies, Composite, Composites, and Constraint.

const { Engine, Render, Runner, Bodies, Composite, Composites, Constraint } = Matter;

const engine = Engine.create();
const world = engine.world;

const render = Render.create({
    element: document.body,
    engine: engine,
    options: {
        width: 800,
        height: 600,
        wireframes: false
    }
});

Render.run(render);
Runner.run(Runner.create(), engine);

2. Create the Bridge Segments Using a Stack

The easiest way to generate bridge planks is via Composites.stack. This creates an array of aligned rectangles across the horizontal axis.

const bridgeLength = 12; // Number of planks
const plankWidth = 45;
const plankHeight = 15;
const startX = 130;
const startY = 300;

const bridge = Composites.stack(startX, startY, bridgeLength, 1, 5, 0, (x, y) => {
    return Bodies.rectangle(x, y, plankWidth, plankHeight, {
        collisionFilter: { group: -1 }, // Prevents planks from colliding with each other
        chamfer: 2,
        density: 0.005
    });
});

3. Chain the Planks Together

Use Composites.chain to automatically generate constraints between consecutive planks in the stack.

Composites.chain(bridge, 0.4, 0, -0.4, 0, {
    stiffness: 0.9,
    length: 2,
    render: {
        visible: true,
        lineWidth: 2,
        strokeStyle: '#666'
    }
});

The offset parameters (0.4 and -0.4) attach the constraint near the edges of adjacent planks rather than their centers, resulting in realistic pivoting.

4. Anchor the Ends

To prevent the bridge from falling under gravity, attach the first and last bodies to fixed world points using independent constraints.

// Anchor the left side
const leftAnchor = Constraint.create({
    pointA: { x: startX - 20, y: startY },
    bodyB: bridge.bodies[0],
    pointB: { x: -plankWidth / 2, y: 0 },
    stiffness: 1,
    length: 0
});

// Anchor the right side
const rightAnchor = Constraint.create({
    pointA: { x: startX + (plankWidth + 5) * bridgeLength, y: startY },
    bodyB: bridge.bodies[bridge.bodies.length - 1],
    pointB: { x: plankWidth / 2, y: 0 },
    stiffness: 1,
    length: 0
});

Composite.add(world, [bridge, leftAnchor, rightAnchor]);

Tuning Physics Behavior