{
  "name": "background-beams-with-collision",
  "type": "registry:ui",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/background-beams-with-collision.tsx",
      "content": "\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport { motion, AnimatePresence } from \"motion/react\";\nimport React, { useRef, useState, useEffect } from \"react\";\n\nexport const BackgroundBeamsWithCollision = ({\n  children,\n  className,\n}: {\n  children: React.ReactNode;\n  className?: string;\n}) => {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const parentRef = useRef<HTMLDivElement>(null);\n\n  const beams = [\n    {\n      initialX: 10,\n      translateX: 10,\n      duration: 7,\n      repeatDelay: 3,\n      delay: 2,\n    },\n    {\n      initialX: 600,\n      translateX: 600,\n      duration: 3,\n      repeatDelay: 3,\n      delay: 4,\n    },\n    {\n      initialX: 100,\n      translateX: 100,\n      duration: 7,\n      repeatDelay: 7,\n      className: \"h-6\",\n    },\n    {\n      initialX: 400,\n      translateX: 400,\n      duration: 5,\n      repeatDelay: 14,\n      delay: 4,\n    },\n    {\n      initialX: 800,\n      translateX: 800,\n      duration: 11,\n      repeatDelay: 2,\n      className: \"h-20\",\n    },\n    {\n      initialX: 1000,\n      translateX: 1000,\n      duration: 4,\n      repeatDelay: 2,\n      className: \"h-12\",\n    },\n    {\n      initialX: 1200,\n      translateX: 1200,\n      duration: 6,\n      repeatDelay: 4,\n      delay: 2,\n      className: \"h-6\",\n    },\n  ];\n\n  return (\n    <div\n      ref={parentRef}\n      className={cn(\n        \"h-96 md:h-[40rem] bg-gradient-to-b from-white to-neutral-100 dark:from-neutral-950 dark:to-neutral-800 relative flex items-center w-full justify-center overflow-hidden\",\n        // h-screen if you want bigger\n        className\n      )}\n    >\n      {beams.map((beam) => (\n        <CollisionMechanism\n          key={beam.initialX + \"beam-idx\"}\n          beamOptions={beam}\n          containerRef={containerRef}\n          parentRef={parentRef}\n        />\n      ))}\n\n      {children}\n      <div\n        ref={containerRef}\n        className=\"absolute bottom-0 bg-neutral-100 w-full inset-x-0 pointer-events-none\"\n        style={{\n          boxShadow:\n            \"0 0 24px rgba(34, 42, 53, 0.06), 0 1px 1px rgba(0, 0, 0, 0.05), 0 0 0 1px rgba(34, 42, 53, 0.04), 0 0 4px rgba(34, 42, 53, 0.08), 0 16px 68px rgba(47, 48, 55, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1) inset\",\n        }}\n      ></div>\n    </div>\n  );\n};\n\nconst CollisionMechanism = React.forwardRef<\n  HTMLDivElement,\n  {\n    containerRef: React.RefObject<HTMLDivElement>;\n    parentRef: React.RefObject<HTMLDivElement>;\n    beamOptions?: {\n      initialX?: number;\n      translateX?: number;\n      initialY?: number;\n      translateY?: number;\n      rotate?: number;\n      className?: string;\n      duration?: number;\n      delay?: number;\n      repeatDelay?: number;\n    };\n  }\n>(({ parentRef, containerRef, beamOptions = {} }, ref) => {\n  const beamRef = useRef<HTMLDivElement>(null);\n  const [collision, setCollision] = useState<{\n    detected: boolean;\n    coordinates: { x: number; y: number } | null;\n  }>({\n    detected: false,\n    coordinates: null,\n  });\n  const [beamKey, setBeamKey] = useState(0);\n  const [cycleCollisionDetected, setCycleCollisionDetected] = useState(false);\n\n  useEffect(() => {\n    const checkCollision = () => {\n      if (\n        beamRef.current &&\n        containerRef.current &&\n        parentRef.current &&\n        !cycleCollisionDetected\n      ) {\n        const beamRect = beamRef.current.getBoundingClientRect();\n        const containerRect = containerRef.current.getBoundingClientRect();\n        const parentRect = parentRef.current.getBoundingClientRect();\n\n        if (beamRect.bottom >= containerRect.top) {\n          const relativeX =\n            beamRect.left - parentRect.left + beamRect.width / 2;\n          const relativeY = beamRect.bottom - parentRect.top;\n\n          setCollision({\n            detected: true,\n            coordinates: {\n              x: relativeX,\n              y: relativeY,\n            },\n          });\n          setCycleCollisionDetected(true);\n        }\n      }\n    };\n\n    const animationInterval = setInterval(checkCollision, 50);\n\n    return () => clearInterval(animationInterval);\n  }, [cycleCollisionDetected, containerRef]);\n\n  useEffect(() => {\n    if (collision.detected && collision.coordinates) {\n      setTimeout(() => {\n        setCollision({ detected: false, coordinates: null });\n        setCycleCollisionDetected(false);\n      }, 2000);\n\n      setTimeout(() => {\n        setBeamKey((prevKey) => prevKey + 1);\n      }, 2000);\n    }\n  }, [collision]);\n\n  return (\n    <>\n      <motion.div\n        key={beamKey}\n        ref={beamRef}\n        animate=\"animate\"\n        initial={{\n          translateY: beamOptions.initialY || \"-200px\",\n          translateX: beamOptions.initialX || \"0px\",\n          rotate: beamOptions.rotate || 0,\n        }}\n        variants={{\n          animate: {\n            translateY: beamOptions.translateY || \"1800px\",\n            translateX: beamOptions.translateX || \"0px\",\n            rotate: beamOptions.rotate || 0,\n          },\n        }}\n        transition={{\n          duration: beamOptions.duration || 8,\n          repeat: Infinity,\n          repeatType: \"loop\",\n          ease: \"linear\",\n          delay: beamOptions.delay || 0,\n          repeatDelay: beamOptions.repeatDelay || 0,\n        }}\n        className={cn(\n          \"absolute left-0 top-20 m-auto h-14 w-px rounded-full bg-gradient-to-t from-indigo-500 via-purple-500 to-transparent\",\n          beamOptions.className\n        )}\n      />\n      <AnimatePresence>\n        {collision.detected && collision.coordinates && (\n          <Explosion\n            key={`${collision.coordinates.x}-${collision.coordinates.y}`}\n            className=\"\"\n            style={{\n              left: `${collision.coordinates.x}px`,\n              top: `${collision.coordinates.y}px`,\n              transform: \"translate(-50%, -50%)\",\n            }}\n          />\n        )}\n      </AnimatePresence>\n    </>\n  );\n});\n\nCollisionMechanism.displayName = \"CollisionMechanism\";\n\nconst Explosion = ({ ...props }: React.HTMLProps<HTMLDivElement>) => {\n  const spans = Array.from({ length: 20 }, (_, index) => ({\n    id: index,\n    initialX: 0,\n    initialY: 0,\n    directionX: Math.floor(Math.random() * 80 - 40),\n    directionY: Math.floor(Math.random() * -50 - 10),\n  }));\n\n  return (\n    <div {...props} className={cn(\"absolute z-50 h-2 w-2\", props.className)}>\n      <motion.div\n        initial={{ opacity: 0 }}\n        animate={{ opacity: 1 }}\n        exit={{ opacity: 0 }}\n        transition={{ duration: 1.5, ease: \"easeOut\" }}\n        className=\"absolute -inset-x-10 top-0 m-auto h-2 w-10 rounded-full bg-gradient-to-r from-transparent via-indigo-500 to-transparent blur-sm\"\n      ></motion.div>\n      {spans.map((span) => (\n        <motion.span\n          key={span.id}\n          initial={{ x: span.initialX, y: span.initialY, opacity: 1 }}\n          animate={{\n            x: span.directionX,\n            y: span.directionY,\n            opacity: 0,\n          }}\n          transition={{ duration: Math.random() * 1.5 + 0.5, ease: \"easeOut\" }}\n          className=\"absolute h-1 w-1 rounded-full bg-gradient-to-b from-indigo-500 to-purple-500\"\n        />\n      ))}\n    </div>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ui/background-beams-with-collision.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Background Beams With Collision"
}