Every canvas below runs the exact same scripted spin: a 6×4 board of real Thunderkick spine symbols lands with a pre-wired 3-cluster of low1 on row 2, those three winners play their authored explode clip (compressed per canvas via TrackEntry.timeScale to match each tumble’s tempo), the loop pauses for a configured beat, then the cascade refill drops survivors into the holes and brings a fresh row from above. Two things vary between canvases:
.tumble({ fall, dropIn }). the animation feel itself.PAUSE_AFTER_REMOVAL_MS. the breathing room between the explosion and the refill drop-in. Different feels want different pauses: snappy slams want ~8 frames (133 ms), slow / dramatic feels want 18-24 frames (300-400 ms). Every timing on this page is a whole number of 60 fps frames written in ms (267 = 16 frames, 400 = 24, 50 = 3). animations land on frame boundaries instead of arbitrary milliseconds.
Classic. the all-rounder default
Loading recipe…
.tumble({
fall: { duration: 267, ease: 'power2.in', rowStagger: 33 },
dropIn: { duration: 400, ease: 'power2.in', rowStagger: 50, distance: 'perHole' },
})
Gravity on both ends: the board accelerates out, the new symbols accelerate in and stop dead on the grid. no settle animation at all. Two ease families are banned here by the art: overshoot (back, bounce). an overshooting frame gaps from its neighbours and only reads well on frameless art. and decelerating settles (*.out). a framed tile easing gently into place reads mushy; a falling tile hits its slot like the physical object it’s drawn as.
Slow drop. long hang, heavy stagger
Loading recipe…
.tumble({
fall: { duration: 333, ease: 'power2.in', rowStagger: 67 },
dropIn: { duration: 700, ease: 'power2.in', rowStagger: 67, distance: 'perHole' },
})
The slow, dramatic variant: a long 700 ms (42-frame) power2.in with a heavy stagger. each row hangs at the top, then accelerates into its slot. The pacing lives entirely in duration + stagger; the landing itself still hits dead. (On frameless art this slot is where you’d reach for bounce.out.)
Slam. hard-landing, sub-half-second tumble
Loading recipe…
.tumble({
fall: { duration: 167, ease: 'power3.in', rowStagger: 17 },
dropIn: { duration: 250, ease: 'power3.in', rowStagger: 17, distance: 'perHole' },
})
power3.in on both ends. the steepest acceleration into a dead stop. The whole tumble plays in under half a second. A reasonable basis for a turbo mode toggle on top of a default-classic build.
Rain column. board-falls-as-a-slab
Loading recipe…
.tumble({
fall: { duration: 233, ease: 'power2.in', rowStagger: 0 },
dropIn: { duration: 367, ease: 'power2.in', rowStagger: 0, distance: 'auto' },
})
rowStagger: 0 makes every row start together. distance: 'auto' overrides the gravity-correct per-hole distance with a uniform full-column-height drop, so the new column appears as a coherent slab from above the viewport. Match-3, puzzle, or chess-board grids where “the board itself moves” is the visual idea.
Wave. rolling top-to-bottom reveal
Loading recipe…
.tumble({
fall: { duration: 183, ease: 'power2.in', rowStagger: 83 },
dropIn: { duration: 333, ease: 'power2.in', rowStagger: 117, distance: 'perHole' },
})
Heavy rowStagger (117 ms = 7 frames on drop-in) makes each row land in its own beat. the wave IS the stagger. Row 0 lands, then row 1, then row 2. Pair with row-by-row sound cues if you want a per-row audio hit. The more cascades in a chain, the more rows arrive in sequence.
Picking between them
| Feel | Pause | Pick when | Avoid when |
|---|---|---|---|
| Classic | 250 ms (15f) | Default if you have no other constraints | . |
| Slow drop | 333 ms (20f) | Long hang, heavy stagger | Turbo-first games. the hang slows the perceived pace |
| Slam | 133 ms (8f) | Turbo mode, sub-half-second tumbles | You want a longer beat between cascades |
| Rain column | 400 ms (24f) | Match-3 / chess-board / puzzle grids | Reels are visually distinct (the cohesive slab look fights the column gaps) |
| Wave | 300 ms (18f) | Strong per-row stagger, row-by-row arrival | Very dense grids. the stagger makes the whole tumble feel long |
The Pause column is PAUSE_AFTER_REMOVAL_MS in each recipe. the gap between the win-fade ending and the refill drop-in starting. It’s not a library setting; it’s just an await wait(ms) in your spin loop. Tuning it per feel is the single biggest lever on cascade pacing after the tumble config itself.
Beyond these five: anything goes. ease accepts any GSAP easing string. rowStagger is plain ms. distance is 'perHole' / 'auto' / a number. Mix to taste; the algorithm and lifecycle stay exactly the same.
Going beyond config
If a feel needs effects the config can’t express (squish, sticky badge tweens, spine state transitions, particle bursts). those are events, not config fields. Subscribe to cascade:fall:symbol / cascade:dropIn:symbol and run parallel tweens on any view property; they fire before the library’s view.y tween so your tweens stay in sync.
See the full tumble recipe doc for the per-symbol event hooks, the cascading-multiplier pattern, and the phase-override escape hatch.
Related
- Cascade 6×5 tumble. the same recipe with cluster-detection logic and a multiplier counter.
- Spin first, cascade after. open with a strip-spin, cascade the respins.
- Cascade wins. present, destroy, refill. the destroy stage three ways, including a
WinPresenter-driven pass.