More Scroll Snippets
Scroll Word Wheel — Free GSAP Headline Snippet
Scroll Word Wheel · Scroll · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Scroll Word Wheel — A Rotating Headline Word Turned by Scroll

The scroll word wheel is the "Built for designers / founders / marketers…" headline — but instead of auto-rotating on a timer, the wheel is turned by the scrollbar. Each segment of scroll snaps the masked word column one notch to the next word, and scrolling up spins it back. Giving the rotation to the reader turns a passive header into a scrubbed reveal of who the product serves. This snippet builds it with GSAP ScrollTrigger (from a CDN) and a masked column.
A one-line-tall mask hides all but the current word
The wheel is an inline-block .sww-wheel sized to exactly 1.24em tall with overflow: hidden — a viewport one line high. Inside it, the word list is a flex column where every <em> occupies that same 1.24em. Only one word can be visible at a time; the rest wait above or below the mask. Sizing in em keeps the mask correct at every clamp() font size without any JS measurement.
yPercent moves in exact word-height notches
Each notch tweens the list to yPercent: -(100 / COUNT) × i. Because yPercent is relative to the *list's* own height, and each word is exactly 1/COUNT of that height, every step lands pixel-perfectly on the next word — no hardcoded pixel offsets to break when the font size changes responsively.
Hold-then-snap pacing instead of continuous slide
Rather than one linear tween (which would show word edges scrolling constantly), the timeline places a short 0.35-duration power2.inOut tween just before each integer position: the wheel *holds* on a word for most of its segment, then snaps decisively to the next. Under a scrub, that means each word gets real reading time and transitions feel mechanical-in-a-good-way, like a slot drum clicking between detents. The pacing lives entirely in the position/duration math — i − 0.35 — so retuning the dwell time is one number.
Baseline alignment keeps the sentence intact
The static "Built for" and the wheel sit in a flex row aligned to baseline, and the wheel uses vertical-align: bottom so the moving words share the sentence's baseline. Word-wheel implementations commonly float half a pixel off the line; locking heights and line-heights to the same 1.24em is what keeps every word sitting exactly where static text would.
Gradient fades sell the drum
Two thin pseudo-element gradients at the mask's top and bottom fade incoming and outgoing words into the background, suggesting a curved drum edge — a purely decorative touch that reads as depth without any 3D transforms.
Scroll distance scales with the word count
end is COUNT × 55%, so each word owns the same scroll budget however many you add; the notch loop derives everything else from COUNT. Add a sixth word by adding one <em> — no other edits.
Per-word color via a custom property
Each word carries its own --wc accent, so the highlight color changes with the audience being named — a small cue that each notch is a distinct claim.
Customizing it
Edit the words (keep them short enough for your narrowest viewport), tune the dwell via the 0.35 constants, or drop the pin and trigger it inside a hero. For the timer-based version see the word flip hero; pair with a scroll typewriter or hand off to a scroll letter stagger headline.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You do not need to work out the yPercent notch math or the hold-then-snap timeline positions by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why each notch is placed at timeline position i minus 0.35 instead of at a plain integer, and why yPercent (rather than a pixel translateY) is used to land on exact word boundaries. The same assistant can help optimize it — for instance checking whether the end value's COUNT times 55 percent scroll budget still feels right once the word list grows past ten entries, or whether the gradient fade pseudo-elements should be simplified for very small type sizes. It is just as useful for extending the effect: ask it to make the wheel loop continuously instead of stopping on the last word, add a subtle 3D rotateX tilt to sell the drum illusion more convincingly, or let a click on the wheel jump directly to a specific word instead of only scroll-driven notches. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a "scroll word wheel" headline in plain HTML, CSS, and JavaScript using GSAP and its ScrollTrigger plugin (load both from a CDN, no build step).
Requirements:
- A headline made of static leading text followed by a masked "wheel" element sized to exactly one line's height in em units (not pixels) with overflow: hidden, so only one word from an inner vertical list is visible at a time.
- The inner word list must be a flex column where every word element is locked to that same one-line em height, so that moving the list by whole multiples of that height lands exactly on word boundaries regardless of the responsive font size.
- Register a single GSAP timeline on a ScrollTrigger with pin: true and scrub, whose end scroll distance scales with the number of words (for example word count times a fixed percentage), so adding or removing words automatically adjusts how much scroll distance the whole effect consumes.
- For each word transition, add a short discrete tween (not one continuous linear tween across the whole timeline) that moves the list by yPercent equal to minus 100 divided by the word count, times the word's index, using an in-out easing curve — and position each of these short tweens just before its corresponding integer timeline position, so the wheel visibly holds on each word for most of its scroll segment and then snaps quickly to the next, like a mechanical drum clicking between detents.
- Add two thin gradient-fade pseudo-elements at the top and bottom edge of the mask to visually suggest a curved drum rather than a flat hard-edged window.
- The whole sequence must reverse cleanly when scrolling back up, spinning the wheel backward through the words in the same notch-by-notch fashion.Step by step
How to Use
- 1Add the GSAP CDNsInclude gsap and ScrollTrigger from the CDN panel.
- 2Paste HTML, CSS, and JSThe masked wheel renders showing its first word.
- 3Scroll into the stageIt pins; the wheel holds, then snaps a notch.
- 4Keep scrollingEach segment clicks to the next colored word.
- 5Scroll back upThe wheel spins backward through its words.
- 6Edit the wordsAdd an em with its own --wc; pacing auto-scales.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
The wheel is an overflow-hidden inline-block exactly 1.24em tall — a one-line viewport — and every word in the inner column is locked to that same height and line-height. Only the word aligned with the window is visible; the rest sit above or below the mask. Because everything is em-based, the mask stays exact at every responsive font size.
Each step tweens the column to yPercent −(100/COUNT) × i. yPercent is relative to the list's own height, and each word is exactly 1/COUNT of it, so steps land on word boundaries by construction — no pixel constants that would break when clamp() changes the font size or a different typeface changes metrics.
The timeline places a short 0.35-unit power2.inOut tween just before each integer position, so under the scrub the wheel dwells on a word for most of its segment and then clicks over. Continuous sliding would show word edges constantly and make everything half-readable; hold-then-snap gives each word genuine reading time, like a slot drum settling into detents.
Edit the em elements — each carries its own --wc accent color. COUNT is read from the DOM, the trigger's end scales at 55% of viewport height per word, and the notch loop derives every position from COUNT, so a sixth word needs zero JS edits. Keep words short enough to fit your narrowest viewport since the wheel is white-space: nowrap.
Render the words from an array and build the timeline in a mount effect — useEffect, onMounted, or ngAfterViewInit — inside gsap.context scoped to the stage ref, reverting on cleanup so the pin unregisters on unmount. Derive COUNT from the array, not the DOM. The mask is two Tailwind-friendly rules (overflow-hidden plus a fixed em height); keep the em heights in a style tag or arbitrary values.