eventEmitter is a typed event bus that bridges JavaScript scope (game logic, bookEvent handlers) and Svelte component scope (rendering, animation). Instead of threading reactive state through component props, handlers in bookEventHandlerMap broadcast events that any mounted Svelte component can subscribe to.
Why an Event Emitter?
In the Web SDK, game logic lives outside the Svelte component tree — inbookEventHandlerMap, stateGame, and similar plain TypeScript files. Svelte components handle display and animation. The eventEmitter is the channel between them.
This separation means:
- Multiple components can react to the same bookEvent independently
- Components do not need to know about game logic; they only handle their own emitterEvents
- Each emitterEventHandler can be kept small and testable (Single Responsibility Principle)
The Three Core Methods
All three methods are defined inpackages/utils-event-emitter/src/createEventEmitter.ts:
broadcastAsync uses Promise.all, meaning all subscribers are started concurrently but the caller waits for all of them to resolve before continuing. This is intentional — multiple components may need to finish their animations before the next bookEvent begins.When to use broadcast vs broadcastAsync
Defining EmitterEvent Types
EmitterEvents are plain discriminated union types. Each variant has atype string and any additional data it needs. Define them in the <script lang="ts" module> block of the component that owns them:
typesEmitterEvent.ts:
eventEmitter.ts composes the game-level type with shared UI types and creates the singleton:
Subscribing in a Component
CallsubscribeOnMount inside the component’s <script> block. It registers the handler map when the component mounts and automatically removes subscriptions when the component is destroyed:
Broadcasting from a BookEvent Handler
FreeSpinIntro.svelte:
Task Breakdown Pattern
For complex bookEvents, split the work into multiple fine-grained emitterEvents rather than one large handler. This keeps each handler small, and makes individual steps independently testable in Storybook (COMPONENTS/<Component>/emitterEvent).
EmitterEvents from a single bookEvent can be handled by different Svelte components. For example,
tumbleBoardExplode might be handled by TumbleBoard.svelte while boardSettle is handled by Board.svelte. This is the primary way the SDK achieves decoupled, composable game logic.