PR pixi-reels

ReelSet

pixi-reels


pixi-reels / index / ReelSet

Class: ReelSet

Defined in: core/ReelSet.ts:377

The whole slot board as one object.

A ReelSet is a PixiJS Container that owns every reel, the spin controller, the speed manager, and the win spotlight. You addChild it to your stage and then drive it from the four public verbs below:

  • spin(). start the reels moving, returns a promise that resolves when every reel has landed (or been slam-stopped)
  • setResult(grid). tell the reels what to land on; the spin controller consumes this and each reel queues its target symbols
  • setAnticipation(reelIndices). slow the given reels before they stop, for “will the third scatter land?” tension
  • skipSpin() lands the in-flight spin immediately. The slam-stop button calls this.

Everything else is subsystems: speed, spotlight, events, viewport. Construction goes through ReelSetBuilder, never new ReelSet() directly. the builder enforces that every required piece is wired.

const reelSet = new ReelSetBuilder()
  .reels(5).visibleRows(3).symbolSize(140, 140)
  .symbols((r) => r.register('cherry', SpriteSymbol, { textures }))
  .ticker(app.ticker)
  .build();
app.stage.addChild(reelSet);

const spin = reelSet.spin();
reelSet.setResult(await server.spin());
await spin;

Teardown cascades: one reelSet.destroy() disposes every child.

Extends

  • Container

Implements

Constructors

Constructor

new ReelSet(params: ReelSetParams): ReelSet;

Defined in: core/ReelSet.ts:460

Parameters

ParameterType
paramsReelSetParams

Returns

ReelSet

Overrides

Container.constructor

Accessors

events

Get Signature

get events(): EventEmitter<ReelSetEvents>;

Defined in: core/ReelSet.ts:545

The event emitter for reel-specific events.

Returns

EventEmitter<ReelSetEvents>


frame

Get Signature

get frame(): FrameAPI;

Defined in: core/ReelSet.ts:1865

Runtime-mutable middleware pipeline for symbol-frame generation.

Example
// Feature entry. swap to a middleware that injects more wilds
reelSet.frame.use(moreWildsMiddleware);

// Feature exit
reelSet.frame.remove('more-wilds');
Returns

FrameAPI


isDestroyed

Get Signature

get isDestroyed(): boolean;

Defined in: core/ReelSet.ts:1871

Returns

boolean

Implementation of

Disposable.isDestroyed


isMultiWaysSlot

Get Signature

get isMultiWaysSlot(): boolean;

Defined in: core/ReelSet.ts:1303

Whether this slot was built with .multiways(...).

Returns

boolean


isSpinning

Get Signature

get isSpinning(): boolean;

Defined in: core/ReelSet.ts:1298

Returns

boolean


pins

Get Signature

get pins(): ReadonlyMap<string, CellPin>;

Defined in: core/ReelSet.ts:1668

All active pins, keyed by "col:row".

Reads are safe at any time. during a spin the map reflects pins that will apply to the NEXT setResult(), not the one already in flight.

Returns

ReadonlyMap<string, CellPin>


reels

Get Signature

get reels(): readonly Reel[];

Defined in: core/ReelSet.ts:1531

Get all reels.

Returns

readonly Reel[]


skipStage

Get Signature

get skipStage(): 0 | 1 | 2;

Defined in: core/ReelSet.ts:1057

Current skipSpin() position within the active round. 0 until the player presses the slam button, 2 after. Read this to drive button labels (e.g. “Skip” to “Skipped”). 1 is reserved for forward compat and is not currently reachable.

requestSkip() that gets queued pre-setResult() does NOT advance the stage until the queued slam actually fires (i.e. once setResult() arrives). If you need a “queued” UI state, track that yourself alongside skipStage.

Returns

0 | 1 | 2


speed

Get Signature

get speed(): SpeedManager;

Defined in: core/ReelSet.ts:1507

Speed profile manager.

Returns

SpeedManager


spotlight

Get Signature

