How to Create a Wind Force Effect in Matter.js

Creating a wind force effect in Matter.js involves applying a continuous vector force to bodies within the physics simulation prior to every engine update. Because Matter.js does not provide a native "wind" primitive, developers can implement this behavior by leveraging the engine's event system to loop through active world bodies and apply directional forces using Matter.Body.applyForce. This guide demonstrates the most efficient way to apply uniform, variable, and area-restricted wind across a Matter.js world.

The Core Concept

Matter.js updates its simulation step-by-step. Forces applied to bodies decay immediately after an engine tick, meaning continuous forces like gravity or wind must be reapplied continuously.

To create a global wind effect:

  1. Listen to the beforeUpdate event on the Matter.js Engine.
  2. Retrieve all bodies currently active in the world composite.
  3. Exclude static bodies (such as boundaries and floors).
  4. Apply a force vector to each eligible dynamic body.

Basic Implementation

The standard way to apply a constant horizontal wind blowing to the right is shown in the following implementation:

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

// Create engine and world
const engine = Engine.create();
const world = engine.world;

// Define wind properties
const windVector = { x: 0.001, y: 0 }; // Positive x blows to the right

// Listen for updates before the physics step calculates positions
Events.on(engine, 'beforeUpdate', () => {
    const bodies = Composite.allBodies(world);

    for (let i = 0; i < bodies.length; i++) {
        const body = bodies[i];

        // Ensure static bodies like walls or floors are unaffected
        if (!body.isStatic) {
            Body.applyForce(body, body.position, windVector);
        }
    }
});

Because applyForce accelerates a body according to its mass (\(F = ma\)), lighter objects will naturally accelerate faster than heavier objects when subjected to the same force vector.

Adding Dynamic and Gusting Wind

Constant wind can feel artificial. You can simulate wind gusts or turbulence by introducing time-based oscillation using trigonometric functions or pseudo-random values:

Events.on(engine, 'beforeUpdate', (event) => {
    const time = event.timestamp * 0.002;
    
    // Create an oscillating wind force with a base direction
    const gustStrength = Math.sin(time) * 0.001 + 0.0015;
    const dynamicWind = { x: gustStrength, y: 0 };

    const bodies = Composite.allBodies(world);
    for (let i = 0; i < bodies.length; i++) {
        const body = bodies[i];
        if (!body.isStatic) {
            Body.applyForce(body, body.position, dynamicWind);
        }
    }
});

Restricting Wind to a Specific Area

To simulate localized effects like fans, wind tunnels, or updrafts, define a spatial boundary and check whether a body's position falls within that region before applying the force:

const windZone = {
    minX: 100,
    maxX: 400,
    minY: 0,
    maxY: 600
};

const upwardDraft = { x: 0, y: -0.003 };

Events.on(engine, 'beforeUpdate', () => {
    const bodies = Composite.allBodies(world);

    for (let i = 0; i < bodies.length; i++) {
        const body = bodies[i];

        if (!body.isStatic) {
            const { x, y } = body.position;

            // Check if the body is within the wind zone boundaries
            const isInZone = x >= windZone.minX && 
                             x <= windZone.maxX && 
                             y >= windZone.minY && 
                             y <= windZone.maxY;

            if (isInZone) {
                Body.applyForce(body, body.position, upwardDraft);
            }
        }
    }
});

Performance Considerations