Events
EventBus is a typed wrapper over eventemitter3. It carries game-wide messages between the engine, renderers, and UI, so nothing has to poll for changes.
import { EventBus, type BaseEventsMap } from "quantum-forge-engine/events";Typing your events
Extend BaseEventsMap with your own event names and payloads. The map keys become the event names and the values become the payload types, so on() and emit() are checked against each other.
interface MyGameEvents extends BaseEventsMap {
"level-complete": { score: number };
"player-hit": { damage: number };
}
const eventBus = new EventBus<MyGameEvents>();BaseEventsMap ships these events:
| Event | Payload |
|---|---|
"game-start" | { mode?: string } |
"game-over" | { mode?: string } |
"game-pause" | {} |
"game-resume" | {} |
"state-changed" | { state: any } |
API
| Method | Returns | Description |
|---|---|---|
on(event, handler) | () => void | Subscribe. Returns an unsubscribe function |
once(event, handler) | () => void | Subscribe for one emission |
off(event, handler) | void | Remove a specific handler |
emit(event, payload) | boolean | Emit. false when nobody is listening |
removeAllListeners(event?) | void | Drop handlers for one event, or all of them |
The constructor takes no arguments.
With the engine
Engine accepts an eventBus in its config. Every setState() then emits "state-changed" with the new state, which is how renderers and HUD code learn about updates.
const eventBus = new EventBus<MyGameEvents>();
const engine = new MyEngine({ logger, eventBus });
const unsubscribe = eventBus.on("state-changed", ({ state }) => {
hud.update(state);
});
eventBus.on("level-complete", ({ score }) => {
eventBus.emit("game-over", { mode: "campaign" });
});
// On teardown
unsubscribe();
eventBus.removeAllListeners();Keep the unsubscribe functions that on() returns and call them when a scene or screen goes away. Handlers left attached to a dead renderer keep firing.