Scroll velocity
Also called scroll-based velocity, velocity marquee, or scroll-reactive marquee
Marquee rows that race while you scroll and turn around when you scroll back up, driven by how fast the page is moving.
import { useRef } from 'react';
import {
motion,
useAnimationFrame,
useMotionValue,
useReducedMotion,
useScroll,
useSpring,
useVelocity
} from 'motion/react';
const BASE_SPEED = 40; // px per second while the page is still
export function VelocityRow({
text,
reverse = false
}: {
text: string;
reverse?: boolean;
}) {
const track = useRef<HTMLDivElement>(null);
const heading = useRef(1);
const reduceMotion = useReducedMotion();
const { scrollY } = useScroll();
// Scroll speed in px/s, smoothed so a mouse wheel's bursts don't jerk the row.
const velocity = useSpring(useVelocity(scrollY), {
stiffness: 300,
damping: 50
});
const x = useMotionValue(0);
useAnimationFrame((_, delta) => {
if (reduceMotion || !track.current) return;
const speed = velocity.get();
// Scrolling up flips the row until the reader scrolls down again.
if (Math.abs(speed) > 30) heading.current = Math.sign(speed);
const multiplier = Math.min(1 + Math.abs(speed) / 200, 8);
const step = BASE_SPEED * multiplier * (delta / 1000);
const next = x.get() - step * heading.current * (reverse ? -1 : 1);
// Wrap within one copy; the second copy hides the jump.
const copyWidth = track.current.scrollWidth / 2;
x.set(((next % copyWidth) - copyWidth) % copyWidth);
});
// Each copy repeats the text so it is wider than the screen.
const repeated = Array.from({ length: 4 }, () => text).join(' ');
return (
<div className='overflow-hidden py-2'>
{/* Screen readers get the text once; the moving copies are hidden. */}
<p className='sr-only'>{text}</p>
<motion.div
ref={track}
aria-hidden
style={{ x }}
className='flex w-max'
>
{[0, 1].map((copy) => (
<span
key={copy}
className='shrink-0 pr-6 text-6xl font-semibold tracking-tight whitespace-nowrap'
>
{repeated}
</span>
))}
</motion.div>
</div>
);
}
// <VelocityRow text='Describe it · Preview it · Publish it ·' />
// <VelocityRow text='Database · Storage · Email · Domains ·' reverse />Add a scroll velocity divider between the features and pricing sections: two rows of 64px semibold words ("Describe it · Preview it · Publish it") that drift sideways at 40px per second in opposite directions. Read scroll speed with Motion’s useScroll, useVelocity, and useSpring (stiffness 300, damping 50), multiply the drift by 1 + speed / 200, capped at 8×, and flip both rows while the reader scrolls up. Duplicate each row for a seamless wrap, hide the copies from screen readers, and keep the rows still when prefers-reduced-motion is set.
Paste into Layerwise or any AI coding tool.
What is Scroll velocity?
A scroll velocity effect takes a marquee, a row of large words or logos drifting sideways, and ties its speed to how fast the page scrolls. At rest the row drifts slowly. A quick flick of the wheel sends it racing, and scrolling up turns it around. Two rows running in opposite directions are the classic layout.
The speed comes from scroll velocity: how many pixels the page moves per second. In Motion, useScroll gives scrollY, useVelocity turns it into pixels per second, and useSpring smooths the bursts a mouse wheel sends. A useAnimationFrame loop then moves the row by its base speed times a multiplier from that velocity, and wraps the offset by the width of one copy so the loop never shows a seam.
Use it as a bold divider between sections on portfolios, agency sites, and launch pages. Cap the multiplier so a fast trackpad swipe doesn’t smear the text, pause the loop while it is off screen, and keep the rows still for people who prefer reduced motion. The moving copies are decorative, so hide them with aria-hidden and give screen readers the text once.
Often confused with
- Marquee
- A marquee scrolls at one steady speed on its own. A scroll velocity row starts from a marquee and speeds up, slows down, or reverses with the page’s scroll.
Related terms
All termsMarquee
A strip of logos or text that scrolls sideways in an endless loop, often used for "trusted by" rows and announcements.
Velocity
The speed and direction an element already has when an animation starts, which a spring carries forward so a flick flows into what follows.
Scroll-driven animation
An animation whose progress is tied directly to the scroll position, so it moves forward as you scroll down and rewinds as you scroll up.
Horizontal scroll section
A pinned section where scrolling down moves a row of cards sideways, turning vertical scrolling into horizontal movement.
Build it with Layerwise
Describe your app, watch it run in a live preview, and publish it with a database, storage, and sign-in built in.