{
  "name": "card-spotlight",
  "type": "registry:ui",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://ui.aceternity.com/registry/canvas-reveal-effect.json"
  ],
  "files": [
    {
      "path": "components/ui/card-spotlight.tsx",
      "content": "\"use client\";\n\nimport { useMotionValue, motion, useMotionTemplate } from \"motion/react\";\nimport React, { MouseEvent as ReactMouseEvent, useState } from \"react\";\nimport { CanvasRevealEffect } from \"@/components/ui/canvas-reveal-effect\";\nimport { cn } from \"@/lib/utils\";\n\nexport const CardSpotlight = ({\n  children,\n  radius = 350,\n  color = \"#262626\",\n  className,\n  ...props\n}: {\n  radius?: number;\n  color?: string;\n  children: React.ReactNode;\n} & React.HTMLAttributes<HTMLDivElement>) => {\n  const mouseX = useMotionValue(0);\n  const mouseY = useMotionValue(0);\n  function handleMouseMove({\n    currentTarget,\n    clientX,\n    clientY,\n  }: ReactMouseEvent<HTMLDivElement>) {\n    let { left, top } = currentTarget.getBoundingClientRect();\n\n    mouseX.set(clientX - left);\n    mouseY.set(clientY - top);\n  }\n\n  const [isHovering, setIsHovering] = useState(false);\n  const handleMouseEnter = () => setIsHovering(true);\n  const handleMouseLeave = () => setIsHovering(false);\n  return (\n    <div\n      className={cn(\n        \"group/spotlight p-10 rounded-md relative border border-neutral-800 bg-black dark:border-neutral-800\",\n        className\n      )}\n      onMouseMove={handleMouseMove}\n      onMouseEnter={handleMouseEnter}\n      onMouseLeave={handleMouseLeave}\n      {...props}\n    >\n      <motion.div\n        className=\"pointer-events-none absolute z-0 -inset-px rounded-md opacity-0 transition duration-300 group-hover/spotlight:opacity-100\"\n        style={{\n          backgroundColor: color,\n          maskImage: useMotionTemplate`\n            radial-gradient(\n              ${radius}px circle at ${mouseX}px ${mouseY}px,\n              white,\n              transparent 80%\n            )\n          `,\n        }}\n      >\n        {isHovering && (\n          <CanvasRevealEffect\n            animationSpeed={5}\n            containerClassName=\"bg-transparent absolute inset-0 pointer-events-none\"\n            colors={[\n              [59, 130, 246],\n              [139, 92, 246],\n            ]}\n            dotSize={3}\n          />\n        )}\n      </motion.div>\n      {children}\n    </div>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ui/card-spotlight.tsx"
    },
    {
      "path": "components/ui/canvas-reveal-effect.tsx",
      "content": "\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport { Canvas, useFrame, useThree } from \"@react-three/fiber\";\nimport React, { useMemo, useRef } from \"react\";\nimport * as THREE from \"three\";\n\nexport const CanvasRevealEffect = ({\n  animationSpeed = 0.4,\n  opacities = [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1],\n  colors = [[0, 255, 255]],\n  containerClassName,\n  dotSize,\n  showGradient = true,\n}: {\n  /**\n   * 0.1 - slower\n   * 1.0 - faster\n   */\n  animationSpeed?: number;\n  opacities?: number[];\n  colors?: number[][];\n  containerClassName?: string;\n  dotSize?: number;\n  showGradient?: boolean;\n}) => {\n  return (\n    <div className={cn(\"h-full relative bg-white w-full\", containerClassName)}>\n      <div className=\"h-full w-full\">\n        <DotMatrix\n          colors={colors ?? [[0, 255, 255]]}\n          dotSize={dotSize ?? 3}\n          opacities={\n            opacities ?? [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1]\n          }\n          shader={`\n              float animation_speed_factor = ${animationSpeed.toFixed(1)};\n              float intro_offset = distance(u_resolution / 2.0 / u_total_size, st2) * 0.01 + (random(st2) * 0.15);\n              opacity *= step(intro_offset, u_time * animation_speed_factor);\n              opacity *= clamp((1.0 - step(intro_offset + 0.1, u_time * animation_speed_factor)) * 1.25, 1.0, 1.25);\n            `}\n          center={[\"x\", \"y\"]}\n        />\n      </div>\n      {showGradient && (\n        <div className=\"absolute inset-0 bg-gradient-to-t from-gray-950 to-[84%]\" />\n      )}\n    </div>\n  );\n};\n\ninterface DotMatrixProps {\n  colors?: number[][];\n  opacities?: number[];\n  totalSize?: number;\n  dotSize?: number;\n  shader?: string;\n  center?: (\"x\" | \"y\")[];\n}\n\nconst DotMatrix: React.FC<DotMatrixProps> = ({\n  colors = [[0, 0, 0]],\n  opacities = [0.04, 0.04, 0.04, 0.04, 0.04, 0.08, 0.08, 0.08, 0.08, 0.14],\n  totalSize = 4,\n  dotSize = 2,\n  shader = \"\",\n  center = [\"x\", \"y\"],\n}) => {\n  const uniforms = React.useMemo(() => {\n    let colorsArray = [\n      colors[0],\n      colors[0],\n      colors[0],\n      colors[0],\n      colors[0],\n      colors[0],\n    ];\n    if (colors.length === 2) {\n      colorsArray = [\n        colors[0],\n        colors[0],\n        colors[0],\n        colors[1],\n        colors[1],\n        colors[1],\n      ];\n    } else if (colors.length === 3) {\n      colorsArray = [\n        colors[0],\n        colors[0],\n        colors[1],\n        colors[1],\n        colors[2],\n        colors[2],\n      ];\n    }\n\n    return {\n      u_colors: {\n        value: colorsArray.map((color) => [\n          color[0] / 255,\n          color[1] / 255,\n          color[2] / 255,\n        ]),\n        type: \"uniform3fv\",\n      },\n      u_opacities: {\n        value: opacities,\n        type: \"uniform1fv\",\n      },\n      u_total_size: {\n        value: totalSize,\n        type: \"uniform1f\",\n      },\n      u_dot_size: {\n        value: dotSize,\n        type: \"uniform1f\",\n      },\n    };\n  }, [colors, opacities, totalSize, dotSize]);\n\n  return (\n    <Shader\n      source={`\n        precision mediump float;\n        in vec2 fragCoord;\n\n        uniform float u_time;\n        uniform float u_opacities[10];\n        uniform vec3 u_colors[6];\n        uniform float u_total_size;\n        uniform float u_dot_size;\n        uniform vec2 u_resolution;\n        out vec4 fragColor;\n        float PHI = 1.61803398874989484820459;\n        float random(vec2 xy) {\n            return fract(tan(distance(xy * PHI, xy) * 0.5) * xy.x);\n        }\n        float map(float value, float min1, float max1, float min2, float max2) {\n            return min2 + (value - min1) * (max2 - min2) / (max1 - min1);\n        }\n        void main() {\n            vec2 st = fragCoord.xy;\n            ${\n              center.includes(\"x\")\n                ? \"st.x -= abs(floor((mod(u_resolution.x, u_total_size) - u_dot_size) * 0.5));\"\n                : \"\"\n            }\n            ${\n              center.includes(\"y\")\n                ? \"st.y -= abs(floor((mod(u_resolution.y, u_total_size) - u_dot_size) * 0.5));\"\n                : \"\"\n            }\n      float opacity = step(0.0, st.x);\n      opacity *= step(0.0, st.y);\n\n      vec2 st2 = vec2(int(st.x / u_total_size), int(st.y / u_total_size));\n\n      float frequency = 5.0;\n      float show_offset = random(st2);\n      float rand = random(st2 * floor((u_time / frequency) + show_offset + frequency) + 1.0);\n      opacity *= u_opacities[int(rand * 10.0)];\n      opacity *= 1.0 - step(u_dot_size / u_total_size, fract(st.x / u_total_size));\n      opacity *= 1.0 - step(u_dot_size / u_total_size, fract(st.y / u_total_size));\n\n      vec3 color = u_colors[int(show_offset * 6.0)];\n\n      ${shader}\n\n      fragColor = vec4(color, opacity);\n      fragColor.rgb *= fragColor.a;\n        }`}\n      uniforms={uniforms}\n      maxFps={60}\n    />\n  );\n};\n\ntype Uniforms = {\n  [key: string]: {\n    value: number[] | number[][] | number;\n    type: string;\n  };\n};\nconst ShaderMaterial = ({\n  source,\n  uniforms,\n  maxFps = 60,\n}: {\n  source: string;\n  hovered?: boolean;\n  maxFps?: number;\n  uniforms: Uniforms;\n}) => {\n  const { size } = useThree();\n  const ref = useRef<THREE.Mesh>();\n  let lastFrameTime = 0;\n\n  useFrame(({ clock }) => {\n    if (!ref.current) return;\n    const timestamp = clock.getElapsedTime();\n    if (timestamp - lastFrameTime < 1 / maxFps) {\n      return;\n    }\n    lastFrameTime = timestamp;\n\n    const material: any = ref.current.material;\n    const timeLocation = material.uniforms.u_time;\n    timeLocation.value = timestamp;\n  });\n\n  const getUniforms = () => {\n    const preparedUniforms: any = {};\n\n    for (const uniformName in uniforms) {\n      const uniform: any = uniforms[uniformName];\n\n      switch (uniform.type) {\n        case \"uniform1f\":\n          preparedUniforms[uniformName] = { value: uniform.value, type: \"1f\" };\n          break;\n        case \"uniform3f\":\n          preparedUniforms[uniformName] = {\n            value: new THREE.Vector3().fromArray(uniform.value),\n            type: \"3f\",\n          };\n          break;\n        case \"uniform1fv\":\n          preparedUniforms[uniformName] = { value: uniform.value, type: \"1fv\" };\n          break;\n        case \"uniform3fv\":\n          preparedUniforms[uniformName] = {\n            value: uniform.value.map((v: number[]) =>\n              new THREE.Vector3().fromArray(v)\n            ),\n            type: \"3fv\",\n          };\n          break;\n        case \"uniform2f\":\n          preparedUniforms[uniformName] = {\n            value: new THREE.Vector2().fromArray(uniform.value),\n            type: \"2f\",\n          };\n          break;\n        default:\n          console.error(`Invalid uniform type for '${uniformName}'.`);\n          break;\n      }\n    }\n\n    preparedUniforms[\"u_time\"] = { value: 0, type: \"1f\" };\n    preparedUniforms[\"u_resolution\"] = {\n      value: new THREE.Vector2(size.width * 2, size.height * 2),\n    }; // Initialize u_resolution\n    return preparedUniforms;\n  };\n\n  // Shader material\n  const material = useMemo(() => {\n    const materialObject = new THREE.ShaderMaterial({\n      vertexShader: `\n      precision mediump float;\n      in vec2 coordinates;\n      uniform vec2 u_resolution;\n      out vec2 fragCoord;\n      void main(){\n        float x = position.x;\n        float y = position.y;\n        gl_Position = vec4(x, y, 0.0, 1.0);\n        fragCoord = (position.xy + vec2(1.0)) * 0.5 * u_resolution;\n        fragCoord.y = u_resolution.y - fragCoord.y;\n      }\n      `,\n      fragmentShader: source,\n      uniforms: getUniforms(),\n      glslVersion: THREE.GLSL3,\n      blending: THREE.CustomBlending,\n      blendSrc: THREE.SrcAlphaFactor,\n      blendDst: THREE.OneFactor,\n    });\n\n    return materialObject;\n  }, [size.width, size.height, source]);\n\n  return (\n    <mesh ref={ref as any}>\n      <planeGeometry args={[2, 2]} />\n      <primitive object={material} attach=\"material\" />\n    </mesh>\n  );\n};\n\nconst Shader: React.FC<ShaderProps> = ({ source, uniforms, maxFps = 60 }) => {\n  return (\n    <Canvas className=\"absolute inset-0  h-full w-full\">\n      <ShaderMaterial source={source} uniforms={uniforms} maxFps={maxFps} />\n    </Canvas>\n  );\n};\ninterface ShaderProps {\n  source: string;\n  uniforms: {\n    [key: string]: {\n      value: number[] | number[][] | number;\n      type: string;\n    };\n  };\n  maxFps?: number;\n}\n",
      "type": "registry:ui",
      "target": "components/ui/canvas-reveal-effect.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Card Spotlight"
}