{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-logoclouds-logocloud-3",
  "title": "Logo Cloud 3",
  "description": "Infinite scrolling logo marquee with progressive blur edges and motion-powered animation.",
  "dependencies": [
    "motion",
    "react-use-measure"
  ],
  "files": [
    {
      "path": "registry/components/logoclouds/logocloud-3/index.tsx",
      "content": "'use client';\n\nimport { cn } from '@/lib/utils';\nimport { animate, HTMLMotionProps, motion, useMotionValue } from 'motion/react';\nimport { useEffect, useRef } from 'react';\nimport useMeasure from 'react-use-measure';\n\ntype InfiniteSliderProps = {\n  children: React.ReactNode;\n  gap?: number;\n  speed?: number;\n  pauseOnHover?: boolean;\n  direction?: 'horizontal' | 'vertical';\n  reverse?: boolean;\n  className?: string;\n};\n\nfunction InfiniteSlider({\n  children,\n  gap = 16,\n  speed = 100,\n  pauseOnHover = false,\n  direction = 'horizontal',\n  reverse = false,\n  className,\n}: InfiniteSliderProps) {\n  const [ref, { width, height }] = useMeasure();\n  const translation = useMotionValue(0);\n  const animationRef = useRef<ReturnType<typeof animate> | null>(null);\n\n  useEffect(() => {\n    const size = direction === 'horizontal' ? width : height;\n    const contentSize = size + gap;\n    const from = reverse ? -contentSize / 2 : 0;\n    const to = reverse ? 0 : -contentSize / 2;\n\n    animationRef.current = animate(translation, [from, to], {\n      ease: 'linear',\n      duration: Math.abs(to - from) / speed,\n      repeat: Infinity,\n      repeatType: 'loop',\n      repeatDelay: 0,\n      onRepeat: () => translation.set(from),\n    });\n\n    return () => animationRef.current?.stop();\n  }, [translation, speed, width, height, gap, direction, reverse]);\n\n  const hoverProps = pauseOnHover\n    ? {\n        onHoverStart: () => animationRef.current?.pause(),\n        onHoverEnd: () => animationRef.current?.play(),\n      }\n    : {};\n\n  return (\n    <div className={cn('overflow-hidden', className)}>\n      <motion.div\n        ref={ref}\n        className=\"flex w-max\"\n        style={{\n          ...(direction === 'horizontal'\n            ? { x: translation }\n            : { y: translation }),\n          gap: `${gap}px`,\n          flexDirection: direction === 'horizontal' ? 'row' : 'column',\n        }}\n        {...hoverProps}\n      >\n        {children}\n        {children}\n      </motion.div>\n    </div>\n  );\n}\n\nconst GRADIENT_ANGLES = { top: 0, right: 90, bottom: 180, left: 270 } as const;\n\ntype ProgressiveBlurProps = {\n  direction?: keyof typeof GRADIENT_ANGLES;\n  blurLayers?: number;\n  className?: string;\n  blurIntensity?: number;\n} & HTMLMotionProps<'div'>;\n\nfunction ProgressiveBlur({\n  direction = 'bottom',\n  blurLayers = 8,\n  className,\n  blurIntensity = 0.25,\n  ...props\n}: ProgressiveBlurProps) {\n  const layers = Math.max(blurLayers, 2);\n  const segmentSize = 1 / (blurLayers + 1);\n  const angle = GRADIENT_ANGLES[direction];\n\n  return (\n    <div className={cn('relative', className)}>\n      {Array.from({ length: layers }).map((_, i) => {\n        const stops = [i, i + 1, i + 2, i + 3]\n          .map(\n            (n, j) =>\n              `rgba(255,255,255,${j === 1 || j === 2 ? 1 : 0}) ${n * segmentSize * 100}%`,\n          )\n          .join(', ');\n        const gradient = `linear-gradient(${angle}deg, ${stops})`;\n        return (\n          <motion.div\n            key={i}\n            className=\"pointer-events-none absolute inset-0 rounded-[inherit]\"\n            style={{\n              maskImage: gradient,\n              WebkitMaskImage: gradient,\n              backdropFilter: `blur(${i * blurIntensity}px)`,\n              WebkitBackdropFilter: `blur(${i * blurIntensity}px)`,\n            }}\n            {...props}\n          />\n        );\n      })}\n    </div>\n  );\n}\n\ntype LogoItem = {\n  name: string;\n  svg: React.ReactNode;\n};\n\ntype LogoCloudProps = {\n  logos: LogoItem[];\n  label?: string;\n  speed?: number;\n  gap?: number;\n  reverse?: boolean;\n};\n\nexport default function LogoCloud({\n  logos,\n  label,\n  speed = 40,\n  gap = 112,\n  reverse = false,\n}: LogoCloudProps) {\n  return (\n    <section className=\"overflow-hidden bg-background py-16\">\n      <div className=\"group relative m-auto max-w-7xl px-6\">\n        <div className=\"flex flex-col items-center md:flex-row\">\n          {label && (\n            <div className=\"md:max-w-44 md:border-r md:pr-6\">\n              <p className=\"text-end text-sm text-muted-foreground\">{label}</p>\n            </div>\n          )}\n          <div\n            className={cn(\n              'relative w-full py-6',\n              label && 'md:w-[calc(100%-11rem)]',\n            )}\n          >\n            <InfiniteSlider\n              speed={speed}\n              gap={gap}\n              reverse={reverse}\n              pauseOnHover\n            >\n              {logos.map(({ name, svg }) => (\n                <span\n                  key={name}\n                  aria-label={name}\n                  className=\"flex items-center\"\n                >\n                  {svg}\n                </span>\n              ))}\n            </InfiniteSlider>\n\n            <div\n              aria-hidden\n              className=\"absolute inset-y-0 left-0 w-20 bg-linear-to-r from-background\"\n            />\n            <div\n              aria-hidden\n              className=\"absolute inset-y-0 right-0 w-20 bg-linear-to-l from-background\"\n            />\n            <ProgressiveBlur\n              className=\"pointer-events-none absolute top-0 left-0 h-full w-20\"\n              direction=\"left\"\n              blurIntensity={1}\n            />\n            <ProgressiveBlur\n              className=\"pointer-events-none absolute top-0 right-0 h-full w-20\"\n              direction=\"right\"\n              blurIntensity={1}\n            />\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/odysseyui/logocloud-3.tsx"
    }
  ],
  "type": "registry:ui"
}