{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "svg-draw",
  "type": "registry:ui",
  "title": "SVG Draw",
  "description": "Wrap any inline SVG and it draws itself in: every path, line, circle, rect and polygon traces its outline, one after another, then its fill fades in. Outline icons draw in their own stroke, filled logos are traced in a thin line that fades as they fill. Plays when it scrolls into view or on mount. GSAP DrawSVG and ScrollTrigger.",
  "dependencies": [
    "gsap",
    "@gsap/react"
  ],
  "registryDependencies": [],
  "cssVars": {
    "theme": {}
  },
  "files": [
    {
      "path": "components/tweenui/svg-draw.tsx",
      "type": "registry:component",
      "target": "components/tweenui/svg-draw.tsx",
      "content": "'use client';\n\nimport { useEffect, useRef, type ComponentPropsWithoutRef } from 'react';\nimport { useGSAP } from '@gsap/react';\nimport gsap from 'gsap';\nimport { DrawSVGPlugin } from 'gsap/DrawSVGPlugin';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\nimport { cn } from '@/lib/utils';\n\ngsap.registerPlugin(useGSAP, DrawSVGPlugin, ScrollTrigger);\n\nconst prefersReducedMotion = () =>\n  typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\nconst SHAPES = 'path, line, polyline, polygon, circle, ellipse, rect';\n// Shapes inside these are never painted where they sit\nconst UNPAINTED = 'defs, clipPath, mask, pattern, marker, symbol';\nconst NO_PAINT = new Set(['none', 'transparent', 'rgba(0, 0, 0, 0)']);\nconst FILL_FADE = 0.5;\n\nexport interface SvgDrawProps extends ComponentPropsWithoutRef<'div'> {\n  /** Seconds each shape takes to draw. */\n  duration?: number;\n  delay?: number;\n  /** Seconds between one shape starting and the next. */\n  stagger?: number;\n  /** Any GSAP ease. */\n  ease?: string;\n  /** Width in screen px of the line that traces a fill-only shape. */\n  width?: number;\n  trigger?: 'view' | 'mount';\n  /** ScrollTrigger start, with `trigger=\"view\"`. */\n  start?: string;\n  onComplete?: () => void;\n}\n\nconst SvgDraw = ({\n  duration = 1.4,\n  delay = 0,\n  stagger = 0.12,\n  ease = 'power2.inOut',\n  width = 1.5,\n  trigger = 'view',\n  start = 'top 85%',\n  onComplete,\n  className,\n  children,\n  ...props\n}: SvgDrawProps) => {\n  const rootRef = useRef<HTMLDivElement>(null);\n  const onCompleteRef = useRef(onComplete);\n\n  useEffect(() => {\n    onCompleteRef.current = onComplete;\n  }, [onComplete]);\n\n  useGSAP(\n    () => {\n      const root = rootRef.current;\n      if (!root) return;\n      gsap.set(root, { visibility: 'visible' });\n      if (prefersReducedMotion()) return;\n\n      const shapes = gsap.utils\n        .toArray<SVGGeometryElement>(root.querySelectorAll(SHAPES))\n        .filter((shape) => !shape.closest(UNPAINTED));\n      if (!shapes.length) return;\n\n      const painted = (shape: Element, paint: 'fill' | 'stroke') =>\n        !NO_PAINT.has(getComputedStyle(shape)[paint]);\n      const filled = shapes.filter((shape) => painted(shape, 'fill'));\n      // Fill-only shapes get a thin line to draw with, which fades once they fill\n      const traced = filled.filter((shape) => !painted(shape, 'stroke'));\n      gsap.set(traced, {\n        stroke: 'currentColor',\n        strokeWidth: width,\n        vectorEffect: 'non-scaling-stroke',\n      });\n\n      gsap\n        .timeline({\n          delay,\n          scrollTrigger: trigger === 'view' ? { trigger: root, start, once: true } : undefined,\n          onComplete: () => onCompleteRef.current?.(),\n        })\n        .from(shapes, { drawSVG: 0, duration, ease, stagger })\n        .from(filled, { fillOpacity: 0, duration: FILL_FADE, stagger }, duration * 0.6)\n        .to(traced, { strokeOpacity: 0, duration: FILL_FADE, stagger }, '<');\n    },\n    {\n      scope: rootRef,\n      dependencies: [duration, delay, stagger, ease, width, trigger, start],\n      revertOnUpdate: true,\n    }\n  );\n\n  return (\n    <div\n      ref={rootRef}\n      className={cn('motion-reduce:visible! [@media(scripting:enabled)]:invisible', className)}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n};\n\nexport default SvgDraw;\n"
    }
  ],
  "docs": "Docs, props and examples: https://tween-ui.vercel.app/component/svg-draw\nGSAP plugins (DrawSVGPlugin, ScrollTrigger) are registered inside the component, so there is nothing to set up.\nWrap inline SVG markup, not an <img src=\"*.svg\">: only shapes in the page DOM can be traced. Give it a new key to play it again."
}