pixi-reels

ReelSetBuilder

pixi-reels


pixi-reels / index / ReelSetBuilder

Class: ReelSetBuilder

Defined in: core/ReelSetBuilder.ts:85

The configurator you call before every reel set.

ReelSetBuilder is a fluent, chainable builder: every call returns the builder so you can string setup onto one expression. It hides the twenty-odd subsystems you would otherwise have to wire by hand, and its .build() step validates that every required piece is present (throws at construction, not at first spin).

Required calls (in any order): .reels(n), .visibleCells(n), .symbolSize(w, h), .symbols((registry) => ...), .ticker(app.ticker). Optional: .symbolGap(), .weights(), .symbolData(), .speed(), .bufferSymbols(), .offset(), .frameMiddleware(), .phases(), .spinningMode().

const reelSet = new ReelSetBuilder()
  .reels(5)
  .visibleCells(3)
  .symbolSize(200, 200)
  .symbols((r) => {
    r.register('cherry', SpriteSymbol, { textures: { cherry: tex } });
  })
  .weights({ cherry: 20 })
  .ticker(app.ticker)
  .build();

Constructors#

Constructor#

new ReelSetBuilder(): ReelSetBuilder;

Returns#

ReelSetBuilder

Methods#

bufferSymbols()#

bufferSymbols(count: 
  | number
  | {
  end: number;
  start: number;
}): this;

Defined in: core/ReelSetBuilder.ts:616

Set number of buffer symbols either side of the visible window. Default: 1.

start is the edge at the smaller main coordinate (above for vertical, left for horizontal) and end the larger one. Both are geometric, not travel-relative: flipping a reel’s direction never moves a buffer teaser to the opposite edge.

Buffer cells are off-screen cells the reel keeps around the visible window so symbols can fade/slide in cleanly. The motion layer’s wrap detection assumes at least one buffer cell each side. the minimum supported count is 1. Passing 0 (or a negative number) is clamped to 1 and a single console warning is printed; the builder does not throw, so existing user code keeps running.

Tumble-only reel sets may drop the end-window buffer entirely with the object form: bufferSymbols({ start: 1, end: 0 }). A pure tumble never scrolls the strip, so nothing ever wraps through the end-window cells. they exist only to be hidden by the mask. This requires .tumble(...) on the builder (validated at build()), and strip spins (spin({ mode: 'standard' })) and nudge() throw on such a set. start keeps the minimum of 1 (drop-in movers are pre-positioned outside the start edge).

Parameters#

ParameterType
count| number | { end: number; start: number; }

Returns#

this


build()#

build(): ReelSet;

Defined in: core/ReelSetBuilder.ts:964

Build the ReelSet. Validates configuration and assembles all internal objects.

Returns#

ReelSet


cellStacking()#

cellStacking(order: Stacking): this;

Defined in: core/ReelSetBuilder.ts:237

Render order of cells inside each reel. Default 'ascending'. the cell at the larger main coordinate (bottom for vertical, right for horizontal) draws in front of its neighbour.

Geometric on purpose: direction('reverse') and per-spin reversal do NOT flip it, so symbol art lit from above keeps overlapping the way the artist drew it. Set 'descending' if your art wants the opposite.

Parameters#

ParameterType
orderStacking

Returns#

this


curve()#

curve(curve: ReelCurveInput): this;

Defined in: core/ReelSetBuilder.ts:304

Fake the curvature of the reel cylinder on every reel in the set.

Cells bunch up and squash toward the window edges the way they would on a real drum, while the middle of the window magnifies slightly because it is the part facing you. It is a per-cell transform, so the art stays crisp, there is no render texture or shader, and a flat set (the default) pays nothing at all.

Parameters#

ParameterTypeDescription
curveReelCurveInput0 = flat, 1 = a hard barrel. Pass ReelCurveConfig to also tune depth, the cross-axis narrowing that keeps it reading as a drum rather than a squeezed flat strip.

Returns#

this

Example#

builder.curve(0.35);
builder.curve({ amount: 0.5, depth: 0.3 });

curveBleed()#

curveBleed(pixels: number): this;

Defined in: core/ReelSetBuilder.ts:404

Cross-axis room, in pixels per side, for symbols whose art is WIDER than their cell - an overflowing mystery plate, leaves spilling past the tile.

