Skip to main content
GSAP Animation TutorialArticle 16

GSAP ScrollTrigger Scrub: Control Animation with Scroll

Connect user scroll progress directly to a tween or timeline, compare direct and smoothed scrub, and build responsive scroll-driven experiences.

GSAP ScrollTrigger Scrub Control Animation with Scroll Tutorial - NavTechSolution

In Blog #15, start and end defined an active scroll range. Without scrub, reaching the start activates a tween that continues according to time. Add scrub, and the scrollbar becomes the playhead.

gsap.to(".box", {
  x: 300,
  ease: "none",
  scrollTrigger: {
    trigger: ".section",
    start: "top center",
    end: "bottom center",
    scrub: true
  }
});
USER SCROLL0%100%
maps to
ANIMATION0%100%
Scroll position and animation progress share the same zero-to-one progress model.

What you will learn

1

Understand what scrub changes

2

Compare scrub true and numeric scrub

3

Design meaningful start/end ranges

4

Scrub tweens, timelines and stagger

5

Read live ScrollTrigger progress

6

Build responsive, accessible scroll effects

1. What is ScrollTrigger scrub?

Scrub links animation progress to ScrollTrigger progress. Around 25% through the range, the animation is around 25% through its progress; the same mental model applies at 50%, 75% and 100%.

SCROLL 25%ANIMATION 25%
SCROLL 50%ANIMATION 50%
SCROLL 75%ANIMATION 75%
SCROLL 100%ANIMATION 100%
The browser continuously maps the configured scroll range to animation progress.

2. Normal ScrollTrigger versus scrub

WITHOUT SCRUBScroll reaches startPlay by timeAnimation continues even if scrolling stops.
WITH SCRUBScroll progressAnimation progressScroll down advances; scroll up reverses.
NORMALN
SCRUBS

Scroll through this section to compare a time-based entrance with a scroll-linked movement.

3. Basic scrub: true

trigger chooses the controlling section, start opens the range, end closes it, and scrub links the animation playhead to that range.

scrollTrigger: {
  trigger: ".basic-scrub-demo",
  start: "top 80%",
  end: "bottom 20%",
  scrub: true
}

4. First scrub demo

STARTSCROLL MEEND

Scroll down and then back up. Rotation and translation follow the same trigger progress.

5. Scroll down and scroll up

SCROLL DOWN↓ ↓ ↓Progress moves forward →
SCROLL UP↑ ↑ ↑Progress moves backward ←

6. Start and end become the ruler

With scrub, the distance between start and end is the scroll-space ruler across which the animation is distributed.

START · 0%25%50%75%END · 100%

7. Short versus long range

SHORTFaster progress change per scroll distance
LONGMore scroll space for the same animation

8. Interactive scrub range lab

STARTMEDIUM RANGEEND
Mode
Medium
Start
top 80%
End
bottom 30%

9. Numeric scrub

A number such as scrub: 1 keeps scroll progress in control but lets the animation playhead catch up smoothly. It does not mean the scrubbed animation simply has a one-second duration.

SCROLLBAR POSITION
ANIMATION PLAYHEAD
→ catches up smoothly

10. scrub: true versus scrub: 1

SettingResponseUseful for
scrub: trueDirect scroll-progress mappingTracks and progress indicators
scrub: 1Smoothed catch-up responseSofter visual storytelling

11. Scrub smoothing playground

0%NAVTECH100%

SCRUB: 1. Scroll through this lab to feel the catch-up.

12. Scrub and duration

NORMAL TWEEN0 seconds2 seconds
SCRUBBED TWEENSTARTEND

For a single scrubbed tween, scroll progress drives the overall motion. Inside a timeline, duration values remain meaningful because they determine how much of the timeline each tween occupies.

13. Scrub and easing

ease: "none" produces a linear property mapping. An ease such as power2.out redistributes the property change across progress; scrub is still in control.

STARTEASEEND

EASE: none

14. Scrub with gsap.to()

gsap.to(card, {
  x: getDistance,
  rotation: 10,
  scale: 1.05,
  ease: "none",
  scrollTrigger: {
    trigger: demo,
    start: "top 80%",
    end: "bottom 20%",
    scrub: true,
    invalidateOnRefresh: true
  }
});

The current visual state becomes progress zero; the declared target state becomes progress one.

15. Scrub with gsap.fromTo()

gsap.fromTo(card,
  { xPercent: -20, opacity: 0.35, scale: 0.9 },
  { xPercent: 0, opacity: 1, scale: 1, ease: "none",
    scrollTrigger: { trigger: demo, start: "top 80%",
      end: "bottom 30%", scrub: true }
  }
);

