{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "mesh-gradient-card",
  "title": "Mesh Gradient Card",
  "dependencies": [
    "@paper-design/shaders-react",
    "motion"
  ],
  "files": [
    {
      "path": "registry/default/ui/mesh-gradient-card.tsx",
      "content": "'use client';\n\nimport React, {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useRef,\n  useState,\n} from 'react';\n\nimport {\n  MeshGradient,\n  type MeshGradientParams,\n  type MeshGradientProps,\n} from '@paper-design/shaders-react';\nimport { animate, AnimatePresence, motion } from 'motion/react';\n\nimport { cn } from '@/lib/utils';\n\ntype GradientStep = Required<\n  Pick<\n    MeshGradientParams,\n    | 'distortion'\n    | 'swirl'\n    | 'grainMixer'\n    | 'grainOverlay'\n    | 'speed'\n    | 'scale'\n    | 'rotation'\n    | 'offsetX'\n    | 'offsetY'\n  >\n>;\n\nconst DEFAULT_STEPS: GradientStep[] = [\n  {\n    distortion: 0.3,\n    swirl: 0.1,\n    grainMixer: 0.16,\n    grainOverlay: 0.15,\n    speed: 0.45,\n    scale: 1.0,\n    rotation: 0,\n    offsetX: 0,\n    offsetY: 0,\n  },\n  {\n    distortion: 0.5,\n    swirl: 0.3,\n    grainMixer: 0.1,\n    grainOverlay: 0.1,\n    speed: 0.55,\n    scale: 1.2,\n    rotation: 15,\n    offsetX: 0.1,\n    offsetY: -0.05,\n  },\n  {\n    distortion: 0.4,\n    swirl: 0.8,\n    grainMixer: 0.2,\n    grainOverlay: 0.1,\n    speed: 0.38,\n    scale: 0.9,\n    rotation: -10,\n    offsetX: -0.15,\n    offsetY: 0.1,\n  },\n  {\n    distortion: 0.9,\n    swirl: 0.5,\n    grainMixer: 0.12,\n    grainOverlay: 0.2,\n    speed: 0.65,\n    scale: 1.4,\n    rotation: 25,\n    offsetX: 0.05,\n    offsetY: -0.1,\n  },\n  {\n    distortion: 0.25,\n    swirl: 0.2,\n    grainMixer: 0.6,\n    grainOverlay: 0.5,\n    speed: 0.5,\n    scale: 1.1,\n    rotation: -5,\n    offsetX: -0.05,\n    offsetY: 0.05,\n  },\n  {\n    distortion: 0.6,\n    swirl: 0.9,\n    grainMixer: 0.08,\n    grainOverlay: 0.05,\n    speed: 0.3,\n    scale: 0.8,\n    rotation: 35,\n    offsetX: 0.12,\n    offsetY: 0.08,\n  },\n  {\n    distortion: 0.15,\n    swirl: 0.05,\n    grainMixer: 0.5,\n    grainOverlay: 0.4,\n    speed: 0.6,\n    scale: 1.3,\n    rotation: -20,\n    offsetX: -0.1,\n    offsetY: -0.08,\n  },\n];\n\nconst MeshGradientCardContext = createContext<{ messageIndex: number }>({\n  messageIndex: 0,\n});\n\ntype MeshGradientCardProps = Partial<\n  Omit<MeshGradientProps, 'width' | 'height'>\n> & {\n  steps?: GradientStep[];\n  interval?: number;\n  children?: React.ReactNode;\n};\n\nfunction MeshGradientCardRoot({\n  className,\n  ...props\n}: React.ComponentProps<'div'>) {\n  return (\n    <div\n      data-slot='mesh-gradient-card'\n      className={cn('relative overflow-hidden rounded-4xl', className)}\n      {...props}\n    />\n  );\n}\n\nfunction MeshGradientCard({\n  className,\n  children,\n  colors = ['#fafafa', '#18181b', '#fafafa', '#18181b'],\n  steps = DEFAULT_STEPS,\n  interval = 4000,\n  ...shaderProps\n}: MeshGradientCardProps) {\n  const { config, messageIndex } = useGradientCycler(steps, interval);\n\n  return (\n    <MeshGradientCardContext.Provider value={{ messageIndex }}>\n      <MeshGradientCardRoot className={className}>\n        <MeshGradient\n          width='100%'\n          height='100%'\n          colors={colors}\n          {...config}\n          {...shaderProps}\n        />\n        {children}\n      </MeshGradientCardRoot>\n    </MeshGradientCardContext.Provider>\n  );\n}\n\nfunction MeshGradientCardMessages({\n  children,\n  className,\n}: {\n  children?: React.ReactNode;\n  className?: string;\n}) {\n  const { messageIndex } = useContext(MeshGradientCardContext);\n  const items = React.Children.toArray(children);\n  const active = items[messageIndex % items.length];\n\n  return (\n    <span data-slot='mesh-gradient-card-messages' className={className}>\n      <AnimatePresence mode='wait'>\n        {React.isValidElement(active)\n          ? React.cloneElement(active, {\n              key: messageIndex,\n            } as React.Attributes)\n          : active}\n      </AnimatePresence>\n    </span>\n  );\n}\n\nfunction MeshGradientCardMessage({\n  children,\n  className,\n}: {\n  children?: React.ReactNode;\n  className?: string;\n}) {\n  return (\n    <motion.span\n      data-slot='mesh-gradient-card-message'\n      initial={{ opacity: 0, filter: 'blur(8px)' }}\n      animate={{ opacity: 1, filter: 'blur(0px)' }}\n      exit={{ opacity: 0, filter: 'blur(8px)' }}\n      transition={{ duration: 0.45, ease: 'easeInOut' }}\n      style={{\n        textShadow: '0 1px 4px rgba(0,0,0,0.3), 0 4px 12px rgba(0,0,0,0.2)',\n      }}\n      className={cn(\n        'absolute right-5 bottom-4 pb-1 text-lg font-medium text-white select-none',\n        className\n      )}\n    >\n      {children}\n    </motion.span>\n  );\n}\n\nfunction useGradientCycler(\n  steps: GradientStep[] = DEFAULT_STEPS,\n  interval: number = 4000\n) {\n  const [stepIndex, setStepIndex] = useState(0);\n  const [config, setConfig] = useState<GradientStep>(steps[0]);\n  const animationRef = useRef<ReturnType<typeof animate> | null>(null);\n  const [messageIndex, setMessageIndex] = useState(0);\n\n  const goToStep = useCallback(\n    (n: number) => {\n      if (n === stepIndex) return;\n      animationRef.current?.stop();\n\n      const from = { ...config };\n      const to = steps[n];\n\n      animationRef.current = animate(from, to, {\n        duration: 0.6,\n        ease: 'easeOut',\n        onUpdate: () => setConfig({ ...from }),\n      });\n\n      setStepIndex(n);\n      setMessageIndex((i) => i + 1);\n    },\n    [stepIndex, config, steps]\n  );\n\n  useEffect(() => {\n    const id = setTimeout(() => {\n      goToStep((stepIndex + 1) % steps.length);\n    }, interval);\n    return () => clearTimeout(id);\n  }, [stepIndex, goToStep, steps.length, interval]);\n\n  return { config, stepIndex, messageIndex, goToStep };\n}\n\nexport {\n  MeshGradientCard,\n  MeshGradientCardMessage,\n  MeshGradientCardMessages,\n  MeshGradientCardRoot,\n  useGradientCycler,\n};\n\nexport type { GradientStep, MeshGradientCardProps };\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}