get spotlight(): SymbolSpotlight;

Defined in: core/ReelSet.ts:1524

Returns

SymbolSpotlight


viewport

Get Signature

get viewport(): ReelViewport;

Defined in: core/ReelSet.ts:1576

Get the viewport.

Returns

ReelViewport

Methods

destroy()

destroy(): void;

Defined in: core/ReelSet.ts:1875

Removes all internal references and listeners as well as removes children from the display list. Do not use a Container after calling destroy.

Returns

void

Example

container.destroy();
container.destroy(true);
container.destroy({ children: true });
container.destroy({ children: true, texture: true, textureSource: true });

Implementation of

Disposable.destroy

Overrides

Container.destroy

destroySymbols()

destroySymbols(cells: readonly Cell[], opts?: DestroySymbolsOptions): Promise<void>;

Defined in: core/ReelSet.ts:718

Destroy a batch of cells in parallel, deferring to each symbol’s own playDestroy() so subclasses (Spine, particles, custom sprites) can provide art-appropriate disintegration without the spin handler caring.

This is the canonical “fade out the winners” step in a cascade chain: call it between win-detection and refill(). Every cell’s view is lifted with a high zIndex so the destroy animation isn’t clipped by neighbours. The default playDestroy is a brief scale/fade implode; override it per symbol class for art-appropriate destruction.

  • Empty cells resolves immediately, no work.
  • Out-of-range cells throw. the contract is that you’ve already run win detection on the visible grid, so coords must be valid.

Parameters

ParameterType
cellsreadonly Cell[]
opts?DestroySymbolsOptions

Returns

Promise<void>

Examples

const winners = detectWinners(reelSet.getVisibleGrid());
await reelSet.destroySymbols(winners);
await reelSet.refill({ winners, grid: nextGrid });
// Per-cell stagger. disintegrate left-to-right with a 30 ms beat.
await reelSet.destroySymbols(winners, {
  delay: (cell, i) => i * 0.03,
});

getBlockBounds()

getBlockBounds(col: number, row: number): CellBounds;

Defined in: core/ReelSet.ts:1474

Pixel rectangle covering a big symbol’s whole N×M block, in ReelSet-local coordinates. Returns the anchor cell’s bounds for 1×1 symbols. Pass any cell of a block. anchor or non-anchor. and you get the same rect.

Useful for win presenters drawing an outline around a whole bonus, or any overlay aligned to the visible footprint of a big symbol:

const rect = reelSet.getBlockBounds(2, 1);
gfx.rect(rect.x, rect.y, rect.width, rect.height)
   .stroke({ color: 0xff6b35, width: 4 });
reelSet.addChild(gfx);

For 1×1 cells this is equivalent to getCellBounds(col, row). For big-symbol cells it multiplies width/height by the block size and starts from the anchor cell’s bounds.

Parameters

ParameterType
colnumber
rownumber

Returns

CellBounds


getCellBounds()

getCellBounds(col: number, row: number): CellBounds;

Defined in: core/ReelSet.ts:1559

Returns the bounding box of a visible grid cell in ReelSet-local coordinates (i.e. relative to this Container, before any parent transforms). Row 0 is the top visible row.

Use this to place payline graphics, hit areas, or debug overlays that must align with a specific symbol cell:

const b = reelSet.getCellBounds(2, 1);
gfx.rect(b.x, b.y, b.width, b.height).stroke({ color: 0xff6b35 });
reelSet.addChild(gfx);

To convert to stage / global coordinates use PixiJS:

const global = reelSet.toGlobal({ x: b.x, y: b.y });

Parameters

ParameterType
colnumber
rownumber

Returns

CellBounds


getPin()

getPin(col: number, row: number): CellPin | undefined;

Defined in: core/ReelSet.ts:1673

Convenience: get the pin at (col, row) or undefined.

Parameters

ParameterType
colnumber
rownumber

Returns

CellPin | undefined


getReel()

getReel(index: number): Reel;

