pixi-reels
Building blocks

MultiWays

Each reel lands on a different cell count. Every spin.

The reel’s LENGTH is fixed. The cell size is derived: reelExtent / visibleCells[i]. So a 2-cell reel has big cells, a 7-cell reel has small ones.

The whole mechanic#

const reelSet = new ReelSetBuilder()
  .reels(6)
  .multiways({ minCells: 2, maxCells: 7, reelExtent: 480 })
  .pinMigrationDuration(300)         // ms for the pin-overlay tween. 0 = snap
  .pinMigrationEase('power2.inOut')  // any GSAP ease
  .symbolSize(68, 68)                // the SPIN-time cell size
  .build();

const promise = reelSet.spin();
reelSet.setShape([3, 5, 7, 4, 6, 2]);  // BEFORE setResult
reelSet.setResult(serverGrid);          // serverGrid[i].visible.length === shape[i]
await promise;

Order matters#

  1. spin() — reels scroll at the previous shape’s cell size.
  2. setShape(cellsPerReel) — records the target, emits shape:changed, then migrates pins (pin:migrated). Before setResult. After it, the engine throws: frames are already cached by then.
  3. setResult(grid)grid[i].visible.length must equal shape[i].
  4. Reshape, between SPIN and STOP. Per reel: adjust:start, commit the geometry, refresh pin overlays, adjust:complete.
  5. StopPhase lands at the new shape.

Pin migration#

A pin remembers where it started (originCell). Every reshape moves it according to its policy, and fires pin:migrated with { fromCell, toCell, clamped, reelIndex }.

'origin' — the default. Clamp, then restore.#

A pin squeezed down by a shrink climbs back when the reel grows again. This is what a sticky wild should do.

SpinCells on reel 2originCellLands atClamped?
1544no
2342yes
3744restored
4443yes

'frozen' — clamp, and stay.#

No restoring. Each clamp rewrites originCell, so the pin never climbs back. Right for walking wilds, or anything where where-it-is-now is the truth and the old position is history.

SpinCells on reel 2originCell beforeLands atoriginCell after
15444
2342 (clamped)2
37222
44222
reelSet.pin(reel, cell, id, { migration: 'frozen' });

What animates, and what does not#

pinMigrationDuration and pinMigrationEase move pin overlays only.

The cells underneath snap. They have to: the reel is still spinning at full speed during the reshape, and tweening a cell would fight the motion layer for the same coordinate.

No pins on a reel? No tween is built. adjust:start and adjust:complete still fire around the reshape, because they come from the reshape step, not the tween. Nothing changed at all? Nothing fires.

skipSpin() bypasses the tween. Slam means now.

Events only MultiWays fires#

  • shape:changedsetShape() accepted a target
  • adjust:start / adjust:complete — per reel, around the reshape
  • pin:migrated — a pin moved because the shape changed

Limits#

  • No big symbols. A 2x2 cannot fit a reel that reshaped to 2 cells. Throws at build().
  • No pyramid. visibleCellsPerReel() and multiways() both claim the cell count. Throws at build().
  • reelExtent is fixed. Change it, rebuild.

Cascades DO work with MultiWays (ADR 015). See multiways-cascade.

See also#