{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "scroll-text-rise", "type": "registry:ui", "title": "Scroll Text Rise", "description": "A scroll-driven text reveal — each word fades up from below as you scroll, with staggered opacity and y-translate transforms powered by Framer Motion's useScroll and useTransform hooks.", "dependencies": [ "motion" ], "registryDependencies": [], "files": [ { "path": "registry/ruixenui/scroll-text-rise.tsx", "content": "\"use client\";\n\nimport { FC, ReactNode, useRef } from \"react\";\nimport { motion, MotionValue, useScroll, useTransform } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface ScrollTextRiseProps {\n text: string;\n className?: string;\n /** Text size classes */\n textClassName?: string;\n}\n\nconst ScrollTextRise: FC = ({\n text,\n className,\n textClassName,\n}) => {\n const containerRef = useRef(null);\n\n const { scrollYProgress } = useScroll({\n container: containerRef,\n });\n\n const words = text.split(\" \");\n\n return (\n \n \n {/* 3× container height creates the scroll runway */}\n
\n {/* sticky viewport — calc(100%/3) of the 300% parent = exact container height */}\n
\n \n {words.map((word, i) => {\n const start = i / words.length;\n const end = start + 0.03;\n return (\n \n {word}\n \n );\n })}\n

\n
\n
\n \n );\n};\n\ninterface RevealWordProps {\n children: ReactNode;\n progress: MotionValue;\n range: [number, number];\n}\n\nconst RevealWord: FC = ({ children, progress, range }) => {\n const opacity = useTransform(progress, range, [0, 1]);\n const y = useTransform(progress, range, [20, 0]);\n\n return (\n \n {children}\n \n {children}\n \n \n );\n};\n\nexport { ScrollTextRise };\n", "type": "registry:ui", "target": "components/ruixen/scroll-text-rise.tsx" } ] }