Scroll Velocity Skew
Skews its content based on how fast the page is being scrolled, relaxing back to flat at rest.
DOM + CSS1 dep1 file · 1 KB TSXreduced-motion aware
Props
"use client";
import { motion, useReducedMotion, useScroll, useSpring, useTransform, useVelocity } from "framer-motion";
import type { ReactNode } from "react";
export function ScrollVelocitySkew({
children,
sensitivity = 1,
maxSkew = 12,
}: {
children: ReactNode;
sensitivity?: number;
maxSkew?: number;
}) {
const prefersReducedMotion = useReducedMotion();
const { scrollY } = useScroll();
const velocity = useVelocity(scrollY);
// ---------------------------------------------------------------
// Full source available with a viberdy Pro subscription.
// https://viberdy.dev/pricing
// ---------------------------------------------------------------
}Details
About this animation
Scroll Velocity Skew animates transform: skewY() — a compositor-cheap property — but derives it from scroll velocity rather than scroll position, so unlike typical parallax it sits at 0 when idle and only tilts while the user is actively scrolling fast. A native CSS scroll-driven animation (animation-timeline: scroll()) can link a transform to scroll position directly, but it has no notion of velocity — that derivative math (useVelocity) is the actual reason this needs Framer Motion rather than pure CSS. The non-obvious detail: the raw velocity signal is spiky, since it's a per-frame derivative of a discrete scroll position, so it's run through a second spring (useSpring) before being mapped to skew degrees — skipping that smoothing step makes the effect visibly jittery on every trackpad or wheel tick instead of fluid. The caveat: because it's inherently a multi-frame, always-reactive effect, treat it as an effect to disable outright under reduced motion rather than one to merely tone down.