Defined in: core/ReelSet.ts:1536

Get a reel by index.

Parameters

ParameterType
indexnumber

Returns

Reel


getSymbolFootprint()

getSymbolFootprint(col: number, row: number): {
  anchor: {
     col: number;
     row: number;
  };
  size: {
     h: number;
     w: number;
  };
};

Defined in: core/ReelSet.ts:1410

Footprint of the symbol at (col, row).

  • 1×1 symbols: { anchor: { col, row }, size: { w: 1, h: 1 } }.
  • Big symbols: returns the anchor cell and block size.
  • OCCUPIED cells: resolves transparently to the anchor.

Useful for win presenters that need to highlight a whole NxM block.

Parameters

ParameterType
colnumber
rownumber

Returns

{
  anchor: {
     col: number;
     row: number;
  };
  size: {
     h: number;
     w: number;
  };
}
NameTypeDefined in
anchor{ col: number; row: number; }core/ReelSet.ts:1413
anchor.colnumbercore/ReelSet.ts:1413
anchor.rownumbercore/ReelSet.ts:1413
size{ h: number; w: number; }core/ReelSet.ts:1413
size.hnumbercore/ReelSet.ts:1413
size.wnumbercore/ReelSet.ts:1413

getVisibleGrid()

getVisibleGrid(): string[][];

Defined in: core/ReelSet.ts:1397

Resolved grid, with all OCCUPIED cells (same-reel and cross-reel) replaced by their anchor’s symbol id. A 2×2 bonus reads as four 'bonus' cells.

Equivalent to reelSet.reels.map(r => r.getVisibleSymbols()) because each reel has a cross-reel resolver wired in by ReelSet’s constructor. the per-reel surface and the grid surface are the same.

Returns

string[][]


movePin()

movePin(
   from: CellCoord, 
   to: CellCoord, 
opts?: MovePinOptions): Promise<void>;

Defined in: core/ReelSet.ts:1707

Move an existing pin from one cell to another. Animates a flight symbol between the two cells, updates pin state atomically, and resolves when the animation completes.

This is the engine-native replacement for ghost sprites in walking-wild recipes. The flight symbol is a pooled ReelSymbol acquired from the factory, parented briefly to the viewport’s unmaskedContainer so it can travel across reel boundaries without being clipped.

Constraints:

  • Only callable at rest (throws if isSpinning === true).
  • to must be within the grid; no pin may already exist there.
  • Calling with from === to is a no-op that still fires pin:moved.

Parameters

ParameterType
fromCellCoord
toCellCoord
opts?MovePinOptions

Returns

Promise<void>

Example

// Walking wild. move the pinned wild one column left each spin
reelSet.events.on('spin:complete', async () => {
  for (const pin of [...reelSet.pins.values()]) {
    if (pin.col > 0) {
      await reelSet.movePin(
        { col: pin.col, row: pin.row },
        { col: pin.col - 1, row: pin.row },
      );
    } else {
      reelSet.unpin(pin.col, pin.row);
    }
  }
});

nudge()

nudge(col: number, options: NudgeOptions): Promise<{
  symbols: string[];
}>;

Defined in: core/ReelSet.ts:1145

Shift a single reel by distance positions after it has landed, revealing caller-supplied symbols.

Per-reel by design. multi-reel sync is via Promise.all([...]) of independent calls. Each call emits its own nudge:start / nudge:complete pair on the ReelSet bus and phase:enter('nudge') / phase:exit('nudge') on the per-reel bus.

Big-symbol blocks on the target reel are nudged through as a unit as long as they fit on the strip post-rotation. Use case: a 1xH block lands with stubs in bufferBelow; nudge up to reveal it fully.

nudge:start fires AFTER pre-placement so listeners observe the about-to-tween state, mirroring nudge:complete which fires after the strip has snapped. To capture the pre-nudge state, snapshot the grid in your call site before awaiting.

