Skip to main content

3.12 release

· 4 min read
Cassie Evans
Jack Doyle
  • Clamp your triggers! - Ever had ScrollTriggered animations at the very top of your page start out partially-scrubbed? Now you can clamp() them! This handy feature ensures that the start and end positions stay within the bounds of the page and ensures that all your "above the fold" elements start off in their native positions.
  • Clamp data-speed - More clamping! This time for ScrollSmoother, you can now wrap your data-speed value in clamp() to make the associated element start out in its natural position if it 's within the viewport at the top of the page.
  • ScrollSmoother speed - Hold onto your hats (or scroll wheels?) We 've added a speed option to ScrollSmoother which you can use to make the page scroll faster or slower.

Clamp Your Triggers


It can be frustrating when your "above the fold" scrubbed animations start off part-way through. With clamp() you can ensure that they always start out in their native positions, no matter where your triggers are placed.

trigger: elem,
start: "clamp(top bottom)", // clamped value - will always fall between 0 and the max scroll
end: "bottom top" // the parsed pixel value could be negative or more than the max scroll,

So what 's going on under the hood?

All scroll triggered animations have trigger points that determine where the animation starts and ends. These values are nice and flexible, you can write them out as a number, as string shorthand or return one of those options from a function.

start: "bottom 50%+=100px" // flexible string shorthand
start: 200, // pixel value
start: () => window.innerHeight / 2 // function that returns a number or string

However you write it out, ScrollTrigger converts these values into a numeric scroll positions.

If you set up your start marker above the fold, the start position will be negative and the animation will start off partway through. Sometimes this is desired behaviour but it can also be a bit awkward and unexpected.

The new clamp feature allows us to prevent these trigger 'leaks '. We can tell ScrollTrigger to always keep the trigger value between 0 (the top of the page) and the maximum scroll position.
Check out this demo and pop open the console to see the differing values. 👀


On load you can see that the un-clamped animation starts part-way through. If you scroll down to the bottom you 'll notice that it also doesn 't complete as the end marker is further down than the maximum possible scroll distance.

If you want to know what 's happening under the hood check out the docs on clamp. Wrapping the trigger in "clamp()" is just like telling ScrollTrigger to run the parsed trigger position through the following util -

gsap.utils.clamp(0, maxScroll, triggerPosition)

Clamp data-speed

You can also use the new clamp feature over in ScrollSmoother-land. Now, when you apply data-speed to "above-the-fold" elements, they 'll start exactly where you placed them in your design, unaffected by their speed value. No more unexpected offsets! Check it out...


Video Walkthrough

Still a bit confused about when and why this is useful? We 've got you - Cassie breaks it down in this new feature video

New speed option for ScrollSmoother

smooth: 2,
effects: true,
speed: 1.5, // 1.5x the normal speed

Now you have the power to control your scroll speed with a simple multiplier. Want things to move faster? Set it to 2 and watch your content zoom past twice as fast! Prefer a leisurely pace? Set it to 0.5 for a leisurely scroll at half the speed.



GSAP 3.12 delivers various bug fixes, so we 'd highly recommend installing the latest version today. There are many ways to get GSAP - see the Installation page for all the options (download, NPM, zip, Github, etc.).


Happy tweening!