phaserjs/phaser · error · Error
Matter.Runner: missing required global window.requestAnimati
Error message
Matter.Runner: missing required global window.requestAnimationFrame.
What it means
Runner.js:200 throws from `_onNextFrame` when `typeof window === 'undefined'` or `window.requestAnimationFrame` is missing. Matter's Runner schedules each physics tick via rAF; without it the loop cannot advance. This is Matter.js's hard dependency on a browser-like global.
Source
Thrown at src/physics/matter-js/lib/core/Runner.js:200
* If you wish to only temporarily pause the engine, see `engine.enabled` instead.
* @method stop
* @param {runner} runner
*/
Runner.stop = function(runner) {
Runner._cancelNextFrame(runner);
};
/**
* Alias for `Runner.run`.
* @method start
* @param {runner} runner
* @param {engine} engine
*/
Runner._onNextFrame = function(runner, callback) {
if (typeof window !== 'undefined' && window.requestAnimationFrame) {
runner.frameRequestId = window.requestAnimationFrame(callback);
} else {
throw new Error('Matter.Runner: missing required global window.requestAnimationFrame.');
}
return runner.frameRequestId;
};
Runner._cancelNextFrame = function(runner) {
if (typeof window !== 'undefined' && window.cancelAnimationFrame) {
window.cancelAnimationFrame(runner.frameRequestId);
} else {
throw new Error('Matter.Runner: missing required global window.cancelAnimationFrame.');
}
};
var _mean = function(values) {
var result = 0,
valuesLength = values.length;
for (var i = 0; i < valuesLength; i += 1) {
result += values[i];
}
return (result / valuesLength) || 0;View on GitHub (pinned to 41be1e462b)
Solutions
- Run physics only in a browser context; for Node use a manual `Runner.tick(engine, delta)` loop or `Engine.update(engine, delta)` instead of `Runner.run`.
- Polyfill `globalThis.requestAnimationFrame` (e.g. via a timer-based shim) before starting the Runner.
- Use Phaser's HEADLESS mode for server stepping and avoid the Matter Runner's rAF scheduling.
Example fix
// before Matter.Runner.create(engine) // then Runner.run under Node -> throws // after (Node) setInterval(() => Matter.Engine.update(engine, 1000 / 60), 1000 / 60)
Defensive patterns
Strategy: validation
Validate before calling
const hasRAF = typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function'
if (!hasRAF) {
// Node/SSR: step manually instead of Runner.run
setInterval(() => Matter.Engine.update(engine, 1000 / 60), 1000 / 60)
} else {
Matter.Runner.run(runner, engine)
} Type guard
const supportsRAF = () => typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function'
Prevention
- Don't use Matter.Runner.run under Node; drive Engine.update manually.
- Polyfill requestAnimationFrame if you must run the Runner in a worker/SSR.
- Isolate physics stepping code from browser-only globals.
When it happens
Trigger: Running `Matter.Runner.run(runner, engine)` (or the Phaser Matter Physics system that uses it) in Node.js, a Web Worker without rAF polyfill, jsdom, or an SSR context where `window.requestAnimationFrame` is undefined.
Common situations: Server-side simulation/SSR that imports Phaser's Matter physics; unit tests in Node; rendering on the server with intent to step physics manually; bundlers that tree-shake the DOM globals.
Related errors
- Matter.Runner: missing required global window.cancelAnimatio
- Cannot create WebGL context, aborting.
- Cannot create Canvas context, aborting.
- WebGL unsupported
AI-assisted analysis of phaserjs/phaser@41be1e462b (2026-08-13).
Data as JSON: /api/errors/6058b28ed517efd6.
Report an issue: GitHub.