curveMode('warp') renders each reel into a texture the size of the reel, so anything hanging over the edge is sliced off at the texture boundary. This gives the texture room, and the overflow is captured, warped with everything else, and sticks out over its neighbours.

Costs texture area, so keep it to what the art actually needs. Warp mode only; ignored under curveMode('symbol'), where symbols are real display objects and overflow already draws.

Pair it with SharedRectMaskStrategy (or a curveFocus other than 'reel', which selects it for you) or the per-reel mask clips the overhang straight back off.

Parameters#

ParameterType
pixelsnumber

Returns#

this

Example#

builder.curve(0.45).curveMode('warp').curveBleed(40).renderer(app.renderer);

curveFocus()#

curveFocus(focus: CurveFocus): this;

Defined in: core/ReelSetBuilder.ts:412

Parameters#

ParameterType
focusCurveFocus

Returns#

this


curveMode()#

curveMode(mode: CurveMode): this;

Defined in: core/ReelSetBuilder.ts:364

How the curve is drawn.

'symbol' (default) projects each cell on its own: crisp, free, and a real keystone - but only for symbols whose content IS a texture. A Container transform is affine, so a Spine skeleton, a Graphics, or a composite subtree can only be displaced and scaled by it, never bent.

'warp' renders each reel to a texture and draws it through a mesh whose VERTICES are displaced by the projection. Everything inside the reel bends identically - skeletons, atlas sprites, text, effects - and no symbol has to cooperate. It costs one extra render pass per reel per frame and resamples the reel once, so hairline art is marginally softer.

'warp' requires ReelSetBuilder.renderer.

Parameters#

ParameterType
modeCurveMode

Returns#

this

Example#

builder.curve(0.5).curveMode('warp').renderer(app.renderer);

curvePerReel()#

curvePerReel(curves: ReelCurveInput[]): this;

Defined in: core/ReelSetBuilder.ts:320

Per-reel curvature override (length must equal reels()). Reels omitted fall back to curve().

Use it when the reels are not all the same size, or for the common trick of bending the middle reels harder than the outer ones so the board reads as one wide drum rather than five identical ones.

Parameters#

ParameterType
curvesReelCurveInput[]

Returns#

this

Example#

builder.curvePerReel([0.2, 0.35, 0.5, 0.35, 0.2]);

direction()#

direction(direction: Direction): this;

Defined in: core/ReelSetBuilder.ts:273

Default travel direction for every reel. 'forward' (default) heads toward the larger coordinate (down for vertical); 'reverse' runs the other way (roll-up on a vertical set).

Parameters#

ParameterType
directionDirection

Returns#

this


directionPerReel()#

directionPerReel(directions: Direction[]): this;

Defined in: core/ReelSetBuilder.ts:282

Per-reel travel direction override (length must equal reels()), for alternating-column effects. Reels omitted fall back to direction().

Parameters#

ParameterType
directionsDirection[]

Returns#

this


frameMiddleware()#

frameMiddleware(middleware: FrameMiddleware): this;

Defined in: core/ReelSetBuilder.ts:846

Add custom frame middleware.

Parameters#

ParameterType
middlewareFrameMiddleware

Returns#

this


gsap()#

gsap(instance: typeof gsap): this;

Defined in: core/ReelSetBuilder.ts:834

Inject the GSAP instance the engine should use for tweens.

When you need this: if your app already imports gsap and your bundler resolves gsap to a different module instance than the one pixi-reels resolved (common with symlinked workspaces, npm-link, or misconfigured dedupe), every tween you start on a target the engine also tweens will fight a separate timeline. Symptoms: spotlights that render but never finish, animations that double-fire, tweens that silently drop on hidden tabs in only one of the two instances.

Calling .gsap(myGsap) binds every phase, motion tween, symbol pin-flight tween, and SpriteSymbol win pulse to the GSAP you pass. guaranteed to be the same instance that drives your own animations.

Default: the gsap import resolved at the engine’s own node_modules/gsap path. If your app and the engine resolve to the same instance (the common case in production bundles with proper dedupe), you do NOT need to call this.

Per reel set, not process-wide. v1 stored one instance in a module global, so the last .gsap() call before any build() silently won for every set. Each set now captures the instance at build() time, so a composed stage can drive two sets from different instances. Pass the same instance to driveGsapWithTicker(ticker, instance).

