Camera Pan Effect in Matter.js Using Render Bounds
This article explains how to create a smooth camera pan effect in
Matter.js by manipulating the render.bounds property. You
will learn how to configure the renderer to support custom viewports,
track a target object dynamically, apply linear interpolation for smooth
camera transitions, and keep the view within your world boundaries.
Enabling Custom Bounds in Matter.js
By default, the Matter.js built-in canvas renderer displays a fixed
coordinate space matching the canvas width and height. To pan the view,
you must enable viewport bounds by setting
render.options.hasBounds to true when
initializing the renderer:
const render = Matter.Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
wireframes: false,
hasBounds: true // Enables custom viewport rendering
}
});When hasBounds is enabled, Matter.js renders only the
region bounded by render.bounds.min (top-left) and
render.bounds.max (bottom-right).
Calculating Camera Position
To pan the camera to a specific point (such as a player body), calculate the desired minimum and maximum bounds based on the target position and your viewport dimensions.
const viewportWidth = 800;
const viewportHeight = 600;
function updateCamera(targetBody) {
// Center the camera on the target
const targetX = targetBody.position.x - viewportWidth / 2;
const targetY = targetBody.position.y - viewportHeight / 2;
render.bounds.min.x = targetX;
render.bounds.min.y = targetY;
render.bounds.max.x = targetX + viewportWidth;
render.bounds.max.y = targetY + viewportHeight;
}Adding Smooth Camera Panning (Lerp)
Snapping directly to the target can feel jarring. Applying linear interpolation (lerp) creates a smooth camera pan that catches up to moving objects gradually:
const camera = {
x: 0,
y: 0,
speed: 0.05 // Lower values result in smoother, slower panning
};
function panCamera(targetBody) {
const targetX = targetBody.position.x - viewportWidth / 2;
const targetY = targetBody.position.y - viewportHeight / 2;
// Linear interpolation
camera.x += (targetX - camera.x) * camera.speed;
camera.y += (targetY - camera.y) * camera.speed;
// Apply interpolated positions to bounds
render.bounds.min.x = camera.x;
render.bounds.min.y = camera.y;
render.bounds.max.x = camera.x + viewportWidth;
render.bounds.max.y = camera.y + viewportHeight;
}Clamping to World Limits
To prevent the camera from panning into empty space beyond the edges of your map, clamp the camera coordinates before assigning them to the bounds:
const worldLimits = {
minX: 0,
minY: 0,
maxX: 3000,
maxY: 2000
};
function clampCamera() {
camera.x = Math.max(worldLimits.minX, Math.min(camera.x, worldLimits.maxX - viewportWidth));
camera.y = Math.max(worldLimits.minY, Math.min(camera.y, worldLimits.maxY - viewportHeight));
}Hooking into the Engine Loop
To ensure the camera updates on every frame before the renderer draws
the physics state, attach the update function to the
beforeRender event:
Matter.Events.on(render, 'beforeRender', () => {
panCamera(player);
clampCamera();
});Using render.bounds alongside linear interpolation
provides an efficient, native camera system in Matter.js without needing
external rendering libraries.