Instructions
This template uses custom-built GSAP-powered systems to create smooth, responsive, and performant animations in Webflow.
Smooth page scroll
How it works
This animation adds smooth, inertia-based page scrolling using Lenis, with GSAP ScrollTrigger registered for scroll-based animations.
The script loads the Lenis stylesheet and library from a CDN, then initializes a Lenis instance once the page has loaded. It skips loading anything that is already on the page, so nothing is duplicated.
Lenis runs on a requestAnimationFrame loop and eases the page toward the target scroll position instead of jumping. Anchor links (a[href^="#"]) are intercepted and scrolled to smoothly.
Customization options
- Adjust scroll smoothness using
lerp.- Lower value → smoother, slower-feeling scroll
- Higher value → snappier, more direct scroll
- Recommended:
0.05to0.15
- Modify mouse wheel speed using
wheelMultiplier.- Default:
1 - Higher value → faster scroll per wheel tick
- Default:
- Modify touch scroll speed using
touchMultiplier.- Default:
1.5
- Default:
- Enable looping scroll using
infinite.false→ page stops at the top and bottom (default)
- Keep
autoResize: trueso Lenis recalculates page height when the window resizes. - Adjust anchor link scrolling using
duration(default1.5seconds) andoffset(default0).- Use a negative
offset(e.g.-80) to leave room for a fixed navbar
- Use a negative
- Change the Lenis version by updating
1.1.13in both CDN URLs. - Control scrolling from anywhere with the global instance:
window.lenis.stop()→ pause scrolling (e.g. when a modal opens)window.lenis.start()→ resume scrollingwindow.lenis.scrollTo("#section-id")→ scroll to a section
Features
- Smooth, inertia-based page scroll
- Lenis stylesheet and library loaded automatically from the CDN
- Duplicate-load protection for the CSS and script
- Smooth anchor link scrolling with adjustable duration
- Separate speed control for wheel and touch input
- Error logging if the Lenis library fails to load
- Global
window.lenisinstance for custom control - GSAP ScrollTrigger registered and ready for scroll animations
- Lightweight, with no extra setup in the Designer
Requirements
- Load GSAP and ScrollTrigger before this script, otherwise
gsap.registerPlugin(ScrollTrigger)will throw an error. - Add this to Page Settings → Custom Code → Before
</body>(or the site-wide footer code) in Webflow. - It only runs on the published or staging site, not in the Designer.
Counter animation
How it works
This animation counts a number up from 0 to a target value when the element scrolls into view, using GSAP and ScrollTrigger.
The script finds every element with the data-counter attribute and reads its value (for example 250+). It splits the value into a number (250) and a suffix (+), then animates a temporary value from 0 to the target.
On every frame, the element's text is updated with the rounded number followed by the suffix. The animation plays once, when the element reaches 85% of the viewport height, and does not repeat.
Customization options
- Use attribute
data-counterfor each counter element.- Example:
<span data-counter="250+"></span> - Any suffix is kept, e.g.
%,+,k,M
- Example:
- Adjust counting speed using
duration.- Lower value → faster count
- Higher value → slower count
- Default:
2seconds
- Change easing using
ease: "power1.out"for a natural slowdown near the end.- Try
power2.outorpower3.outfor a stronger slowdown - Use
nonefor a constant speed
- Try
- Adjust when the counter starts using
start: "top 85%".- Lower percentage (e.g.
top 70%) → starts later, deeper in the viewport - Higher percentage (e.g.
top 95%) → starts earlier
- Lower percentage (e.g.
- Keep
once: trueso the counter plays only one time.- Remove it (and change
toggleActionsto"play none none reset") to replay on every scroll
- Remove it (and change
- Control number formatting with
toLocaleString.useGrouping: false→1000useGrouping: true→1,000
- Start from a different number by changing
value: 0in theobjobject.
Features
- Scroll-triggered counting, so it only plays when the number is visible
- Works with any number of counters on the page
- Suffix support (
+,%,k, etc.) with no extra setup - Commas in the attribute value are handled (e.g.
1,200+) - Plays once, with no repeated animation
- Smooth ease-out that slows near the final number
- Lightweight, with no external libraries beyond GSAP and ScrollTrigger
- Ideal for stats, achievements, client counts, and results sections
Text appearance
How it works
This animation reveals a heading word by word on scroll. Each word starts blurred, faded, slightly enlarged, and pushed down, then sharpens into place one after another, using GSAP and ScrollTrigger.
The script finds every element with the data-heading attribute and splits its text into individual words, wrapping each word in a span. Elements inside the heading (such as a colored or bold word) are kept intact and treated as one unit.
When the heading reaches 90% of the viewport height, the words animate in with a stagger. Scrolling back up reverses the animation. The effect runs only on screens 992px and wider. Below that, the original heading markup is restored and the text shows normally.
Customization options
- Use attribute
data-headingon each heading you want animated.- Example:
<h2 data-heading>We're building a smarter way to run business</h2>
- Example:
- Adjust reveal speed per word using
duration.- Lower value → faster reveal
- Higher value → slower reveal
- Default:
0.6seconds
- Adjust the delay between words using
stagger.- Lower value → words appear almost together
- Higher value → words appear one by one
- Default:
0.12seconds
- Change easing using
ease: "power2.out"for a soft landing.- Try
power3.outfor a stronger slowdown - Use
back.out(1.7)for a slight overshoot
- Try
- Adjust when the animation starts using
start: "top 90%".- Lower percentage (e.g.
top 75%) → starts later, deeper in the viewport - Higher percentage (e.g.
top 95%) → starts earlier
- Lower percentage (e.g.
- Change the replay behavior using
toggleActions."play none none reverse"→ plays on enter, reverses when scrolling back above"play none none none"→ plays once and stays
- Modify the starting look of each word (set in the script and matched by the end values in the tween):
blur(10px)→ amount of bluropacity 0.3→ starting transparencyscale(1.15)→ starting sizetranslateY(0.75rem)→ starting vertical offset
- Change the breakpoint by updating
(min-width: 992px)inmatchMedia.- Use
(min-width: 0px)to run on all screen sizes
- Use
Features
- Word-by-word blur reveal with a smooth stagger
- Scroll-triggered, so it plays when the heading is visible
- Reverses when scrolling back up
- Keeps inner elements (colored, bold, or linked words) intact
- Runs on desktop only, with the original text restored on smaller screens
- Automatic cleanup when the viewport changes, with no leftover spans or triggers
- Works with any number of headings on the page
- Lightweight, with no external libraries beyond GSAP and ScrollTrigger
- Ideal for section headings, hero titles, and statements
Card appearance
How it works
This animation reveals cards as they scroll into view. Each card starts blurred, transparent, slightly smaller, and offset to one side or below, then slides into place and sharpens, using GSAP and ScrollTrigger.
The script looks for elements carrying one of seven attributes (card-1 to card-7). Each attribute has its own entry direction: cards 1, 4, and 7 come in from the left, cards 3 and 6 from the right, and cards 2 and 5 rise from below. When a card reaches 90% of the viewport height, it animates in. Scrolling back up reverses the animation.
The effect runs only on screens wider than 991px. On tablet and mobile, the script exits early and the cards show normally.
Customization options
- Use attributes
card-1tocard-7on each card you want animated.- Example:
<div card-1>...</div> - Several elements can share the same attribute, and each one animates on its own trigger
- Example:
- Change the entry direction in the
directionsobject.x: -60→ slides in from the leftx: 60→ slides in from the righty: 60→ rises from belowy: -60→ drops from above- Larger values → longer travel distance
- Adjust animation speed using
duration.- Lower value → faster reveal
- Higher value → slower reveal
- Default:
0.9seconds
- Change easing using
ease: "power3.out"for a smooth, strong slowdown.- Try
power2.outfor a softer landing - Use
back.out(1.4)for a slight overshoot
- Try
- Adjust the starting look of each card:
blur(12px)→ amount of bluropacity: 0→ starting transparencyscale: 0.96→ starting size
- Adjust when the animation starts using
start: "top 90%".- Lower percentage (e.g.
top 75%) → starts later, deeper in the viewport - Higher percentage (e.g.
top 95%) → starts earlier
- Lower percentage (e.g.
- Change the replay behavior using
toggleActions."play none none reverse"→ plays on enter, reverses when scrolling back above"play none none none"→ plays once and stays
- Change the breakpoint by updating
window.innerWidth <= 991.- Remove the line to run on all screen sizes
- Add more directions by adding a new key (e.g.
"card-8": { x: 0, y: -60 }).
Features
- Scroll-triggered reveal with blur, fade, scale, and slide
- Seven preset entry directions that alternate for a varied layout
- Each card has its own trigger, so cards animate independently
- Supports multiple elements per attribute
- Reverses when scrolling back up
- Runs on desktop only, with cards shown normally on smaller screens
- Lightweight, with no external libraries beyond GSAP and ScrollTrigger
- Ideal for feature cards, service grids, pricing cards, and bento layouts
Awards hover
How it works
This animation turns the awards list into a hover-driven highlight list where one row is active at a time, using GSAP.
The script finds every .rt-awards-item and, for each one, its matching line (.rt-line-v4), arrow (.rt-arrow-wrapper), and badge (.rt-award-badge-v1). These are matched by position, so the 1st item uses the 1st line, arrow, and badge, and so on.
On load, the 3rd item is set active instantly with no animation. When the cursor enters any item, that item becomes active: its line grows to full width, its arrow fades in, and its badge fades in. All other items reset, with the line shrinking to 0%, and the arrow and badge fading out.
Customization options
- Use these class names in the Designer:
.rt-awards-itemfor each award row.rt-line-v4for the line inside each row.rt-arrow-wrapperfor the arrow inside each row.rt-award-badge-v1for the badge inside each row (optional)
- Choose which item starts active using
defaultIndex.0→ first item2→ third item (default)
- Adjust line speed using
duration: 0.5(thedurvalue).- Lower value → faster fill
- Higher value → slower fill
- Adjust arrow fade speed using
duration: 0.35. - Adjust badge fade speed using
duration: 0.4. - Change easing using
ease: "power2.out".- Try
power3.outfor a stronger slowdown
- Try
- Change the line direction using
width.- Set the line's transform origin to left or right in the Designer to control which side it grows from
- Change the inactive look by editing the
"0%"and0values.- Use
opacity: 0.3for a dimmed arrow or badge instead of hidden
- Use
- Set
animatetofalseinsetActive()to make changes instant.
Features
- One row active at a time
- Smooth line fill, arrow fade, and badge fade on hover
- Default active row set instantly on load, with no flash
- Works with any number of award rows
- Badge is optional
- Lightweight, with no external libraries beyond GSAP