
Stagger card reveal
How it works
This animation reveals cards one by one using a staggered fade-up effect.
The animation targets elements with the attribute data="bottom" and separates cards into two groups:
- Cards already visible in the viewport animate immediately on page load.
- Remaining cards animate as they enter the viewport while scrolling.
Each card transitions from lower opacity and a downward Y offset to its original position, creating a smooth layered reveal effect.
Customization options
- Use the attribute
data="bottom"to apply the animation. - Adjust the stagger value to control the delay between cards.
- Default:
0.3 - Lower value → faster sequence
- Higher value → more dramatic reveal
- Default:
- Customize the Y movement distance.
- Default:
80 - Smaller values create subtler motion.
- Default:
- Modify the animation duration.
- Default:
0.8s
- Default:
- Change the easing style for different motion feels.
power2.out→ smooth and modernpower3.out→ softer finish
- Adjust the ScrollTrigger start position.
- Default:
"top 85%" - Earlier trigger:
"top 95%" - Later trigger:
"top 70%"
- Default:
Features
- Smooth staggered card entrance animation
- Instantly animates visible cards on page load
- Reveals additional cards on scroll
- Creates depth and visual rhythm in layouts
- Fully customizable timing, spacing, and movement
- Lightweight and performance-friendly for large grids
1gsap.registerPlugin(ScrollTrigger);
2
3const cards = gsap.utils.toArray('[data="bottom"]');
4
5// Helper: check if element is already in viewport
6function isInViewport(el) {
7 const rect = el.getBoundingClientRect();
8 return rect.top < window.innerHeight && rect.bottom > 0;
9}
10
11// Split cards
12const visibleCards = cards.filter(isInViewport);
13const hiddenCards = cards.filter(card => !isInViewport(card));
14
15
16// ✅ 1. Animate visible cards on load
17gsap.from(visibleCards, {
18 opacity: 0,
19 y: 80,
20 duration: 0.8,
21 ease: "power2.out",
22 stagger: 0.3
23});
24
25
26// ✅ 2. Animate remaining cards on scroll
27hiddenCards.forEach((card, i) => {
28 gsap.from(card, {
29 opacity: 0,
30 y: 80,
31 duration: 0.8,
32 ease: "power2.out",
33 delay: i * 0.1,
34 scrollTrigger: {
35 trigger: card,
36 start: "top 85%",
37 toggleActions: "play none none none"
38 }
39 });
40});
41Counter animation
How it works
This animation creates a counting effect by animating numbers from 0 to a specified target value when the element enters the viewport.
The animation targets elements with the attribute data-counter. Each element reads its target number directly from the attribute value and smoothly increments the number using GSAP.
The animation is triggered using ScrollTrigger when the element reaches 85% of the viewport.
Customization options
- Use the attribute
data-counterto define the target number.- Example:
data-counter="150"
- Example:
- Adjust the animation duration to control counting speed.
- Default:
2s
- Default:
- Customize the easing for different motion styles.
power1.out→ smooth decelerationpower2.out→ softer finish
- Change the ScrollTrigger start point.
- Default:
"top 85%" - Earlier trigger:
"top 95%" - Later trigger:
"top 60%"
- Default:
- Use
snapto create whole-number counting instead of decimals. - Add prefixes or suffixes using additional text elements.
- Example:
+150 - Example:
150K
- Example:
Features
- Smooth animated number counting effect
- Triggered on scroll using ScrollTrigger
- Automatically reads values from attributes
- Supports customizable speed and trigger position
- Lightweight and performance-friendly
- Perfect for stats, achievements, and metrics sections
1
2document.addEventListener("DOMContentLoaded", () => {
3 gsap.registerPlugin(ScrollTrigger);
4
5 const counters = document.querySelectorAll("[data-counter]");
6
7 counters.forEach((counter) => {
8 // 1. Get the target number from data-counter (e.g., "98")
9 const targetNumber = parseInt(counter.getAttribute("data-counter"), 10) || 0;
10
11 // 2. Get the symbol from data-suffix (e.g., "%"). Default to empty string if none.
12 const suffix = counter.getAttribute("data-suffix") || "";
13
14 // 3. Create a clean proxy object for GSAP to animate
15 const obj = { value: 0 };
16
17 gsap.to(obj, {
18 value: targetNumber,
19 duration: 2,
20 ease: "power1.out",
21
22 scrollTrigger: {
23 trigger: counter,
24 start: "top 85%",
25 toggleActions: "play none none none",
26 },
27
28 onUpdate: function () {
29 // 4. Force string concatenation explicitly
30 counter.textContent = String(Math.floor(obj.value)) + String(suffix);
31 }
32 });
33 });
34});
35Navbar hamburger
How it works
This animation transforms the navbar hamburger icon into a close icon when the mobile menu is opened.
The animation targets the hamburger lines:
.rt-top-line.rt-middle-line.rt-bottom-line
Using a GSAP timeline, the top and middle lines rotate into an “X” shape while the bottom line scales down and disappears.
The animation automatically syncs with Webflow’s native navbar state by detecting the w--open class on .w-nav-button.
On desktop screens, the animation resets automatically to prevent unwanted states during resizing.
Customization options
- Use
.w-nav-buttonas the Webflow navbar trigger. - Customize the line movement and rotation values.
- Top line:
y: 7.5rotateZ: 44
- Middle line:
rotateZ: -44
- Top line:
- Modify the bottom line hide animation.
- Default:
scaleX: 0
- Default:
- Adjust animation duration.
- Default:
0.45s
- Default:
- Customize easing styles.
power3.inOut→ smooth and polishedpower2.out→ faster interaction feel
- Change the transform origin for different rotation behavior.
- Adjust responsive breakpoint behavior.
- Current desktop reset breakpoint:
991px
- Current desktop reset breakpoint:
- Add opacity, color, or background transitions for enhanced interactions.
Features
- Smooth hamburger-to-close icon transformation
- Fully synced with Webflow native navbar state
- Responsive behavior with automatic desktop reset
- Timeline-based animation control
- Smooth rotation and scaling transitions
- Lightweight and performance-friendly
- Ideal for mobile navigation menus and responsive headers
1 gsap.registerPlugin();
2 window.addEventListener("DOMContentLoaded", () => {
3 // Select elements using custom attributes instead of classes
4 const navButton = document.querySelector('[data-nav="button"]');
5 const topLine = document.querySelector('[data-nav="top-line"]');
6 const middleLine = document.querySelector('[data-nav="middle-line"]');
7 const bottomLine = document.querySelector('[data-nav="bottom-line"]');
8
9 // Timeline (Unchanged logic)
10 const navMenuTl = gsap.timeline({
11 paused: true,
12 defaults: {
13 duration: 0.45,
14 ease: "power3.inOut"
15 }
16 });
17
18 navMenuTl
19 .to(topLine, {
20 y: 5, // Tighter downward shift (try 4 if 5 is still too wide)
21 rotateZ: 45,
22 transformOrigin: "50% 50%"
23 }, 0)
24 .to(middleLine, {
25 opacity: 0,
26 scaleX: 0,
27 duration: 0.2
28 }, 0)
29 .to(bottomLine, {
30 y: -5, // Tighter upward shift (must match the top line exactly)
31 rotateZ: -45,
32 transformOrigin: "50% 50%"
33 }, 0);
34
35 // Smooth sync function (Unchanged logic)
36 function syncNavAnimation() {
37 // Webflow still applies 'w--open' to the classList, so this check remains accurate
38 const isOpen = navButton.classList.contains("w--open");
39
40 // Desktop Reset
41 if (window.innerWidth > 991) {
42 gsap.to(navMenuTl, {
43 progress: 0,
44 duration: 0.4,
45 ease: "power3.inOut"
46 });
47 return;
48 }
49 // Mobile / Tablet
50 gsap.to(navMenuTl, {
51 progress: isOpen ? 1 : 0,
52 duration: 0.45,
53 ease: "power3.inOut"
54 });
55 }
56
57 // Observe Webflow nav state (Unchanged logic)
58 const observer = new MutationObserver(syncNavAnimation);
59 observer.observe(navButton, {
60 attributes: true,
61 attributeFilter: ["class"]
62 });
63
64 // Resize handling (Unchanged logic)
65 window.addEventListener("resize", syncNavAnimation);
66
67 // Initial state
68 syncNavAnimation();
69 });
70Smooth scroll to top
How it works
This interaction smoothly scrolls the page back to the top whenever a designated element is clicked.
The animation targets elements with the attribute data-scroll-to-top and uses the GSAP ScrollToPlugin to animate the window's scroll position instead of jumping instantly.
- Clicking the element prevents the browser's default behavior.
- The page smoothly scrolls back to the top.
- The animation uses easing to create a polished scrolling experience.
- Multiple elements can share the same attribute and work automatically.
Customization options
- Use the attribute
data-scroll-to-topto enable the interaction on any button, link, or clickable element. - Adjust the animation duration.
- Default:
1.2s - Lower value → faster scroll
- Higher value → smoother, slower movement
- Default:
- Change the scroll destination.
- Default:
y: 0(top of the page) - You can replace it with any scroll position or target element.
- Default:
- Modify the easing style.
power3.inOut→ smooth acceleration and decelerationpower2.out→ quicker finishnone→ linear scrolling
- Apply the same attribute to multiple elements to create reusable scroll-to-top buttons throughout your website.
Features
- Smooth animated scroll-to-top interaction
- Supports multiple buttons with one script
- Easy to customize duration, easing, and destination
- Prevents abrupt page jumps
- Lightweight and performance-friendly implementation
- Improves navigation on long pages
1<script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/ScrollToPlugin.min.js"></script>
2
3<script>
4document.addEventListener("DOMContentLoaded", () => {
5
6 gsap.registerPlugin(ScrollToPlugin);
7
8 // Changed from '.rt-back-to-top' to the attribute selector '[data-scroll-to-top]'
9 const buttons = document.querySelectorAll("[data-scroll-to-top]");
10
11 buttons.forEach((button) => {
12
13 button.addEventListener("click", (e) => {
14 e.preventDefault();
15
16 gsap.to(window, {
17 duration: 1.2,
18 scrollTo: {
19 y: 0
20 },
21 ease: "power3.inOut"
22 });
23
24 });
25
26 });
27
28});
29FAQ accordion animation
How it works
This interaction creates a smooth accordion animation for FAQ sections, allowing users to expand and collapse answers with a single click.
The animation targets FAQ elements using custom attributes and synchronizes the answer reveal with a rotating icon for a polished user experience.
- The FAQ wrapper uses the attribute
faq="item". - The clickable icon uses the attribute
faq="icon". - The answer container uses the attribute
faq="answer". - Clicking an FAQ item expands its answer while rotating the icon from
0°to90°. - Clicking the item again collapses the answer and returns the icon to its original position.
Customization options
- Use the attribute
faq="item"to define each FAQ accordion item. - Use the attribute
faq="icon"for the rotating indicator.- Default rotation:
0° → 90° - You can change the rotation angle to match your design.
- Default rotation:
- Use the attribute
faq="answer"for the collapsible content.- Default animation:
height: 0 → auto - You can also animate opacity for a softer reveal.
- Default animation:
- Adjust the animation duration.
- Default:
0.5s - Lower value → faster interaction
- Higher value → smoother transition
- Default:
- Modify the easing style.
power2.out→ smooth and responsivepower3.out→ softer finishnone→ linear animation
Features
- Smooth accordion open and close animation
- Animated icon rotation from
0°to90° - Expands answer height from
0toauto - Supports multiple FAQ items using reusable attributes
- Clean and lightweight GSAP implementation
- Easy to customize timing, easing, and rotation angle
- Improves readability and user experience for FAQ sections
Marquee
How it works
This animation creates a continuous horizontal scrolling effect by moving elements from their original position to the left across the screen.
The animation targets elements with the attribute visiond= "marquee" and transitions the X position from 0% to -100%, creating a seamless marquee movement commonly used for logos, announcements, or looping text sections.
Customization options
- Use the attribute
data= "marquee"to apply the animation. - Adjust the animation speed by changing the duration.
- Lower duration → faster movement
- Higher duration → slower movement
- Modify the movement direction by changing the X values.
0% → -100%→ left scroll0% → 100%→ right scroll
- Enable infinite looping for continuous movement.
- Add linear easing for a consistent scrolling speed.
- Recommended:
ease: "none"
- Recommended:
- Combine with duplicated content for a seamless infinite marquee effect.
Features
- Smooth infinite horizontal scrolling animation
- Ideal for logo strips, text banners, and announcements
- Fully customizable speed and direction
- Lightweight and performance-friendly
- Creates dynamic movement and visual engagement