fromTo() is useful when both endpoints need to be explicit.

16. Scrub a timeline

SCROLL RANGE
TITLETEXTCARDS + STAGGER
const tl = gsap.timeline({
  scrollTrigger: { trigger: section, start: "top 80%",
    end: "bottom 20%", scrub: true }
});

tl.from(label, { opacity: 0, y: 20 })
  .from(title, { opacity: 0, y: 50 }, "-=0.2")
  .from(cards, { opacity: 0, y: 30, stagger: 0.1 }, "-=0.2");

17. Timeline duration ratios

A · duration 1
B · duration 2
Both fit inside one scroll-controlled timeline.

18. Scrub plus stagger

ScrollTrigger controls overall progress. Stagger distributes timing between targets inside that progress.

01Scroll
02Progress
03Timeline
04Motion

19. Live ScrollTrigger progress

0%

This percentage belongs only to this demo’s start/end range.

20. Moving object along a safe track

STARTNAVTECHEND
const getDistance = () =>
  Math.max(0, track.clientWidth - box.offsetWidth);

gsap.to(box, {
  x: getDistance,
  ease: "none",
  scrollTrigger: { trigger: demo, scrub: true,
    invalidateOnRefresh: true }
});

21. Responsive travel distance

A fixed x: 1000 can escape its container on a phone. Measuring the track creates a safe endpoint and invalidateOnRefresh: true lets ScrollTrigger recalculate it after responsive layout changes.

22. Scale and rotation with scroll

SCALE

Decorative motion can rotate; reading content should stay calm and legible.

23. Image reveal with scrub

Alternate GSAP scrub tutorial poster with a scroll progress track

The image scales from 1.08 to 1 while a subtle vertical shift settles into place.

24. A simple parallax-like effect

NavTechSolution

SCROLL-DRIVEN
EXPERIENCES

Two decorative layers move by different small amounts. Native page scrolling remains untouched.

25. Multiple properties

A single scrubbed tween can map x, y, rotation, scale and borderRadius together. Keep the effect purposeful and transform-heavy.

SCROLL DISTANCEstart → endHow much page movement maps progress
ANIMATION DISTANCEx: 0 → x: 300How far the target itself moves

26. Scrub does not mean pin

SCRUBScroll controls progress
PINSection stays fixed
TOGETHERCan be combined later

Moving an element horizontally also does not create a horizontal-scrolling site. This tutorial clips tracks and never intercepts wheel or touch scrolling.

27. Practical hero-like scrub

NavTechSolution

Scroll-Driven Experiences

Build smooth interactions that respond to user progress.

28. Practical services scrub

Web Development
AI Solutions
SEO
UI/UX

29. Practical process sequence

01Discover
02Design
03Build
04Launch

A transform-based progress line fills while each step enters its portion of the timeline. Scrolling upward reverses the story.

30. Numeric scrub mental model

SCROLLBAR PLAYHEAD THE PLAYHEAD CATCHES UP →

Direct scrub suits precise indicators and tracks. Numeric scrub can soften image motion, text decoration and storytelling; too much smoothing may feel disconnected.

31. GSAP ScrollTrigger Scrub Lab

NavTechSolution

Control Animation with Scroll

Connect user scroll progress directly to GSAP animation progress.

STARTNAVTECHEND
Scroll
Start
End
Scrub
Scrub
Ease
Range
Scrub
1
Ease
none
Range
Medium
Progress
0%
Direction
Ready
Start / End
top 80% / bottom 20%

Lab ready. Scroll through this section.

32. Safe rebuild architecture

function destroyLab() {
  if (!labAnimation) return;
  if (labAnimation.scrollTrigger) labAnimation.scrollTrigger.kill();
  labAnimation.kill();
  labAnimation = null;
}

The controls kill only the lab-owned timeline and its trigger, reset only lab properties, and rebuild. They never call ScrollTrigger.getAll().

33. Common scrub mistakes

1. Adding scrub without a meaningful end
2. Using a range too short to control comfortably
3. Treating numeric scrub as tween duration
4. Assuming scrub automatically pins
5. Using huge fixed x values
6. Forgetting upward scrolling reverses progress
7. Using strong easing without testing
8. Scrubbing essential paragraph content
9. Accumulating triggers during rebuilds
10. Killing unrelated ScrollTriggers globally
11. Ignoring mobile viewport geometry
12. Ignoring reduced-motion preferences
13. Refreshing on every scroll
14. Animating expensive filters on large layers
15. Hiding content until a long scrub finishes