Read at build(). calling it afterwards does not move an existing set.

Parameters#

ParameterType
instancetypeof gsap

Returns#

this

Example#

import { gsap } from 'gsap';
const reelSet = new ReelSetBuilder()
  .reels(5).visibleCells(3).symbolSize(200, 200)
  .symbols(...)
  .ticker(app.ticker)
  .gsap(gsap)              // ensure engine and app share one instance
  .build();

initialFrame()#

initialFrame(frame: ColumnTarget[]): this;

Defined in: core/ReelSetBuilder.ts:949

Set the initial symbol grid the reels show before the first spin.

One ColumnTarget per reel. visible lists the symbols in the visible window; optional bufferStart / bufferEnd prefill cells outside it ([0] is the slot closest to the visible window, later indices go further out).

Parameters#

ParameterType
frameColumnTarget[]

Returns#

this

Example#

builder.initialFrame([
  { visible: ['A','B','C'] },
  { visible: ['A','B','C'], bufferStart: ['COIN'] },
  { visible: ['A','B','C'], bufferEnd: ['SCATTER'] },
]);

initialSpeed()#

initialSpeed(name: string): this;

Defined in: core/ReelSetBuilder.ts:745

Set which speed profile to use initially. Default: ‘normal’.

Parameters#

ParameterType
namestring

Returns#

this


maskStrategy()#

maskStrategy(strategy: MaskStrategy): this;

Defined in: core/ReelSetBuilder.ts:437

Custom mask strategy for the viewport. Defaults to RectMaskStrategy (one clip rect per reel. clean for pyramid + uniform layouts).

Use SharedRectMaskStrategy when reels have horizontal gaps AND symbols (typically big symbols) need to overlap across reel boundaries. the per-reel default would clip them at the gaps.

Or pass any custom MaskStrategy for non-rectangular masks (rounded frames, hexagonal grids, etc.).

Parameters#

ParameterType
strategyMaskStrategy

Returns#

this

Example#

import { SharedRectMaskStrategy } from 'pixi-reels';
builder.maskStrategy(new SharedRectMaskStrategy())

motionModel()#

Call Signature#

motionModel(model: "tween"): this;

Defined in: core/ReelSetBuilder.ts:510

Choose how reel.speed gets from one value to the next.

  • 'tween' (default) - phases tween the speed with a GSAP ease. Every existing game uses this and nothing about it changes.
  • 'drive' - the reel integrates toward a target speed under an acceleration bound, and phases set that target instead of tweening.

Why the second one exists: an ease applied to a SPEED is a step in acceleration. power2.out puts peak deceleration on the very first frame and decays from there, which is why the stock tease reads as the speed setting changing rather than as the reel slowing down. Bounding acceleration is the physical model instead - the reel can only change speed so fast, whatever it is asked for. Add jerk and the acceleration itself ramps, which is the pedal feel: down over time rather than stamped.

The drive also makes interruption free. A skip press, a mid-tease retarget or a setSpeed mid-spin is a new target assignment, and the motion stays continuous by construction - there is no timeline to kill and no leftover speed to reconcile.

Set at build time only. There is no runtime toggle, because handing the speed field to a second owner while a phase is mid-tween is exactly the failure this design avoids.

Bounds are profile-relative by default: accelFrames: 20 means “reach whatever the active profile calls full speed in 20 frames”, so Turbo accelerates harder than Normal in proportion to how much faster it spins. The absolute form (accel, px/frame^2) is still accepted, but one fixed number cannot serve the shipped presets - their spinSpeed runs 30 / 50 / 80, so an absolute bound tuned for Normal makes SuperTurbo take 53 frames to reach speed instead of 20, i.e. a turbo that starts SLOWER than normal.

Parameters
ParameterType
model"tween"
Returns

this

Examples
builder.motionModel('drive', { accelFrames: 20, decelFrames: 34, jerkFrames: 260 })
// Single-profile game, tuned in raw px/frame^2.
builder.motionModel('drive', { accel: 1.5, decel: 0.9, jerk: 0.12 })

Call Signature#

motionModel(model: "drive", config: ReelDriveConfig): this;

Defined in: core/ReelSetBuilder.ts:511

