Invert Gravity for Specific Bodies in Matter.js

Matter.js simulates a uniform global gravity vector across all active bodies in an engine, offering no built-in, per-body gravity toggles. However, you can easily invert gravity for individual bodies without altering the global engine.gravity configuration by hooking into the simulation's update loop and applying an opposing corrective force on every frame. This technique cancels standard downward gravity and imparts an equivalent upward acceleration exclusively to targeted objects.

The Mathematical Principle

Matter.js calculates gravitational force on a body as:

\[\vec{F}_{\text{gravity}} = m \cdot \vec{g} \cdot s\]

Where:

Because the physics engine automatically applies this force downward each step, merely applying an equal upward force would result in zero net acceleration (weightlessness). To achieve inverted gravity of equal magnitude in the opposite direction, you must apply twice the gravitational force in the inverted direction: one unit to cancel the world gravity, and one unit to accelerate the body upward.

Implementation via beforeUpdate

The standard approach uses the Matter.Events.on(engine, 'beforeUpdate', callback) event hook. Within this callback, iterate over your custom collection of inverted bodies and use Matter.Body.applyForce() to apply the counter-force.

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

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

// Create a standard body and an anti-gravity body
const standardBox = Bodies.rectangle(300, 100, 50, 50);
const invertedBox = Bodies.rectangle(500, 500, 50, 50, {
  render: { fillStyle: '#ff4d4d' }
});

// Custom flag or property to identify inverted bodies
invertedBox.customGravityMultiplier = -1;

Composite.add(world, [standardBox, invertedBox]);

// Apply opposing forces prior to every engine update
Events.on(engine, 'beforeUpdate', () => {
  const bodies = Composite.allBodies(world);
  const gravity = engine.gravity;

  bodies.forEach((body) => {
    if (body.customGravityMultiplier !== undefined && !body.isStatic) {
      // Calculate normal gravity force applied by the engine
      const baseForceX = body.mass * gravity.x * gravity.scale;
      const baseForceY = body.mass * gravity.y * gravity.scale;

      // When customGravityMultiplier is -1:
      // Required upward force = -2 * baseForce
      const correctiveFactor = body.customGravityMultiplier - 1;

      const force = {
        x: baseForceX * correctiveFactor,
        y: baseForceY * correctiveFactor
      };

      Body.applyForce(body, body.position, force);
    }
  });
});

Considerations for Accuracy