{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "CircularText-TS-TW",
	"title": "CircularText",
	"description": "Layouts characters around a circle with optional rotation animation.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:component",
			"path": "CircularText/CircularText.tsx",
			"content": "import React, { useEffect } from 'react';\nimport { motion, useAnimation, useMotionValue, MotionValue, type Transition } from 'motion/react';\ninterface CircularTextProps {\n  text: string;\n  spinDuration?: number;\n  onHover?: 'slowDown' | 'speedUp' | 'pause' | 'goBonkers';\n  className?: string;\n}\n\nconst getRotationTransition = (duration: number, from: number, loop: boolean = true) => ({\n  from,\n  to: from + 360,\n  ease: 'linear' as const,\n  duration,\n  type: 'tween' as const,\n  repeat: loop ? Infinity : 0\n});\n\nconst getTransition = (duration: number, from: number) => ({\n  rotate: getRotationTransition(duration, from),\n  scale: {\n    type: 'spring' as const,\n    damping: 20,\n    stiffness: 300\n  }\n});\n\nconst CircularText: React.FC<CircularTextProps> = ({\n  text,\n  spinDuration = 20,\n  onHover = 'speedUp',\n  className = ''\n}) => {\n  const letters = Array.from(text);\n  const controls = useAnimation();\n  const rotation: MotionValue<number> = useMotionValue(0);\n\n  useEffect(() => {\n    const start = rotation.get();\n    controls.start({\n      rotate: start + 360,\n      scale: 1,\n      transition: getTransition(spinDuration, start)\n    });\n  }, [spinDuration, text, onHover, controls]);\n\n  const handleHoverStart = () => {\n    const start = rotation.get();\n\n    if (!onHover) return;\n\n    let transitionConfig: ReturnType<typeof getTransition> | Transition;\n    let scaleVal = 1;\n\n    switch (onHover) {\n      case 'slowDown':\n        transitionConfig = getTransition(spinDuration * 2, start);\n        break;\n      case 'speedUp':\n        transitionConfig = getTransition(spinDuration / 4, start);\n        break;\n      case 'pause':\n        transitionConfig = {\n          rotate: { type: 'spring', damping: 20, stiffness: 300 },\n          scale: { type: 'spring', damping: 20, stiffness: 300 }\n        };\n        break;\n      case 'goBonkers':\n        transitionConfig = getTransition(spinDuration / 20, start);\n        scaleVal = 0.8;\n        break;\n      default:\n        transitionConfig = getTransition(spinDuration, start);\n    }\n\n    controls.start({\n      rotate: start + 360,\n      scale: scaleVal,\n      transition: transitionConfig\n    });\n  };\n\n  const handleHoverEnd = () => {\n    const start = rotation.get();\n    controls.start({\n      rotate: start + 360,\n      scale: 1,\n      transition: getTransition(spinDuration, start)\n    });\n  };\n\n  return (\n    <motion.div\n      className={`m-0 mx-auto rounded-full w-[200px] h-[200px] relative font-black text-white text-center cursor-pointer origin-center ${className}`}\n      style={{ rotate: rotation }}\n      initial={{ rotate: 0 }}\n      animate={controls}\n      onMouseEnter={handleHoverStart}\n      onMouseLeave={handleHoverEnd}\n    >\n      {letters.map((letter, i) => {\n        const rotationDeg = (360 / letters.length) * i;\n        const factor = Math.PI / letters.length;\n        const x = factor * i;\n        const y = factor * i;\n        const transform = `rotateZ(${rotationDeg}deg) translate3d(${x}px, ${y}px, 0)`;\n\n        return (\n          <span\n            key={i}\n            className=\"absolute inline-block inset-0 text-2xl transition-all duration-500 ease-[cubic-bezier(0,0,0,1)]\"\n            style={{ transform, WebkitTransform: transform }}\n          >\n            {letter}\n          </span>\n        );\n      })}\n    </motion.div>\n  );\n};\n\nexport default CircularText;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"motion@^12.23.12"
	]
}