Throws (synchronously) if:

  • the reel set is currently spinning (avoid races with the spin pipeline),
  • col is out of range,
  • any visible cell on the target reel has an active pin,
  • Reel.nudge itself rejects (bad distance / direction / incoming / incompatible big-symbol layout).

While nudge() is in flight, calling spin(), setResult(), pin(), or setShape() throws. Await the returned promise before calling any of those methods.

Rejects with an AbortError if options.signal aborts or the reel is destroyed mid-tween. nudge:cancelled fires on the bus in that case.

Parameters

ParameterType
colnumber
optionsNudgeOptions

Returns

Promise<{ symbols: string[]; }>

Examples

await reelSet.spin(); // landed
await reelSet.nudge(2, { distance: 1, direction: 'down', incoming: ['wild'] });
Parallel nudges across two reels:
await Promise.all([
  reelSet.nudge(2, { distance: 1, direction: 'down', incoming: ['wild'] }),
  reelSet.nudge(3, { distance: 1, direction: 'down', incoming: ['wild'] }),
]);
Staggered parallel via `startDelay`:
await Promise.all(
  [1, 2, 3].map((col, i) =>
    reelSet.nudge(col, { ...opts, startDelay: i * 80 }),
  ),
);
Abortable nudge:
const controller = new AbortController();
skipButton.onclick = () => controller.abort();
await reelSet.nudge(2, { ...opts, signal: controller.signal })
  .catch((e) => { if (e.name !== 'AbortError') throw e; });

pin()

pin(
   col: number, 
   row: number, 
   symbolId: string, 
   options?: CellPinOptions): CellPin;

Defined in: core/ReelSet.ts:1607

Pin a symbol to a grid cell. Applied immediately if the reel is idle; applied at the next setResult() otherwise. Fires pin:placed.

Passing the same (col, row) replaces the previous pin. The old one is replaced silently (no pin:expired fires for replacement).

Negative rows are rejected. Place buffer-row anchors via setResult() with bufferAbove / bufferBelow on the column’s ColumnTarget.

Parameters

ParameterType
colnumber
rownumber
symbolIdstring
options?CellPinOptions

Returns

CellPin

Example

// Sticky wild for 3 spins
reelSet.pin(2, 1, 'wild', { turns: 3 })

// Hold & Win coin with a payout value
reelSet.pin(col, row, 'coin', { turns: 'permanent', payload: { value: 50 } })

// Expanding wild: fill column for the current spin's evaluation only
for (let r = 0; r < 3; r++) reelSet.pin(2, r, 'wild', { turns: 'eval' })

refill()

refill(opts: RefillOptions): Promise<RefillResult>;

Defined in: core/ReelSet.ts:658

Tumble cascade: cascade refill (Moment B). Call this AFTER you’ve faded out the winning symbols in your own code, with the list of winner cells and the next grid the server returned.

  • Untouched survivors don’t animate.
  • Survivors above a hole slide down to fill it.
  • New symbols enter from above into the top winners.length rows of each reel.

The new grid must follow the gravity convention: per reel, the top winnerRows.length rows are the new symbols, the remaining rows are survivors in their original top-to-bottom order. This matches what server-side gravity simulations emit.

Resolves with a RefillResult (mirror of RunCascadeResult. one stage’s worth). Requires the builder to have been configured with .tumble(...).

For the common destroy → refill → check → repeat loop, prefer ReelSet.runCascade. it composes refill, destroySymbols, and win-detection with the same cancellation semantics.

Parameters

ParameterType
optsRefillOptions

Returns

Promise<RefillResult>

Examples

const winners = detectWins(currentGrid);
await reelSet.destroySymbols(winners);
const next = await server.cascade(winners);
const result = await reelSet.refill({ winners, grid: next });
console.log(result.finalGrid, result.wasSkipped);
// Abort mid-refill: slams the in-flight animation, resolves with wasSkipped.
const ac = new AbortController();
skipButton.onclick = () => ac.abort();
const result = await reelSet.refill({
  winners, grid: next, signal: ac.signal,
});

