{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "ElectricBorder-JS-CSS",
	"title": "ElectricBorder",
	"description": "Jittery electric energy border with animated arcs, glow and adjustable intensity.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:file",
			"path": "ElectricBorder.css",
			"target": "@components/ElectricBorder.css",
			"content": ".electric-border {\n  --electric-light-color: oklch(from var(--electric-border-color) l c h);\n  position: relative;\n  border-radius: inherit;\n  overflow: visible;\n  isolation: isolate;\n}\n\n.eb-canvas-container {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  pointer-events: none;\n  z-index: 2;\n}\n\n.eb-canvas {\n  display: block;\n}\n\n.eb-content {\n  position: relative;\n  border-radius: inherit;\n  z-index: 1;\n}\n\n.eb-layers {\n  position: absolute;\n  inset: 0;\n  border-radius: inherit;\n  pointer-events: none;\n  z-index: 0;\n}\n\n.eb-glow-1,\n.eb-glow-2,\n.eb-background-glow {\n  position: absolute;\n  inset: 0;\n  border-radius: inherit;\n  pointer-events: none;\n  box-sizing: border-box;\n}\n\n.eb-glow-1 {\n  border: 2px solid oklch(from var(--electric-border-color) l c h / 0.6);\n  filter: blur(1px);\n}\n\n.eb-glow-2 {\n  border: 2px solid var(--electric-light-color);\n  filter: blur(4px);\n}\n\n.eb-background-glow {\n  z-index: -1;\n  transform: scale(1.1);\n  filter: blur(32px);\n  opacity: 0.3;\n  background: linear-gradient(-30deg, var(--electric-light-color), transparent, var(--electric-border-color));\n}\n"
		},
		{
			"type": "registry:component",
			"path": "ElectricBorder.jsx",
			"content": "import { useEffect, useRef, useCallback } from 'react';\nimport './ElectricBorder.css';\n\nconst ElectricBorder = ({\n  children,\n  color = '#5227FF',\n  speed = 1,\n  chaos = 0.12,\n  borderRadius = 24,\n  className,\n  style\n}) => {\n  const canvasRef = useRef(null);\n  const containerRef = useRef(null);\n  const animationRef = useRef(null);\n  const timeRef = useRef(0);\n  const lastFrameTimeRef = useRef(0);\n\n  // Noise functions\n  const random = useCallback(x => {\n    return (Math.sin(x * 12.9898) * 43758.5453) % 1;\n  }, []);\n\n  const noise2D = useCallback(\n    (x, y) => {\n      const i = Math.floor(x);\n      const j = Math.floor(y);\n      const fx = x - i;\n      const fy = y - j;\n\n      const a = random(i + j * 57);\n      const b = random(i + 1 + j * 57);\n      const c = random(i + (j + 1) * 57);\n      const d = random(i + 1 + (j + 1) * 57);\n\n      const ux = fx * fx * (3.0 - 2.0 * fx);\n      const uy = fy * fy * (3.0 - 2.0 * fy);\n\n      return a * (1 - ux) * (1 - uy) + b * ux * (1 - uy) + c * (1 - ux) * uy + d * ux * uy;\n    },\n    [random]\n  );\n\n  const octavedNoise = useCallback(\n    (x, octaves, lacunarity, gain, baseAmplitude, baseFrequency, time, seed, baseFlatness) => {\n      let y = 0;\n      let amplitude = baseAmplitude;\n      let frequency = baseFrequency;\n\n      for (let i = 0; i < octaves; i++) {\n        let octaveAmplitude = amplitude;\n        if (i === 0) {\n          octaveAmplitude *= baseFlatness;\n        }\n        y += octaveAmplitude * noise2D(frequency * x + seed * 100, time * frequency * 0.3);\n        frequency *= lacunarity;\n        amplitude *= gain;\n      }\n\n      return y;\n    },\n    [noise2D]\n  );\n\n  const getCornerPoint = useCallback((centerX, centerY, radius, startAngle, arcLength, progress) => {\n    const angle = startAngle + progress * arcLength;\n    return {\n      x: centerX + radius * Math.cos(angle),\n      y: centerY + radius * Math.sin(angle)\n    };\n  }, []);\n\n  const getRoundedRectPoint = useCallback(\n    (t, left, top, width, height, radius) => {\n      const straightWidth = width - 2 * radius;\n      const straightHeight = height - 2 * radius;\n      const cornerArc = (Math.PI * radius) / 2;\n      const totalPerimeter = 2 * straightWidth + 2 * straightHeight + 4 * cornerArc;\n      const distance = t * totalPerimeter;\n\n      let accumulated = 0;\n\n      // Top edge\n      if (distance <= accumulated + straightWidth) {\n        const progress = (distance - accumulated) / straightWidth;\n        return { x: left + radius + progress * straightWidth, y: top };\n      }\n      accumulated += straightWidth;\n\n      // Top-right corner\n      if (distance <= accumulated + cornerArc) {\n        const progress = (distance - accumulated) / cornerArc;\n        return getCornerPoint(left + width - radius, top + radius, radius, -Math.PI / 2, Math.PI / 2, progress);\n      }\n      accumulated += cornerArc;\n\n      // Right edge\n      if (distance <= accumulated + straightHeight) {\n        const progress = (distance - accumulated) / straightHeight;\n        return { x: left + width, y: top + radius + progress * straightHeight };\n      }\n      accumulated += straightHeight;\n\n      // Bottom-right corner\n      if (distance <= accumulated + cornerArc) {\n        const progress = (distance - accumulated) / cornerArc;\n        return getCornerPoint(left + width - radius, top + height - radius, radius, 0, Math.PI / 2, progress);\n      }\n      accumulated += cornerArc;\n\n      // Bottom edge\n      if (distance <= accumulated + straightWidth) {\n        const progress = (distance - accumulated) / straightWidth;\n        return { x: left + width - radius - progress * straightWidth, y: top + height };\n      }\n      accumulated += straightWidth;\n\n      // Bottom-left corner\n      if (distance <= accumulated + cornerArc) {\n        const progress = (distance - accumulated) / cornerArc;\n        return getCornerPoint(left + radius, top + height - radius, radius, Math.PI / 2, Math.PI / 2, progress);\n      }\n      accumulated += cornerArc;\n\n      // Left edge\n      if (distance <= accumulated + straightHeight) {\n        const progress = (distance - accumulated) / straightHeight;\n        return { x: left, y: top + height - radius - progress * straightHeight };\n      }\n      accumulated += straightHeight;\n\n      // Top-left corner\n      const progress = (distance - accumulated) / cornerArc;\n      return getCornerPoint(left + radius, top + radius, radius, Math.PI, Math.PI / 2, progress);\n    },\n    [getCornerPoint]\n  );\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    const container = containerRef.current;\n    if (!canvas || !container) return;\n\n    const ctx = canvas.getContext('2d');\n    if (!ctx) return;\n\n    // Configuration\n    const octaves = 10;\n    const lacunarity = 1.6;\n    const gain = 0.7;\n    const amplitude = chaos;\n    const frequency = 10;\n    const baseFlatness = 0;\n    const displacement = 60;\n    const borderOffset = 60;\n\n    const updateSize = () => {\n      const rect = container.getBoundingClientRect();\n      const width = rect.width + borderOffset * 2;\n      const height = rect.height + borderOffset * 2;\n\n      // Use device pixel ratio for sharp rendering\n      const dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = width * dpr;\n      canvas.height = height * dpr;\n      canvas.style.width = `${width}px`;\n      canvas.style.height = `${height}px`;\n      ctx.scale(dpr, dpr);\n\n      return { width, height };\n    };\n\n    let { width, height } = updateSize();\n    let lastDpr = Math.min(window.devicePixelRatio || 1, 2);\n\n    const drawElectricBorder = currentTime => {\n      if (!canvas || !ctx) return;\n\n      const dpr = Math.min(window.devicePixelRatio || 1, 2);\n      if (dpr !== lastDpr) {\n        lastDpr = dpr;\n        const newSize = updateSize();\n        width = newSize.width;\n        height = newSize.height;\n      }\n\n      const deltaTime = (currentTime - lastFrameTimeRef.current) / 1000;\n      timeRef.current += deltaTime * speed;\n      lastFrameTimeRef.current = currentTime;\n\n      ctx.setTransform(1, 0, 0, 1, 0, 0);\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n      ctx.scale(dpr, dpr);\n\n      ctx.strokeStyle = color;\n      ctx.lineWidth = 1;\n      ctx.lineCap = 'round';\n      ctx.lineJoin = 'round';\n\n      const scale = displacement;\n      const left = borderOffset;\n      const top = borderOffset;\n      const borderWidth = width - 2 * borderOffset;\n      const borderHeight = height - 2 * borderOffset;\n      const maxRadius = Math.min(borderWidth, borderHeight) / 2;\n      const radius = Math.min(borderRadius, maxRadius);\n\n      const approximatePerimeter = 2 * (borderWidth + borderHeight) + 2 * Math.PI * radius;\n      const sampleCount = Math.floor(approximatePerimeter / 2);\n\n      ctx.beginPath();\n\n      for (let i = 0; i <= sampleCount; i++) {\n        const progress = i / sampleCount;\n\n        const point = getRoundedRectPoint(progress, left, top, borderWidth, borderHeight, radius);\n\n        const xNoise = octavedNoise(\n          progress * 8,\n          octaves,\n          lacunarity,\n          gain,\n          amplitude,\n          frequency,\n          timeRef.current,\n          0,\n          baseFlatness\n        );\n\n        const yNoise = octavedNoise(\n          progress * 8,\n          octaves,\n          lacunarity,\n          gain,\n          amplitude,\n          frequency,\n          timeRef.current,\n          1,\n          baseFlatness\n        );\n\n        const displacedX = point.x + xNoise * scale;\n        const displacedY = point.y + yNoise * scale;\n\n        if (i === 0) {\n          ctx.moveTo(displacedX, displacedY);\n        } else {\n          ctx.lineTo(displacedX, displacedY);\n        }\n      }\n\n      ctx.closePath();\n      ctx.stroke();\n\n      animationRef.current = requestAnimationFrame(drawElectricBorder);\n    };\n\n    // Handle resize\n    const resizeObserver = new ResizeObserver(() => {\n      const newSize = updateSize();\n      width = newSize.width;\n      height = newSize.height;\n    });\n    resizeObserver.observe(container);\n\n    // Start animation\n    animationRef.current = requestAnimationFrame(drawElectricBorder);\n\n    return () => {\n      if (animationRef.current) {\n        cancelAnimationFrame(animationRef.current);\n      }\n      resizeObserver.disconnect();\n    };\n  }, [color, speed, chaos, borderRadius, octavedNoise, getRoundedRectPoint]);\n\n  const vars = {\n    '--electric-border-color': color,\n    borderRadius: borderRadius\n  };\n\n  return (\n    <div ref={containerRef} className={`electric-border ${className ?? ''}`} style={{ ...vars, ...style }}>\n      <div className=\"eb-canvas-container\">\n        <canvas ref={canvasRef} className=\"eb-canvas\" />\n      </div>\n      <div className=\"eb-layers\">\n        <div className=\"eb-glow-1\" />\n        <div className=\"eb-glow-2\" />\n        <div className=\"eb-background-glow\" />\n      </div>\n      <div className=\"eb-content\">{children}</div>\n    </div>\n  );\n};\n\nexport default ElectricBorder;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": []
}