{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "magnetize",
  "title": "Magnetize",
  "description": "Letters scattered, then snap into place with a slight overshoot. Per-char varied origin.",
  "files": [
    {
      "path": "registry/default/magnetize/magnetize.tsx",
      "content": "import { type ElementType, type CSSProperties } from 'react';\nimport { cn } from '@/lib/utils';\n\nexport interface MagnetizeProps {\n  text: string;\n  /** Delay before letters start snapping in, in ms. */\n  delay?: number;\n  /** Delay between successive letters, in ms. */\n  stagger?: number;\n  /** Element tag. */\n  as?: ElementType;\n  className?: string;\n}\n\nconst PRIMES = [73, 19, 41, 53, 89, 61, 47, 31, 79];\n\nfunction det(seed: number, range: number, offset = 0): number {\n  return ((Math.abs((seed + 1) * (PRIMES[seed % PRIMES.length] ?? 73)) % range) + offset);\n}\n\nexport function Magnetize({\n  text,\n  delay = 0,\n  stagger = 60,\n  as: Component = 'span',\n  className\n}: MagnetizeProps) {\n  return (\n    <Component className={cn('inline-block', className)} aria-label={text}>\n      {text.split('').map((char, i) => {\n        const x = det(i * 7, 200, -100);\n        const y = det(i * 11, 100, -50);\n        const r = det(i * 13, 240, -120);\n        return (\n          <span\n            key={i}\n            aria-hidden='true'\n            className='inline-block whitespace-pre animate-trickle-magnetize'\n            style={\n              {\n                animationDelay: `${delay + i * stagger}ms`,\n                ['--trickle-magnetize-x' as string]: `${x}px`,\n                ['--trickle-magnetize-y' as string]: `${y}px`,\n                ['--trickle-magnetize-r' as string]: `${r}deg`\n              } as CSSProperties\n            }\n          >\n            {char}\n          </span>\n        );\n      })}\n    </Component>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/trickle/magnetize.tsx"
    }
  ],
  "cssVars": {
    "theme": {
      "--animate-trickle-magnetize": "trickle-magnetize 0.9s cubic-bezier(0.34, 1.56, 0.64, 1) both"
    }
  },
  "css": {
    "@keyframes trickle-magnetize": {
      "0%": {
        "opacity": "0",
        "transform": "translate(var(--trickle-magnetize-x, 60px), var(--trickle-magnetize-y, 30px)) rotate(var(--trickle-magnetize-r, 30deg))"
      },
      "60%": {
        "opacity": "1",
        "transform": "translate(0, 0) rotate(0)"
      },
      "80%": {
        "transform": "translate(0, 0) rotate(0) scale(1.05)"
      },
      "100%": {
        "opacity": "1",
        "transform": "translate(0, 0) rotate(0) scale(1)"
      }
    },
    "@media (prefers-reduced-motion: reduce)": {
      ".animate-trickle-magnetize": {
        "animation": "none",
        "opacity": "1",
        "transform": "none"
      }
    }
  },
  "type": "registry:ui"
}