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.
- Skill ID
- phaserjs/phaser/events-system
- Publisher
- phaserjs
- Repository
- phaser
- Installs
- 0
- Files
- 1
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
phaserjs/phaser/events-systemInstalls these files- SKILL.md
What this skill tells the agent
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
// 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 eventsUsing Named Constants (Preferred)
// 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:
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:
// 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.
// '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
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
// 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
// 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
// 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 |
More from phaserjs
Use this skill in a project
Open any RiverX project, search the Skills panel for phaserjs/phaser/events-system, and install it in one click.
