EngineEventBus
Strongly typed pub/sub bus: the sole communication channel between the engine and the outside world. Accessible via engine.events.
import { EngineEventBus } from 'catalyst-engine';Conceptual guide: Event Bus.
Events and payloads
The EngineEvents type defines the three events and their payloads:
type EngineEvents = {
STAT_CHANGED: { statId: string; newValue: number; baseValue: number };
LEVEL_UP: { currentLevel: number; levelsGained: number; excessXP: number };
XP_GAINED: { currentXP: number; nextRequiredXP: number; percentage: number };
};The methods are generic over K extends keyof EngineEvents: the payload type is inferred from the event name, so a callback with the wrong signature is a compile-time error.
Methods
on()
on<K extends keyof EngineEvents>(
event: K,
callback: EventCallback<EngineEvents[K]>
): voidRegisters a callback for the event. Multiple callbacks on the same event are invoked in registration order.
engine.events.on('XP_GAINED', ({ percentage }) => updateBar(percentage));off()
off<K extends keyof EngineEvents>(
event: K,
callback: EventCallback<EngineEvents[K]>
): voidRemoves a registered callback. The comparison is by reference identity: pass the same function used in on().
const cb = ({ currentLevel }) => {};
engine.events.on('LEVEL_UP', cb);
engine.events.off('LEVEL_UP', cb); // ✅ removedWARNING
An inline anonymous callback can never be removed, because each use is a different reference.
emit()
emit<K extends keyof EngineEvents>(
event: K,
data: EngineEvents[K]
): voidInvokes all callbacks registered for the event, passing the payload. Normally it is the engine that calls it; use it directly only if you extend the engine.
engine.events.emit('STAT_CHANGED', { statId: 'mana', newValue: 50, baseValue: 40 });Helper type
type EventCallback<T> = (data: T) => void;