Choose how reel.speed gets from one value to the next.

  • 'tween' (default) - phases tween the speed with a GSAP ease. Every existing game uses this and nothing about it changes.
  • 'drive' - the reel integrates toward a target speed under an acceleration bound, and phases set that target instead of tweening.

Why the second one exists: an ease applied to a SPEED is a step in acceleration. power2.out puts peak deceleration on the very first frame and decays from there, which is why the stock tease reads as the speed setting changing rather than as the reel slowing down. Bounding acceleration is the physical model instead - the reel can only change speed so fast, whatever it is asked for. Add jerk and the acceleration itself ramps, which is the pedal feel: down over time rather than stamped.

The drive also makes interruption free. A skip press, a mid-tease retarget or a setSpeed mid-spin is a new target assignment, and the motion stays continuous by construction - there is no timeline to kill and no leftover speed to reconcile.

Set at build time only. There is no runtime toggle, because handing the speed field to a second owner while a phase is mid-tween is exactly the failure this design avoids.

Bounds are profile-relative by default: accelFrames: 20 means “reach whatever the active profile calls full speed in 20 frames”, so Turbo accelerates harder than Normal in proportion to how much faster it spins. The absolute form (accel, px/frame^2) is still accepted, but one fixed number cannot serve the shipped presets - their spinSpeed runs 30 / 50 / 80, so an absolute bound tuned for Normal makes SuperTurbo take 53 frames to reach speed instead of 20, i.e. a turbo that starts SLOWER than normal.

Parameters
ParameterType
model"drive"
configReelDriveConfig
Returns

this

Examples
builder.motionModel('drive', { accelFrames: 20, decelFrames: 34, jerkFrames: 260 })
// Single-profile game, tuned in raw px/frame^2.
builder.motionModel('drive', { accel: 1.5, decel: 0.9, jerk: 0.12 })

multiways()#

multiways(config: MultiWaysConfig): this;

Defined in: core/ReelSetBuilder.ts:543

Configure this slot as MultiWays: per-spin cell variation. Pass minCells, maxCells, and the fixed reel pixel height. After build, call reelSet.setShape(cellsPerReel) mid-spin to set the next stop’s shape.

Mutually exclusive with big-symbol registration (SymbolData.size). Mutually exclusive with cascade mode in v1.

Parameters#

ParameterType
configMultiWaysConfig

Returns#

this


offsetConfig()#

offsetConfig(config: OffsetConfig): this;

Defined in: core/ReelSetBuilder.ts:751

Set X-axis offset config (e.g., trapezoid perspective). Default: ‘none’.

Parameters#

ParameterType
configOffsetConfig

Returns#

this


orientation()#

orientation(orientation: Orientation): this;

Defined in: core/ReelSetBuilder.ts:263

Strip travel axis for the whole set. 'vertical' (default) runs strips on Y with reels marched along X; 'horizontal' runs them on X with reels marched along Y.

Everything else is orientation-neutral: uniform grids, pyramids (visibleCellsPerReel), MultiWays, big symbols and cascades all work on either axis from the same arithmetic. symbolSize(width, height) stays SCREEN-space, so a horizontal set gives the cell its main extent through width where a vertical one uses height.

Parameters#

ParameterType
orientationOrientation

Returns#

this


phases()#

phases(configurator: (factory: PhaseFactory) => void): this;

Defined in: core/ReelSetBuilder.ts:864

Override default phases.

Configurators are DEFERRED to build() and run after the built-in registrations, so a .phases(...) override of a cascade or MultiWays key wins regardless of where it sits in the chain. Running them at call time meant .tumble() / .multiways() registered their defaults later, inside build(), and silently clobbered any 'cascade:*' / 'adjust' override the caller had made. no error, just the built-in phase.

Multiple calls are kept and applied in call order, so the last override of a given key wins.

Parameters#

ParameterType
configurator(factory: PhaseFactory) => void

Returns#

this


pinMigrationDuration()#

pinMigrationDuration(value: number | ((reelIndex: number) => number)): this;

Defined in: core/ReelSetBuilder.ts:558

AdjustPhase tween duration in ms (MultiWays only). Pass a number for a uniform duration across reels, or a function (reelIndex) => number for per-reel control. Default: 200. Pass 0 for an instant snap (no tween).

