{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "scroll-text-reveal",
  "title": "Scroll Text Reveal",
  "description": "Pins the section and reveals text word by word as you scroll; the page resumes once the reveal completes.",
  "dependencies": [
    "gsap",
    "@gsap/react"
  ],
  "registryDependencies": [
    "https://trytweenly.vercel.app/r/use-reduced-motion.json",
    "utils"
  ],
  "files": [
    {
      "path": "registry/new-york/scroll-text-reveal/scroll-text-reveal.tsx",
      "content": "\"use client\"\n\nimport { useRef } from \"react\"\nimport gsap from \"gsap\"\nimport { ScrollTrigger } from \"gsap/ScrollTrigger\"\nimport { useGSAP } from \"@gsap/react\"\nimport { useReducedMotion } from \"@/registry/new-york/hooks/use-reduced-motion\"\nimport { cn } from \"@/lib/utils\"\n\ngsap.registerPlugin(useGSAP, ScrollTrigger)\n\nexport interface ScrollTextRevealProps {\n  /** The text to reveal. */\n  text: string\n  /** Reveal word by word or character by character. Default: \"word\" */\n  split?: \"word\" | \"char\"\n  /** Opacity of text that hasn't been revealed yet, 0 to 1. Default: 0.15 */\n  dim?: number\n  /** Starting blur in px for unrevealed text. Default: 0 */\n  blur?: number\n  /** Starting vertical offset in px for unrevealed text. Default: 0 */\n  lift?: number\n  /** How many section-heights of scrolling the reveal lasts. Default: 2 */\n  scrollLength?: number\n  /** Smoothing applied to the scroll link, in seconds (0 = instant). Default: 0.8 */\n  scrub?: number\n  /** Hold the section in place until the reveal completes. Default: true */\n  pin?: boolean\n  /** Text alignment. Default: \"left\" */\n  align?: \"left\" | \"center\"\n  /** Scroll container to track instead of the window (selector or element). */\n  scroller?: string | HTMLElement\n  /** Height of the pinned section (any CSS length). Default: \"100vh\" */\n  height?: string\n  className?: string\n  /** Classes for the text element (font size, weight, color). */\n  textClassName?: string\n}\n\nexport function ScrollTextReveal({\n  text,\n  split = \"word\",\n  dim = 0.15,\n  blur = 0,\n  lift = 0,\n  scrollLength = 2,\n  scrub = 0.8,\n  pin = true,\n  align = \"left\",\n  scroller,\n  height = \"100vh\",\n  className,\n  textClassName,\n}: ScrollTextRevealProps) {\n  const sectionRef = useRef<HTMLElement>(null)\n  const reduced = useReducedMotion()\n\n  useGSAP(\n    () => {\n      const section = sectionRef.current\n      if (!section || reduced) return\n\n      const pieces = gsap.utils.toArray<HTMLElement>(\"[data-piece]\", section)\n      gsap.set(pieces, { opacity: dim, filter: blur ? `blur(${blur}px)` : \"none\", y: lift })\n\n      gsap\n        .timeline({\n          scrollTrigger: {\n            trigger: section,\n            scroller,\n            start: pin ? \"top top\" : \"top 80%\",\n            end: () => `+=${section.offsetHeight * scrollLength}`,\n            pin,\n            scrub: scrub || true,\n            invalidateOnRefresh: true,\n          },\n        })\n        .to(pieces, {\n          opacity: 1,\n          filter: \"blur(0px)\",\n          y: 0,\n          ease: \"none\",\n          stagger: 0.1,\n          duration: 0.4,\n        })\n    },\n    { scope: sectionRef, dependencies: [text, split, dim, blur, lift, scrollLength, scrub, pin, scroller, reduced], revertOnUpdate: true }\n  )\n\n  const words = text.split(\" \")\n\n  return (\n    <section\n      ref={sectionRef}\n      className={cn(\"flex w-full items-center px-6 sm:px-12\", align === \"center\" && \"justify-center\", className)}\n      style={{ height }}\n    >\n      <p\n        aria-label={text}\n        className={cn(\n          \"max-w-4xl text-3xl font-medium leading-tight tracking-tight sm:text-5xl\",\n          align === \"center\" && \"text-center\",\n          textClassName\n        )}\n      >\n        {words.map((word, wi) => (\n          <span key={wi} aria-hidden=\"true\">\n            {split === \"word\" ? (\n              <span data-piece className=\"inline-block\">\n                {word}\n              </span>\n            ) : (\n              <span className=\"inline-block whitespace-nowrap\">\n                {Array.from(word).map((c, ci) => (\n                  <span key={ci} data-piece className=\"inline-block\">\n                    {c}\n                  </span>\n                ))}\n              </span>\n            )}\n            {wi < words.length - 1 && \" \"}\n          </span>\n        ))}\n      </p>\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "docs": "Docs, live playground and every prop: https://trytweenly.vercel.app/docs/components/scroll-text-reveal",
  "type": "registry:component"
}