contact-new-CTA-background
[ our testimonials ]

GSAP instructions

All graphical assets in this template are licensed for personal and commercial use. If you'd like to use a specific asset, please check the license below.

Home
Our testimonials

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
  • Customize the Y movement distance.
    • Default: 80
    • Smaller values create subtler motion.
  • Modify the animation duration.
    • Default: 0.8s
  • Change the easing style for different motion feels.
    • power2.out → smooth and modern
    • power3.out → softer finish
  • Adjust the ScrollTrigger start position.
    • Default: "top 85%"
    • Earlier trigger: "top 95%"
    • Later trigger: "top 70%"

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});
41

Counter 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-counter to define the target number.
    • Example: data-counter="150"
  • Adjust the animation duration to control counting speed.
    • Default: 2s
  • Customize the easing for different motion styles.
    • power1.out → smooth deceleration
    • power2.out → softer finish
  • Change the ScrollTrigger start point.
    • Default: "top 85%"
    • Earlier trigger: "top 95%"
    • Later trigger: "top 60%"
  • Use snap to create whole-number counting instead of decimals.
  • Add prefixes or suffixes using additional text elements.
    • Example: +150
    • Example: 150K

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});
35

Navbar 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-button as the Webflow navbar trigger.
  • Customize the line movement and rotation values.
    • Top line:
      • y: 7.5
      • rotateZ: 44
    • Middle line:
      • rotateZ: -44
  • Modify the bottom line hide animation.
    • Default:
      • scaleX: 0
  • Adjust animation duration.
    • Default: 0.45s
  • Customize easing styles.
    • power3.inOut → smooth and polished
    • power2.out → faster interaction feel
  • Change the transform origin for different rotation behavior.
  • Adjust responsive breakpoint behavior.
    • Current desktop reset breakpoint:
      • 991px
  • 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  });
70

Smooth 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-top to 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
  • Change the scroll destination.
    • Default: y: 0 (top of the page)
    • You can replace it with any scroll position or target element.
  • Modify the easing style.
    • power3.inOut → smooth acceleration and deceleration
    • power2.out → quicker finish
    • none → 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});
29

FAQ 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 to 90°.
  • 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.
  • Use the attribute faq="answer" for the collapsible content.
    • Default animation: height: 0 → auto
    • You can also animate opacity for a softer reveal.
  • Adjust the animation duration.
    • Default: 0.5s
    • Lower value → faster interaction
    • Higher value → smoother transition
  • Modify the easing style.
    • power2.out → smooth and responsive
    • power3.out → softer finish
    • none → linear animation

 

Features

  • Smooth accordion open and close animation
  • Animated icon rotation from to 90°
  • Expands answer height from 0 to auto
  • 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 scroll
    • 0% → 100% → right scroll
  • Enable infinite looping for continuous movement.
  • Add linear easing for a consistent scrolling speed.
    • Recommended: ease: "none"
  • 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