The built-in phases run named step lists. StartPhase runs delay, launch, pull, accelerate, announce, StopPhase runs delay, spinOut, land, bounce, AnticipationPhase runs tease, and f.register('stop', StopPhase, { steps }) hands you the list before it runs. These recipes are the feel work that used to mean a subclass: each is one insertBefore / insertAfter / replaceStep, or a list built by hand, and every one keeps slam and quicken working because the waits stay marked cut. The step API itself is on the Phases page.
Stagger curves#
The flat stagger arrives as ctx.config.delay and the delay step is the only place it is spent, so a curve is one replaceStep per phase: the start ripples out from the middle reel, the stop’s gaps grow so reels 1-3 fall fast and reel 5 hangs. The profile still owns the unit, and the second readout line is measured landings, not the schedule.
Gotcha: keep { cut: true } on the replacement. It is a wait, and a quicken press must cut it the way it cuts the flat one.
Loading recipe…
A wind-up launch#
The built-in pull is a two-pixel twitch. Replace it with a real drag back, insert a hold after it, and the untouched accelerate ramps from wherever the reel is. Tap the readout to switch the wind-up off and compare.
Gotcha: cover both motion models the way the built-in does. Under the drive, name a targetSpeed and wait; under the tween, tween reel.speed. reel.hasDrive tells you which.
Loading recipe…
A landing kick, with dust#
One step after land, before bounce: the set kicks and a puff spreads under the reel, harder on the last one. The step returns nothing, so the bounce starts on the same frame. Return the tween and the phase waits for it: that is the difference between an effect and a beat.
Gotcha: a slam lands through onSkip, not through the list, so a step after land does not fire on a slam. FX that must play on a slam too hangs off spin:reelLanded. A quicken keeps the list.
Loading recipe…
Beats and FX that follow the speed mode#
ctx.profile is the profile the game registered under the active speed name, custom fields included. A breath beat before the spin-out and a glow after land both read the profile, so normal gets both and turbo gets neither, and the glow’s fade rides bounceDuration. Tap the readout to switch speeds; the skip button here is requestSkip({ mode: 'quicken', speed: 'turbo' }), which swaps the profile the same way.
Gotcha: a step never asks “is this turbo”. Put the decision on the profile and every speed mode you add later comes with its own answer.
Loading recipe…
A spotlight around the tease#
AnticipationPhase runs one step and is created on the teased reel only, so “shade the other reels while the tease runs” is a list built by hand around the built-in: [dim, ...steps, lift]. Both wraps are awaited, 150 ms each, so the spotlight is on before the reel starts to crawl and off before the stop takes over.
Gotcha: a slam cancels the list in flight and lift never runs. Clear the shades on spin:complete as the backstop. A quicken cuts the tease step and lift still runs.
Loading recipe…
One extra beat on the last reel#
Every reel runs the same list, so a per-reel beat is a step that returns nothing on the reels it does not concern. suspense waits 700 ms before reel 5’s spin-out and is instant on the others, pulsing the backlight while it waits.
Gotcha: a step that starts something must own it both ways out. ctx.wait resolves early when the step is cut, ctx.signal fires when it is cancelled; one stop handles the natural end, a quicken and a slam.
Loading recipe…