{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "orbital-letters",
  "title": "Orbital Letters",
  "description": "component for the Orbital Letters",
  "dependencies": [
    "framer-motion"
  ],
  "files": [
    {
      "path": "app/registry/animatedtext/components/orbital-text.tsx",
      "content": "\"use client\"\n\nimport { useMemo } from \"react\"\nimport { OrbitalChar } from \"./orbital-char\" \n\ntype Props = {\n  text?: string\n  radius?: number \n  duration?: number\n  decay?: number \n}\n\nexport function OrbitalText({ text = \"Orbital Letters\", radius = 18, duration = 2000, decay = 0.9 }: Props) {\n  const chars = useMemo(() => text.split(\"\"), [text])\n\n  return (\n    <div className=\"relative font-semibold tracking-tight text-[clamp(28px,5vw,56px)]\" aria-label={text} role=\"img\">\n      <div className=\"flex select-none items-center justify-center gap-[0.02em] text-neutral-900 dark:text-neutral-200\">\n        {chars.map((c, i) => (\n          <OrbitalChar\n            key={i} \n            char={c}\n            index={i}\n            radius={radius}\n            duration={duration}\n            decay={decay}\n          />\n        ))}\n      </div>\n      <div className=\"pointer-events-none absolute inset-0 -z-10 opacity-[0.08]\">\n\n        <div className=\"h-full w-full bg-[radial-gradient(50%_50%_at_50%_40%,#8882_0%,transparent_60%)]\" />\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/spectrumui/orbital-text.tsx"
    },
    {
      "path": "app/registry/animatedtext/components/orbital-char.tsx",
      "content": "'use client';\n\nimport { motion, useSpring, useTransform } from 'framer-motion';\nimport { useEffect } from 'react';\n\ntype Props = {\n  char: string;\n  index: number;\n  radius: number;\n  duration: number;\n  decay: number;\n};\n\nexport function OrbitalChar({ char, index, radius, duration, decay }: Props) {\n  const initialX = (Math.random() - 0.5) * 40;\n  const initialY = (Math.random() - 0.5) * 40;\n  const initialRot = (Math.random() - 0.5) * 30;\n\n\n  const springX = useSpring(initialX, { stiffness: 100, damping: 15 });\n  const springY = useSpring(initialY, { stiffness: 100, damping: 15 });\n  const springRot = useSpring(initialRot, { stiffness: 100, damping: 15 });\n  const springOpacity = useSpring(0, { stiffness: 100, damping: 15 });\n  const springBlur = useSpring(4, { stiffness: 100, damping: 15 });\n\n  useEffect(() => {\n    const animateChar = async () => {\n\n      springX.set(initialX);\n      springY.set(initialY);\n      springRot.set(initialRot);\n      springOpacity.set(0);\n      springBlur.set(4);\n\n      await Promise.all([\n        springX.set(0),\n        springY.set(0),\n        springRot.set(0),\n        springOpacity.set(1),\n        springBlur.set(0),\n      ]);\n\n      let currentAmp = 1;\n      let currentPhase = (Math.random() * Math.PI * 2 + index * 0.4) % (Math.PI * 2);\n      let startTime: number | null = null;\n\n      const step = (t: number) => {\n        if (!startTime) startTime = t;\n        const elapsed = t - startTime;\n        const normalized = Math.min(1, elapsed / duration);\n\n        currentAmp *= decay + (1 - decay) * (1 - normalized);\n        currentPhase += 0.004 + index * 0.003; \n\n        const r = radius * currentAmp;\n        const newX = Math.sin(currentPhase) * r;\n        const newY = Math.cos(currentPhase * 0.9) * (r * 0.65);\n        const newRot = Math.sin(currentPhase * 0.7) * (currentAmp * 8);\n\n        springX.set(newX);\n        springY.set(newY);\n        springRot.set(newRot);\n        springOpacity.set(0.75 + 0.25 * (1 - currentAmp));\n        springBlur.set(currentAmp * 1.2);\n\n        if (normalized < 1 || currentAmp > 0.005) {\n          requestAnimationFrame(step);\n        } else {\n          // Settle perfectly\n          springX.set(0);\n          springY.set(0);\n          springRot.set(0);\n          springOpacity.set(1);\n          springBlur.set(0);\n        }\n      };\n      requestAnimationFrame(step);\n    };\n    animateChar();\n  }, [char, index, radius, duration, decay, initialX, initialY, initialRot, springX, springY, springRot, springOpacity, springBlur]);\n\n  return (\n    <motion.span\n      style={{\n        x: springX,\n        y: springY,\n        rotate: springRot,\n        opacity: springOpacity,\n        filter: useTransform(springBlur, (b) => `blur(${b}px)`),\n      }}\n      className=\"inline-block will-change-transform\"\n      onMouseEnter={() => {\n        springX.set((Math.random() - 0.5) * 40);\n        springY.set((Math.random() - 0.5) * 40);\n        springRot.set((Math.random() - 0.5) * 30);\n        springOpacity.set(0);\n        springBlur.set(4);\n      }}\n    >\n      {char === ' ' ? '\\u00A0' : char}\n    </motion.span>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/spectrumui/orbital-char.tsx"
    }
  ],
  "type": "registry:component"
}
