Create a Newton's Cradle with Matter.js

This guide explains how to quickly build a realistic Newton's cradle simulation using Matter.js and its specialized composite helper, Matter.Composites.newtonCradle. You will learn how to configure the engine, initialize the cradle with custom physical dimensions, add interactive controls, and tune collision properties to achieve an accurate kinetic motion effect.

Understanding Matter.Composites.newtonCradle

Matter.js provides a built-in composite function specifically designed to generate a Newton's cradle assembly. The function signature is:

Matter.Composites.newtonCradle(xx, yy, number, size, length)

Internally, this method automatically creates the circular bodies and attaches them to static anchor points using Matter.Constraint instances.


Step-by-Step Implementation

1. Initialize the Matter.js Modules

First, alias the core Matter.js modules for convenience:

const {
    Engine,
    Render,
    Runner,
    Composites,
    Composite,
    Mouse,
    MouseConstraint,
    Body
} = Matter;

2. Create the Engine and Renderer

Create an engine to manage the physics updates and a renderer to draw the simulation to an HTML canvas:

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

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

Render.run(render);

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

3. Instantiate the Newton's Cradle

Generate the cradle composite and add it to the physics world:

const cradle = Composites.newtonCradle(280, 100, 5, 30, 300);

Composite.add(world, cradle);

4. Trigger the Initial Motion

In a real Newton's cradle, the motion begins when one ball is pulled back and released. To replicate this automatically on startup, displace the first ball:

// Displace the leftmost ball along the X and Y axes
Body.translate(cradle.bodies[0], { x: -180, y: -100 });

5. Add Mouse Interaction (Optional)

Allow users to grab and pull any ball manually using a mouse constraint:

const mouse = Mouse.create(render.canvas);
const mouseConstraint = MouseConstraint.create(engine, {
    mouse: mouse,
    constraint: {
        stiffness: 0.2,
        render: {
            visible: false
        }
    }
});

Composite.add(world, mouseConstraint);
render.mouse = mouse;

Tuning Physics for Maximum Realism

By default, Matter.js bodies lose kinetic energy due to air resistance and inelastic collisions. To make your Newton's cradle swing back and forth for longer periods:

  1. Restitution (Bounciness): The default balls generated by Composites.newtonCradle have a restitution value of 1 (perfectly elastic). Avoid reducing this value.
  2. Air Resistance: Set frictionAir to zero across all bodies in the cradle to eliminate drag:
cradle.bodies.forEach((ball) => {
    ball.frictionAir = 0;
    ball.friction = 0;
    ball.restitution = 1;
});
  1. Collision Precision: Increase the engine solver iterations if you observe balls clipping through one another during high-velocity impacts:
engine.positionIterations = 10;
engine.velocityIterations = 10;