{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "gradient-text",
  "title": "Gradient Text",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "Text filled with a gradient of theme colors that slowly drifts, or a shiny variant that sweeps a glint of light across it on a pause. Static under reduced motion; plain text in forced colors.",
  "dependencies": [
    "motion@^12"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/gradient-text.tsx",
      "content": "// Ballmac UI: Gradient Text. https://ui.ballmac.com/components/gradient-text\n\"use client\"\n\nimport * as React from \"react\"\nimport { animate, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype GradientTextElement = \"span\" | \"p\" | \"div\" | \"h1\" | \"h2\" | \"h3\" | \"h4\"\n\ntype GradientTextProps = React.ComponentProps<\"span\"> & {\n  /** The element to render. */\n  as?: GradientTextElement\n  /** \"flow\" drifts the gradient across the text; \"shiny\" keeps it still and sweeps a glint of light over it. */\n  variant?: \"flow\" | \"shiny\"\n  /** Gradient colors as CSS colors or variables. */\n  colors?: string[]\n  /** Seconds for one drift (flow) or one sweep (shiny). */\n  duration?: number\n  /** Shiny only: seconds between sweeps. */\n  repeatDelay?: number\n  /** Gradient angle in degrees. */\n  angle?: number\n  /** Shiny only: color of the glint. White reads best over saturated colors. */\n  shineColor?: string\n}\n\nfunction GradientText({\n  as = \"span\",\n  variant = \"flow\",\n  colors = [\"var(--chart-1)\", \"var(--chart-4)\", \"var(--chart-5)\", \"var(--chart-3)\"],\n  duration,\n  repeatDelay = 2.4,\n  angle = 100,\n  shineColor = \"rgb(255 255 255 / 0.95)\",\n  className,\n  style,\n  ...props\n}: GradientTextProps) {\n  const Comp = as as React.ElementType\n  const ref = React.useRef<HTMLElement>(null)\n  const reduceMotion = useReducedMotion()\n  const seconds = duration ?? (variant === \"flow\" ? 6 : 1.4)\n\n  React.useEffect(() => {\n    const node = ref.current\n    if (!node || reduceMotion) return\n    const controls =\n      variant === \"flow\"\n        ? animate(node, { \"--gradient-x\": [\"0%\", \"100%\"] }, { duration: seconds, ease: \"easeInOut\", repeat: Infinity, repeatType: \"mirror\" })\n        : animate(node, { \"--shine-x\": [\"100%\", \"0%\"] }, { duration: seconds, ease: [0.4, 0, 0.2, 1], repeat: Infinity, repeatDelay })\n    return () => {\n      controls.stop()\n      node.style.removeProperty(\"--gradient-x\")\n      node.style.removeProperty(\"--shine-x\")\n    }\n  }, [variant, seconds, repeatDelay, reduceMotion])\n\n  // Flow repeats the first color at the end so the drift has no hard edge.\n  const gradient = `linear-gradient(${angle}deg, ${[...colors, ...(variant === \"flow\" ? [colors[0]] : [])].join(\", \")})`\n  const glint = `linear-gradient(${angle + 10}deg, transparent 40%, ${shineColor} 50%, transparent 60%)`\n\n  return (\n    <Comp\n      ref={ref}\n      data-slot=\"gradient-text\"\n      data-variant={variant}\n      className={cn(\n        \"inline-block bg-clip-text bg-no-repeat text-transparent [-webkit-background-clip:text] forced-colors:bg-none forced-colors:text-[CanvasText]\",\n        className\n      )}\n      style={{\n        backgroundImage: variant === \"flow\" ? gradient : `${glint}, ${gradient}`,\n        backgroundSize: variant === \"flow\" ? \"300% 100%\" : \"250% 100%, 100% 100%\",\n        // Resting positions double as the reduced-motion state: a centered gradient, glint parked off the text.\n        backgroundPosition: variant === \"flow\" ? \"var(--gradient-x, 30%) 50%\" : \"var(--shine-x, 100%) 0%, 0% 0%\",\n        ...style,\n      }}\n      {...props}\n    />\n  )\n}\n\nexport { GradientText, type GradientTextProps }\n",
      "type": "registry:ui",
      "target": "@components/ballmac/gradient-text.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "text",
      "gradient",
      "headline",
      "shine",
      "hero",
      "motion"
    ],
    "version": "1.0.0",
    "updated": "2026-09-29",
    "ai": {
      "summary": "Wrap a few words: <GradientText>ship software</GradientText> inside a heading, or as=\"h2\". variant=\"flow\" (default) drifts the gradient; variant=\"shiny\" adds a periodic white glint. Colors default to --chart-1/4/5/3.",
      "whenToUse": [
        "Highlighting two or three words in a hero headline",
        "Product or plan names (shiny)"
      ],
      "whenNotToUse": [
        "Body text or long passages (contrast varies along the gradient)",
        "A muted loading shimmer on status text (use shimmer-text)"
      ],
      "composesWith": [
        "word-rotate",
        "shimmer-text"
      ],
      "a11y": [],
      "customization": [
        "variant: flow | shiny",
        "colors: CSS colors or var(--chart-n); angle in degrees (default 100)",
        "duration: seconds per drift (default 6) or sweep (default 1.4); repeatDelay for shiny (default 2.4)",
        "shineColor: glint color for the shiny variant (default near-white; keep colors saturated so it shows)",
        "Add pb-[0.08em] if descenders clip at large sizes"
      ]
    },
    "examples": [
      "gradient-text-demo",
      "gradient-text-shiny"
    ],
    "url": "https://ui.ballmac.com/components/gradient-text"
  },
  "categories": [
    "text"
  ],
  "type": "registry:ui"
}