Implement Base Isolation Dampers in Matter.js

This article explains how to simulate seismic base isolation systems beneath multi-story structures using Matter.js. By decoupling a building from ground motion using a combination of flexible constraints, linear damping, and kinematic ground drivers, you can replicate how elastomeric bearings and friction dampers absorb lateral earthquake energy. The following sections walk through the mechanics, configuration properties, and code implementation required to build a functional, sway-reducing 2D physics simulation.

The Physics of Base Isolation in 2D

Base isolation protects structures by lengthening their natural vibration period and dissipating kinetic energy before it propagates upward. In Matter.js, simulating this involves three core layers:

  1. The Ground Foundation: A kinematic body driven laterally by a periodic function to simulate horizontal earthquake waves.
  2. The Isolation Interface: Horizontal sliders or spring-damper constraints that allow controlled lateral movement while supporting vertical loads.
  3. The Superstructure: A rigid or semi-flexible assembly of dynamic bodies representing building floors and structural columns.

Step 1: Setting Up the Simulation World

Initialize the standard Matter.js engine, renderer, and runner modules.

const { Engine, Render, Runner, Bodies, Composite, Constraint, 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);

Step 2: Creating the Ground and Seismic Excitation

Create a base plate that acts as the moving bedrock. Mark it as isKinematic (or isStatic updated manually via position) so it carries infinite mass and ignores forces exerted by the building above.

const ground = Bodies.rectangle(400, 550, 600, 40, {
    isStatic: true,
    render: { fillStyle: '#2c3e50' }
});
Composite.add(world, ground);

// Drive the ground with sinusoidal lateral displacement
let time = 0;
const earthquakeFrequency = 0.05;
const earthquakeAmplitude = 8;

Matter.Events.on(engine, 'beforeUpdate', () => {
    time += 1;
    const targetVelocityX = Math.cos(time * earthquakeFrequency) * earthquakeAmplitude;
    Body.setVelocity(ground, { x: targetVelocityX, y: 0 });
    Body.setPosition(ground, { 
        x: 400 + Math.sin(time * earthquakeFrequency) * (earthquakeAmplitude / earthquakeFrequency), 
        y: 550 
    });
});

Step 3: Designing the Base Isolation Dampers

To construct an elastomeric lead-rubber bearing equivalent, couple the ground to an isolated base slab using two components: a rigid support boundary to carry the vertical load and non-rigid constraints that control horizontal stiffness and energy dissipation.

Matter.js provides stiffness and damping properties directly within constraints:

// Base slab of the building resting above the ground
const baseSlab = Bodies.rectangle(400, 500, 200, 20, {
    density: 0.005,
    render: { fillStyle: '#7f8c8d' }
});

// Left Damper Constraint
const damperLeft = Constraint.create({
    bodyA: ground,
    pointA: { x: -80, y: -20 },
    bodyB: baseSlab,
    pointB: { x: -80, y: 10 },
    stiffness: 0.05,
    damping: 0.1,
    render: { strokeStyle: '#e74c3c', lineWidth: 5 }
});

// Right Damper Constraint
const damperRight = Constraint.create({
    bodyA: ground,
    pointA: { x: 80, y: -20 },
    bodyB: baseSlab,
    pointB: { x: 80, y: 10 },
    stiffness: 0.05,
    damping: 0.1,
    render: { strokeStyle: '#e74c3c', lineWidth: 5 }
});

Composite.add(world, [baseSlab, damperLeft, damperRight]);

Step 4: Constructing the Building Superstructure

Stack several floor slabs connected by structural columns above the base slab. Using semi-stiff constraints to connect the superstructure components allows you to visually observe story drift and inter-story shear forces.

const floors = [];
const numFloors = 4;
const floorHeight = 60;
let previousFloor = baseSlab;

for (let i = 0; i < numFloors; i++) {
    const yPos = 500 - (i + 1) * floorHeight;
    const floor = Bodies.rectangle(400, yPos, 160, 15, {
        density: 0.002,
        render: { fillStyle: '#34495e' }
    });

    // Vertical structural columns (stiff connections)
    const leftColumn = Constraint.create({
        bodyA: previousFloor,
        pointA: { x: -70, y: -10 },
        bodyB: floor,
        pointB: { x: -70, y: 10 },
        stiffness: 0.9,
        render: { strokeStyle: '#95a5a6', lineWidth: 3 }
    });

    const rightColumn = Constraint.create({
        bodyA: previousFloor,
        pointA: { x: 70, y: -10 },
        bodyB: floor,
        pointB: { x: 70, y: 10 },
        stiffness: 0.9,
        render: { strokeStyle: '#95a5a6', lineWidth: 3 }
    });

    // Cross-bracing to prevent column shear collapse
    const crossBrace = Constraint.create({
        bodyA: previousFloor,
        pointA: { x: -70, y: -10 },
        bodyB: floor,
        pointB: { x: 70, y: 10 },
        stiffness: 0.7,
        render: { strokeStyle: '#bdc3c7', lineWidth: 1 }
    });

    Composite.add(world, [floor, leftColumn, rightColumn, crossBrace]);
    previousFloor = floor;
}

Tuning Damper Performance

To verify the damper's effectiveness, compare the top floor's lateral displacement against the ground motion.