PR pixi-reels
All recipes

Nudge a big symbol in, then hold it across a respin

A tall wild lands with its anchor in bufferAbove (tail visible at row 0). Nudge the trigger reel to drag the full block into view, then call spin with holdReels so the now-revealed wild survives a respin of the other reels.

Loading recipe…

A tall wild lands with most of its body hidden above the visible window. only the tail (the bottom cell) shows at row 0. The player nudges to drag the whole wild into view, then gets a respin of the OTHER reels with the wild reel held. the revealed block stays put. This recipe wires the full sequence.

Why this works end-to-end

Three pieces have to cooperate, and they do. the audit case for the buffer-row anchor feature:

  1. setResult accepts an anchor in bufferAbove. Pass the anchor id at bufferAbove[i] (or frame[col][-i-1] via legacy negative indexing) and _coordinateBigSymbols paints OCCUPIED across the rest of the block. even when stubs fall in visible rows. The validation rule is the full strip (anchorRow + h <= visibleRows + bufferBelow), not just visible.

  2. nudge() slides the block as a unit from buffer-anchored to fully visible. The survival check (anchor + h - 1 + distance < total) applies; for a 1×3 wild at strip[0] and a distance=2 down nudge, 0 + 3 - 1 + 2 = 4 < 7 (where total is bufferAbove(2) + visibleRows(3) + bufferBelow(2)). The wrap pipeline never splits the anchor from its stubs. Post-nudge the anchor sits at strip[2] = visible[0]; the block fills all three visible rows.

  3. spin({ holdReels: [...] }) skips the held reels entirely. START / SPIN / STOP never fire on the held column. The strip array, the resized anchor sprite, and the _occupancy map all carry through unchanged. The block sits exactly where the nudge left it. no jitter, no re-land.

What the recipe runs

// 1. Land the tail-visible wild.
const initialGrid = [
  ct(), ct(),
  // Anchor at bufferAbove[1] = row -2. Block spans rows -2, -1, 0.
  { visible: [filler(), filler(), filler()], bufferAbove: [undefined, 'tall'] },
  ct(), ct(),
];
const spin1 = reelSet.spin();
reelSet.setResult(initialGrid);
await spin1;

// 2. Nudge the held reel down by 2. block slides into full view.
await reelSet.nudge(2, {
  distance: 2,
  direction: 'down',
  incoming: [filler(), filler()],
});

// 3. Respin reels 0, 1, 3, 4. reel 2 held, revealed block preserved.
const spin2 = reelSet.spin({ holdReels: [2] });
reelSet.setResult([
  ct(), ct(),
  ct(), // ignored. reel 2 is held
  ct(), ct(),
]);
await spin2;

Required configuration

  • bufferSymbols(n) where n >= the largest off-screen extension. For a 1×3 wild with its tail at row 0, the anchor sits at row -2. needs bufferAbove >= 2. The builder sets both buffers to the same value, so bufferSymbols(2) works.

  • The big-symbol id needs weight: 0. Random fill can’t place blocks; non-zero weight throws at build.

  • Bounce should be 0 for big symbols. bounceDistance: 0, bounceDuration: 0 in the speed profile. the default landing bounce doesn’t account for stubs and produces a visual jitter on big anchors.

What still throws

  • Cross-reel (w > 1) blocks held across a respin work, but you can’t nudge them. nudging shifts only the one held reel, and the block’s right-side cells live on other reels.

  • Mixing string[] and ColumnTarget columns inside one setResult call. toLegacyTargetGrid rejects mixed shapes. pick one form for the whole grid. The recipe uses ColumnTarget everywhere, including the held reel’s placeholder, because the wild reel needs the bufferAbove field.

  • An anchor in bufferAbove whose h pushes the block past bufferBelow. _coordinateBigSymbols validates against the full strip; an over-tall anchor throws with extends past the bottom of the strip.