Staggered ARRIVAL cascade — words/elements whip in from below (one consistent direction), each starting before the previous settles, an accelerating wave that resolves into a composed layout. Title cards, segment openers, list/feature intros. Opacity is BINARY 0→1 via tl.set — never fade an arrival.
Staggered ARRIVAL cascade: words/elements whip in from below (one consistent direction),
each starting before the previous settles — an accelerating wave that resolves into a
composed layout. Title cards, segment openers, list/feature intros.
This is an in-scene arrival, not a seam. Its seam sibling is the waterfall CUT
(cut-the-curve doctrine skill, seams/waterfall-cut.md); do not mix their rules:
Entry (this rule — arrival)
Waterfall Cut (seam)
Opacity
BINARY 0→1 via tl.set at entry — never fade
ignites at 0.35 mid-path — the fade IS the velocity trick
Axis default
Y, from below
X, riding the current
Outgoing side
none
words ramp out on mirrored power4.in
Choreography
Overlap, don't queue — next element starts within ±2 frames of the previous
settling; gaps SHRINK across the cascade; the last element snaps.
Velocity varies by weight — heavy/anchor elements travel further and longer;
light words/punctuation snap in tight:
Parameter
Anchor/heavy
Normal word
Light/punctuation
Y offset
60–80px
40–50px
30–48px
Duration
0.16–0.20s
0.13–0.16s
0.10–0.13s
Overlap
0–2f gap
1f overlap
1–2f overlap
Ease power4.out (expo.out for extra snap); never .inOut on an entry.
One direction per cascade.
Split the FINAL word into fragments to extend the climax; fragments travel further.
Post-settle, the group usually slides to make room for the next beat — that's
nudge-curve.md.
JS
Each element: tl.set (instant reveal + offset) then tl.to (whip to rest).
nextStart = prevStart + prevDuration − (overlapFrames × F); +overlap = cascade,
−overlap = deliberate gap. CSS: elements start opacity: 0; display: inline-block.
varF=1/60;vart0=0.1;// anchor (heaviest): biggest travel, longest settle
tl.set("#el-1",{opacity:1,y:80},t0);tl.to("#el-1",{y:0,duration:0.18,ease:"power4.out"},t0);// normal word: 2 frames after the anchor finishes
vart1=t0+0.18+2*F;tl.set("#el-2",{opacity:1,y:45},t1);tl.to("#el-2",{y:0,duration:0.15,ease:"power4.out"},t1);// light word: 1 frame BEFORE the previous finishes (overlap)
vart2=t1+0.15-F;tl.set("#el-3",{opacity:1,y:40},t2);tl.to("#el-3",{y:0,duration:0.14,ease:"power4.out"},t2);// split final-word fragments: tightest overlap, extra travel (lighter)
vart3=t2+0.14-F;tl.set("#frag-a",{opacity:1,y:70},t3);tl.to("#frag-a",{y:0,duration:0.16,ease:"power4.out"},t3);vart4=t3+0.14-F;tl.set("#frag-b",{opacity:1,y:70},t4);tl.to("#frag-b",{y:0,duration:0.15,ease:"power4.out"},t4);// punctuation: lightest, fastest
vart5=t4+0.13-2*F;tl.set("#dot",{opacity:1,y:48},t5);tl.to("#dot",{y:0,duration:0.12,ease:"power4.out"},t5);
Anti-patterns
Don't
Instead
Queued entries (each waits for the previous to settle)
Overlap ±1–2 frames — the cascade is a wave, not a queue
Same offset/duration for every cascade element
Vary by weight: anchors travel further, punctuation snaps
Gradual opacity fade on an arrival
Binary 0→1 via tl.set — fading fights the snap (seam cuts fade; arrivals don't)