{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "BorderGlow-JS-TW",
	"title": "BorderGlow",
	"description": "Glowing mesh-gradient border that follows cursor direction and intensifies near edges.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:component",
			"path": "BorderGlow/BorderGlow.jsx",
			"content": "import { useRef, useCallback, useState, useEffect } from 'react';\n\nfunction parseHSL(hslStr) {\n  const match = hslStr.match(/([\\d.]+)\\s*([\\d.]+)%?\\s*([\\d.]+)%?/);\n  if (!match) return { h: 40, s: 80, l: 80 };\n  return { h: parseFloat(match[1]), s: parseFloat(match[2]), l: parseFloat(match[3]) };\n}\n\nfunction buildBoxShadow(glowColor, intensity) {\n  const { h, s, l } = parseHSL(glowColor);\n  const base = `${h}deg ${s}% ${l}%`;\n  const layers = [\n    [0, 0, 0, 1, 100, true], [0, 0, 1, 0, 60, true], [0, 0, 3, 0, 50, true],\n    [0, 0, 6, 0, 40, true], [0, 0, 15, 0, 30, true], [0, 0, 25, 2, 20, true],\n    [0, 0, 50, 2, 10, true],\n    [0, 0, 1, 0, 60, false], [0, 0, 3, 0, 50, false], [0, 0, 6, 0, 40, false],\n    [0, 0, 15, 0, 30, false], [0, 0, 25, 2, 20, false], [0, 0, 50, 2, 10, false],\n  ];\n  return layers.map(([x, y, blur, spread, alpha, inset]) => {\n    const a = Math.min(alpha * intensity, 100);\n    return `${inset ? 'inset ' : ''}${x}px ${y}px ${blur}px ${spread}px hsl(${base} / ${a}%)`;\n  }).join(', ');\n}\n\nfunction easeOutCubic(x) { return 1 - Math.pow(1 - x, 3); }\nfunction easeInCubic(x) { return x * x * x; }\n\nfunction animateValue({ start = 0, end = 100, duration = 1000, delay = 0, ease = easeOutCubic, onUpdate, onEnd }) {\n  const t0 = performance.now() + delay;\n  function tick() {\n    const elapsed = performance.now() - t0;\n    const t = Math.min(elapsed / duration, 1);\n    onUpdate(start + (end - start) * ease(t));\n    if (t < 1) requestAnimationFrame(tick);\n    else if (onEnd) onEnd();\n  }\n  setTimeout(() => requestAnimationFrame(tick), delay);\n}\n\nconst GRADIENT_POSITIONS = ['80% 55%', '69% 34%', '8% 6%', '41% 38%', '86% 85%', '82% 18%', '51% 4%'];\nconst COLOR_MAP = [0, 1, 2, 0, 1, 2, 1];\n\nfunction buildMeshGradients(colors) {\n  const gradients = [];\n  for (let i = 0; i < 7; i++) {\n    const c = colors[Math.min(COLOR_MAP[i], colors.length - 1)];\n    gradients.push(`radial-gradient(at ${GRADIENT_POSITIONS[i]}, ${c} 0px, transparent 50%)`);\n  }\n  gradients.push(`linear-gradient(${colors[0]} 0 100%)`);\n  return gradients;\n}\n\nconst BorderGlow = ({\n  children,\n  className = '',\n  edgeSensitivity = 30,\n  glowColor = '40 80 80',\n  backgroundColor = '#120F17',\n  borderRadius = 28,\n  glowRadius = 40,\n  glowIntensity = 1.0,\n  coneSpread = 25,\n  animated = false,\n  colors = ['#c084fc', '#f472b6', '#38bdf8'],\n  fillOpacity = 0.5,\n}) => {\n  const cardRef = useRef(null);\n  const [isHovered, setIsHovered] = useState(false);\n  const [cursorAngle, setCursorAngle] = useState(45);\n  const [edgeProximity, setEdgeProximity] = useState(0);\n  const [sweepActive, setSweepActive] = useState(false);\n\n  const getCenterOfElement = useCallback((el) => {\n    const { width, height } = el.getBoundingClientRect();\n    return [width / 2, height / 2];\n  }, []);\n\n  const getEdgeProximity = useCallback((el, x, y) => {\n    const [cx, cy] = getCenterOfElement(el);\n    const dx = x - cx;\n    const dy = y - cy;\n    let kx = Infinity;\n    let ky = Infinity;\n    if (dx !== 0) kx = cx / Math.abs(dx);\n    if (dy !== 0) ky = cy / Math.abs(dy);\n    return Math.min(Math.max(1 / Math.min(kx, ky), 0), 1);\n  }, [getCenterOfElement]);\n\n  const getCursorAngle = useCallback((el, x, y) => {\n    const [cx, cy] = getCenterOfElement(el);\n    const dx = x - cx;\n    const dy = y - cy;\n    if (dx === 0 && dy === 0) return 0;\n    const radians = Math.atan2(dy, dx);\n    let degrees = radians * (180 / Math.PI) + 90;\n    if (degrees < 0) degrees += 360;\n    return degrees;\n  }, [getCenterOfElement]);\n\n  const handlePointerMove = useCallback((e) => {\n    const card = cardRef.current;\n    if (!card) return;\n    const rect = card.getBoundingClientRect();\n    const x = e.clientX - rect.left;\n    const y = e.clientY - rect.top;\n    setEdgeProximity(getEdgeProximity(card, x, y));\n    setCursorAngle(getCursorAngle(card, x, y));\n  }, [getEdgeProximity, getCursorAngle]);\n\n  useEffect(() => {\n    if (!animated) return;\n    const angleStart = 110;\n    const angleEnd = 465;\n    setSweepActive(true);\n    setCursorAngle(angleStart);\n\n    animateValue({ duration: 500, onUpdate: v => setEdgeProximity(v / 100) });\n    animateValue({ ease: easeInCubic, duration: 1500, end: 50, onUpdate: v => {\n      setCursorAngle((angleEnd - angleStart) * (v / 100) + angleStart);\n    }});\n    animateValue({ ease: easeOutCubic, delay: 1500, duration: 2250, start: 50, end: 100, onUpdate: v => {\n      setCursorAngle((angleEnd - angleStart) * (v / 100) + angleStart);\n    }});\n    animateValue({ ease: easeInCubic, delay: 2500, duration: 1500, start: 100, end: 0,\n      onUpdate: v => setEdgeProximity(v / 100),\n      onEnd: () => setSweepActive(false),\n    });\n  }, [animated]);\n\n  const colorSensitivity = edgeSensitivity + 20;\n  const isVisible = isHovered || sweepActive;\n  const borderOpacity = isVisible\n    ? Math.max(0, (edgeProximity * 100 - colorSensitivity) / (100 - colorSensitivity))\n    : 0;\n  const glowOpacity = isVisible\n    ? Math.max(0, (edgeProximity * 100 - edgeSensitivity) / (100 - edgeSensitivity))\n    : 0;\n\n  const meshGradients = buildMeshGradients(colors);\n  const borderBg = meshGradients.map(g => `${g} border-box`);\n  const fillBg = meshGradients.map(g => `${g} padding-box`);\n  const angleDeg = `${cursorAngle.toFixed(3)}deg`;\n\n  return (\n    <div\n      ref={cardRef}\n      onPointerMove={handlePointerMove}\n      onPointerEnter={() => setIsHovered(true)}\n      onPointerLeave={() => setIsHovered(false)}\n      className={`relative grid isolate border border-white/15 ${className}`}\n      style={{\n        background: backgroundColor,\n        borderRadius: `${borderRadius}px`,\n        transform: 'translate3d(0, 0, 0.01px)',\n        boxShadow: 'rgba(0,0,0,0.1) 0 1px 2px, rgba(0,0,0,0.1) 0 2px 4px, rgba(0,0,0,0.1) 0 4px 8px, rgba(0,0,0,0.1) 0 8px 16px, rgba(0,0,0,0.1) 0 16px 32px, rgba(0,0,0,0.1) 0 32px 64px',\n      }}\n    >\n      {/* mesh gradient border */}\n      <div\n        className=\"absolute inset-0 rounded-[inherit] -z-[1]\"\n        style={{\n          border: '1px solid transparent',\n          background: [\n            `linear-gradient(${backgroundColor} 0 100%) padding-box`,\n            'linear-gradient(rgb(255 255 255 / 0%) 0% 100%) border-box',\n            ...borderBg,\n          ].join(', '),\n          opacity: borderOpacity,\n          maskImage: `conic-gradient(from ${angleDeg} at center, black ${coneSpread}%, transparent ${coneSpread + 15}%, transparent ${100 - coneSpread - 15}%, black ${100 - coneSpread}%)`,\n          WebkitMaskImage: `conic-gradient(from ${angleDeg} at center, black ${coneSpread}%, transparent ${coneSpread + 15}%, transparent ${100 - coneSpread - 15}%, black ${100 - coneSpread}%)`,\n          transition: isVisible ? 'opacity 0.25s ease-out' : 'opacity 0.75s ease-in-out',\n        }}\n      />\n\n      {/* mesh gradient fill near edges */}\n      <div\n        className=\"absolute inset-0 rounded-[inherit] -z-[1]\"\n        style={{\n          border: '1px solid transparent',\n          background: fillBg.join(', '),\n          maskImage: [\n            'linear-gradient(to bottom, black, black)',\n            'radial-gradient(ellipse at 50% 50%, black 40%, transparent 65%)',\n            'radial-gradient(ellipse at 66% 66%, black 5%, transparent 40%)',\n            'radial-gradient(ellipse at 33% 33%, black 5%, transparent 40%)',\n            'radial-gradient(ellipse at 66% 33%, black 5%, transparent 40%)',\n            'radial-gradient(ellipse at 33% 66%, black 5%, transparent 40%)',\n            `conic-gradient(from ${angleDeg} at center, transparent 5%, black 15%, black 85%, transparent 95%)`,\n          ].join(', '),\n          WebkitMaskImage: [\n            'linear-gradient(to bottom, black, black)',\n            'radial-gradient(ellipse at 50% 50%, black 40%, transparent 65%)',\n            'radial-gradient(ellipse at 66% 66%, black 5%, transparent 40%)',\n            'radial-gradient(ellipse at 33% 33%, black 5%, transparent 40%)',\n            'radial-gradient(ellipse at 66% 33%, black 5%, transparent 40%)',\n            'radial-gradient(ellipse at 33% 66%, black 5%, transparent 40%)',\n            `conic-gradient(from ${angleDeg} at center, transparent 5%, black 15%, black 85%, transparent 95%)`,\n          ].join(', '),\n          maskComposite: 'subtract, add, add, add, add, add',\n          WebkitMaskComposite: 'source-out, source-over, source-over, source-over, source-over, source-over',\n          opacity: borderOpacity * fillOpacity,\n          mixBlendMode: 'soft-light',\n          transition: isVisible ? 'opacity 0.25s ease-out' : 'opacity 0.75s ease-in-out',\n        }}\n      />\n\n      {/* outer glow */}\n      <span\n        className=\"absolute pointer-events-none z-[1] rounded-[inherit]\"\n        style={{\n          inset: `${-glowRadius}px`,\n          maskImage: `conic-gradient(from ${angleDeg} at center, black 2.5%, transparent 10%, transparent 90%, black 97.5%)`,\n          WebkitMaskImage: `conic-gradient(from ${angleDeg} at center, black 2.5%, transparent 10%, transparent 90%, black 97.5%)`,\n          opacity: glowOpacity,\n          mixBlendMode: 'plus-lighter',\n          transition: isVisible ? 'opacity 0.25s ease-out' : 'opacity 0.75s ease-in-out',\n        }}\n      >\n        <span\n          className=\"absolute rounded-[inherit]\"\n          style={{\n            inset: `${glowRadius}px`,\n            boxShadow: buildBoxShadow(glowColor, glowIntensity),\n          }}\n        />\n      </span>\n\n      <div className=\"flex flex-col relative overflow-auto z-[1]\">\n        {children}\n      </div>\n    </div>\n  );\n};\n\nexport default BorderGlow;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": []
}