AdjustPhase plays on top of whatever stop staggering you’ve configured; its duration is independent of stopDelay.

Parameters#

ParameterType
valuenumber | ((reelIndex: number) => number)

Returns#

this


pinMigrationEase()#

pinMigrationEase(ease: string): this;

Defined in: core/ReelSetBuilder.ts:573

GSAP easing string used by AdjustPhase tweens (MultiWays only). Applied to both the cell-resize tween and any pin-overlay migration tween. Defaults to 'power2.out'. See gsap.com/docs/v3/Eases for the full vocabulary.

Parameters#

ParameterType
easestring

Returns#

this

Example#

builder.pinMigrationEase('back.out(1.4)')          // pop-in feel
builder.pinMigrationEase('expo.inOut')             // slow start + slow end

poolCapacity()#

poolCapacity(maxPerSymbol: number): this;

Defined in: core/ReelSetBuilder.ts:792

Override the per-symbol-id recycle-pool capacity. By default the engine sizes the pool to the whole strip (every visible + buffer cell), so even a grid that is briefly all one symbol recycles instead of churning through destroy() + recreate. Set this only to cap memory on very large grids, or to raise headroom for unusually heavy simultaneous symbol swaps.

Parameters#

ParameterType
maxPerSymbolnumber

Returns#

this


randomSymbols()#

randomSymbols(pool: SymbolPool, scope?: SymbolPoolScope): this;

Defined in: core/ReelSetBuilder.ts:671

Narrow what the engine may draw when it fills a cell you did not name.

weights() sets the base table for every reel; this layers pools on top of it, so a symbol can be common on the strip and impossible in the buffer cells, or heavy on one reel only. Call it once per scope.

Buffer pools apply ON TOP of the spinning ones (see SymbolPoolScope), and the same pools are reachable at run time as reelSet.randomSymbols, which is where a game mode switch belongs.

Parameters#

ParameterType
poolSymbolPool
scopeSymbolPoolScope

Returns#

this

Example#

.randomSymbols({ exclude: ['EMPTY'] })                       // every reel
.randomSymbols({ exclude: ['COIN'] }, { slots: 'buffer' })   // buffers only
.randomSymbols({ weights: { WILD: 40 } }, { reel: 2 })       // reel 2 only

reelAnchor()#

reelAnchor(anchor: ReelAnchor): this;

Defined in: core/ReelSetBuilder.ts:222

Vertical alignment of short reels inside the tallest reel’s box. Default ‘center’.

Parameters#

ParameterType
anchorReelAnchor

Returns#

this


reelExtents()#

reelExtents(heights: number[]): this;

Defined in: core/ReelSetBuilder.ts:216

Per-reel pixel-box heights. Length MUST equal reels().

  • Pyramid: defaults to visibleCellsPerReel[i] * symbolHeight. Override to make all reels the same height with different cell heights per reel.
  • MultiWays: every entry equals the same fixed reel height. Cell height per reel is derived as reelExtent / visibleCells[i].

Precedence: when both reelExtents and reelAnchor are set, reelExtents wins. anchor is derived from the explicit boxes.

Parameters#

ParameterType
heightsnumber[]

Returns#

this


reelPixelHeights()#

reelPixelHeights(_heights: number[]): never;

Defined in: core/ReelSetBuilder.ts:167

Parameters#

ParameterType
_heightsnumber[]

Returns#

never

Deprecated#

Removed in v2 - throws. Use ReelSetBuilder.reelExtents.


reels()#

reels(count: number): this;

Defined in: core/ReelSetBuilder.ts:174

Set number of reel columns.

Parameters#

ParameterType
countnumber

Returns#

this


reelStacking()#

reelStacking(order: Stacking): this;

Defined in: core/ReelSetBuilder.ts:247

Render order of reels inside the set. Default 'ascending'. the last reel draws in front, which reads as “rightmost on top” for vertical and “bottom-most on top” for horizontal.

Parameters#

ParameterType
orderStacking

Returns#

this


renderer()#

renderer(renderer: Renderer): this;

Defined in: core/ReelSetBuilder.ts:379

The renderer curveMode('warp') draws each reel’s texture with. Required for warp mode and unused otherwise.

Parameters#

ParameterType
rendererRenderer

Returns#

this

Example#

builder.renderer(app.renderer)

