Skills

Melonjs Events

Use this skill for the melonJS event bus and lifecycle hooks, subscribing to engine...

Install

npx skills add melonjs/melonJS --skill melonjs-events -g -a claude-code -y
Repository
melonjs/melonJS6.4k
Category
Engineering
Updated
3d ago
License
MIT
Context cost
Mediumabout 1,652 tokens
Runs scripts
No, instructions only

What it does

Use this skill for the melonJS event bus and lifecycle hooks, subscribing to engine events, the per-frame and per-state event names, renderable lifecycle callbacks, and how to unsubscribe without leaking. Triggers on: event.on, event.off, event.once, event.emit, GAME_UPDATE, GAME_BEFORE_DRAW, LEVEL_LOADED, LOADER_COMPLETE, STATE_CHANGE, CANVAS_ONRESIZE, POINTERMOVE, WORLD_STEP, onActivateEvent, onDeactivateEvent, onDestroyEvent, lifecycle, subscribe, listener.

Events and lifecycle

The bus

import { event } from "melonjs";

const onUpdate = () => { /* … */ };
const unsubscribe = event.on(event.GAME_UPDATE, onUpdate);  // on() returns its own off()
event.once(event.LEVEL_LOADED, () => { /* … */ });

// two ways to undo it, the same reference, or the returned function
event.off(event.GAME_UPDATE, onUpdate);
unsubscribe();

event.on/once/off/has all take an optional third context argument, invoked as the handler's this. off matches on the pair, handler identity AND context identity. on(EVT, fn, this) followed by off(EVT, fn) removes nothing, silently.

Store the handler reference, or use the context argument. An inline arrow or a fresh .bind(this) in the on call can never be removed, that is the standard way to leak listeners in melonJS.

// ✗ unremovable
event.on(event.GAME_UPDATE, this.tick.bind(this));

// ✓ keep the bound reference
this._tick = this.tick.bind(this);
event.on(event.GAME_UPDATE, this._tick);
// later: event.off(event.GAME_UPDATE, this._tick);

// ✓ or skip the bind entirely, the context is part of the identity
event.on(event.GAME_UPDATE, this.tick, this);
// later: event.off(event.GAME_UPDATE, this.tick, this);

Custom event names work at runtime (event.emit("my.custom.event", payload)), but on/emit are typed against a closed map of the engine's own events, so in TypeScript a name outside that map is a compile error. Use your own emitter for game events in a .ts project.

The events worth knowing

Per frame

eventwhen
GAME_BEFORE_UPDATE / GAME_UPDATE / GAME_AFTER_UPDATEaround the world update, GAME_UPDATE is not emitted while paused
GAME_BEFORE_DRAW / GAME_AFTER_DRAWaround the draw pass
WORLD_STEPafter the physics step
TICKthe raw engine tick

Lifecycle

Read the whole SKILL.md on GitHub

More in Engineering