{
  "name": "scroll-based-velocity",
  "type": "registry:ui",
  "dependencies": [
    "framer-motion"
  ],
  "registryDependencies": [],
  "description": "Text that scrolls across the screen and skews/speeds up based on the users scroll velocity.",
  "files": [
    {
      "path": "components/ui/scroll-based-velocity.tsx",
      "content": "\"use client\";\n\nimport React, { useRef } from \"react\";\nimport {\n    motion,\n    useScroll,\n    useSpring,\n    useTransform,\n    useMotionValue,\n    useVelocity,\n    useAnimationFrame,\n    wrap,\n} from \"framer-motion\";\nimport { cn } from \"@workspace/ui/lib/utils\";\n\ninterface ScrollBasedVelocityProps {\n    text: string;\n    default_velocity?: number;\n    className?: string;\n    containerRef?: React.RefObject<HTMLElement | null>;\n}\n\ninterface ParallaxProps {\n    children: string;\n    baseVelocity: number;\n    className?: string;\n    containerRef?: React.RefObject<HTMLElement | null>;\n}\n\nfunction ParallaxText({ children, baseVelocity = 100, className, containerRef }: ParallaxProps) {\n    const baseX = useMotionValue(0);\n    const { scrollY } = useScroll(containerRef ? { container: containerRef } : undefined);\n    const scrollVelocity = useVelocity(scrollY);\n    const smoothVelocity = useSpring(scrollVelocity, {\n        damping: 50,\n        stiffness: 400,\n    });\n    const velocityFactor = useTransform(smoothVelocity, [0, 1000], [0, 5], {\n        clamp: false,\n    });\n\n    /**\n     * This is a magic wrapping for the length of the text - you\n     * have to replace for wrapping that works for you or dynamically\n     * calculate\n     */\n    const x = useTransform(baseX, (v) => `${wrap(-12.5, 0, v)}%`);\n\n    const directionFactor = useRef<number>(1);\n    useAnimationFrame((t, delta) => {\n        let moveBy = directionFactor.current * baseVelocity * (delta / 1000);\n\n        /**\n         * This is what changes the direction of the scroll once we\n         * switch scrolling directions.\n         */\n        if (velocityFactor.get() < 0) {\n            directionFactor.current = -1;\n        } else if (velocityFactor.get() > 0) {\n            directionFactor.current = 1;\n        }\n\n        moveBy += directionFactor.current * moveBy * velocityFactor.get();\n\n        baseX.set(baseX.get() + moveBy);\n    });\n\n    return (\n        <div className=\"overflow-hidden whitespace-nowrap flex flex-nowrap\" style={{ width: '100%' }}>\n            <motion.div\n                className={cn(\"flex whitespace-nowrap\", className)}\n                style={{ x }}\n            >\n                {Array.from({ length: 8 }).map((_, i) => (\n                    <span key={i} className=\"block mr-10 last:mr-10\">{children}</span>\n                ))}\n            </motion.div>\n        </div>\n    );\n}\n\nexport function ScrollBasedVelocity({\n    text,\n    default_velocity = 5,\n    className,\n    containerRef,\n}: ScrollBasedVelocityProps) {\n    return (\n        <section className=\"relative w-full\">\n            <ParallaxText baseVelocity={default_velocity} className={className} containerRef={containerRef}>\n                {text}\n            </ParallaxText>\n            <ParallaxText baseVelocity={-default_velocity} className={className} containerRef={containerRef}>\n                {text}\n            </ParallaxText>\n        </section>\n    );\n}\n",
      "type": "registry:ui"
    }
  ]
}