rng()#

rng(fn: () => number): this;

Defined in: core/ReelSetBuilder.ts:780

Inject the source of randomness used to fill the scrolling strip (buffer fill, the symbols shown during SPIN before setResult lands, nudge padding). Must return a value in [0, 1). Default: Math.random.

Why you’d set this: server-authoritative outcomes do not make the on-screen strip reproducible — the symbols a player sees scrolling are drawn from this RNG. Injecting a seeded, audited PRNG lets you replay the exact visual sequence from a seed, which provably-fair and regulated real-money deployments are eventually required to produce.

Parameters#

ParameterType
fn() => number

Returns#

this

Example#

import { ReelSetBuilder } from 'pixi-reels';
const seeded = mulberry32(serverSeed); // your audited PRNG
const reelSet = new ReelSetBuilder().reels(5).visibleCells(3)
  .symbols(...).ticker(app.ticker).rng(seeded).build();

skipMode()#

skipMode(mode: SkipMode): this;

Defined in: core/ReelSetBuilder.ts:875

What a skip press does to the reels it frees when the call does not say: 'slam' places them (the default), 'quicken' asks each for its landing sooner. See SkipMode. requestSkip({ mode }) and skipSpin({ mode }) override it per press; slamStop() is always a slam.

Parameters#

ParameterType
modeSkipMode

Returns#

this


speed()#

speed(name: string, profile: SpeedProfile): this;

Defined in: core/ReelSetBuilder.ts:739

Add a named speed profile.

Parameters#

ParameterType
namestring
profileSpeedProfile

Returns#

this


spinningMode()#

spinningMode(mode: SpinningMode): this;

Defined in: core/ReelSetBuilder.ts:840

Set the spinning mode. Default: StandardMode.

Parameters#

ParameterType
modeSpinningMode

Returns#

this


symbolData()#

symbolData(overrides: Record<string, Partial<SymbolData>>): this;

Defined in: core/ReelSetBuilder.ts:695

Per-symbol metadata overrides (zIndex, unmask, or a custom weight that replaces the one from weights()). Merged into the final symbolsData map; any field you don’t specify falls back to the default.

zIndex sorts within ONE reel’s container only. it can never lift a symbol above the reel to its right (reels are separate containers). Cross-reel and out-of-mask layering needs unmask: true, which is an at-rest presentation: while the reel spins the symbol stays masked like everything else; on land, visible-cell instances are lifted into the viewport-wide unmaskedContainer (above every reel and the mask) and pulled back down when the next spin starts.

Parameters#

ParameterType
overridesRecord<string, Partial<SymbolData>>

Returns#

this

Example#

.symbolData({
  wild:  { zIndex: 5 },                // above reel-mates (same reel only)
  bonus: { zIndex: 10, unmask: true }, // landed: above all reels + mask
})

symbolGap()#

symbolGap(x: number, y: number): this;

Defined in: core/ReelSetBuilder.ts:586

Set gap between symbols. Default: { x: 0, y: 0 }.

Parameters#

ParameterType
xnumber
ynumber

Returns#

this


symbols()#

symbols(configurator: (registry: SymbolRegistry) => void): this;

Defined in: core/ReelSetBuilder.ts:644

Configure symbols via a registry callback.

Parameters#

ParameterType
configurator(registry: SymbolRegistry) => void

Returns#

this


symbolSize()#

symbolSize(width: number, height: number): this;

Defined in: core/ReelSetBuilder.ts:579

Set symbol dimensions in pixels.

Parameters#

ParameterType
widthnumber
heightnumber

Returns#

this


symbolZIndex()#

symbolZIndex(resolver: SymbolZIndexResolver): this;

Defined in: core/ReelSetBuilder.ts:730

Decide every symbol view’s zIndex yourself instead of taking the engine’s symbolData.zIndex * 100 + cellStackingIndex.

The resolver is the single source of symbol draw order once set: the engine asks it again whenever a symbol’s id, cell, reel shape or rest state changes (every wrap, snap, swap, reshape, landing and departure). It must be pure and cheap. Return ctx.defaultZIndex for the ids you do not care about.

