pixi-reels
Docs · Architecture
Flow

Events

What fires when, and in what order.

Every event pixi-reels emits is typed. The headline stream comes offreelSet.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

EventPayloadFires when
spin:start(none)Any spin() call
spin:allStarted(none)Every reel is in SPIN phase
spin:stoppingreelIndexA reel begins STOP (or ANTICIPATION)
spin:reelLandedreelIndex, symbols[]A reel finished landing
spin:allLandedresult: SpinResultLast reel landed
spin:completeresult: SpinResultJust after spin:allLanded
skip:requested{ reels, partial }A slam is about to place reels
skip:completed{ reels, partial }Those reels have been force-landed
speed:changedprofile, previoussetSpeed() called
spotlight:startpositions: 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, ... });
});