{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "animated-gradient-text",
  "type": "registry:ui",
  "title": "Animated Gradient Text",
  "description": "Gradient-filled text: a `bg-clip-text text-transparent` span whose three-stop linear gradient slides horizontally on a loop. Built for a short eyebrow, badge or headline fragment — never a paragraph, since the text has no solid fill to fall back to.",
  "author": "ofri-peretz <https://github.com/ofri-peretz>",
  "categories": [
    "decorative",
    "effect"
  ],
  "dependencies": [],
  "registryDependencies": [
    "https://ds.interlace.tools/r/theme.json",
    "https://ds.interlace.tools/r/cn.json"
  ],
  "files": [
    {
      "path": "registry/interlace-ui/magicui/animated-gradient-text.tsx",
      "target": "components/ui/magicui/animated-gradient-text.tsx",
      "type": "registry:ui",
      "content": "import { ComponentPropsWithoutRef } from \"react\"\n\n\n\n// @interlace/animated-gradient-text v1.1.0 — Interlace design system.\n// Docs, props and live preview: https://ds.interlace.tools/c/animated-gradient-text\n// What changed since: https://ds.interlace.tools/c/animated-gradient-text#history\n// Generated banner — keep it, the upgrade diff reads this version.\n\n/**\n * @interlace/ui — AnimatedGradientText\n *\n * Gradient-filled text: a `bg-clip-text text-transparent` span whose\n * three-stop linear gradient slides horizontally on a loop. Built for a short\n * eyebrow, badge or headline fragment — never a paragraph, since the text has\n * no solid fill to fall back to.\n *\n * Our reimplementation of the Magic UI component of the same name. It is a\n * single span plus one keyframe, so the whole effect lives in three places:\n * this file, `--animate-gradient` in `styles/tokens.css`, and the `gradient`\n * keyframe next to it.\n *\n * ## Anatomy\n *\n *   AnimatedGradientText             (span — .animate-gradient)\n *     └─ children                    (painted through the clipped gradient)\n *\n * ## Motion\n *\n * Pure CSS, and covered twice. `.animate-gradient` is named in the\n * `prefers-reduced-motion: reduce` block in `styles/tokens.css`, which sets\n * `animation: none !important`, and it is also caught by the\n * `animation-duration: 0.01ms` wildcard in `styles/preflight.css`. There is no\n * `useReducedMotion` call here and none is needed. Under `reduce` the gradient\n * stops moving but still paints, so the text stays readable.\n *\n * ## `speed` changes distance, not duration\n *\n * The animation is a fixed `8s linear infinite`. `speed` sets\n * `--bg-size: speed × 300%`, and the keyframe animates\n * `background-position` to `var(--bg-size)`, so a larger `speed` moves the\n * gradient further in the same eight seconds — which reads as faster.\n *\n * ## The gradient IS the text, so both stops are text-grade tokens\n *\n * `colorFrom` / `colorTo` default to `var(--primary)` → `var(--primary-active)`.\n * The span is `bg-clip-text text-transparent`: there is no solid fill\n * underneath, so the gradient stops are the glyph colour and SC 1.4.3's 4.5:1\n * binds on every one of them. Both defaults are measured body-text tokens in\n * both schemes — 8.80:1 and 13.76:1 on light, 11.79:1 and 14.68:1 on dark\n * (`styles/interlace-theme.css`). A `--chart-*` token would NOT be admissible\n * here even though it is on the token system, because those are tuned to the\n * 3:1 graphical floor; `magicui/border-beam.tsx` may use one precisely because\n * nothing there is text.\n *\n * The previous defaults were the raw literals `#ffaa40` and `#9c40ff`. Beyond\n * being off the token system (R19), `#ffaa40` measures ≈2:1 on white — a real\n * AA failure, on text, in the DS's default surface.\n *\n * Override with any CSS colour, but keep the constraint in mind: whatever you\n * pass is being read as words.\n */\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface AnimatedGradientTextProps extends ComponentPropsWithoutRef<\"span\"> {\n  /**\n   * How far the gradient travels in the fixed 8s cycle, as a multiplier on\n   * `--bg-size`. Larger reads as faster. @default 1\n   */\n  speed?: number\n  /**\n   * First and third gradient stop — the colour the text starts and ends on.\n   * This is the GLYPH FILL, so it must clear SC 1.4.3 against whatever surface\n   * the text sits on. @default \"var(--primary)\"\n   */\n  colorFrom?: string\n  /**\n   * Middle gradient stop. Same contrast constraint as `colorFrom`.\n   * @default \"var(--primary-active)\"\n   */\n  colorTo?: string\n}\n\nexport function AnimatedGradientText({\n  children,\n  className,\n  speed = 1,\n  colorFrom = \"var(--primary)\",\n  colorTo = \"var(--primary-active)\",\n  ...props\n}: AnimatedGradientTextProps) {\n  return (\n    <span\n      style={\n        {\n          \"--bg-size\": `${speed * 300}%`,\n          \"--color-from\": colorFrom,\n          \"--color-to\": colorTo,\n        } as React.CSSProperties\n      }\n      className={cn(\n        `animate-gradient inline bg-gradient-to-r from-[var(--color-from)] via-[var(--color-to)] to-[var(--color-from)] bg-[length:var(--bg-size)_100%] bg-clip-text text-transparent`,\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </span>\n  )\n}\n"
    }
  ],
  "meta": {
    "tier": "effect",
    "client": false,
    "minViewport": null,
    "loading": false,
    "version": "1.1.0",
    "since": "1.0.0"
  },
  "docs": "## @interlace/animated-gradient-text\n\nInstalled to `components/ui/magicui/animated-gradient-text.tsx`.\n\n```tsx\nimport { /* … */ } from '@/components/ui/magicui/animated-gradient-text';\n```\n\nProps, a11y contract, live preview and source: https://ds.interlace.tools/c/animated-gradient-text\n\nRequires the `@interlace/theme` CSS baseline (installed automatically as a registry dependency)."
}
