Simulate Resonance and Structural Failure in Matter.js

This article explains how to build an interactive 2D physics sandbox using Matter.js to visualize harmonic resonance and structural failure modes. By modeling a lattice of rigid bodies connected by elastic, breakable constraints and applying a periodic oscillatory force, you can observe how mechanical systems store energy and catastrophic failure occurs when external driving frequencies match the system's natural frequencies.

1. Setting Up the Matter.js Environment

Begin by initializing the foundational Matter.js modules: the engine, renderer, runner, and world.

const { Engine, Render, Runner, Bodies, Composite, Constraint, Events, Body, Vector } = 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);
const runner = Runner.create();
Runner.run(runner, engine);

2. Constructing the Breakable Structure

A structure such as a bridge, tower, or cantilever is constructed using an array of rigid nodes (Bodies.circle or Bodies.rectangle) connected by elastic links (Constraint.create).

To simulate material limits, assign a custom property—such as maxElongation or breakingForce—to each constraint.

function createBeam(bodyA, bodyB, stiffness = 0.05, damping = 0.01) {
    const length = Vector.magnitude(Vector.sub(bodyA.position, bodyB.position));
    return Constraint.create({
        bodyA: bodyA,
        bodyB: bodyB,
        length: length,
        stiffness: stiffness,
        damping: damping,
        render: {
            strokeStyle: '#4a90e2',
            lineWidth: 3
        },
        plugin: {
            restLength: length,
            maxStrain: 0.25 // Fails at 25% elongation
        }
    });
}

Construct a multi-segment bridge anchored at both ends to static bodies:

const nodes = [];
const segments = 10;
const spacing = 60;
const startY = 300;

for (let i = 0; i <= segments; i++) {
    const isAnchor = (i === 0 || i === segments);
    const node = Bodies.circle(100 + i * spacing, startY, 6, {
        isStatic: isAnchor,
        frictionAir: 0.005
    });
    nodes.push(node);
    Composite.add(world, node);
}

const beams = [];
for (let i = 0; i < nodes.length - 1; i++) {
    const beam = createBeam(nodes[i], nodes[i + 1]);
    beams.push(beam);
    Composite.add(world, beam);
}

3. Implementing Structural Failure Logic

Matter.js constraints do not break natively. You must inspect structural strain on every tick using the beforeUpdate engine event and detach constraints exceeding their failure threshold.

Events.on(engine, 'beforeUpdate', () => {
    for (let i = beams.length - 1; i >= 0; i--) {
        const beam = beams[i];
        if (!beam.bodyA || !beam.bodyB) continue;

        const currentLength = Vector.magnitude(
            Vector.sub(beam.bodyA.position, beam.bodyB.position)
        );
        const strain = Math.abs(currentLength - beam.plugin.restLength) / beam.plugin.restLength;

        // Visual stress indication: Interpolate color based on strain
        if (strain > beam.plugin.maxStrain * 0.7) {
            beam.render.strokeStyle = '#e74c3c'; // Warning: near failure
        }

        // Failure condition
        if (strain > beam.plugin.maxStrain) {
            Composite.remove(world, beam);
            beams.splice(i, 1); // Remove from tracking array
        }
    }
});

4. Applying Harmonic Forcing for Resonance

Resonance occurs when an external periodic force matches the natural frequency of the physical system. Model this by applying a sinusoidal force vector to a central node.

let time = 0;
const targetNode = nodes[Math.floor(nodes.length / 2)];
const drivingFrequency = 0.05; // Adjust to match natural frequency
const forceAmplitude = 0.004;

Events.on(engine, 'beforeUpdate', (event) => {
    time += event.delta * 0.001; // Convert delta to seconds

    if (targetNode && !targetNode.isStatic) {
        const forceMagnitude = Math.sin(2 * Math.PI * drivingFrequency * time) * forceAmplitude;
        Body.applyForce(targetNode, targetNode.position, {
            x: 0,
            y: forceMagnitude
        });
    }
});

5. Analyzing Structural Failure Modes

By adjusting the drivingFrequency and forceAmplitude, you can trigger distinct modes of structural collapse: