PR pixi-reels
All recipes

Spotlight after a nudge

Land a near-miss, nudge three reels down by one to complete a wild line across the top row, then run SymbolSpotlight on the new winners. Chains nudge() and spotlight.show() in their canonical order.

Loading recipe…

Land a near-miss, nudge to complete a line, then run a win presenter on the new cells. This recipe chains three primitives in order:

  1. Spin lands on a flat near-miss (no wilds anywhere).
  2. Parallel nudge of reels 1, 2, 3 each shifts down by one and drops a wild at the new top row.
  3. Spotlight on those three new cells dims the rest of the board and runs each symbol’s playWin() animation.

The orchestration

// 1. Land the near-miss.
const p = reelSet.spin();
await new Promise((r) => setTimeout(r, 220));
reelSet.setResult(nearMissGrid);
await p;

// 2. Parallel nudge. all three tweens kick off the same frame.
await Promise.all(
  [1, 2, 3].map((col) =>
    reelSet.nudge(col, {
      distance: 1,
      direction: 'down',
      incoming: ['wild'],
      duration: 380,
    }),
  ),
);

// 3. Spotlight the new winning cells.
const winners = [1, 2, 3].map((col) => ({ reelIndex: col, row: 0 }));
await reelSet.spotlight.show(winners, { dimAmount: 0.6 });
reelSet.spotlight.hide();

Sequencing trade-offs

Parallel nudges. one spotlight. All three tweens start on the same frame; the row of wilds drops together, then a single spotlight.show covers all three new cells.

Sequential nudges. sequential spotlights. Each reel reveals, then its own spotlight.show runs, then spotlight.hide before the next reel’s nudge begins. Total wall time scales with cols.length.

// Sequential variant: nudge, spotlight, nudge, spotlight, ...
for (const col of [1, 2, 3]) {
  await reelSet.nudge(col, { distance: 1, direction: 'down', incoming: ['wild'] });
  await reelSet.spotlight.show([{ reelIndex: col, row: 0 }], { dimAmount: 0.5 });
  reelSet.spotlight.hide();
}

Re-detecting the win

The nudge’s resolved promise carries the new visible column. you can feed that straight into your win-detection logic instead of re-querying the grid:

const results = await Promise.all(
  [1, 2, 3].map((col) =>
    reelSet.nudge(col, { distance: 1, direction: 'down', incoming: ['wild'] }),
  ),
);
// results[i].symbols is reel `i`'s new visible column.

const newGrid = reelSet.getVisibleGrid();
const wins = detectWins(newGrid);
await reelSet.spotlight.show(wins.flatMap((w) => w.cells));
reelSet.spotlight.hide();

Aborting the celebration

If the player taps SPIN during the spotlight, abort it cleanly with the spotlight’s own hide() (synchronous):

const spotlightP = reelSet.spotlight.show(winners);
spinButton.addEventListener('click', () => reelSet.spotlight.hide(), { once: true });
await spotlightP;

For the nudge itself, pass an AbortSignal:

const controller = new AbortController();
skipButton.onclick = () => controller.abort();
await reelSet.nudge(2, { ...opts, signal: controller.signal })
  .catch((e) => { if (e.name !== 'AbortError') throw e; });

Aborts and skips land the strip deterministically. your spotlight cells are still in the right places regardless of how the tween ended.