refreshPinOverlaysForReel()

refreshPinOverlaysForReel(reelIndex: number): void;

Defined in: core/ReelSet.ts:2158

Reposition + resize every pin overlay on the given reel.

The engine calls this automatically after every MultiWays AdjustPhase reshape (and from the skip path), so applications that just use setShape() / setResult() never need to invoke it. Call it yourself only if you mutate Reel.symbolWidth, Reel.symbolHeight, or a pin’s row outside the normal MultiWays flow. e.g. a custom mid-spin layout swap that bypasses AdjustPhase.

No-op for reels with no active pin overlays.

Parameters

ParameterType
reelIndexnumber

Returns

void


requestSkip()

requestSkip(): void;

Defined in: core/ReelSet.ts:1029

Slam-stop safe before setResult() arrives: queues until then. Bypasses the two-stage skipSpin() machine. An explicit slam intent.

Note on skipStage: when this call queues a slam (pre-setResult) rather than firing one, skipStage stays at 0 until setResult() arrives and the queued slam actually runs. If your UI labels the button off skipStage, expect a beat of “Skip” still shown while the queued intent is in flight; the queued state is not exposed as its own stage on purpose (kept the 0 | 1 | 2 shape stable).

Returns

void


runCascade()

runCascade(opts: RunCascadeOptions): Promise<RunCascadeResult>;

Defined in: core/ReelSet.ts:832

Run the canonical cascade chain on top of refill(). Loops: detect winners → destroy → pause → refill → emit. until detectWinners returns an empty list (or maxChain is hit, or the player slammed via skipSpin() / abort). Resolves with the final grid and a summary.

The orchestration is library-owned; the game rules (what counts as a winner, how the next grid is computed) stay in your callbacks. This is the cascade equivalent of spin() + setResult(). three lines instead of fifteen, and the slam path is handled for you.

Typical usage:

await reelSet.spin();
reelSet.setResult(await server.spin());
const summary = await reelSet.runCascade({
  detectWinners: (grid) => detectClusters(grid),
  nextGrid: async (grid, winners) => server.cascade(winners),
  onCascade: ({ chain, winners }) => bumpMultiplier(chain),
});
console.log(summary.chainLength, summary.totalWinners);

Composes with everything else in the library:

  • setDropOrder(...) is honoured on every refill in the chain. set it before runCascade and the same order applies to every drop.
  • cascade:fall:symbol, cascade:place:end, cascade:dropIn:symbol fire on each refill.
  • reelSet.skipSpin() ends the chain immediately; the returned summary reports wasSkipped: true.

Event order per stage with winners: cascade:chain:startcascade:destroy:start → (destroy tweens) → cascade:destroy:endonCascade → pause → refill (cascade:place:end + cascade:dropIn:* per reel) → cascade:chain:end. The chain itself is delimited by the returned Promise. await the call to know when it’s done.

Requires .tumble(...) on the builder (same as refill()).

Parameters

ParameterType
optsRunCascadeOptions

Returns

Promise<RunCascadeResult>


setAnticipation()

setAnticipation(reelIndices: number[]): void;

Defined in: core/ReelSet.ts:963

Set which reels should show anticipation before stopping.

Parameters

ParameterType
reelIndicesnumber[]

Returns

void


setDropOrder()

setDropOrder(order: number[] | "all" | "ltr" | "rtl", stepMs?: number): void;

Defined in: core/ReelSet.ts:1277

Set the per-reel drop order for the next stop / refill sequence.

Convenience wrapper over setStopDelays() for common patterns. The stagger step defaults to the active speed profile’s stopDelay (or 150 ms if stopDelay is 0).

Sticky. The override persists indefinitely. until another setDropOrder() / setStopDelays() call overwrites it (a null / absent override falls back to the default i * speed.stopDelay stagger). It survives across spin() AND refill() boundaries by design, because runCascade(...) calls refill() in a loop and the order set once before the chain must apply to every iteration.

