{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cool-mode",
  "type": "registry:ui",
  "title": "Cool Mode",
  "description": "Cool mode effect for buttons, links, and other DOMs",
  "files": [
    {
      "path": "registry/magicui/cool-mode.tsx",
      "content": "\"use client\"\n\nimport React, { useEffect, useRef, type ReactNode } from \"react\"\n\nexport interface BaseParticle {\n  element: HTMLElement | SVGSVGElement\n  left: number\n  size: number\n  top: number\n}\n\nexport interface BaseParticleOptions {\n  particle?: string\n  size?: number\n}\n\nexport interface CoolParticle extends BaseParticle {\n  direction: number\n  speedHorz: number\n  speedUp: number\n  spinSpeed: number\n  spinVal: number\n}\n\nexport interface CoolParticleOptions extends BaseParticleOptions {\n  particleCount?: number\n  speedHorz?: number\n  speedUp?: number\n}\n\nconst SVG_NS = \"http://www.w3.org/2000/svg\"\n\nconst getContainer = () => {\n  const id = \"_coolMode_effect\"\n  const existingContainer = document.getElementById(id)\n\n  if (existingContainer) {\n    return existingContainer\n  }\n\n  const container = document.createElement(\"div\")\n  container.setAttribute(\"id\", id)\n  container.setAttribute(\n    \"style\",\n    \"overflow:hidden; position:fixed; height:100%; top:0; left:0; right:0; bottom:0; pointer-events:none; z-index:2147483647\"\n  )\n\n  document.body.appendChild(container)\n\n  return container\n}\n\nlet instanceCounter = 0\n\nconst applyParticleEffect = (\n  element: HTMLElement,\n  options?: CoolParticleOptions\n): (() => void) => {\n  instanceCounter++\n\n  const defaultParticle = \"circle\"\n  const particleType = options?.particle || defaultParticle\n  const sizes = [15, 20, 25, 35, 45]\n  const limit = 45\n\n  let particles: CoolParticle[] = []\n  let autoAddParticle = false\n  let mouseX = 0\n  let mouseY = 0\n\n  const container = getContainer()\n\n  const appendCircleParticle = (particle: HTMLDivElement, size: number) => {\n    const circleSVG = document.createElementNS(SVG_NS, \"svg\")\n    const circle = document.createElementNS(SVG_NS, \"circle\")\n\n    circle.setAttributeNS(null, \"cx\", (size / 2).toString())\n    circle.setAttributeNS(null, \"cy\", (size / 2).toString())\n    circle.setAttributeNS(null, \"r\", (size / 2).toString())\n    circle.setAttributeNS(null, \"fill\", `hsl(${Math.random() * 360}, 70%, 50%)`)\n\n    circleSVG.appendChild(circle)\n    circleSVG.setAttribute(\"width\", size.toString())\n    circleSVG.setAttribute(\"height\", size.toString())\n\n    particle.appendChild(circleSVG)\n  }\n\n  const appendImageParticle = (\n    particle: HTMLDivElement,\n    imageSrc: string,\n    size: number\n  ) => {\n    const image = document.createElement(\"img\")\n    image.src = imageSrc\n    image.width = size\n    image.height = size\n    image.alt = \"\"\n    image.style.borderRadius = \"50%\"\n\n    particle.appendChild(image)\n  }\n\n  const appendTextParticle = (\n    particle: HTMLDivElement,\n    particleContent: string,\n    size: number\n  ) => {\n    const fontSizeMultiplier = 3\n    const emojiSize = size * fontSizeMultiplier\n    const content = document.createElement(\"div\")\n\n    content.textContent = particleContent\n    content.style.fontSize = `${emojiSize}px`\n    content.style.lineHeight = \"1\"\n    content.style.textAlign = \"center\"\n    content.style.width = `${size}px`\n    content.style.height = `${size}px`\n    content.style.display = \"flex\"\n    content.style.alignItems = \"center\"\n    content.style.justifyContent = \"center\"\n    content.style.transform = `scale(${fontSizeMultiplier})`\n    content.style.transformOrigin = \"center\"\n\n    particle.appendChild(content)\n  }\n\n  function generateParticle() {\n    const size =\n      options?.size || sizes[Math.floor(Math.random() * sizes.length)]\n    const speedHorz = options?.speedHorz || Math.random() * 10\n    const speedUp = options?.speedUp || Math.random() * 25\n    const spinVal = Math.random() * 360\n    const spinSpeed = Math.random() * 35 * (Math.random() <= 0.5 ? -1 : 1)\n    const top = mouseY - size / 2\n    const left = mouseX - size / 2\n    const direction = Math.random() <= 0.5 ? -1 : 1\n\n    const particle = document.createElement(\"div\")\n\n    if (particleType === \"circle\") {\n      appendCircleParticle(particle, size)\n    } else if (\n      particleType.startsWith(\"http\") ||\n      particleType.startsWith(\"/\")\n    ) {\n      appendImageParticle(particle, particleType, size)\n    } else {\n      appendTextParticle(particle, particleType, size)\n    }\n\n    particle.style.position = \"absolute\"\n    particle.style.transform = `translate3d(${left}px, ${top}px, 0px) rotate(${spinVal}deg)`\n\n    container.appendChild(particle)\n\n    particles.push({\n      direction,\n      element: particle,\n      left,\n      size,\n      speedHorz,\n      speedUp,\n      spinSpeed,\n      spinVal,\n      top,\n    })\n  }\n\n  function refreshParticles() {\n    particles.forEach((p) => {\n      p.left = p.left - p.speedHorz * p.direction\n      p.top = p.top - p.speedUp\n      p.speedUp = Math.min(p.size, p.speedUp - 1)\n      p.spinVal = p.spinVal + p.spinSpeed\n\n      if (\n        p.top >=\n        Math.max(window.innerHeight, document.body.clientHeight) + p.size\n      ) {\n        particles = particles.filter((o) => o !== p)\n        p.element.remove()\n      }\n\n      p.element.setAttribute(\n        \"style\",\n        [\n          \"position:absolute\",\n          \"will-change:transform\",\n          `top:${p.top}px`,\n          `left:${p.left}px`,\n          `transform:rotate(${p.spinVal}deg)`,\n        ].join(\";\")\n      )\n    })\n  }\n\n  let animationFrame: number | undefined\n\n  let lastParticleTimestamp = 0\n  const particleGenerationDelay = 30\n\n  function loop() {\n    const currentTime = performance.now()\n    if (\n      autoAddParticle &&\n      particles.length < limit &&\n      currentTime - lastParticleTimestamp > particleGenerationDelay\n    ) {\n      generateParticle()\n      lastParticleTimestamp = currentTime\n    }\n\n    refreshParticles()\n    animationFrame = requestAnimationFrame(loop)\n  }\n\n  loop()\n\n  const isTouchInteraction = \"ontouchstart\" in window\n\n  const tap = isTouchInteraction ? \"touchstart\" : \"mousedown\"\n  const tapEnd = isTouchInteraction ? \"touchend\" : \"mouseup\"\n  const move = isTouchInteraction ? \"touchmove\" : \"mousemove\"\n\n  const updateMousePosition = (e: MouseEvent | TouchEvent) => {\n    if (\"touches\" in e) {\n      mouseX = e.touches?.[0].clientX\n      mouseY = e.touches?.[0].clientY\n    } else {\n      mouseX = e.clientX\n      mouseY = e.clientY\n    }\n  }\n\n  const tapHandler = (e: MouseEvent | TouchEvent) => {\n    updateMousePosition(e)\n    autoAddParticle = true\n  }\n\n  const disableAutoAddParticle = () => {\n    autoAddParticle = false\n  }\n\n  element.addEventListener(move, updateMousePosition, { passive: true })\n  element.addEventListener(tap, tapHandler, { passive: true })\n  element.addEventListener(tapEnd, disableAutoAddParticle, { passive: true })\n  element.addEventListener(\"mouseleave\", disableAutoAddParticle, {\n    passive: true,\n  })\n\n  return () => {\n    element.removeEventListener(move, updateMousePosition)\n    element.removeEventListener(tap, tapHandler)\n    element.removeEventListener(tapEnd, disableAutoAddParticle)\n    element.removeEventListener(\"mouseleave\", disableAutoAddParticle)\n\n    const interval = setInterval(() => {\n      if (animationFrame && particles.length === 0) {\n        cancelAnimationFrame(animationFrame)\n        clearInterval(interval)\n\n        if (--instanceCounter === 0) {\n          container.remove()\n        }\n      }\n    }, 500)\n  }\n}\n\ninterface CoolModeProps {\n  children: ReactNode\n  options?: CoolParticleOptions\n}\n\nexport const CoolMode: React.FC<CoolModeProps> = ({ children, options }) => {\n  const ref = useRef<HTMLSpanElement>(null)\n\n  useEffect(() => {\n    const element = ref.current\n    let cleanup: (() => void) | null = null\n\n    if (element) {\n      cleanup = applyParticleEffect(element, options)\n    }\n\n    return () => {\n      if (cleanup) {\n        cleanup()\n      }\n    }\n  }, [options])\n\n  return <span ref={ref}>{children}</span>\n}\n",
      "type": "registry:ui"
    }
  ]
}