Loading recipe…
Press Run a few times. every coin that lands stays put on the next respin.
The full Hold & Win loop. Combines setResult() with a game-side held map to keep coins sticky across respins. The library doesn’t own the mechanic. it gives you deterministic landings and event hooks; the respin accounting is yours.
import { ReelSetBuilder, SpriteSymbol } from 'pixi-reels';
const held = new Map<string, string>(); // "r,row" -> symbolId
async function holdAndWinRound() {
const maxRespins = 3;
let respinsLeft = maxRespins;
while (respinsLeft > 0) {
const promise = reelSet.spin();
// Produce a grid that keeps held coins in place, lands 0..N new coins
const grid = buildGridKeepingHeld(held);
reelSet.setResult(grid);
const result = await promise;
const newCoins = findNewCoins(result.symbols, held);
if (newCoins.length > 0) {
respinsLeft = maxRespins; // reset on every new coin
for (const c of newCoins) held.set(`${c.r},${c.row}`, c.symbolId);
} else {
respinsLeft--;
}
const totalCells = reelSet.reels.length * reelSet.reels[0].getVisibleSymbols().length;
if (held.size === totalCells) {
console.log('GRAND JACKPOT');
break;
}
}
}
The three moving parts
buildGridKeepingHeld(held). every held position MUST appear with its locked symbolId; the rest are random / from your weighted generator.findNewCoins(grid, held). any coin on the grid that isn’t already inheldis a new land.- Respin counter. resets to
maxRespinson every new land, decrements on every dry spin. When it hits zero, the round ends.
Full playable demo
For the playable version with a cheat panel (force landing, guaranteed jackpot, reset), see the hold-and-win-respin demo.
Simpler variant: spin({ holdReels }) on a single ReelSet
The single-coin / column-respin patterns (“hold reels 0 and 4, reroll the middle three”) used to require N independent ReelSet instances bundled into a row. With the new holdReels option that’s one spin() call:
// Hold the outer columns; only middle three reroll.
const spin = reelSet.spin({ holdReels: [0, 4] });
reelSet.setResult(serverGrid); // entries at indices 0 and 4 are ignored
await spin;
Behaviour:
- Held reels skip START / SPIN / STOP entirely. they don’t move at all.
- They count as already-landed for
spin:allLanded, so the resolver fires once the non-held reels land. setAnticipation([...])silently filters held indices;setStopDelays([...])ignores entries at held indices.SpinResult.symbolsreports the full visible grid (held rows unchanged, non-held rows landed).
When to pick which:
- Per-cell hold-and-win (this recipe’s main pattern, with coins locked one cell at a time): the per-column
ReelSetarray is still the cleanest model. Each cell is its ownReelSetwithvisibleRows(1). - Single-reel respin / partial reroll (whole columns held, others spin): use
spin({ holdReels })on a singleReelSet. Spotlight, anticipation, win presenters keep working since everything stays inside one engine.
Related recipes
EmptySymbol. the blank-cell symbol class this recipe registers as the bonus-board background- Near-miss. tease a coin just off the board
- Anticipate a reel. slow the final reel when close to a jackpot
- Sticky wild (CellPin). the engine-blessed sticky-symbol path