34. Performance

Prefer transforms and opacity, use transform-based progress bars, keep DOM updates lightweight, and avoid repeated layout reads inside onUpdate. Test the full page because several individually smooth effects can still compete when they overlap.

35. Accessibility and mobile

Essential content is visible in the HTML before JavaScript runs. The script respects prefers-reduced-motion, keeps native scrolling, shortens nothing into an unreadable state, and uses real buttons with aria-pressed. Tracks clip locally at 320px rather than creating page-level overflow.

36. Mini challenge

NavTechSolution

Scroll to Control Progress

Connect this animation directly to the user’s scroll position.

GSAP
Show suggested solution
gsap.to(box, {
  x: () => Math.max(0, track.clientWidth - box.offsetWidth),
  ease: "none",
  scrollTrigger: {
    trigger: challenge,
    start: "top 80%",
    end: "bottom 20%",
    scrub: true,
    invalidateOnRefresh: true,
    onUpdate: self => gsap.set(progressBar, { scaleX: self.progress })
  }
});

37. Quick reference

FeatureExamplePurpose
Basic scrubscrub: trueDirect progress mapping
Smooth scrubscrub: 1Catch-up smoothing
Triggertrigger: sectionChoose controlling element
Startstart: "top 80%"Begin scroll range
Endend: "bottom 20%"Finish scroll range
Linear easeease: "none"Linear property mapping
Timelinegsap.timeline({ scrollTrigger })Scrub a sequence
Progressself.progressRead zero-to-one progress
UpdateonUpdateRespond to progress changes
RefreshScrollTrigger.refresh()Recalculate only when needed

38. Scrub cheat sheet

WITHOUT SCRUBSCROLL ↓ START ↓ PLAY BY TIME
WITH SCRUBSCROLL 0% ⇔ ANIMATION 0%SCROLL 100% ⇔ ANIMATION 100%
scrub: truescrub: 1

39. Final mental model

TRIGGERWhich section?
STARTWhere does progress begin?
ENDWhere does progress finish?
SCRUBShould animation progress follow scroll?
USER SCROLL ⇔ SCROLLTRIGGER PROGRESS ⇔ GSAP ANIMATION

40. Preview Blog #17

Scrub connects animation to scrolling. The next lesson will introduce pin, which can keep a section fixed while its scroll-driven sequence progresses. Blog #17 is not linked until it exists.

ScrollTrigger.create({
  trigger: ".pin-section",
  start: "top top",
  end: "+=1000",
  pin: true
});

Continue the GSAP series

Review GSAP stagger, GSAP easing, timelines, timeline position parameters, timeline + stagger, the ScrollTrigger tutorial, and ScrollTrigger start and end.

Frequently asked questions

What does scrub do in GSAP ScrollTrigger?

Scrub maps animation progress to ScrollTrigger progress between the configured start and end positions.

What is the difference between scrub true and scrub 1?

scrub true follows scroll progress directly, while scrub 1 adds a one-second catch-up smoothing response to the animation playhead.

Does scrub control animation duration?

Scroll progress controls the overall progress. Durations still define relative timing inside a scrubbed timeline.

Why do I need an end value with scrub?

Start and end define the scroll range that maps from zero to one hundred percent animation progress.

What happens when I scroll backward with scrub?

The ScrollTrigger progress decreases and the animation moves back toward its earlier state.

Can I use scrub with a GSAP timeline?

Yes. Put ScrollTrigger on the timeline and the complete sequence maps across its scroll range.

Can I combine scrub and stagger?

Yes. Scrub controls overall progress while stagger distributes timing between targets.

Should I use ease none with scrub?

It is useful for linear mapping, but other eases are valid when their property distribution supports the design.

Can ScrollTrigger scrub animate horizontally?

Yes. Animate x within a clipped track and calculate a safe travel distance to prevent page overflow.

Does scrub automatically pin a section?

No. Scrub links progress to scrolling; pin is a separate feature.

How do I make scrub animations responsive?

Measure available space, use function-based values, invalidate on refresh and test real viewport sizes.

Is GSAP scrub good for mobile?

It can be when motion is restrained, travel distances are responsive and touch scrolling remains native.

How do I show ScrollTrigger progress?

Read self.progress in that trigger’s onUpdate callback and convert the zero-to-one value to a percentage.

How do I make scrub animations accessible?

Keep content visible, respect reduced-motion preferences and never make motion necessary to understand the page.

Can I use ScrollTrigger scrub on a PHP website?

Yes. PHP renders the page and GSAP runs in the visitor’s browser like it would on any HTML page.