Fix Matter.js Window Object Errors in Node.js
Running Matter.js in a server-side environment like Node.js often
results in a ReferenceError: window is not defined. This
occurs because Matter.js includes modules designed for web browsers,
specifically its built-in canvas renderer. This article outlines why
this error happens and provides actionable methods to resolve it,
including isolating the physics engine, replacing the browser renderer,
and polyfilling global objects.
Why the Error Occurs
Node.js is a headless JavaScript runtime that lacks browser-specific
global APIs such as window, document, and
requestAnimationFrame. Matter.js bundles both its core
physics engine and a canvas-based visualizer
(Matter.Render). When Node.js loads components that attempt
to inspect or bind to the browser's display lifecycle via the
window object, execution halts immediately with a reference
error.
Solution 1: Do Not Use
Matter.Render
In a Node.js environment, your application should handle only the
physics simulation, not the rendering. The most common cause of the
error is importing or instantiating Matter.Render.
Avoid using Render.create() or Render.run()
on the server:
const Matter = require('matter-js');
// Deconstruct only physics-related modules
const { Engine, Bodies, Composite } = Matter;
// Create the engine
const engine = Engine.create();
// Create rigid bodies
const box = Bodies.rectangle(400, 200, 80, 80);
const ground = Bodies.rectangle(400, 610, 810, 60, { isStatic: true });
// Add bodies to the world
Composite.add(engine.world, [box, ground]);Solution 2: Run a Headless Update Loop
Because browser-based helpers rely on
window.requestAnimationFrame, run your simulation in
Node.js using Engine.update inside a custom loop or via
standard Node.js timing mechanisms:
const delta = 1000 / 60; // 60 FPS
setInterval(() => {
Matter.Engine.update(engine, delta);
// Access body coordinates for your server logic
console.log(`Box Position: x=${box.position.x}, y=${box.position.y}`);
}, delta);For high-precision server-side physics, prefer using
process.hrtime() or performance.now() to
calculate the exact delta time between updates.
Solution 3: Polyfill the
window Object
If you are using an older version of Matter.js or a plugin that
references window during module initialization, create a
mock window object globally before importing the
library.
Add the following polyfill at the entry point of your application before importing Matter.js:
// Polyfill global browser objects
if (typeof window === 'undefined') {
global.window = {};
global.document = {
createElement: () => ({
getContext: () => null
})
};
}
const Matter = require('matter-js');This mock satisfies initial object checks without importing heavyweight browser emulation libraries, allowing the core physics calculations to run smoothly in headless environments.