PR pixi-reels

RunCascadeOptions

pixi-reels


pixi-reels / index / RunCascadeOptions

Interface: RunCascadeOptions

Defined in: core/ReelSet.ts:188

Options for ReelSet.runCascade. The two required callbacks (detectWinners, nextGrid) encode game rules; everything else is timing / cancellation / forwarded-to-destroy plumbing with sensible defaults.

Properties

PropertyTypeDescriptionDefined in
destroyOptions?DestroySymbolsOptionsForwarded to destroySymbols(cells, opts) on every cascade. Useful for per-cell stagger, viewport dim, an abort signal, etc.core/ReelSet.ts:255
detectWinners(grid: string[][], chainLevel: number) => | readonly Cell[] | Promise<readonly Cell[]>Win-detection callback. Receives the current grid (a fresh copy from getVisibleGrid()) and the chain level (0 on the first iteration). Returns the cells whose symbols are “winners” that should be cleared before the next refill. Return [] to end the chain. Sync or async.core/ReelSet.ts:195
gravityHold?(info: { chain: number; winners: readonly Cell[]; }) => Promise<void>Per-cascade promise-builder. Invoked once per chain stage at the gravity-end boundary (i.e. AFTER every reel’s gravity stage has settled, just before the global hold begins). The returned promise is awaited in parallel with gravityHoldMs via Promise.all. whichever finishes LAST gates the drop-in. Only fires when refillMode === 'gravity-then-drop'. Use this when each cascade starts its own anticipation animation (multiplier roll, mascot reaction, anticipation SFX) and you want the builder’s side effects (e.g. multiplier.bumpTo(chain + 1)) to fire AT gravity-end. not back when the refill args were assembled. The library calls your function at the right beat and awaits the promise you return. - chain. same 1-indexed chain stage as cascade:chain:start. - winners. cells cleared this cascade. A rejection from the returned promise is surfaced via the cascade:gravity:error event AND logged via console.error; the engine slams the refill so the awaited promise still settles.core/ReelSet.ts:307
gravityHoldMs?numberFixed wall-clock pause between gravity end and drop-in start, in ms. Only used when refillMode === 'gravity-then-drop'. Default 250. Combines via Promise.all with gravityHold if both are provided. The natural place for asymmetric anticipation visuals: register a listener on cascade:gravity:end (one per reel) and trigger your mascot / multiplier roll / SFX from there. Use gravityHold if you already have an in-flight animation promise, or onGravityComplete if you need a post-hold callback.core/ReelSet.ts:284
maxChain?numberSafety cap on cascade-chain length. Defaults to 32. a sane upper bound that protects against pathological server bugs while being well above any commercial slot’s natural cap. Pass Infinity to disable.core/ReelSet.ts:250
nextGrid(grid: string[][], winners: readonly Cell[], chainLevel: number) => | string[][] | ColumnTarget[] | Promise<string[][]> | Promise<ColumnTarget[]>Next-grid callback. Given the post-destroy grid and the winners that were cleared, return the grid the survivors + new symbols should land on. This is your server-side gravity simulation (or the fallback cascadeNextGrid from your client). Sync or async. Must follow the gravity convention: top winners.length rows per reel are new symbols; the rest are survivors in original top-to- bottom order. Same contract as refill({ grid }). May return string[][] (visible cells only) or ColumnTarget[] (when the next grid places anchors in bufferAbove / bufferBelow).core/ReelSet.ts:212
onCascade?(info: { chain: number; currentGrid: string[][]; winners: readonly Cell[]; }) => void | Promise<void>Per-cascade hook fired AFTER destroySymbols and BEFORE the refill starts. Use it to bump multipliers, play SFX, run “winners gone” UI animations. Return a promise to delay the refill (e.g. for a number-roll animation). - chain. same 1-indexed chain stage as cascade:chain:start. - winners. cells that were just destroyed. - currentGrid. the grid as it stood at cascade:chain:start (same reference). The symbols at winners are visually gone but the grid array still names them. nextGrid will replace them.core/ReelSet.ts:233
onGravityComplete?(info: { chain: number; winners: readonly Cell[]; }) => void | Promise<void>Per-cascade callback fired AFTER gravityHoldMs + gravityHold both resolve, BEFORE the drop-in stage. Only fires when refillMode === 'gravity-then-drop'. Use for last-mile side effects that need to read post-hold state (e.g. snapshot the multiplier value that just finished its count-up). - chain. same 1-indexed chain stage as cascade:chain:start. - winners. cells cleared this cascade.core/ReelSet.ts:321
pauseAfterDestroyMs?numberMilliseconds to wait between win-destroy completing and the next refill starting. Commercial slots dial this between 150 ms (snappy) and 500 ms (dramatic). Default 250.core/ReelSet.ts:243
refillMode?"combined" | "gravity-then-drop"How each refill in the chain animates. - 'combined' (default). survivors and new symbols animate together in one drop-in beat. The Sweet Bonanza / Sugar Rush feel. - 'gravity-then-drop'. survivors slide down to fill holes FIRST, then a global pause (gravityHoldMs), then new symbols enter from above with the per-reel stop delay applied. The Mummyland Treasures / Reactoonz feel. gives space for an anticipation beat between gravity and new-symbol entry. Per-column stagger inside the new-symbol drop is controlled by setDropOrder('ltr', stepMs) exactly as in combined mode. when the step is shorter than dropIn.duration you get overlapping waves; when it’s at least as long you get strictly sequential columns.core/ReelSet.ts:272
signal?AbortSignalAbort signal for caller-driven cancellation. The loop exits at the next await boundary, the in-flight refill (if any) is slammed via slamStop(), and the resolved summary reports wasSkipped: true. Use this for “player tapped SLAM mid-cascade”. reelSet.skipSpin() is a no-op when called between refills (the engine is idle), so it cannot end the chain from a button handler. AbortController can. const controller = new AbortController(); skipButton.addEventListener('click', () => controller.abort()); await reelSet.runCascade({ ..., signal: controller.signal });core/ReelSet.ts:340