{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "spinning-text",
  "title": "Spinning Text",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "Text laid out on a circle that turns slowly, with a center slot for a logo or arrow, pausing on hover.",
  "dependencies": [
    "motion@^12"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/spinning-text.tsx",
      "content": "// Ballmac UI: Spinning Text. https://ui.ballmac.com/components/spinning-text\n\"use client\"\n\nimport * as React from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype SpinningTextProps = Omit<React.ComponentProps<\"div\">, \"children\"> & {\n  /** The words that run around the circle. */\n  text: string\n  /** Shown between repeats of the text. */\n  separator?: string\n  /** Seconds for one full turn. */\n  duration?: number\n  /** Turn counter-clockwise. */\n  reverse?: boolean\n  /** Pause the spin while the pointer is over it or it has keyboard focus. */\n  pauseOnHover?: boolean\n  /** Content in the middle of the ring, such as a logo or an arrow. */\n  children?: React.ReactNode\n}\n\nfunction SpinningText({ text, separator = \" • \", duration = 14, reverse = false, pauseOnHover = true, className, children, ...props }: SpinningTextProps) {\n  const reduce = useReducedMotion()\n  const id = React.useId().replace(/:/g, \"\")\n  const [paused, setPaused] = React.useState(false)\n  const label = text.trim()\n  const run = `${label}${separator}`\n  // Fit the string to the circle: every character gets a small even share of the circumference.\n  const radius = 76\n  const circumference = 2 * Math.PI * radius\n\n  return (\n    <div\n      data-slot=\"spinning-text\"\n      role=\"img\"\n      aria-label={label}\n      onPointerEnter={() => pauseOnHover && setPaused(true)}\n      onPointerLeave={() => setPaused(false)}\n      className={cn(\"relative inline-flex size-40 items-center justify-center text-foreground\", className)}\n      {...props}\n    >\n      <motion.svg\n        aria-hidden=\"true\"\n        viewBox=\"0 0 200 200\"\n        className=\"absolute inset-0 size-full overflow-visible\"\n        animate={reduce || paused ? undefined : { rotate: reverse ? -360 : 360 }}\n        transition={{ duration, ease: \"linear\", repeat: Infinity }}\n        style={{ originX: \"50%\", originY: \"50%\" }}\n      >\n        <defs>\n          <path id={id} d={`M100 100 m-${radius} 0 a${radius} ${radius} 0 1 1 ${radius * 2} 0 a${radius} ${radius} 0 1 1 -${radius * 2} 0`} />\n        </defs>\n        <text fill=\"currentColor\" className=\"font-medium uppercase\" style={{ fontSize: 15, letterSpacing: \"0.04em\" }}>\n          <textPath href={`#${id}`} textLength={circumference - 4} lengthAdjust=\"spacing\">\n            {run}\n          </textPath>\n        </text>\n      </motion.svg>\n      {children && <div className=\"relative flex items-center justify-center\">{children}</div>}\n    </div>\n  )\n}\n\nexport { SpinningText, type SpinningTextProps }\n",
      "type": "registry:ui",
      "target": "@components/ballmac/spinning-text.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "text",
      "circle",
      "rotate",
      "badge",
      "marketing"
    ],
    "version": "1.0.0",
    "updated": "2026-10-01",
    "ai": {
      "summary": "<SpinningText text duration reverse pauseOnHover className='size-40'>{center}</SpinningText>. The string is fitted to the circle, so shorter text spreads wider.",
      "whenToUse": [
        "Scroll-down or 'new' badges",
        "Decorative seals and stamps"
      ],
      "whenNotToUse": [
        "Information people need to read (rotating text is hard to read)"
      ],
      "composesWith": [
        "orbiting-circles",
        "gradient-text"
      ],
      "a11y": [
        {
          "keys": "Screen readers",
          "action": "The ring is an image named by the text; the center slot is read normally"
        },
        {
          "keys": "Reduced motion",
          "action": "The ring stays still"
        }
      ],
      "customization": [
        "text and separator",
        "duration",
        "reverse",
        "size via className"
      ]
    },
    "examples": [
      "spinning-text-demo",
      "spinning-text-sizes"
    ],
    "url": "https://ui.ballmac.com/components/spinning-text"
  },
  "categories": [
    "text"
  ],
  "type": "registry:ui"
}