{
  "name": "ball-bounce-alternate-default",
  "type": "registry:ui",
  "tier": "free",
  "dependencies": [
    "framer-motion"
  ],
  "registryDependencies": [
    "https://www.craftui.space/r/craftui-base.json"
  ],
  "files": [
    {
      "path": "components/craftui/loaders/ball-bounce-alternate/default.tsx",
      "content": "'use client';\n\nimport { useEffect } from 'react';\nimport { motion, useAnimation } from 'motion/react';\n\ninterface BallBounceAlternateProps {\n  width?: number;\n  height?: number;\n  color?: string;\n  lineColor?: string;\n  isAnimating?: boolean;\n  duration?: number;\n  ease?: any;\n  strokeWidth?: number;\n}\n\nexport function BallBounceAlternate({\n  width = 90,\n  height = 45,\n  color = \"currentColor\",\n  lineColor = \"currentColor\",\n  isAnimating = true,\n  duration = 2.0,\n  ease = 'linear',\n  strokeWidth = 3,\n}: BallBounceAlternateProps) {\n  const ballRadius = height * 0.15;\n  const ballCY = height - ballRadius - 1.5;\n\n  const controls = useAnimation();\n\n  useEffect(() => {\n    if (isAnimating) {\n      // x and y have different durations — animate them independently via separate sequences\n      // We use a combined animate call; motion handles each property's transition separately\n      controls.start({\n        x: [-width * 5, width * 5],\n        transition: {\n          duration,\n          repeat: Infinity,\n          repeatType: 'reverse',\n          ease,\n        },\n      });\n    } else {\n      controls.stop();\n      controls.set({ x: 0, y: 0 });\n    }\n  }, [isAnimating, duration, ease, width, height, controls]);\n\n  const controlsY = useAnimation();\n\n  useEffect(() => {\n    if (isAnimating) {\n      controlsY.start({\n        y: [0, -height * 0.15, 0],\n        transition: {\n          duration: duration * 0.25,\n          repeat: Infinity,\n          times: [0, 0.08, 1],\n          ease: [0.455, 0.03, 0.515, 0.955],\n        },\n      });\n    } else {\n      controlsY.stop();\n      controlsY.set({ y: 0 });\n    }\n  }, [isAnimating, duration, height, controlsY]);\n\n  return (\n    <svg\n      width={width}\n      height={height}\n      viewBox={`0 0 ${width} ${height}`}\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      aria-label=\"Loading\"\n      role=\"img\"\n      style={{ overflow: 'hidden' }}\n    >\n      <line\n        x1={0}\n        y1={height - 1.5}\n        x2={width}\n        y2={height - 1.5}\n        stroke={lineColor}\n        strokeWidth={strokeWidth}\n      />\n      {/* Outer motion element handles x translation */}\n      <motion.g animate={controls}>\n        {/* Inner motion element handles y (bounce) */}\n        <motion.circle\n          cx={width * 0.425}\n          cy={ballCY}\n          r={ballRadius}\n          fill={color}\n          animate={controlsY}\n        />\n      </motion.g>\n    </svg>\n  );\n}\n",
      "type": "registry:ui",
      "target": "~/components/craftui/loaders/ball-bounce-alternate/default.tsx"
    }
  ],
  "meta": {
    "displayName": "Ball Bounce Alternate - Ball Bounce Alternate",
    "description": "A ball slides left to right then reverses direction, bouncing on the ground line creating a pendulum-like motion",
    "category": "loaders",
    "tags": [
      "bounce",
      "slide",
      "ball",
      "simple",
      "alternating",
      "linear",
      "horizontal"
    ],
    "animationType": "loop"
  }
}