{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cursor-edge-glow-button",
  "title": "Cursor Edge Glow Button",
  "author": "henriquegpb <https://github.com/henriquegpb>",
  "description": "A spring-tracked pill light with mirrored edge glows that crossfade as the pointer changes sides.",
  "files": [
    {
      "path": "registry/microkit/cursor-edge-glow-button.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useRef } from \"react\";\n\nconst FREQUENCY = 3.4;\nconst DAMPING = 0.78;\nconst GLOW_RISE = 0.5;\nconst EDGE_SATURATION = 0.55;\nconst EDGE_BRIGHTNESS = 0.12;\nconst HUE_SHIFT = -5;\n\nexport function CursorEdgeGlowButton() {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const buttonRef = useRef<HTMLButtonElement>(null);\n  const lightTrackRef = useRef<HTMLSpanElement>(null);\n  const rightGlowRef = useRef<HTMLSpanElement>(null);\n  const leftGlowRef = useRef<HTMLSpanElement>(null);\n  const animationFrameRef = useRef<number | null>(null);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const button = buttonRef.current;\n    const lightTrack = lightTrackRef.current;\n    const rightGlow = rightGlowRef.current;\n    const leftGlow = leftGlowRef.current;\n    if (!container || !button || !lightTrack || !rightGlow || !leftGlow) return;\n\n    let bound = container.getBoundingClientRect().width / 2 + 12;\n    let x = bound;\n    let velocity = 0;\n    let target = bound;\n    let inside = false;\n    let last = 0;\n\n    const measure = () => {\n      bound = container.getBoundingClientRect().width / 2 + 12;\n    };\n\n    const paint = () => {\n      lightTrack.style.setProperty(\"--light-x\", x.toFixed(2) + \"px\");\n      const normalized = Math.max(-1, Math.min(1, x / bound));\n      const magnitude = Math.abs(normalized);\n      const intensity = Math.pow(magnitude, GLOW_RISE);\n      const colorTuning =\n        \"hue-rotate(\" + HUE_SHIFT + \"deg)\" +\n        \" saturate(\" + (1 + EDGE_SATURATION * magnitude).toFixed(3) + \")\" +\n        \" brightness(\" + (1 + EDGE_BRIGHTNESS * magnitude).toFixed(3) + \")\";\n\n      rightGlow.style.opacity = (normalized > 0 ? intensity : 0).toFixed(3);\n      leftGlow.style.opacity = (normalized < 0 ? intensity : 0).toFixed(3);\n      rightGlow.style.filter = colorTuning;\n      leftGlow.style.filter = colorTuning;\n    };\n\n    measure();\n    paint();\n    const resizeObserver = new ResizeObserver(measure);\n    resizeObserver.observe(container);\n\n    if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) {\n      return () => resizeObserver.disconnect();\n    }\n\n    const frame = (now = performance.now()) => {\n      const delta = Math.min((now - last) / 1000, 0.032);\n      last = now;\n      const angularFrequency = 2 * Math.PI * FREQUENCY;\n      velocity +=\n        (angularFrequency * angularFrequency * (target - x) -\n          2 * DAMPING * angularFrequency * velocity) *\n        delta;\n      x += velocity * delta;\n      paint();\n\n      if (inside || Math.abs(target - x) > 0.15 || Math.abs(velocity) > 0.6) {\n        animationFrameRef.current = requestAnimationFrame(frame);\n      } else {\n        animationFrameRef.current = null;\n        x = target;\n        velocity = 0;\n        paint();\n      }\n    };\n\n    const kick = () => {\n      if (animationFrameRef.current === null) {\n        last = performance.now();\n        animationFrameRef.current = requestAnimationFrame(frame);\n      }\n    };\n\n    container.onpointermove = (event) => {\n      const bounds = container.getBoundingClientRect();\n      inside = true;\n      target = Math.max(-bound, Math.min(bound, event.clientX - (bounds.left + bounds.width / 2)));\n      kick();\n    };\n\n    container.onpointerleave = () => {\n      inside = false;\n      target = x;\n      kick();\n    };\n\n    button.onfocus = () => {\n      inside = false;\n      target = 0;\n      kick();\n    };\n\n    button.onblur = () => {\n      inside = false;\n      target = x;\n      kick();\n    };\n\n    return () => {\n      resizeObserver.disconnect();\n      container.onpointermove = null;\n      container.onpointerleave = null;\n      button.onfocus = null;\n      button.onblur = null;\n      if (animationFrameRef.current !== null) cancelAnimationFrame(animationFrameRef.current);\n    };\n  }, []);\n\n  return (\n    <div ref={containerRef} className=\"relative z-10 inline-flex items-center\">\n      <span ref={rightGlowRef} aria-hidden=\"true\" className=\"pointer-events-none absolute left-1/2 top-1/2 h-[calc(100%+9px)] w-[calc(100%+9px)] rounded-full border-[3px] border-transparent opacity-100 will-change-transform [transform:translate(-50%,-50%)]\">\n        <span className=\"absolute left-[-3px] top-[-3px] z-20 box-content h-full w-full rounded-full border-[3px] border-transparent blur-[15px] [background:linear-gradient(transparent,transparent)_padding-box,linear-gradient(91.88deg,rgba(255,137,100,.2)_46.45%,#cd3100_98.59%)_border-box]\" />\n        <span className=\"absolute left-[-2px] top-[-2px] z-10 box-content h-full w-full rounded-full border-2 border-transparent blur-[2px] [background:linear-gradient(transparent,transparent)_padding-box,linear-gradient(97.68deg,rgba(255,177,153,0)_38.1%,rgba(255,177,153,.2)_82.47%,#ff7950_93.3%)_border-box]\" />\n        <span className=\"relative block h-full w-full rounded-full border border-transparent [background:linear-gradient(transparent,transparent)_padding-box,linear-gradient(103.7deg,rgba(188,155,143,.1)_38.66%,rgba(233,132,99,.1)_68.55%,#e98463_85.01%,#fff_92.12%)_border-box]\">\n          <span className=\"absolute left-[-2px] top-[-2px] z-30 box-content h-full w-full rounded-full border-2 border-transparent blur-[7px] [background:linear-gradient(transparent,transparent)_padding-box,linear-gradient(91.96deg,rgba(255,177,153,0)_6.11%,rgba(255,177,153,.2)_53.57%,#ff7950_93.6%)_border-box]\" />\n        </span>\n      </span>\n      <span ref={leftGlowRef} aria-hidden=\"true\" className=\"pointer-events-none absolute left-1/2 top-1/2 h-[calc(100%+9px)] w-[calc(100%+9px)] rounded-full border-[3px] border-transparent opacity-0 will-change-transform [transform:translate(-50%,-50%)_scaleX(-1)]\">\n        <span className=\"absolute left-[-3px] top-[-3px] z-20 box-content h-full w-full rounded-full border-[3px] border-transparent blur-[15px] [background:linear-gradient(transparent,transparent)_padding-box,linear-gradient(91.88deg,rgba(255,137,100,.2)_46.45%,#cd3100_98.59%)_border-box]\" />\n        <span className=\"absolute left-[-2px] top-[-2px] z-10 box-content h-full w-full rounded-full border-2 border-transparent blur-[2px] [background:linear-gradient(transparent,transparent)_padding-box,linear-gradient(97.68deg,rgba(255,177,153,0)_38.1%,rgba(255,177,153,.2)_82.47%,#ff7950_93.3%)_border-box]\" />\n        <span className=\"relative block h-full w-full rounded-full border border-transparent [background:linear-gradient(transparent,transparent)_padding-box,linear-gradient(103.7deg,rgba(188,155,143,.1)_38.66%,rgba(233,132,99,.1)_68.55%,#e98463_85.01%,#fff_92.12%)_border-box]\">\n          <span className=\"absolute left-[-2px] top-[-2px] z-30 box-content h-full w-full rounded-full border-2 border-transparent blur-[7px] [background:linear-gradient(transparent,transparent)_padding-box,linear-gradient(91.96deg,rgba(255,177,153,0)_6.11%,rgba(255,177,153,.2)_53.57%,#ff7950_93.6%)_border-box]\" />\n        </span>\n      </span>\n      <button ref={buttonRef} type=\"button\" className=\"relative z-10 flex h-10 cursor-pointer items-center justify-center gap-1 overflow-hidden rounded-full border border-white/60 bg-[#d1d1d1] px-[3.25rem] text-xs font-bold uppercase leading-none tracking-[-.015em] text-[#5a250a] transition-colors duration-200 ease-[cubic-bezier(.4,0,.2,1)] [font-family:Inter,-apple-system,'Segoe_UI',sans-serif] focus-visible:outline-2 focus-visible:outline-offset-8 focus-visible:outline-[#ff8964]\">\n        <span ref={lightTrackRef} aria-hidden=\"true\" className=\"absolute left-1/2 top-0 z-[-10] ml-[-102px] flex h-full w-[204px] items-center justify-center [--light-x:120px] [transform:translateX(var(--light-x))_translateZ(0)]\">\n          <span className=\"absolute top-1/2 h-[121px] w-[121px] -translate-y-1/2 [background:radial-gradient(50%_50%_at_50%_50%,#fffff5_3.5%,#ffaa81_26.5%,#ffda9f_37.5%,rgba(255,170,129,.5)_49%,rgba(210,106,58,0)_92.5%)]\" />\n          <span className=\"absolute top-1/2 h-[103px] w-[204px] -translate-y-1/2 blur-[5px] [background:radial-gradient(43.3%_44.23%_at_50%_49.51%,#fffff7_29%,#fffacd_48.5%,#f4d2bf_60.71%,rgba(214,211,210,0)_100%)]\" />\n        </span>\n        <span>See in Action</span>\n        <svg className=\"h-[9px] w-[17px] flex-none text-[#5a250a]\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 17 9\" aria-hidden=\"true\">\n          <path fill=\"currentColor\" fillRule=\"evenodd\" d=\"m12.495 0 4.495 4.495-4.495 4.495-.99-.99 2.805-2.805H0v-1.4h14.31L11.505.99z\" clipRule=\"evenodd\" />\n        </svg>\n      </button>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/microkit/cursor-edge-glow-button.tsx"
    }
  ],
  "docs": "Live preview and the CSS, JavaScript and Tailwind variants: https://microkit.co/components/cursor-edge-glow-button",
  "categories": [
    "button",
    "hover"
  ],
  "type": "registry:component"
}