Skip to main content

events-system

Use this skill when working with the Phaser 4 event system. Covers EventEmitter, scene events, game events, custom events, and event-driven communication. Triggers on: events, on, emit, EventEmitter, scene events, listeners.

Source facts

Repository
phaserjs/phaser
Last source activity
April 10, 2026 at 12:38
Detected SKILL.md language
English
Stars
40,602
Forks
7,182

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
events-system
description
Use this skill when working with the Phaser 4 event system. Covers EventEmitter, scene events, game events, custom events, and event-driven communication. Triggers on: events, on, emit, EventEmitter, scene events, listeners.
# Events System > Phaser uses the EventEmitter pattern (via eventemitter3) throughout the entire framework. Every major system -- Game, Scene, Input, Loader, Cameras, Sound, Tweens, Physics, Textures, Animations -- is an EventEmitter or contains one. Events use lowercase string keys. Phaser provides named constants for all built-in events to avoid typos and enable IDE autocomplete. **Key source paths:** `src/events/EventEmitter.js`, `src/scene/events/`, `src/core/events/`, `src/input/events/`, `src/loader/events/`, `src/animations/events/`, `src/cameras/2d/events/`, `src/sound/events/`, `src/tweens/events/`, `src/physics/arcade/events/`, `src/textures/events/`, `src/gameobjects/events/`, `src/time/events/` **Related skills:** ../scenes/SKILL.md, ../input-keyboard-mouse-touch/SKILL.md ## Quick Start ```js // on — listen for an event (persists until removed) this.input.on('pointerdown', (pointer) => { console.log('clicked at', pointer.x, pointer.y); }); // once — listen for an event, auto-removes after first fire this.events.once('shutdown', () => { console.log('scene shutting down'); }); // off — remove a specific listener (must pass same function reference) const handler = (pointer) => { /* ... */ }; this.input.on('pointerdown', handler); this.input.off('pointerdown', handler); // emit — fire a custom event with arguments this.events.emit('player-died', this.player, this.score); // removeAllListeners — remove all listeners for an event (or all events) this.events.removeAllListeners('player-died'); this.events.removeAllListeners(); // all events ``` ### Using Named Constants (Preferred) ```js // Always prefer constants over raw strings to prevent typos this.events.on(Phaser.Scenes.Events.UPDATE, (time, delta) => { // runs every frame }); this.input.on(Phaser.Input.Events.POINTER_DOWN, (pointer) => { // pointer pressed }); this.game.events.on(Phaser.Core.Events.BLUR, () => { // browser tab lost focus }); ``` ## Core Concepts ### EventEmitter Base Class `Phaser.Events.EventEmitter` extends eventemitter3. It adds `shutdown()` and `destroy()` methods that both call `removeAllListeners()`. **Full API (inherited from eventemitter3):** | Method | Description | |---|---| | `on(event, fn, context?)` | Add persistent listener. Returns `this` for chaining | | `addListener(event, fn, context?)` | Alias for `on` | | `once(event, fn, context?)` | Add one-time listener; auto-removed after first fire | | `off(event, fn?, context?, once?)` | Remove listener(s). Must pass same `fn` reference to remove specific listener | | `removeListener(event, fn?, context?, once?)` | Alias for `off` | | `removeAllListeners(event?)` | Remove all listeners for event, or all events if no arg | | `emit(event, ...args)` | Fire event. Returns `true` if it had listeners | | `listeners(event)` | Return array of listener functions for an event | | `listenerCount(event)` | Return number of listeners for an event | | `eventNames()` | Return array of event names that have listeners | | `shutdown()` | Calls `removeAllListeners()` | | `destroy()` | Calls `removeAllListeners()` | ### Event Strings vs Constants Every built-in event is a lowercase string exported as a constant. The constant name maps predictably to the string: ```js Phaser.Scenes.Events.UPDATE // 'update' Phaser.Scenes.Events.PRE_UPDATE // 'preupdate' Phaser.Scenes.Events.SHUTDOWN // 'shutdown' Phaser.Core.Events.BOOT // 'boot' Phaser.Input.Events.POINTER_DOWN // 'pointerdown' ``` Some events use a key-suffix pattern for per-key listening: ```js // Loader: listen for a specific file completing this.load.on(Phaser.Loader.Events.FILE_KEY_COMPLETE + 'image-logo', (key, type, data) => {}); // String value: 'filecomplete-image-logo' // Animations: listen for a specific animation completing on a sprite sprite.on(Phaser.Animations.Events.ANIMATION_COMPLETE_KEY + 'walk', () => {}); // String value: 'animationcomplete-walk' // Textures: listen for a specific texture being added this.textures.on(Phaser.Textures.Events.ADD_KEY + 'myTexture', () => {}); // String value: 'addtexture-myTexture' ``` ### Context (Third Argument) The third argument to `on`/`once` sets `this` inside the callback. Defaults to the emitter. ```js // 'this' inside handler refers to the scene this.input.on('pointerdown', function (pointer) { this.cameras.main.shake(100); // 'this' = scene }, this); // Arrow functions ignore the context argument (they capture lexical 'this') this.input.on('pointerdown', (pointer) => { this.cameras.main.shake(100); // 'this' = enclosing scope (scene in create) }); ``` ## Common Patterns ### Scene Lifecycle Events Frame loop order: `preupdate` -> `update` -> `Scene.update()` -> `postupdate` -> `prerender` -> `render` ```js create() { this.events.on(Phaser.Scenes.Events.UPDATE, this.onUpdate, this); // CRITICAL: always clean up on shutdown to prevent leaks on scene restart this.events.on(Phaser.Scenes.Events.SHUTDOWN, () => { this.events.off(Phaser.Scenes.Events.UPDATE, this.onUpdate, this); this.input.off('pointerdown', this.onPointerDown, this); }); } ``` ### Game-Level Events ```js // game.events fires on the Game instance, shared across all scenes // Access from a scene via this.game.events this.game.events.on(Phaser.Core.Events.BLUR, this.handleBlur, this); this.game.events.on(Phaser.Core.Events.VISIBLE, this.handleVisible, this); ``` ### Inter-Scene Communication ```js // METHOD 1: game.events — a global event bus accessible from all scenes // Scene A emits: this.game.events.emit('score-changed', this.score); // Scene B listens: this.game.events.on('score-changed', (score) => { this.scoreText.setText(score); }); // METHOD 2: this.registry — a shared DataManager across all scenes // The registry is a Phaser.Data.DataManager on the Game instance. // Scene A sets data: this.registry.set('score', 100); // Scene B listens for changes: this.registry.events.on('changedata-score', (parent, value, previousValue) => { this.scoreText.setText(value); }); // METHOD 3: Direct scene access via ScenePlugin this.scene.get('UIScene').events.emit('update-health', hp); ``` ### Custom Events ```js // Emit custom events with arbitrary data arguments this.events.emit('player-died', this.player, { lives: this.lives }); this.events.on('player-died', (player, data) => { console.log('Lives remaining:', data.lives); }); ``` ## All Event Namespaces Reference ### Scene Events (`Phaser.Scenes.Events`) Emitter: `this.events` (the Scene's Systems EventEmitter) | Constant | String | When | |---|---|---| | `BOOT` | `'boot'` | Scene Systems boot (for plugins) | | `READY` | `'ready'` | Scene Systems fully ready | | `START` | `'start'` | Scene starts running | | `CREATE` | `'create'` | After Scene.create() completes | | `PRE_UPDATE` | `'preupdate'` | Before update each frame | | `UPDATE` | `'update'` | Main update each frame | | `POST_UPDATE` | `'postupdate'` | After update each frame | | `PRE_RENDER` | `'prerender'` | Before render each frame | | `RENDER` | `'render'` | During render each frame | | `PAUSE` | `'pause'` | Scene paused | | `RESUME` | `'resume'` | Scene resumed from pause | | `SLEEP` | `'sleep'` | Scene put to sleep | | `WAKE` | `'wake'` | Scene woken from sleep | | `SHUTDOWN` | `'shutdown'` | Scene shutting down (may restart) | | `DESTROY` | `'destroy'` | Scene permanently destroyed | | `ADDED_TO_SCENE` | `'addedtoscene'` | GameObject added to scene | | `REMOVED_FROM_SCENE` | `'removedfromscene'` | GameObject removed from scene | | `TRANSITION_INIT` | `'transitioninit'` | Transition initialized (target scene) | | `TRANSITION_START` | `'transitionstart'` | Transition started (target scene) | | `TRANSITION_OUT` | `'transitionout'` | Transition out (source scene) | | `TRANSITION_COMPLETE` | `'transitioncomplete'` | Transition finished | | `TRANSITION_WAKE` | `'transitionwake'` | Transition wakes target scene | ### Game Events (`Phaser.Core.Events`) Emitter: `this.game.events` or `game.events` | Constant | String | When | |---|---|---| | `BOOT` | `'boot'` | Game instance finished booting | | `READY` | `'ready'` | Game ready to start running | | `SYSTEM_READY` | `'systemready'` | All global systems ready | | `PRE_STEP` | `'prestep'` | Before game loop step | | `STEP` | `'step'` | Main game loop step | | `POST_STEP` | `'poststep'` | After game loop step | | `PRE_RENDER` | `'prerender'` | Before rendering all scenes | | `POST_RENDER` | `'postrender'` | After rendering all scenes | | `PAUSE` | `'pause'` | Game paused | | `RESUME` | `'resume'` | Game resumed | | `BLUR` | `'blur'` | Browser tab lost focus | | `FOCUS` | `'focus'` | Browser tab gained focus | | `HIDDEN` | `'hidden'` | Page Visibility API: hidden | | `VISIBLE` | `'visible'` | Page Visibility API: visible | | `CONTEXT_LOST` | `'contextlost'` | WebGL context lost | | `DESTROY` | `'destroy'` | Game being destroyed | ### Input Events (`Phaser.Input.Events`) Emitter: `this.input` (scene-level) or individual GameObjects. Events exist at three levels: scene-level (`this.input`), scene-level with gameobject prefix, and directly on interactive GameObjects. See ../input-keyboard-mouse-touch/SKILL.md for full usage. **Scene-level pointer events (on `this.input`):** `POINTER_DOWN` `'pointerdown'` | `POINTER_UP` `'pointerup'` | `POINTER_MOVE` `'pointermove'` | `POINTER_OVER` `'pointerover'` | `POINTER_OUT` `'pointerout'` | `POINTER_WHEEL` `'wheel'` | `POINTER_DOWN_OUTSIDE` `'pointerdownoutside'` | `POINTER_UP_OUTSIDE` `'pointerupoutside'` **Scene-level gameobject events (on `this.input`):** `GAMEOBJECT_DOWN` `'gameobjectdown'` | `GAMEOBJECT_UP` `'gameobjectup'` | `GAMEOBJECT_MOVE` `'gameobjectmove'` | `GAMEOBJECT_OVER` `'gameobjectover'` | `GAMEOBJECT_OUT` `'gameobjectout'` | `GAMEOBJECT_WHEEL` `'gameobjectwheel'` **Per-GameObject events (emitted on the GameObject itself, requires `setInteractive()`):** `GAMEOBJECT_POINTER_DOWN` `'pointerdown'` | `GAMEOBJECT_POINTER_UP` `'pointerup'` | `GAMEOBJECT_POINTER_MOVE` `'pointermove'` | `GAMEOBJECT_POINTER_OVER` `'pointerover'` | `GAMEOBJECT_POINTER_OUT` `'pointerout'` | `GAMEOBJECT_POINTER_WHEEL` `'wheel'` **Drag events (on `this.input` and on GameObjects with same string):**
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub