PR pixi-reels
All recipes

MultiWays cascade

Per-spin row variation on a strip-spin landing; the cascade tumble pops winners and drops new symbols in from above. Shape-aware on every reel.

Loading recipe…

A slot that varies its shape per spin AND uses cascade-style tumbling on winners. the cascade-Megaways pattern that BTG’s Bonanza and Extra Chilli popularized. The initial landing is a classic strip-spin (so the multiways AdjustPhase reshapes the reels between SPIN and STOP); winners then pop, survivors fall, and new symbols drop in from above via reelSet.runCascade(...). The reels never re-spin between tumbles.

A ways win is the multiways win pattern: a symbol that lands on N consecutive reels starting from reel 0 wins, and every instance of that symbol on those reels is part of the win. not just one cell per column the way a payline game would resolve it. This recipe pops them all in one cascade. If the resulting fill creates another ways win, the chain continues (capped at 4 cascades per round for demo legibility).

import { ReelSetBuilder, SpriteSymbol } from 'pixi-reels';

const reelSet = new ReelSetBuilder()
  .reels(6)
  .multiways({ minRows: 2, maxRows: 5, reelPixelHeight: 360 })
  .symbolSize(72, 72)
  .symbols((r) => { /* register your symbols */ })
  // tumble() registers cascade:place + cascade:dropIn so refill() can run.
  // We don't use cascade:fall here. the initial drop is a strip-spin.
  .tumble({
    fall:   { duration: 0, ease: 'none', rowStagger: 0 },
    dropIn: { duration: 280, ease: 'back.out(1.4)', rowStagger: 0, distance: 'perHole' },
  })
  .ticker(app.ticker)
  .build();

document.getElementById('spin')!.addEventListener('click', async () => {
  const shape = rollShape();             // your random or server-driven shape
  const grid  = buildGrid(shape);        // grid lengths must match `shape`

  // Round 1. strip-spin lands the multiways grid (override the builder's
  // cascade default so AdjustPhase runs between SPIN and STOP).
  const p = reelSet.spin({ mode: 'standard' });
  reelSet.setShape(shape);
  reelSet.setResult(grid);
  await p;

  // Cascade chain: detect ways wins → destroy → refill → re-detect.
  // `runCascade` re-evaluates wins after every refill; when none are
  // found, the chain ends and the awaited promise resolves.
  reelSet.setDropOrder('all');
  await reelSet.runCascade({
    detectWinners: (g) => collectAllWaysWinners(g),
    nextGrid:      (prev, winners) => applyCascade(prev, [...winners]),
    maxChain:      4,
  });
});

Why this works on a multiways slot

reelSet.refill({ winners, grid }) reads each reel’s visibleRows at call time. A reel that landed at 2 rows and a reel that landed at 5 rows refill independently in the same chain. the engine builds per-reel fall jobs against each reel’s live geometry, so jagged multiways shapes aren’t a special case.

A ways win that hits three cells on a single 5-row reel pops all three; the three cleared rows refill from above with new symbols entering staggered, regardless of where the winners were in the column. Your nextGrid callback supplies the post-gravity column; the engine handles the geometry.

The initial strip-spin is the multiways primary motion: AdjustPhase runs between SpinPhase and StopPhase, commits the new shape, and StopPhase lands the reel at its new row count. By the time runCascade runs, every reel is already at its post-reshape geometry.

Two ways to combine cascade with multiways

This recipe uses the post-landing tumble approach (runCascade on a strip-spun landing). The library also supports the cascade-mode spin approach: build with .multiways(...).tumble({...}) and call spin({ mode: 'cascade' }) for a full top-down drop-in landing on a multiways shape. The cascade-mode path runs cascade:fall → Spin → Adjust → cascade:place → cascade:dropIn per reel. see ADR 015 for the design rationale and the per-chain shape rule.

Pick the post-landing pattern when you want a classic spin feel with cascade tumbles on winners (this recipe). Pick the cascade-mode pattern when every round should drop in from above with no strip motion at all.

What you can’t combine

  • Big symbols + multiways still throws at build time. anchor coordinates don’t have stable semantics under reshape.
  • Shape change mid-cascade-chain is not supported. runCascade operates on the live grid for the chain it’s animating; reshape between cascade respins must start a fresh spin().