Simulating a Mousetrap Snap in Matter.js

This guide explains how to simulate the rapid, violent snapping motion of a mechanical mousetrap in Matter.js using high-torque spring constraints. By anchoring a dynamic lever arm to a static base with a revolute pivot and applying an offset, high-stiffness distance constraint, you can generate the angular acceleration necessary to mimic a spring-loaded trap. The following sections break down the physical architecture, constraint configurations, stability adjustments, and the release mechanism.

1. Setting Up the Physical Bodies

A mousetrap requires two primary bodies: a static base and a dynamic lever arm (the striker or hammer).

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

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

// Mousetrap base
const base = Bodies.rectangle(400, 500, 200, 20, { 
    isStatic: true 
});

// Striking arm
const armLength = 120;
const arm = Bodies.rectangle(460, 485, armLength, 10, {
    density: 0.005,
    collisionFilter: { group: -1 } // Prevent collision with the base pivot
});

Composite.add(world, [base, arm]);

2. Establishing the Fulcrum Pivot

Matter.js does not have a native "revolute joint" object, but you can create a hinge by using a zero-length constraint that connects the arm to the base at a shared pivot point:

const pivot = Constraint.create({
    bodyA: base,
    pointA: { x: -60, y: -10 },
    bodyB: arm,
    pointB: { x: -armLength / 2, y: 0 },
    length: 0,
    stiffness: 1
});

Composite.add(world, pivot);

3. Creating High-Torque Rotational Force

Because Matter.js does not provide a dedicated torsional spring constraint, rotational torque is achieved by connecting a linear constraint between an anchor point behind the fulcrum and an offset point on the lever arm.

Torque is the product of force and the perpendicular distance from the fulcrum. To maximize torque:

  1. Attach the spring to an offset point along the arm rather than the exact pivot center.
  2. Set the length of the spring constraint to zero or a very small resting value.
  3. Maximize stiffness (approaching 1.0) to create instantaneous acceleration.
const spring = Constraint.create({
    bodyA: base,
    pointA: { x: -80, y: -10 }, // Fixed anchor point on the base
    bodyB: arm,
    pointB: { x: -armLength / 2 + 15, y: -5 }, // Offset point on the arm
    length: 0,
    stiffness: 0.8,
    damping: 0.05
});

Composite.add(world, spring);

When the arm is rotated 180 degrees into the "set" position, the distance between these two attachment points stretches significantly, storing the potential energy required for the snap.

4. Holding and Triggering the Trap

To hold the trap under tension, define a temporary latch constraint or a static catch body that holds the arm in the cocked position. When triggered by a collision or a timer, remove the latch from the world.

// Latch holding the arm fully open at the opposite side of the base
const latch = Constraint.create({
    bodyA: base,
    pointA: { x: 70, y: -10 },
    bodyB: arm,
    pointB: { x: armLength / 2, y: 0 },
    stiffness: 1,
    length: 0
});

Composite.add(world, latch);

// Trigger: Release the latch to snap the trap shut
function triggerTrap() {
    Composite.remove(world, latch);
}

5. Managing Simulation Stability

High-velocity constraints can cause bodies to tunnel through barriers or violently oscillate upon impact. To ensure stability during the snap: