How to Build a Marble Run in Matter.js

This guide demonstrates how to build a dynamic, 2D physics-based marble run featuring wooden tracks, vertical drops, and funnels using the Matter.js physics engine. You will learn how to configure the physics world, create dynamic marble bodies, style static segments to mimic wooden planks, and construct geometry that reliably directs rolling objects through gravity-driven obstacles.

1. Initialize the Matter.js Environment

Begin by setting up the foundational Matter.js modules: the engine, renderer, runner, and world composite.

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

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

const render = Render.create({
  element: document.body,
  engine: engine,
  options: {
    width: 800,
    height: 900,
    wireframes: false,
    background: '#f4ecd8'
  }
});

Render.run(render);
const runner = Runner.create();
Runner.run(runner, engine);

2. Configure the Marble

Create the marble using a high-density circle body. Set restitution (bounciness) to a moderate level so it rolls smoothly without bouncing off the tracks, and reduce friction to simulate smooth glass.

function createMarble(x, y) {
  return Bodies.circle(x, y, 12, {
    restitution: 0.3,
    friction: 0.05,
    density: 0.004,
    render: {
      fillStyle: '#3498db',
      strokeStyle: '#2980b9',
      lineWidth: 2
    }
  });
}

const marble = createMarble(150, 40);
Composite.add(world, marble);

3. Build Wooden Track Channels

Tracks are static rectangular bodies tilted at an angle using Matter.Body.setAngle or positioned with native rotation. Style them using brown hex codes to simulate wood.

const woodStyle = {
  fillStyle: '#8B5A2B',
  strokeStyle: '#5C3A1E',
  lineWidth: 2
};

// Helper function to create angled tracks
function createTrack(x, y, width, height, angle) {
  return Bodies.rectangle(x, y, width, height, {
    isStatic: true,
    angle: angle,
    friction: 0.02,
    render: woodStyle
  });
}

// Upper tracks
const track1 = createTrack(260, 120, 320, 16, 0.18);
const track2 = createTrack(540, 260, 320, 16, -0.22);

4. Implement Vertical Drops

A vertical drop occurs by ending a track cleanly above another surface, allowing gravity to accelerate the marble. Add small static guide pegs or backstops to prevent the marble from overshooting its landing zone.

// Drop landing platform with an end-stopper
const dropLanding = createTrack(250, 430, 280, 16, 0.15);

// Safety wall to capture high-velocity drops from track2
const catchWall = Bodies.rectangle(400, 370, 14, 80, {
  isStatic: true,
  render: woodStyle
});

5. Construct a Funnel

A funnel directs marbles from wide drops into a narrow exit. Form a funnel using two converging static rectangles angled toward each other with an intentional gap at the bottom center.

// Left funnel slope
const funnelLeft = Bodies.rectangle(350, 600, 180, 16, {
  isStatic: true,
  angle: 0.65,
  friction: 0.01,
  render: woodStyle
});

// Right funnel slope
const funnelRight = Bodies.rectangle(490, 600, 180, 16, {
  isStatic: true,
  angle: -0.65,
  friction: 0.01,
  render: woodStyle
});

// Exit chute directly below the funnel opening
const exitChuteLeft = Bodies.rectangle(400, 720, 14, 100, {
  isStatic: true,
  render: woodStyle
});

const exitChuteRight = Bodies.rectangle(440, 720, 14, 100, {
  isStatic: true,
  render: woodStyle
});

6. Assemble the Course and Add Interaction

Add all components to the composite world. To test flow and throughput, use an interval to drop new marbles continuously.

// Add all track structures to the world
Composite.add(world, [
  track1, 
  track2, 
  catchWall, 
  dropLanding, 
  funnelLeft, 
  funnelRight, 
  exitChuteLeft, 
  exitChuteRight
]);

// Continuously spawn marbles
setInterval(() => {
  const newMarble = createMarble(130 + Math.random() * 20, 20);
  Composite.add(world, newMarble);
}, 2500);

This configuration forms a complete loop of continuous physical action where gravity pulls each marble along shallow channels, accelerates it through drops, and centers it within the funnel structure.