scroll-based-velocity
componentry/scroll-based-velocityFreeComponent
Text that scrolls across the screen and skews/speeds up based on the users scroll velocity.
Live preview
live · rendered by the registry
Rendered by componentry on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://componentry.dev/r/scroll-based-velocity.jsonSource
1"use client";23import React, { useRef } from "react";4import {5 motion,6 useScroll,7 useSpring,8 useTransform,9 useMotionValue,10 useVelocity,11 useAnimationFrame,12 wrap,13} from "framer-motion";14import { cn } from "@workspace/ui/lib/utils";1516interface ScrollBasedVelocityProps {17 text: string;18 default_velocity?: number;19 className?: string;20 containerRef?: React.RefObject<HTMLElement | null>;21}2223interface ParallaxProps {24 children: string;25 baseVelocity: number;26 className?: string;27 containerRef?: React.RefObject<HTMLElement | null>;28}2930function ParallaxText({ children, baseVelocity = 100, className, containerRef }: ParallaxProps) {31 const baseX = useMotionValue(0);32 const { scrollY } = useScroll(containerRef ? { container: containerRef } : undefined);33 const scrollVelocity = useVelocity(scrollY);34 const smoothVelocity = useSpring(scrollVelocity, {35 damping: 50,36 stiffness: 400,37 });38 const velocityFactor = useTransform(smoothVelocity, [0, 1000], [0, 5], {39 clamp: false,40 });4142 /**43 * This is a magic wrapping for the length of the text - you44 * have to replace for wrapping that works for you or dynamically45 * calculate46 */47 const x = useTransform(baseX, (v) => `${wrap(-12.5, 0, v)}%`);4849 const directionFactor = useRef<number>(1);50 useAnimationFrame((t, delta) => {51 let moveBy = directionFactor.current * baseVelocity * (delta / 1000);5253 /**54 * This is what changes the direction of the scroll once we55 * switch scrolling directions.56 */57 if (velocityFactor.get() < 0) {58 directionFactor.current = -1;59 } else if (velocityFactor.get() > 0) {60 directionFactor.current = 1;61 }6263 moveBy += directionFactor.current * moveBy * velocityFactor.get();6465 baseX.set(baseX.get() + moveBy);66 });6768 return (69 <div className="overflow-hidden whitespace-nowrap flex flex-nowrap" style={{ width: '100%' }}>70 <motion.div71 className={cn("flex whitespace-nowrap", className)}72 style={{ x }}73 >74 {Array.from({ length: 8 }).map((_, i) => (75 <span key={i} className="block mr-10 last:mr-10">{children}</span>76 ))}77 </motion.div>78 </div>79 );80}8182export function ScrollBasedVelocity({83 text,84 default_velocity = 5,85 className,86 containerRef,87// … truncated
More from componentry
All 59 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Gradientanimated-gradient | componentry | Components | Free | no deps | |
| ASCII Effectascii-effect | componentry | Components | Free | no deps | |
| Aurora Flowaurora-flow | componentry | Components | Free | no deps | |
| auth-modalauth-modal | componentry | Components | Free | no deps | |
| border-beamborder-beam | componentry | Components | Free | no deps | |
| circuit-boardcircuit-board | componentry | Components | Free | no deps | |
| closing-plasmaclosing-plasma | componentry | Components | Free | no deps | |
| collection-surfercollection-surfer | componentry | Components | Free | no deps |
