{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "featured-grain-gradient",
  "title": "Grain Gradient Card",
  "description": "Generative grain-gradient shader (via @paper-design/shaders-react) — no image input, just colors + shape. Seven shapes (wave/dots/truchet/corners/ripple/blob/sphere), up to 7 colors, animated by default. Great for hero backgrounds and OG images. Includes the shared title overlay API (titleText/titlePosition/titleSize/titleColor).",
  "dependencies": [
    "@paper-design/shaders-react"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/featured-grain-gradient/featured-grain-gradient.tsx",
      "content": "\"use client\";\n\nimport { GrainGradient } 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 FeaturedGrainGradientProps = {\n  /** Up to 7 colors. */\n  colors?: string[];\n  /** Background color. */\n  colorBack?: string;\n  /** Shape variant. */\n  shape?:\n    | \"wave\"\n    | \"dots\"\n    | \"truchet\"\n    | \"corners\"\n    | \"ripple\"\n    | \"blob\"\n    | \"sphere\";\n  /** Color transition smoothness, 0-1. */\n  softness?: number;\n  /** Distortion strength, 0-1. */\n  intensity?: number;\n  /** Grain noise overlay, 0-1. */\n  noise?: number;\n  /** Animation speed multiplier. 0 = static. */\n  speed?: number;\n  /** Zoom, 0.01-4. */\n  scale?: number;\n  /** Rotation in degrees, 0-360. */\n  rotation?: number;\n  /** Title overlay. */\n  title?: React.ReactNode;\n  /** Small label above title. */\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  /** Optional arbitrary content rendered over the gradient. */\n  children?: React.ReactNode;\n  /** Aspect ratio, default \"16/9\". */\n  aspectRatio?: string;\n  className?: string;\n};\n\nconst DEFAULT_COLORS = [\"#7300ff\", \"#eba8ff\", \"#00bfff\", \"#2a00ff\"];\n\nexport function FeaturedGrainGradient({\n  colors = DEFAULT_COLORS,\n  colorBack = \"#000000\",\n  shape = \"corners\",\n  softness = 0.5,\n  intensity = 0.5,\n  noise = 0.25,\n  speed = 1,\n  scale = 1,\n  rotation = 0,\n  title,\n  eyebrow,\n  titlePosition = \"bottom-left\",\n  titleSize = 30,\n  titleColor,\n  titleClassName = \"text-white\",\n  children,\n  aspectRatio = \"16/9\",\n  className,\n}: FeaturedGrainGradientProps) {\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-neutral-900\",\n        className\n      )}\n      style={{ aspectRatio }}\n    >\n      <GrainGradient\n        colorBack={colorBack}\n        colors={colors}\n        fit=\"cover\"\n        intensity={intensity}\n        noise={noise}\n        rotation={rotation}\n        scale={scale}\n        shape={shape}\n        softness={softness}\n        speed={speed}\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          width: \"100%\",\n          height: \"100%\",\n        }}\n      />\n\n      {children ? (\n        <div className=\"relative z-10 size-full\">{children}</div>\n      ) : null}\n\n      {title || eyebrow ? (\n        <div\n          className={cn(\n            \"pointer-events-none absolute inset-0 z-10 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"
}