{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "matrix-image",
  "title": "Matrix Image",
  "description": "An animated image component that simulates the iconic Matrix digital rain effect.",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "registry/components/unlumen/matrix-image/index.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { type Frame, Matrix } from \"@/components/unlumen-ui/matrix\";\n\ninterface MatrixImageProps extends React.HTMLAttributes<HTMLDivElement> {\n  src?: string;\n  data?: Frame;\n  rows?: number;\n  cols?: number;\n  size?: number;\n  gap?: number;\n  palette?: { on: string; off: string };\n  brightness?: number;\n  invert?: boolean;\n  ariaLabel?: string;\n}\n\nexport function imageToMatrix(\n  image: HTMLImageElement | HTMLCanvasElement,\n  rows: number,\n  cols: number,\n  invert = false,\n): Frame {\n  const canvas = document.createElement(\"canvas\");\n  canvas.width = cols;\n  canvas.height = rows;\n  const ctx = canvas.getContext(\"2d\")!;\n\n  ctx.imageSmoothingEnabled = true;\n  ctx.imageSmoothingQuality = \"high\";\n  ctx.drawImage(image, 0, 0, cols, rows);\n\n  const imageData = ctx.getImageData(0, 0, cols, rows);\n  const pixels = imageData.data;\n  const frame: Frame = [];\n\n  for (let r = 0; r < rows; r++) {\n    const row: number[] = [];\n    for (let c = 0; c < cols; c++) {\n      const i = (r * cols + c) * 4;\n      const R = pixels[i];\n      const G = pixels[i + 1];\n      const B = pixels[i + 2];\n      const A = pixels[i + 3] / 255;\n      const luma = (0.299 * R + 0.587 * G + 0.114 * B) / 255;\n      const value = (invert ? luma : 1 - luma) * A;\n      row.push(Math.round(value * 100) / 100);\n    }\n    frame.push(row);\n  }\n\n  return frame;\n}\n\nexport function fileToMatrix(\n  file: File,\n  rows: number,\n  cols: number,\n  invert?: boolean,\n): Promise<Frame> {\n  return new Promise((resolve, reject) => {\n    const url = URL.createObjectURL(file);\n    const img = new Image();\n    img.crossOrigin = \"anonymous\";\n    img.onload = () => {\n      resolve(imageToMatrix(img, rows, cols, invert));\n      URL.revokeObjectURL(url);\n    };\n    img.onerror = () => {\n      URL.revokeObjectURL(url);\n      reject(new Error(\"Failed to load image\"));\n    };\n    img.src = url;\n  });\n}\n\nexport function srcToMatrix(\n  src: string,\n  rows: number,\n  cols: number,\n  invert?: boolean,\n): Promise<Frame> {\n  return new Promise((resolve, reject) => {\n    const img = new Image();\n    img.crossOrigin = \"anonymous\";\n    img.onload = () => resolve(imageToMatrix(img, rows, cols, invert));\n    img.onerror = () => reject(new Error(\"Failed to load image\"));\n    img.src = src;\n  });\n}\n\nexport const MatrixImage = React.forwardRef<HTMLDivElement, MatrixImageProps>(\n  (\n    {\n      src,\n      data,\n      rows = 32,\n      cols = 32,\n      size = 6,\n      gap = 2,\n      palette,\n      brightness = 1,\n      invert = false,\n      ariaLabel,\n      className,\n      ...props\n    },\n    ref,\n  ) => {\n    const [frame, setFrame] = useState<Frame | null>(data ?? null);\n    const prevSrc = useRef<string | undefined>(undefined);\n\n    const loadImage = useCallback(\n      async (imageSrc: string) => {\n        try {\n          const result = await srcToMatrix(imageSrc, rows, cols, invert);\n          setFrame(result);\n        } catch {\n          setFrame(null);\n        }\n      },\n      [rows, cols, invert],\n    );\n\n    useEffect(() => {\n      if (data) {\n        setFrame(data);\n        return;\n      }\n\n      if (src && src !== prevSrc.current) {\n        prevSrc.current = src;\n        loadImage(src);\n      }\n    }, [src, data, loadImage]);\n\n    if (!frame) {\n      return (\n        <div ref={ref} className={cn(\"inline-block\", className)} {...props} />\n      );\n    }\n\n    return (\n      <Matrix\n        ref={ref}\n        rows={rows}\n        cols={cols}\n        pattern={frame}\n        size={size}\n        gap={gap}\n        palette={palette}\n        brightness={brightness}\n        ariaLabel={ariaLabel ?? \"matrix image\"}\n        className={className}\n        {...props}\n      />\n    );\n  },\n);\n\nMatrixImage.displayName = \"MatrixImage\";\n",
      "type": "registry:ui",
      "target": "components/unlumen-ui/matrix-image.tsx"
    }
  ],
  "type": "registry:ui"
}