GSAP Timeline Studio
Compose a scroll-tied GSAP timeline for the Custom Code (Motion Snippet) field — the things the built-in Scroll Motion effects can't do: choreograph several targets on one timeline, real 3D, full per-property control, keyframes, loops and advanced stagger. Build it below, watch it run, copy the code.
Trigger start & Scrub are options next to the code field in the builder. Loop is written into the snippet.
tl
.from(el, { y: 60, opacity: 0, duration: 0.8, ease: 'power2.out' })
.from(el.querySelectorAll('.card'), { rotationY: 60, opacity: 0, transformPerspective: 1000, duration: 0.8, ease: 'power2.out', stagger: 0.1 }, '<');When 20% into view (default)Scrub → Play once on enterOne tl (already ScrollTrigger-tied), your el and its children — composed into a single scroll timeline. All GSAP core, so every snippet pastes and runs as-is.
How the Custom Code field works
Your snippet runs with three things already set up — you just add tweens to the timeline:
| You get | What it is |
|---|---|
el | This element. Target its children with el.querySelectorAll('.card'). |
tl | A gsap.timeline() already tied to a ScrollTrigger on el. Add tweens to it. |
gsap | The GSAP object, if you need it directly. |
- Admin-only by design. Baked snippets execute only when the page author can use unfiltered HTML (an admin), so untrusted code never runs.
- Reduced motion & mobile are respected automatically — snippets skip for visitors who ask for reduced motion, and can be disabled on phones.
- GSAP core + ScrollTrigger only. SplitText / MorphSVG / MotionPath and other plugins aren't guaranteed to be loaded for a snippet, so the Studio stays on core — which still covers everything here.
- Trigger start & scrub are options next to the code field (the snippet is what animates; those control when). Loop is written into the snippet.
Why use this over the built-in effects?
The Scroll Motion tiles apply one effect to one target. Custom Code lets you do what they can't — and the Studio writes it for you:
- Choreograph a composition — heading rises, then cards stagger in, then a button pops, all on one timeline.
- Real 3D —
rotationX/Y+transformPerspectivefor card flips, door-opens, cube turns. - Keyframes — multi-stage motion (bounce, wobble, shake, glitch) impossible with a single preset.
- Loops —
repeat/yoyofor float / pulse / breathe that never stops. - Advanced stagger — from center / edges / random, for grids and cascades.
Advanced recipes
Paste-ready snippets that are flatly impossible in the options UI (all core GSAP):
Heading, then a 3D-flip card stagger:
tl.from(el.querySelector('h2'), { y: 40, opacity: 0, duration: 0.7, ease: 'power3.out' })
.from(el.querySelectorAll('.card'), {
rotationY: 60, opacity: 0, transformPerspective: 1000,
stagger: { each: 0.1, from: 'start' }, duration: 0.7, ease: 'power2.out'
}, '-=0.3');
Letter cascade (wrap letters in <span class="ch"> in your Text Block):
tl.from(el.querySelectorAll('.ch'), { yPercent: 120, opacity: 0, stagger: 0.04, ease: 'power4.out', duration: 0.7 });
Grid-stagger reveal from the centre, with overshoot:
tl.from(el.querySelectorAll('.card'), {
scale: 0, opacity: 0, transformOrigin: 'center',
stagger: { grid: 'auto', from: 'center', amount: 0.6 }, ease: 'back.out(1.7)'
});
Ambient floating loop (never stops):
tl.to(el, { y: -12, duration: 1.6, ease: 'sine.inOut', repeat: -1, yoyo: true });
Bounce-in with keyframes:
tl.to(el, { keyframes: { y: [60, 0, -18, 0], opacity: [0, 1, 1, 1] }, duration: 1, ease: 'power1.out' });
Glitch (keyframed jitter):
tl.to(el, { keyframes: { x: [0, -6, 6, -4, 0], skewX: [0, 10, -8, 4, 0] }, duration: 0.5, ease: 'steps(5)' });
Where to learn more
The generated code is standard GSAP — the official GSAP docs cover every tween property, ease, the timeline position parameter, and advanced stagger if you want to go further.