Scroll Skew Velocity — Free GSAP ScrollTrigger Skew Effect

Scroll Skew Velocity · Scroll · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Velocity read
ScrollTrigger getVelocity per frame.
Clamped skew
Hard limit keeps shear tasteful.
quickTo setters
Reusable, no tween-per-frame cost.
Smooth easing
power3 ramps and settles the skew.
Auto reset
Returns to 0 when velocity drops.
Direction-aware
Leans the way it scrolls.
GPU transform
skewY composites, no reflow.
Scales to many
One velocity read drives all cards.

About this UI Snippet

Scroll Skew Velocity — Cards That Lean Into Your Scroll Speed

Screenshot of the Scroll Skew Velocity snippet rendered live

Velocity skew is the tactile effect where list items shear slightly in the direction you're scrolling and snap upright when you stop — the "the page has momentum" feel from award-winning sites. This snippet builds it with GSAP and ScrollTrigger (from a CDN), reading raw scroll velocity and mapping it to a live skew.

Reading scroll velocity

A global ScrollTrigger with an onUpdate callback runs on every scroll frame and calls self.getVelocity(), which returns the current scroll speed in pixels per second — positive scrolling down, negative scrolling up. That number is the engine of the effect: fast scrolling yields a big value, easing off yields a small one, and stopping yields zero. No manual delta tracking or timing is needed; ScrollTrigger measures it.

Mapping velocity to skew

The raw velocity is divided down (/ -260) to a sensible degree range and passed through gsap.utils.clamp(-14, 14) so even a violent flick can't shear the cards past a tasteful maximum. The negative divisor flips the sign so the cards lean the way that reads as "trailing" the scroll. This clamp-and-scale step is what keeps the effect feeling like physics rather than a glitch.

quickTo for cheap per-frame updates

Instead of creating a new tween every frame (expensive and janky), each card gets a gsap.quickTo(el, 'skewY', ...) setter — a reusable function that smoothly interpolates that one property toward whatever value you pass. On each scroll update the code calls every setter with the current skew, and GSAP eases the actual skewY toward it with a short power3 duration. That built-in easing is what makes the skew ramp up and settle smoothly, and crucially returns the cards to 0 when velocity drops, with no separate "reset" logic.

Why this is the right pattern

Skewing on scroll naively (writing transform directly from velocity) looks twitchy because raw velocity is noisy. Routing it through quickTo's interpolation low-passes the motion, and the clamp bounds it — together they turn a jittery signal into a fluid lean. ScrollTrigger's getVelocity removes the need to compute speed by hand across frames.

Composited and contained

Only transform (skewY) animates, so the browser composites the cards on the GPU with no reflow, and will-change: transform promotes them. The effect scales to many items because every card shares the same single velocity read per frame.

Customizing it

Change the divisor for more or less shear, the clamp for a tighter or looser limit, the quickTo duration for snappier or floatier recovery, or skew on skewX for a horizontal feel. Pair it with a scroll velocity marquee, a scroll reveal grid, or an animated list.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to reason through the velocity-to-skew pipeline alone. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why gsap.quickTo is used instead of writing a fresh tween or direct style write on every scroll frame, or why dividing getVelocity's raw pixels-per-second value by a negative constant both scales it into a usable degree range and flips its sign to make the lean feel like trailing motion. The same assistant can help optimize it — asking whether the clamp bounds (-14 to 14 degrees) should adapt for touch devices where flick velocities are typically higher, or whether a single shared quickTo could replace one setter per card if all cards should skew identically. It's also useful for extending the effect: ask it to add a matching horizontal skewX version, tie the skew intensity to an accessibility-respecting prefers-reduced-motion check, or drive a secondary blur amount from the same velocity reading for extra momentum feel. 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:

text
Build a "scroll skew velocity" list effect in plain HTML, CSS, and JavaScript using GSAP with its ScrollTrigger plugin (load both from a CDN) — using ScrollTrigger's velocity API, not manual scroll-delta timing.

Requirements:
- A vertical list of card elements between two spacer sections.
- Create one GSAP quickTo setter per card (not a full tween created fresh each frame) targeting the card's skewY property, with a short duration and an easing curve, so each card can be smoothly nudged toward a new skew value on every call without allocating new tweens.
- Register a single global ScrollTrigger (it does not need a specific trigger element or pin) with an onUpdate callback that runs on every scroll frame.
- Inside that onUpdate callback, read the current scroll velocity using ScrollTrigger's built-in velocity getter (pixels per second, signed by direction), divide it by a constant to scale it into a small degree range, and negate it so the sign matches the direction the cards should visually lean.
- Clamp that scaled velocity value to a reasonable maximum range (e.g. -14 to 14 degrees) using a clamp utility, so a very fast flick can never shear the cards past a tasteful limit.
- Call every card's quickTo setter with that same clamped skew value every frame, so all cards skew together and, thanks to quickTo's built-in easing, smoothly return to zero skew on their own once scroll velocity drops back to zero — do not write any separate "reset to zero" logic.
- Only animate the skewY transform property, never a layout-affecting property, so the effect stays GPU-composited even as more cards are added to the list.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Add the GSAP CDNsInclude gsap and ScrollTrigger from the CDN panel.
  2. 2
    Paste HTML, CSS, and JSA list of cards renders between spacers.
  3. 3
    Scroll quicklyThe cards skew in the scroll direction.
  4. 4
    Stop scrollingThe skew eases back to zero.
  5. 5
    Tune the shearChange the velocity divisor and clamp.
  6. 6
    Tune the recoveryAdjust the quickTo duration.

Real-world uses

Common Use Cases

Feature lists
Add momentum to an animated list.
Marquees
Galleries
Lean a scroll reveal grid on scroll.
Portfolios
Editorial
Give body sections a kinetic feel.
Landing
Energize a feature cards section.

Got questions?

Frequently Asked Questions

A global ScrollTrigger's onUpdate runs each scroll frame and calls self.getVelocity(), which returns the scroll speed in pixels per second — positive down, negative up. Fast scrolling gives a large value, easing off gives a small one, and stopping gives zero, so ScrollTrigger supplies the velocity without manual delta or timing code.

The raw velocity is divided down and clamped to a max of about 14 degrees, then passed to per-card gsap.quickTo setters. quickTo interpolates the skewY toward the new value with a short power3 ease, which low-passes the noisy signal into a fluid lean and naturally returns the cards to zero when velocity drops — no separate reset logic.

Writing the transform straight from velocity looks twitchy because the signal is jittery, and creating a fresh tween every frame is expensive. quickTo builds one reusable setter per property that smoothly eases toward whatever value you pass, giving cheap per-frame updates and built-in easing in one — the recommended GSAP pattern for continuous scroll-driven values.

Yes. Only skewY, a transform, animates, so the browser composites the cards on the GPU with no reflow, and will-change promotes them. There is a single getVelocity read per frame shared by all cards, so adding more items costs only the quickTo setter calls, which are lightweight.

In a mount effect, register ScrollTrigger, build quickTo setters for the card refs, and create one ScrollTrigger whose onUpdate clamps getVelocity and calls the setters. Return a cleanup that kills the ScrollTrigger and reverts the GSAP context so it stops on unmount. The CSS ports unchanged; keep the setters in a ref so they persist across renders.