Skip to content

Motion Engineering

GSAP ScrollTrigger Patterns Velocity X Uses on Every Marketing Site

Pin, Scrub, Stagger, Snap — Four Patterns That Convert

🎬 📌

CSS `@scroll-timeline` landed in 2024 and everyone celebrated. Then 60% of your audience tried it on Safari and saw nothing. Enter GSAP ScrollTrigger: the production-grade scroll-driven animation library that's been shipping on high-converting sites since 2019. It outpaces CSS today because browser support is real, the API is stupid simple, and the integration story with Lenis + Astro View Transitions doesn't crater your motion on navigation.

Velocity X uses four core patterns on every marketing site: pin + scrub for hero reveals, stagger for grid animations, snap for full-screen scenes, and parallax speed/lag attributes for depth layering. All four are declarative, all four integrate with `prefers-reduced-motion`, and all four can be wired in ~200 lines of JavaScript. Let's dig.

Pattern 1: Pin + Scrub — Lock an Element While the User Scrolls

The pin trigger ties an element to the scroll position. As you scroll past it, the element stays locked in the viewport for the duration of a custom animation. Scrub syncs that animation's progress to your scroll position — a 30% scroll through the trigger's range = 30% through the animation. No timeline, no delay; pure input-output binding.

{`gsap.to('.hero-image', {
  scrollTrigger: {
    trigger: '.hero-section',
    start: 'top top',
    end: 'bottom center',
    pin: true,
    scrub: 1, // 1-second lag for smooth feel
    markers: false, // set true to debug
  },
  y: 50,
  rotation: 5,
  opacity: 0.8,
});`}

That's a hero image that locks to the top of the viewport, then animates down + rotates + fades as you scroll through the trigger zone. The `scrub: 1` adds a 1-second delay between scroll input and animation output, creating a silky feel. Increase to 2–3 on slower pages, drop to 0.5 on snappy flows. Pin is the spine of every Velocity home page's "Get Setup" section.

Pattern 2: Stagger — Animate Grid Items in Sequence on Scroll

Stagger fires a timeline of child animations with a delay between each. Pair it with ScrollTrigger and you get grid cards that cascade in as the section crosses the viewport — expensive visually, cheap computationally because GSAP batches the whole group in one trigger.

{`gsap.to('.grid-item', {
  stagger: 0.15, // 150ms between each child
  opacity: 1,
  y: 0,
  duration: 0.6,
  scrollTrigger: {
    trigger: '.grid-section',
    start: 'top 70%',
    end: 'top 30%',
    markers: false,
  },
});`}

Each `.grid-item` starts at opacity 0 and y: 20 (set via CSS), then animates in. The first item starts at the trigger, the second 150ms later, etc. On a 6-item grid, the last item finishes 750ms after the first one crossed the viewport. Slower feels premium; faster feels snappy. Velocity's standard is 0.1–0.2.

Pattern 3: Snap — Jump Between Full-Screen Sections

Snap locks the scroll position to predefined offsets. Scroll through three full-screen sections and the scroll "snaps" to the top of each as you cross the midpoint, creating a cinematic scene-by-scene feel. Works with ScrollTrigger's `snap` config.

{`ScrollTrigger.create({
  onUpdate: (self) => {
    // Snap to every full-screen section
    if (Math.abs(self.getVelocity()) < 300) {
      self.snap({
        snapTo: 1 / 3, // snap to thirds of the page height
        duration: 0.6,
        delay: 0,
        ease: 'power2.inOut',
      });
    }
  },
});`}

The snap fires only if scroll velocity drops below 300px/s — prevents snapping while users are actively flicking. Snap every third of the page for a 3-scene hero, every 100vh for full-screen cards. Velocity's "With/Without Velocity" comparison table uses this pattern to create a locked, intentional reveal flow.

Pattern 4: Parallax Speed + Lag — Data-Driven Depth Layering

Instead of hard-coded parallax logic per component, declare movement with HTML attributes. A global ScrollTrigger setup reads those attributes and generates the animation — designers tweak numbers without touching code. The `lag` attribute smooths the parallax value, preventing jitter on lower-frame-rate devices.

{`document.querySelectorAll('[data-parallax-speed]').forEach((el) => {
  const speed = parseFloat(el.dataset.parallaxSpeed) || 0.5;
  const lag = parseFloat(el.dataset.parallaxLag) || 0.9;

  gsap.to(el, {
    y: () => {
      const box = el.getBoundingClientRect();
      const progress = (window.innerHeight - box.top) / (window.innerHeight + box.height);
      return progress * 100 * speed;
    },
    scrollTrigger: {
      trigger: el,
      start: 'top bottom',
      end: 'bottom top',
      scrub: lag,
    },
  });
});

/* HTML */
`}

The speed controls depth (0.3 = 30% of viewport motion), the lag controls the feel (0.9 = smooth, 0 = instant). Foreground elements get speed 0.1–0.3, midground 0.4–0.6, background 0.7–1.0. Velocity's testimonials section stacks three parallax layers at different speeds to create perceived depth.

Lenis + ScrollTrigger Integration

Lenis (inertia scroll library) and ScrollTrigger can fight for scroll control if not wired correctly. The fix is ScrollTrigger.proxy(), which tells GSAP to read scroll position from Lenis instead of the browser. See /blog/lenis-smooth-scroll-gsap-parallax-pattern for the full handoff pattern — one proxy call at startup syncs them permanently.

Reduce-Motion Guard

Wrap all ScrollTrigger setup in a `prefers-reduced-motion` check: if the user has motion sensitivity enabled, ScrollTrigger fires instantly (no scrub, no stagger delay), and animations complete in 0ms. Two lines cover it: `if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) { /* init ScrollTrigger */ }`. Roughly 12–15% of users have this enabled — ship it.

The Bottom Line

ScrollTrigger isn't a luxury. Pin + scrub lock user attention on hero moments. Stagger cascades grid items with zero per-component code. Snap creates cinematic flow. Parallax attributes let designers dial in depth. Pair it with Lenis for smooth scroll, guard with reduce-motion for accessibility, and you've got the motion stack every Velocity site ships with. To see it live, head to /pricing.

Let us make some quick suggestions?
Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.