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.
What this skill does
# 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 ERelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.