Custom Gravity for Specific Bodies in Matter.js

This article explains how to override default global gravity in Matter.js to apply custom directional forces to individual rigid bodies. Because Matter.js applies its world gravity settings across all non-static bodies by default, achieving independent gravity requires neutralizing the global gravitational pull on the target body inside the simulation loop and manually applying your desired custom force vectors.

Understanding Matter.js Gravity Mechanics

Matter.js calculates gravitational acceleration globally via the engine.gravity object. During each simulation step, the engine applies a force proportional to each dynamic body's mass:

\[\text{Force}_y = \text{body.mass} \times \text{engine.gravity.y} \times \text{engine.gravity.scale}\]

Because bodies lack a native ignoreGravity property, you must hook into the simulation's update loop to counteract this automatic calculation before physics integration occurs.

Neutralizing World Gravity and Applying Custom Forces

The standard method is listening to the beforeUpdate event on the Matter.Engine. During this event, calculate the exact inverse of the world gravity force, combine it with your desired custom gravity vector, and apply the resulting net force using Matter.Body.applyForce.

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

// Target body configuration
const customBody = Bodies.circle(400, 200, 30, {
  // Custom gravity direction and strength
  customGravity: { x: 0, y: -0.001 } 
});

// Hook into beforeUpdate
Events.on(engine, 'beforeUpdate', () => {
  const gravity = engine.gravity;
  
  // 1. Calculate the counter-force to negate world gravity
  const counterForce = {
    x: -customBody.mass * gravity.x * gravity.scale,
    y: -customBody.mass * gravity.y * gravity.scale
  };

  // 2. Define custom gravity force scaled by mass
  const customForce = {
    x: customBody.mass * customBody.customGravity.x,
    y: customBody.mass * customBody.customGravity.y
  };

  // 3. Combine forces and apply to body center
  const netForce = {
    x: counterForce.x + customForce.x,
    y: counterForce.y + customForce.y
  };

  Body.applyForce(customBody, customBody.position, netForce);
});

Alternative Approach: Zero Global Gravity

If multiple bodies in your simulation require distinct gravities, orbital mechanics, or localized point attractors, consider setting global gravity to zero entirely:

engine.gravity.scale = 0;

With world gravity disabled, no counteracting math is needed. You can iterate through all active bodies in beforeUpdate and directly apply whatever individual gravity vectors each entity requires.