Motion delivery flow
A three stage diagram showing content in place first, then a short reveal, then a calm settled state.
Motion is not proof that a site is expensive. A clear hierarchy is. Animation should reveal the next thing, support a decision, then get out of the way. If the message only works after the effect has finished, the effect has won and the page has lost.
1. Start with the finished state
Build readable HTML and a complete visual layout before JavaScript arrives. Then add a small opacity and transform reveal to secondary elements. The title leads. Supporting copy follows. Decorative work comes last, if it comes at all.
gsap.from('[data-reveal]', {
opacity: 0,
y: 18,
duration: 0.7,
ease: 'power2.out',
stagger: 0.08
});Use a reveal once for an entrance. Replaying a hero every time somebody scrolls back to check a price is a tiny punishment dressed as polish.
2. Put scroll control on stories, not furniture
ScrollTrigger earns its place when progress through the page changes the thing being explained: a product walkthrough, a gallery position or a before and after state. It is not required for every card drifting six pixels into view. For a pinned sequence, set the content up as a timeline and give each beat one obvious purpose.
const tl = gsap.timeline({
scrollTrigger: {
trigger: '.product-story',
start: 'top top',
end: '+=900',
scrub: 0.6,
pin: true
}
});
tl.to('.story-a', { autoAlpha: 0 })
.from('.story-b', { autoAlpha: 0, y: 16 });Keep the static copy useful without the sequence. Test it with JavaScript disabled and at narrow widths. If the story becomes a hole in the page, it was never a story.
3. Respect reduced motion in the same component
The user preference is a real product requirement. GSAP matchMedia() can place animation setup behind the motion preference and revert the work when the condition changes. The reduced path should show the final state immediately. It should not replace one animation with a slower, polite looking animation.
const mm = gsap.matchMedia();
mm.add('(prefers-reduced-motion: no-preference)', () => {
gsap.from('[data-reveal]', { opacity: 0, y: 18, stagger: 0.08 });
return () => gsap.set('[data-reveal]', { clearProps: 'all' });
});
mm.add('(prefers-reduced-motion: reduce)', () => {
gsap.set('[data-reveal]', { autoAlpha: 1, y: 0 });
});4. Scope and clean up the work
In a component based app, create animations inside a scoped context and revert it when the component leaves. That clears the animations and ScrollTriggers created in that context. It prevents duplicate triggers after navigation and makes the page predictable in development.
const ctx = gsap.context(() => {
// animation setup for this component only
}, element);
return () => ctx.revert();5. Keep the movement cheap and the copy in charge
Prefer transform and opacity for simple reveals, then profile the real page on a modest mobile device. Avoid treating any CSS property as a performance promise. Large images, expensive filters, layout work and a busy main thread can still make a tasteful tween feel rough.
GSAP is usable in commercial websites and applications under its standard licence. The important restriction is for visual animation builders that compete with Webflow's animation tooling. Check the current licence before shipping a tool in that category.
A practical release check
- Can somebody read every key message before animation runs?
- Does reduced motion show the final state with no movement?
- Does navigating away remove every trigger?
- Does the movement explain progress, hierarchy or feedback?
- Can you delete one effect and make the page clearer?
Velocity Components is built around this standard: useful content first, then motion with a reason. Browse the component library for production ready building blocks, or read the ScrollTrigger pinning guide before making a section stick just because you can.








