2025-05-05 22:33:15 +08:00

61 lines
1.8 KiB
TypeScript

"use client"
import {useRef} from "react"
import {
motion,
useScroll,
useSpring,
useTransform,
useMotionValue,
useVelocity,
useAnimationFrame,
} from "framer-motion"
import {wrap} from "@motionone/utils"
interface ParallaxProps {
children: string
baseVelocity: number
}
export default function ParallaxText({children, baseVelocity = 100}: ParallaxProps) {
const baseX = useMotionValue(0)
const {scrollY} = useScroll()
const scrollVelocity = useVelocity(scrollY)
const smoothVelocity = useSpring(scrollVelocity, {
damping: 50,
stiffness: 400,
})
const velocityFactor = useTransform(smoothVelocity, [0, 1000], [0, 5], {
clamp: false,
})
const x = useTransform(baseX, (v) => `${wrap(-20, -45, v)}%`)
const directionFactor = useRef<number>(1)
useAnimationFrame((t, delta) => {
let moveBy = directionFactor.current * baseVelocity * (delta / 1000)
if (velocityFactor.get() < 0) {
directionFactor.current = -1
} else if (velocityFactor.get() > 0) {
directionFactor.current = 1
}
moveBy += directionFactor.current * moveBy * velocityFactor.get()
baseX.set(baseX.get() + moveBy)
})
return (
<div className="overflow-hidden whitespace-nowrap flex flex-nowrap m-0 py-6">
<motion.div className="font-bold text-4xl md:text-6xl flex whitespace-nowrap flex-nowrap"
style={{x}}>
<span className="block mr-6">{children}</span>
<span className="block mr-6">{children}</span>
<span className="block mr-6">{children}</span>
<span className="block mr-6">{children}</span>
</motion.div>
</div>
)
}