Make Bodies Float Upward in Matter.js
Simulating a helium-filled balloon in Matter.js requires counteracting the default downward engine gravity and introducing an upward buoyant force. Because Matter.js applies gravity globally across the entire physics world, individual bodies cannot have negative gravity assigned directly to their properties. This guide demonstrates how to achieve a realistic helium effect by applying a continuous upward force on a specific body using the engine's update loop, combined with air resistance adjustments for a natural terminal ascent velocity.
Understanding the Physics in Matter.js
By default, a Matter.js world applies downward acceleration along the
Y-axis defined by engine.gravity.y and
engine.gravity.scale. The downward force exerted on any
rigid body during a step is:
\[\text{Force}_{\text{gravity}} = \text{body.mass} \times \text{engine.gravity.y} \times \text{engine.gravity.scale}\]
To make a body rise, you must continuously apply an upward force along the negative Y-axis that exceeds this gravitational pull.
Step-by-Step Implementation
1. Create the Helium Body with Air Resistance
When an object floats, air resistance prevents it from accelerating
upward indefinitely. Set a moderate frictionAir value on
the body so it quickly reaches a stable, realistic terminal
velocity.
const { Bodies } = Matter;
const balloon = Bodies.circle(400, 500, 30, {
density: 0.001,
frictionAir: 0.05, // Prevents infinite upward acceleration
restitution: 0.8
});
Matter.Composite.add(engine.world, balloon);2. Apply Upward Force in the Update Loop
Listen to the beforeUpdate event on the engine to apply
an upward force before physics calculations are executed on each
frame.
const { Events, Body } = Matter;
Events.on(engine, 'beforeUpdate', () => {
// Calculate the exact force needed to counteract gravity
const gravityForce = balloon.mass * engine.gravity.y * engine.gravity.scale;
// Define additional buoyant force to push it upward
const buoyancy = 0.0015;
// Apply the total upward force (negative Y direction)
Body.applyForce(balloon, balloon.position, {
x: 0,
y: -(gravityForce + buoyancy)
});
});Adding Realism: Simulating Wind and Oscillation
Helium balloons rarely rise in a straight vertical line. You can introduce a slight horizontal wobble using a sine wave inside the same update loop:
Events.on(engine, 'beforeUpdate', (event) => {
const gravityForce = balloon.mass * engine.gravity.y * engine.gravity.scale;
const buoyancy = 0.0015;
// Create a gentle side-to-side drift
const sway = Math.sin(event.timestamp * 0.003) * 0.0002;
Body.applyForce(balloon, balloon.position, {
x: sway,
y: -(gravityForce + buoyancy)
});
});Alternative: Inverting Gravity Globally
If every body in your simulation represents a floating object, you do not need per-body force loops. Instead, set the global gravity to a negative value:
engine.gravity.y = -1;For mixed environments containing both floating balloons and standard
falling objects, the continuous Body.applyForce method
within beforeUpdate remains the standard and most reliable
solution.