The canonical cascade pattern resets it per phase:

  • setDropOrder('ltr') before spin(). left-to-right reveal on the initial drop.
  • setDropOrder('all') before runCascade(). every refill in the chain drops all columns simultaneously (the commercial-cascade pattern).

If you leave the order set between rounds and don’t re-set before the next spin(), the previous value carries over. Re-set explicitly per round if your rounds use different patterns.

Call again with a different value to change it; the previous value is replaced, not stacked.

Parameters

ParameterType
ordernumber[] | "all" | "ltr" | "rtl"
stepMs?number

Returns

void

Example

reelSet.setDropOrder('ltr');  // left-to-right
reelSet.setDropOrder('rtl');  // right-to-left
reelSet.setDropOrder('all');  // all columns simultaneously
reelSet.setDropOrder([0, 0, 200, 200, 400]); // custom per-reel delays

setResult()

setResult(symbols: ColumnTarget[]): void;

Defined in: core/ReelSet.ts:607

Set the target result symbols. Triggers the stop sequence.

One ColumnTarget per reel. visible is the visible-window target; optional bufferAbove / bufferBelow target cells outside it.

If any pins are active (reelSet.pin(...)), their symbols are overlaid onto the result before it reaches the stop sequencer, so pinned cells always land on the pin’s symbolId regardless of what the server sent.

Parameters

ParameterType
symbolsColumnTarget[]

Returns

void

Example

reelSet.setResult([
  { visible: ['A','B','C'] },
  { visible: ['A','B','C'] },
  { visible: ['A','B','C'], bufferAbove: ['COIN'] },
  { visible: ['A','B','C'] },
  { visible: ['A','B','C'] },
]);

setShape()

setShape(rowsPerReel: number[]): void;

Defined in: core/ReelSet.ts:1322

MultiWays: record the row count each reel should land on this spin. The AdjustPhase between SPIN and STOP will reshape reels (resize symbols, reshape motion) before the stop sequence runs.

Must be called between spin() and setResult(). The shape stays in effect for the current spin only. call again on every spin.

Throws if:

  • this slot was not built with .multiways(...)
  • rowsPerReel.length !== reelCount
  • any entry falls outside [multiways.minRows, multiways.maxRows]

Parameters

ParameterType
rowsPerReelnumber[]

Returns

void


setSpeed()

setSpeed(name: string): void;

Defined in: core/ReelSet.ts:1512

Change speed and emit event.

Parameters

ParameterType
namestring

Returns

void


setStopDelays()

setStopDelays(delays: number[]): void;

Defined in: core/ReelSet.ts:981

Override the per-reel stop delay (in ms). Pass one value per reel.

Sticky. The override persists indefinitely. it survives across spin() AND refill() boundaries until you call setStopDelays() (or setDropOrder()) again. The persistence is deliberate: cascade recipes that set setDropOrder('all') once before runCascade(...) want every internal refill() to honor it. If your rounds use different patterns, re-set explicitly per round.

Parameters

ParameterType
delaysnumber[]

Returns

void

Example

// Stagger the last two reels more than the default for dramatic effect:
reelSet.setStopDelays([0, 140, 280, 600, 1100]);

setSymbolAt()

setSymbolAt(
   col: number, 
   row: number, 
   symbolId: string): void;

Defined in: core/ReelSet.ts:1077

Swap the symbol at a single grid cell in-place, at rest.

Caller-facing wrapper over Reel.setSymbolAt that ALSO refuses pinned cells (since Reel itself can’t see the pin map). Use this for live presentation effects. sticky-after-win, mid-feature rewrites. without going through setResult().

Throws (in addition to the per-reel guards documented on Reel.setSymbolAt) if (col, row) currently has an active pin. Use unpin(col, row) first if you intentionally want to overwrite it.

Parameters

ParameterType
colnumber
rownumber
symbolIdstring

Returns

void

Example

await reelSet.spin(); // landed
reelSet.setSymbolAt(2, 1, 'wild'); // swap centre cell to wild