Cross-reel order only exists for symbols that share a container: an unmask: true symbol at rest is lifted into the viewport-wide unmaskedContainer, where the value orders it against every other lifted symbol. A masked symbol stays inside its reel’s own container, which has its own zIndex (reelStacking), so a resolver’s reel term does nothing for it. ctx.atRest tells the two situations apart: the usual shape keeps the engine’s order in motion and grades at rest.

Parameters#

ParameterType
resolverSymbolZIndexResolver

Returns#

this

Example#

.symbolZIndex((ctx) => {
  if (!ctx.atRest || ctx.visibleCell === null) return ctx.defaultZIndex;
  const grade = GRADES[ctx.symbolId];
  return grade === undefined
    ? ctx.defaultZIndex
    : grade * 1000 + ctx.visibleCell * 10 + ctx.reelIndex;
})

ticker()#

ticker(ticker: Ticker): this;

Defined in: core/ReelSetBuilder.ts:758

Set the PixiJS ticker for frame updates.

Parameters#

ParameterType
tickerTicker

Returns#

this


tumble()#

tumble(config?: TumbleConfig): this;

Defined in: core/ReelSetBuilder.ts:915

Enable tumble cascade mechanics. Replaces strip-spin + bounce-stop with a three-phase pipeline:

  1. cascade:fall. on spin(), existing visible symbols fall off the bottom of the viewport.
  2. cascade:place. when setResult() arrives, new symbol identities swap into the buffer at their final grid positions.
  3. cascade:dropIn. new symbols animate from above (and survivors slide down to fill holes) into the grid.

For a Moment B refill after wins are cleared, call reelSet.refill({ winners, grid }). that skips fall + wait and runs place + dropIn only, with gravity-correct geometry driven by the winners list (untouched symbols don’t animate; survivors slide; new symbols come from above).

Every phase boundary fires a cascade:* event on reelSet.events. per-symbol events (cascade:fall:symbol / cascade:dropIn:symbol) carry the symbol, view, and the timing the library is about to apply, so listeners can run parallel tweens on any other property in sync with the library’s view.y motion.

Override any individual phase via .phases(f => f.register('cascade:fall', MyPhase)). Chain position does not matter. .phases(...) is applied after these defaults regardless. Subclasses of the cascade phases need registerFactory and the extra constructor args, which resolveTumbleConfig(config) produces.

Parameters#

ParameterType
config?TumbleConfig

Returns#

this

Example#

builder.tumble({
  fall:   { duration: 300, ease: 'sine.in',    cellStagger: 60 },
  dropIn: { duration: 600, ease: 'power2.out', cellStagger: 60, distance: 'perHole' },
});

visibleCells()#

visibleCells(count: number): this;

Defined in: core/ReelSetBuilder.ts:187

Number of visible cells per reel (uniform across all reels). Mutually exclusive with visibleCellsPerReel(). calling both throws at build().

Parameters#

ParameterType
countnumber

Returns#

this

Example#

builder.reels(5).visibleCells(3)  // classic 5x3

visibleCellsPerReel()#

visibleCellsPerReel(cells: number[]): this;

Defined in: core/ReelSetBuilder.ts:199

Per-reel static cell counts. Length MUST equal reels(). Mutually exclusive with visibleCells(); calling both throws at build().

Parameters#

ParameterType
cellsnumber[]

Returns#

this

Example#

builder.reels(5).visibleCellsPerReel([3, 5, 5, 5, 3])  // pyramid

visibleRows()#

visibleRows(_count: number): never;

Defined in: core/ReelSetBuilder.ts:155

Parameters#

ParameterType
_countnumber

Returns#

never

Deprecated#

Removed in v2 - throws. Use ReelSetBuilder.visibleCells.

TypeScript catches a v1 call at compile time, but an untyped consumer would otherwise get “x.visibleRows is not a function”, which names neither the replacement nor the codemod. These stubs do.


visibleRowsPerReel()#

visibleRowsPerReel(_cells: number[]): never;

Defined in: core/ReelSetBuilder.ts:160

Parameters#

ParameterType
_cellsnumber[]

Returns#

never

Deprecated#

Removed in v2 - throws. Use ReelSetBuilder.visibleCellsPerReel.


weights()#

weights(weights: Record<string, number>): this;

Defined in: core/ReelSetBuilder.ts:650

Set weights for random symbol generation.

Parameters#

ParameterType
weightsRecord<string, number>

Returns#

this