{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "circle-path",
  "type": "registry:component",
  "title": "Circle Path",
  "author": "Toby Belhome",
  "description": "Animated display of objects or images placed at regular intervals along a circular path. You can use this in integration sections, on pages that list your brands, or within bento grids. Built with Tailwind CSS, Framer Motion, and React.",
  "dependencies": [
    "framer-motion"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "examples/motion/animations/circle-path/01/page.tsx",
      "content": "\"use client\";\n\nimport { motion, animate } from \"framer-motion\";\nimport { useEffect, useState } from \"react\";\n\nconst images = [\n  {\n    id: 1,\n    url: \"https://images.pexels.com/photos/1144176/pexels-photo-1144176.jpeg?auto=compress&cs=tinysrgb&w=400\"\n  },\n  {\n    id: 2,\n    url: \"https://images.pexels.com/photos/1276518/pexels-photo-1276518.jpeg?auto=compress&cs=tinysrgb&w=400\"\n  },\n  {\n    id: 3,\n    url: \"https://images.pexels.com/photos/1591373/pexels-photo-1591373.jpeg?auto=compress&cs=tinysrgb&w=400\"\n  },\n  {\n    id: 4,\n    url: \"https://images.pexels.com/photos/1542252/pexels-photo-1542252.jpeg?auto=compress&cs=tinysrgb&w=400\"\n  },\n  {\n    id: 5,\n    url: \"https://images.pexels.com/photos/1858175/pexels-photo-1858175.jpeg?auto=compress&cs=tinysrgb&w=400\"\n  },\n  {\n    id: 6,\n    url: \"https://images.pexels.com/photos/1239291/pexels-photo-1239291.jpeg?auto=compress&cs=tinysrgb&w=400\"\n  },\n  {\n    id: 7,\n    url: \"https://images.pexels.com/photos/1640777/pexels-photo-1640777.jpeg?auto=compress&cs=tinysrgb&w=400\"\n  },\n  {\n    id: 8,\n    url: \"https://images.pexels.com/photos/1059078/pexels-photo-1059078.jpeg?auto=compress&cs=tinysrgb&w=400\"\n  },\n  {\n    id: 9,\n    url: \"https://images.pexels.com/photos/1402787/pexels-photo-1402787.jpeg?auto=compress&cs=tinysrgb&w=400\"\n  }\n];\n\nexport default function CirclePath() {\n  const radius = 42;\n  const [rotation, setRotation] = useState(0);\n  const [isPaused, setIsPaused] = useState(false);\n\n  useEffect(() => {\n    const controls = animate(rotation, -360, {\n      duration: 10,\n      repeat: Infinity,\n      ease: \"linear\"\n    });\n    return controls.stop;\n  }, [rotation]);\n\n  return (\n    <div className=\"aspect-square w-full max-w-md\">\n      <div\n        className=\"relative h-full w-full\"\n        onMouseEnter={() => setIsPaused(true)}\n        onMouseLeave={() => setIsPaused(false)}>\n        <motion.div\n          animate={{ rotate: isPaused ? rotation : -360 }}\n          transition={{\n            duration: isPaused ? 0 : 60,\n            ease: \"linear\",\n            repeat: isPaused ? 0 : Infinity\n          }}\n          onUpdate={(latest) => {\n            if (!isPaused && typeof latest.rotate === \"number\") {\n              setRotation(latest.rotate % 360);\n            }\n          }}\n          className=\"absolute inset-0\">\n          {images.map((image, index) => {\n            const angle = (index * -360) / images.length;\n            const x = radius * Math.cos((angle * Math.PI) / 180);\n            const y = radius * Math.sin((angle * Math.PI) / 180);\n\n            return (\n              <motion.div\n                key={image.id}\n                className=\"absolute size-20\"\n                style={{\n                  left: `calc(50% + ${x}%)`,\n                  top: `calc(50% + ${y}%)`,\n                  x: \"-50%\",\n                  y: \"-50%\"\n                }}\n                initial={{ scale: 0, opacity: 0 }}\n                animate={{ scale: 1, opacity: 1 }}\n                transition={{\n                  delay: index * 0.1,\n                  duration: 0.5,\n                  type: \"spring\",\n                  stiffness: 260,\n                  damping: 20\n                }}\n                whileHover={{\n                  scale: 1.15,\n                  zIndex: 10,\n                  transition: { duration: 0.2 }\n                }}\n                whileTap={{ scale: 0.95 }}>\n                <motion.div\n                  animate={{ rotate: -rotation }}\n                  transition={{ duration: 0 }}\n                  className=\"h-full w-full\">\n                  <img\n                    src={image.url}\n                    alt={`Image ${image.id}`}\n                    className=\"h-full w-full cursor-pointer rounded-full object-cover\"\n                    loading=\"lazy\"\n                  />\n                </motion.div>\n              </motion.div>\n            );\n          })}\n        </motion.div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/circle-path.tsx"
    }
  ],
  "meta": {
    "isPro": false
  }
}