PR pixi-reels
All recipes

Spin first, cascade after

Open every play with a classic strip-spin. The landing's winning cells pop, survivors fall down, new symbols drop in from above. repeat for every cascade in the chain.

Loading recipe…

A common request: “the first round of the play should feel like a normal slot, but if there’s a hit, the winners should pop and new symbols should drop in from above. like a tumble.” That’s exactly what the demo above does:

  1. Round 1. a regular strip-spin lands the grid. The left three columns are deliberately stacked: J on top, 10 in the middle, random on the bottom.
  2. First cascade pop. the three 10s on the middle row vanish. The Js above each fall down to fill the gap; brand-new symbols drop in at the top. The middle row now reads J J J _ _. a second cluster.
  3. Second cascade pop. those three Js vanish, survivors fall, new symbols drop in. No more wins, the play ends.

The reels never re-spin between cascades. The landed grid stays landed; only the cells involved in each pop move. The right two columns (4 and 5) are untouched throughout the cascade chain. they landed during the strip-spin and stay frozen.

How it works

The cascade animation is a separate concern from the spin. Once the strip-spin lands, reelSet.runCascade({ detectWinners, nextGrid }) owns the entire detect → destroy → pause → refill loop:

// Round 1. classic strip-spin lands stage 0.
const p = reelSet.spin({ mode: 'standard' });
reelSet.setResult(stage0);
await p;

// Cascade chain. runCascade owns the orchestration; we supply the
// game rules via the two callbacks.
reelSet.setDropOrder('all');
await reelSet.runCascade({
  detectWinners: (grid) => /* cells whose symbol id is the current trigger */,
  nextGrid:      (prev, winners) => /* post-gravity grid */,
  pauseAfterDestroyMs: 160,
});

runCascade does NOT call reelSet.spin(). It works on the symbols already on screen, calling reelSet.destroySymbols(...) and reelSet.refill(...) for each chain stage. that’s why the reels appear to stay still while the symbols rearrange themselves.

When to use this vs spin({ mode: 'cascade' })

Both build on the same .tumble({ fall, dropIn }) config, but they solve different framings:

Spin-then-cascade (this recipe)Pure cascade (spin({ mode: 'cascade' }))
Round opens withClassic strip-spin, top-to-bottom motionDrop-in from above. no strip motion
Win pop animationreelSet.destroySymbols(winners) per cascadeSame
RefillreelSet.refill({ winners, grid }) per cascadeSame
Chain orchestratorreelSet.runCascade(...)reelSet.runCascade(...)
Builder requirement.tumble({...}) so refill phases exist.tumble({...}) so the initial drop and refill share the pipeline
Use case”Win on the spin, watch winners pop” feel”Every round is a top-down drop”. Sweet Bonanza / Gates of Olympus style

This recipe builds with .tumble({...}) so refill() works, then uses spin({ mode: 'standard' }) so the first spin uses the classic strip-spin landing. For a pure cascade slot. every round is a drop. see Cascade 6×5 tumble.