How to Set a Custom Gravity Vector in Matter.js

In Matter.js, controlling the direction and strength of gravity allows you to create unique physics environments such as zero-gravity space simulations, inverted worlds, or sideways pulling forces. This guide explains how to define a global custom gravity vector directly on the engine instance and how to apply directional or radial gravity forces to individual bodies using update loops.

Defining Global Gravity on the Engine

Matter.js provides a built-in gravity object on the Engine instance. The gravity vector consists of three primary properties: x, y, and scale.

By default, Matter.js sets gravity downwards along the Y-axis:

1. Setting Gravity During Initialization

You can define the custom vector when instantiating the engine by passing a gravity configuration in the Engine.create() options:

const engine = Matter.Engine.create({
  gravity: {
    x: 0.5,        // Pulls bodies to the right
    y: -0.5,       // Pulls bodies upward
    scale: 0.001   // Strength multiplier
  }
});

2. Modifying Gravity at Runtime

If your engine is already running, you can modify the vector dynamically by updating the properties directly:

// Reverse gravity upside down
engine.gravity.y = -1;

// Create horizontal wind or sideways gravity
engine.gravity.x = 1;
engine.gravity.y = 0;

// Disable world gravity completely
engine.gravity.scale = 0;

Creating Custom Per-Body Gravity

When you need non-uniform gravity—such as a planetary attraction point or individual gravity directions for specific objects—you should disable the global gravity and apply forces manually before each engine step.

Implementation Example:

const { Engine, Events, Body, Vector } = Matter;

const engine = Engine.create();

// Disable global gravity
engine.gravity.scale = 0;

// Define a custom force to apply continuously
Events.on(engine, 'beforeUpdate', () => {
  const customGravity = { x: 0, y: -0.002 }; // Upward vector

  // Apply to a specific body
  Body.applyForce(myBody, myBody.position, customGravity);
});

For radial or planetary gravity toward an attractor point:

Events.on(engine, 'beforeUpdate', () => {
  const attractorPosition = { x: 400, y: 300 };
  const G = 0.001; // Gravitational constant

  bodies.forEach((body) => {
    const force = Vector.sub(attractorPosition, body.position);
    const distance = Vector.magnitude(force);

    if (distance > 0) {
      const normal = Vector.normalise(force);
      const magnitude = (G * body.mass) / (distance * 0.05);
      Body.applyForce(body, body.position, Vector.mult(normal, magnitude));
    }
  });
});