skipNudge()

skipNudge(col?: number): void;

Defined in: core/ReelSet.ts:1229

Fast-forward an in-flight nudge() to its landed state. No-op if the given reel is not currently nudging.

The tween’s onComplete fires synchronously, the strip snaps to the final position, and the original nudge() promise resolves on the next microtask. nudge:complete fires normally. From a listener’s POV the nudge just landed fast.

Pairs with skipSpin() (round-aware spin land + boost) and slamStop() (unconditional spin land-now). These three are distinct: spin actions do not affect a nudge in flight, and skipNudge does not touch spin state.

Parameters

ParameterTypeDescription
col?numberReel index, or undefined to skip all in-flight nudges.

Returns

void


skipSpin()

skipSpin(): void;

Defined in: core/ReelSet.ts:1014

Round-aware spin skip. The button-press entry point. The first press in a round slams the current drop AND applies a round-scoped side effect:

  • Standard mode: boost the active speed profile to the fastest registered one (emits skip:boosted). Restored on the next spin() (unless the app manually changed speed in between).
  • Cascade/tumble mode: flag every subsequent refill() to auto-slam with no animation. One press ends a multi-drop cascade.

Subsequent presses also slam each current drop.

Throws if called before setResult() arrives (nothing to land on: slamming now would land on random spin-buffer content). The universal “spin/skip” button pattern should call requestSkip() in that window (or wrap skipSpin() in a try/catch that routes to requestSkip() in the catch). Callers that want a slam without the round-scoped side effects (tests, anti-cheat) should use slamStop().

Pairs with skipNudge() (skip an in-flight nudge()) and slamStop() (unconditional land-now, no boost). Three distinct actions:

  • skipSpin() lands the in-flight spin and applies the round-scoped boost / auto-slam-refills side effect.
  • skipNudge() fast-forwards an in-flight nudge() to its landed position. Spin state is unrelated.
  • slamStop() lands every un-landed reel unconditionally. No boost.

Returns

void


slamStop()

slamStop(): void;

Defined in: core/ReelSet.ts:1042

Hard slam-stop. Always lands every un-landed reel immediately. Bypasses the two-stage skipSpin() machine and any speed boost. For tests, anti-cheat flows, or any caller with unambiguous “end now” intent.

Pairs with skipSpin() (round-aware land + boost) and skipNudge() (fast-forward an in-flight nudge()).

Returns

void


spin()

spin(options?: SpinOptions): Promise<SpinResult>;

Defined in: core/ReelSet.ts:583

Start spinning. Returns a promise that resolves when all (non-held) reels land.

Pass { holdReels: [i, ...] } to keep specific columns frozen for this spin. they skip START / SPIN / STOP entirely and stay on whatever symbols they’re currently showing. The use cases are Hold & Win respins, sticky / expanding wilds, and “the trigger column stays in place” bonus rounds.

Pass { mode: 'standard' | 'cascade' } to override the builder-time default for a single spin (e.g. classic strip-spin on the first round, drop-in on the cascade waves). 'cascade' requires .tumble(...) on the builder.

Parameters

ParameterType
options?SpinOptions

Returns

Promise<SpinResult>

Examples

// Plain spin. every reel animates.
await reelSet.spin();
// Hold reels 0 and 4; only the middle three reroll.
const spin = reelSet.spin({ holdReels: [0, 4] });
reelSet.setResult(serverGrid); // entries at 0/4 are ignored
await spin;
// Per-spin cascade override.
await reelSet.spin({ mode: 'cascade' });

See {@link SpinOptions} for the full contract (event behaviour,
setResult interaction, setAnticipation filtering).

unpin()

unpin(col: number, row: number): void;

Defined in: core/ReelSet.ts:1653

Remove a pin at (col, row). If no pin exists at that cell, this is a no-op. Fires pin:expired with reason 'explicit'.

Parameters

ParameterType
colnumber
rownumber

Returns

void