{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "primitives-effects-particles",
  "title": "Particles",
  "description": "A particles effect that creates a particle system.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "@animate-ui/primitives-animate-slot",
    "@animate-ui/hooks-use-is-in-view",
    "@animate-ui/lib-get-strict-context"
  ],
  "files": [
    {
      "path": "registry/primitives/effects/particles/index.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { motion, AnimatePresence, type HTMLMotionProps } from 'motion/react';\n\nimport { Slot, type WithAsChild } from '@/components/animate-ui/primitives/animate/slot';\nimport {\n  useIsInView,\n  type UseIsInViewOptions,\n} from '@/hooks/use-is-in-view';\nimport { getStrictContext } from '@/lib/get-strict-context';\n\ntype Side = 'top' | 'bottom' | 'left' | 'right';\ntype Align = 'start' | 'center' | 'end';\n\ntype ParticlesContextType = {\n  animate: boolean;\n  isInView: boolean;\n};\n\nconst [ParticlesProvider, useParticles] =\n  getStrictContext<ParticlesContextType>('ParticlesContext');\n\ntype ParticlesProps = WithAsChild<\n  Omit<HTMLMotionProps<'div'>, 'children'> & {\n    animate?: boolean;\n    children: React.ReactNode;\n  } & UseIsInViewOptions\n>;\n\nfunction Particles({\n  ref,\n  animate = true,\n  asChild = false,\n  inView = false,\n  inViewMargin = '0px',\n  inViewOnce = true,\n  children,\n  style,\n  ...props\n}: ParticlesProps) {\n  const { ref: localRef, isInView } = useIsInView(\n    ref as React.Ref<HTMLDivElement>,\n    { inView, inViewOnce, inViewMargin },\n  );\n\n  const Component = asChild ? Slot : motion.div;\n\n  return (\n    <ParticlesProvider value={{ animate, isInView }}>\n      <Component\n        ref={localRef}\n        style={{ position: 'relative', ...style }}\n        {...props}\n      >\n        {children}\n      </Component>\n    </ParticlesProvider>\n  );\n}\n\ntype ParticlesEffectProps = Omit<HTMLMotionProps<'div'>, 'children'> & {\n  side?: Side;\n  align?: Align;\n  count?: number;\n  radius?: number;\n  spread?: number;\n  duration?: number;\n  holdDelay?: number;\n  sideOffset?: number;\n  alignOffset?: number;\n  delay?: number;\n};\n\nfunction ParticlesEffect({\n  side = 'top',\n  align = 'center',\n  count = 6,\n  radius = 30,\n  spread = 360,\n  duration = 0.8,\n  holdDelay = 0.05,\n  sideOffset = 0,\n  alignOffset = 0,\n  delay = 0,\n  transition,\n  style,\n  ...props\n}: ParticlesEffectProps) {\n  const { animate, isInView } = useParticles();\n\n  const isVertical = side === 'top' || side === 'bottom';\n  const alignPct = align === 'start' ? '0%' : align === 'end' ? '100%' : '50%';\n\n  const top = isVertical\n    ? side === 'top'\n      ? `calc(0% - ${sideOffset}px)`\n      : `calc(100% + ${sideOffset}px)`\n    : `calc(${alignPct} + ${alignOffset}px)`;\n\n  const left = isVertical\n    ? `calc(${alignPct} + ${alignOffset}px)`\n    : side === 'left'\n      ? `calc(0% - ${sideOffset}px)`\n      : `calc(100% + ${sideOffset}px)`;\n\n  const containerStyle: React.CSSProperties = {\n    position: 'absolute',\n    top,\n    left,\n    transform: 'translate(-50%, -50%)',\n  };\n\n  const angleStep = (spread * (Math.PI / 180)) / Math.max(1, count - 1);\n\n  return (\n    <AnimatePresence>\n      {animate &&\n        isInView &&\n        [...Array(count)].map((_, i) => {\n          const angle = i * angleStep;\n          const x = Math.cos(angle) * radius;\n          const y = Math.sin(angle) * radius;\n\n          return (\n            <motion.div\n              key={i}\n              style={{ ...containerStyle, ...style }}\n              initial={{ scale: 0, opacity: 0 }}\n              animate={{\n                x: `${x}px`,\n                y: `${y}px`,\n                scale: [0, 1, 0],\n                opacity: [0, 1, 0],\n              }}\n              transition={{\n                duration,\n                delay: delay + i * holdDelay,\n                ease: 'easeOut',\n                ...transition,\n              }}\n              {...props}\n            />\n          );\n        })}\n    </AnimatePresence>\n  );\n}\n\nexport {\n  Particles,\n  ParticlesEffect,\n  type ParticlesProps,\n  type ParticlesEffectProps,\n};\n",
      "type": "registry:ui",
      "target": "components/animate-ui/primitives/effects/particles.tsx"
    }
  ],
  "type": "registry:ui"
}