PR pixi-reels
Docs · Architecture
Flow

Events

What fires when, and in what order.

Every event pixi-reels emits is typed. The headline stream comes off reelSet.events. Each Reel also has its own per-reel stream. useful when you want to drive behavior on one column without the whole set.

The spin timeline

A typical spin unfolds in this exact order. The timeline below has the reel-set-level events on the top track and per-reel events on the bottom. Read left-to-right as wall-clock time.

sequenceDiagram
  participant Caller
  participant ReelSet
  participant Reel as Reel (per-reel)

  Note over Caller,Reel: START phase
  Caller->>ReelSet: spin()
  ReelSet-->>Caller: spin:start
  ReelSet->>Reel: phase:enter "start"

  Note over Caller,Reel: SPIN phase
  Reel-->>Caller: phase:exit "start"
  Reel-->>Caller: phase:enter "spin"
  ReelSet-->>Caller: spin:allStarted
  Reel-->>Caller: symbol:created (many)
  Caller->>ReelSet: setResult(symbols[][])
  Caller->>ReelSet: setAnticipation([3,4])

  Note over Caller,Reel: ANTICIPATION phase (optional)
  Reel-->>Caller: phase:exit "spin"
  Reel-->>Caller: phase:enter "anticipation"

  Note over Caller,Reel: STOP phase
  ReelSet-->>Caller: spin:stopping (per reel)
  Reel-->>Caller: phase:enter "stop"

  Note over Caller,Reel: LANDED
  Reel-->>Caller: phase:exit "stop"
  Reel-->>Caller: landed (symbols[])
  ReelSet-->>Caller: spin:reelLanded (per reel)
  ReelSet-->>Caller: spin:allLanded
  ReelSet-->>Caller: spin:complete
  
ReelSet events · reelSet.events.on(...)
Per-reel events · reelSet.getReel(i).events.on(...)
Caller actions · setResult, setAnticipation, skipSpin

The full event map

Event Payload Fires when
spin:start (none) Any spin() call
spin:allStarted (none) Every reel is in SPIN phase
spin:stopping reelIndex A reel begins STOP (or ANTICIPATION)
spin:reelLanded reelIndex, symbols[] A reel finished landing
spin:allLanded result: SpinResult Last reel landed
spin:complete result: SpinResult Just after spin:allLanded
skip:requested (none) skipSpin() called
skip:completed (none) All reels force-landed
speed:changed profile, previous setSpeed() called
spotlight:start positions: SymbolPosition[] spotlight.cycle(...) began
spotlight:end (none) Spotlight sequence finished
destroyed (none) destroy() called

Two interaction patterns

Wiring these events together gets you every major slot UX without custom state tracking:

Pattern: Skip button

Use isSpinning to branch the same button between "start" and "slam-stop."

button.addEventListener('click', () => {
  if (reelSet.isSpinning) reelSet.skipSpin();
  else               reelSet.spin();
});
Pattern: Fetch + stop

Real slots fetch the server answer while the reels are spinning, then call setResult() to trigger the stop.

const p = reelSet.spin();
const r = await fetch('/spin').then(x => x.json());
reelSet.setAnticipation(r.anticipationReels);
reelSet.setResult(r.symbols);
await p;

Listening on a single reel

Each Reel has its own typed emitter. Useful when only one column's state matters. e.g. a sticky wild tracker that needs to know exactly when reel 2 landed:

reelSet.getReel(2).events.on('landed', (symbols) => {
  if (symbols.includes('wild')) stickyWilds.push({ reel: 2, ... });
});