{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "featured-halftone-dots",
  "title": "Halftone Dots Photo Card",
  "description": "Single-color halftone dot shader (via @paper-design/shaders-react) — square or hex grids, four dot styles (classic / gooey / holes / soft), grain controls, and an originalColors mode for sampled palettes. Includes the shared title overlay API (titleText/titlePosition/titleSize/titleColor).",
  "dependencies": [
    "@paper-design/shaders-react"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/featured-halftone-dots/featured-halftone-dots.tsx",
      "content": "\"use client\";\n\nimport { HalftoneDots } from \"@paper-design/shaders-react\";\nimport type * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport type TitlePosition =\n  | \"top-left\"\n  | \"top-center\"\n  | \"top-right\"\n  | \"center-left\"\n  | \"center\"\n  | \"center-right\"\n  | \"bottom-left\"\n  | \"bottom-center\"\n  | \"bottom-right\";\n\nconst POSITION_CLASSES: Record<TitlePosition, string> = {\n  \"top-left\": \"items-start justify-start text-left\",\n  \"top-center\": \"items-start justify-center text-center\",\n  \"top-right\": \"items-start justify-end text-right\",\n  \"center-left\": \"items-center justify-start text-left\",\n  center: \"items-center justify-center text-center\",\n  \"center-right\": \"items-center justify-end text-right\",\n  \"bottom-left\": \"items-end justify-start text-left\",\n  \"bottom-center\": \"items-end justify-center text-center\",\n  \"bottom-right\": \"items-end justify-end text-right\",\n};\n\nexport type FeaturedHalftoneDotsProps = {\n  image: string;\n  imageAlt?: string;\n  title?: React.ReactNode;\n  eyebrow?: React.ReactNode;\n  /** Where to anchor the title block. Default \"bottom-left\". */\n  titlePosition?: TitlePosition;\n  /** Title font size in px. Eyebrow scales proportionally. Default 30. */\n  titleSize?: number;\n  /** Inline color for the title + eyebrow. Overrides titleClassName color. */\n  titleColor?: string;\n  titleClassName?: string;\n  /** Dot rendering style. */\n  type?: \"classic\" | \"gooey\" | \"holes\" | \"soft\";\n  /** Grid pattern. */\n  grid?: \"square\" | \"hex\";\n  /** Grid size relative to image (0-1). */\n  size?: number;\n  /** Max dot size relative to cell (0-2). */\n  radius?: number;\n  /** Image contrast (0-1). */\n  contrast?: number;\n  /** Paper / background color. */\n  colorBack?: string;\n  /** Dot color. */\n  colorFront?: string;\n  /** Use the image's actual colors instead of colorFront. */\n  originalColors?: boolean;\n  /** Invert image luminance. */\n  inverted?: boolean;\n  /** Grain distortion on dot edges (0-1). */\n  grainMixer?: number;\n  /** Black/white grain overlay (0-1). */\n  grainOverlay?: number;\n  /** Grain scale (0-1). */\n  grainSize?: number;\n  aspectRatio?: string;\n  className?: string;\n};\n\nexport function FeaturedHalftoneDots({\n  image,\n  imageAlt: _imageAlt,\n  title,\n  eyebrow,\n  titlePosition = \"bottom-left\",\n  titleSize = 30,\n  titleColor,\n  titleClassName = \"text-stone-900\",\n  type = \"gooey\",\n  grid = \"hex\",\n  size = 0.5,\n  radius = 1.25,\n  contrast = 0.4,\n  colorBack = \"#f2f1e8\",\n  colorFront = \"#2b2b2b\",\n  originalColors = false,\n  inverted = false,\n  grainMixer = 0.2,\n  grainOverlay = 0.2,\n  grainSize = 0.5,\n  aspectRatio = \"16/9\",\n  className,\n}: FeaturedHalftoneDotsProps) {\n  const eyebrowSize = Math.max(11, Math.round(titleSize * 0.4));\n\n  return (\n    <figure\n      className={cn(\n        \"relative isolate overflow-hidden rounded-2xl bg-stone-100\",\n        className\n      )}\n      style={{ aspectRatio }}\n    >\n      <HalftoneDots\n        colorBack={colorBack}\n        colorFront={colorFront}\n        contrast={contrast}\n        fit=\"cover\"\n        grainMixer={grainMixer}\n        grainOverlay={grainOverlay}\n        grainSize={grainSize}\n        grid={grid}\n        image={image}\n        inverted={inverted}\n        originalColors={originalColors}\n        radius={radius}\n        size={size}\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          width: \"100%\",\n          height: \"100%\",\n        }}\n        type={type}\n      />\n\n      {title || eyebrow ? (\n        <div\n          className={cn(\n            \"pointer-events-none absolute inset-0 flex p-4 sm:p-6\",\n            POSITION_CLASSES[titlePosition]\n          )}\n        >\n          <figcaption className=\"flex max-w-full flex-col gap-1\">\n            {eyebrow ? (\n              <span\n                className={cn(\"font-medium opacity-80\", titleClassName)}\n                style={{ fontSize: `${eyebrowSize}px`, color: titleColor }}\n              >\n                {eyebrow}\n              </span>\n            ) : null}\n            {title ? (\n              <h3\n                className={cn(\n                  \"font-bold leading-tight tracking-tight\",\n                  titleClassName\n                )}\n                style={{ fontSize: `${titleSize}px`, color: titleColor }}\n              >\n                {title}\n              </h3>\n            ) : null}\n          </figcaption>\n        </div>\n      ) : null}\n    </figure>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "featured"
  ],
  "type": "registry:block"
}