About
this is bouncing balls animation anyone can use this as their loader or represent thinking of modal or agent.
Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds loading-balls to your project and fits it to your theme.
Code
How loading-balls is used: the demo's code. The component's own source comes with a free account.
Usage.tsx
import { motion } from 'framer-motion';
const BouncingBallsLoader = () => {
// Animation variants for the bouncing balls
const ballVariants = {
initial: {
y: 60,
scaleX: 1.7,
scaleY: 0.25,
borderRadius: '50px 50px 25px 25px'
},
animate: {
y: [60, 20, 0],
scaleX: [1.7, 1, 1],
scaleY: [0.25, 1, 1],
borderRadius: ['50px 50px 25px 25px', '50%', '50%'],
transition: {
duration: 0.5,
ease: 'easeInOut',
repeat: Infinity,
repeatType: 'reverse'
}
}
};
// Animation variants for the shadows
const shadowVariants = {
initial: {
scaleX: 1.5,
opacity: 0.9
},
animate: {
scaleX: [1.5, 1, 0.2],
opacity: [0.9, 0.7, 0.4],
transition: {
duration: 0.5,
ease: 'easeInOut',
repeat: Infinity,
repeatType: 'reverse'
}
}
};
return (
<div className="relative w-52 h-20 z-10">
{/* Bouncing Balls */}
<motion.div
className="absolute w-5 h-5 bg-white rounded-full left-[15%] origin-center"
variants={ballVariants}
initial="initial"
animate="animate"
/>
<motion.div
className="absolute w-5 h-5 bg-white rounded-full left-[45%] origin-center"
variants={ballVariants}
initial="initial"
animate="animate"
transition={{ delay: 0.2 }}
/>
<motion.div
className="absolute w-5 h-5 bg-white rounded-full right-[15%] origin-center"
variants={ballVariants}
initial="initial"
animate="animate"
transition={{ delay: 0.3 }}
/>
{/* Shadows */}
<motion.div
className="absolute w-5 h-1 rounded-full bg-black bg-opacity-90 top-[62px] left-[15%] origin-center -z-10 blur-sm"
variants={shadowVariants}
initial="initial"
animate="animate"
/>
<motion.div
className="absolute w-5 h-1 rounded-full bg-black bg-opacity-90 top-[62px] left-[45%] origin-center -z-10 blur-sm"
variants={shadowVariants}
initial="initial"
animate="animate"
transition={{ delay: 0.2 }}
/>
<motion.div
className="absolute w-5 h-1 rounded-full bg-black bg-opacity-90 top-[62px] right-[15%] origin-center -z-10 blur-sm"
variants={shadowVariants}
initial="initial"
animate="animate"
transition={{ delay: 0.3 }}
/>
</div>
);
};
// Example usage with customizable props
const CustomizableBouncingBalls = ({
ballColor = 'bg-white',
shadowColor = 'bg-black',
size = 'medium',
speed = 0.5
}) => {
const sizeClasses = {
small: { wrapper: 'w-32 h-12', ball: 'w-3 h-3', shadow: 'w-3 h-0.5', shadowTop: 'top-[38px]' },
};
const currentSize = sizeClasses[size];
const ballVariants = {
initial: {
y: 60,
scaleX: 1.7,
scaleY: 0.25,
borderRadius: '50px 50px 25px 25px'
},
animate: {
y: [60, 20, 0],
scaleX: [1.7, 1, 1],
scaleY: [0.25, 1, 1],
borderRadius: ['50px 50px 25px 25px', '50%', '50%'],
transition: {
duration: speed,
ease: 'easeInOut',
repeat: Infinity,
repeatType: 'reverse'
}
}
};
const shadowVariants = {
initial: {
scaleX: 1.5,
opacity: 0.9
},
animate: {
scaleX: [1.5, 1, 0.2],
opacity: [0.9, 0.7, 0.4],
transition: {
duration: speed,
ease: 'easeInOut',
repeat: Infinity,
repeatType: 'reverse'
}
}
};
return (
<div className={`relative ${currentSize.wrapper} z-10`}>
{/* Bouncing Balls */}
<motion.div
className={`absolute ${currentSize.ball} ${ballColor} rounded-full left-[15%] origin-center`}
variants={ballVariants}
initial="initial"
animate="animate"
/>
<motion.div
className={`absolute ${currentSize.ball} ${ballColor} rounded-full left-[45%] origin-center`}
variants={ballVariants}
initial="initial"
animate="animate"
transition={{ delay: 0.2 }}
/>
<motion.div
className={`absolute ${currentSize.ball} ${ballColor} rounded-full right-[15%] origin-center`}
variants={ballVariants}
initial="initial"
animate="animate"
transition={{ delay: 0.3 }}
/>
{/* Shadows */}
<motion.div
className={`absolute ${currentSize.shadow} rounded-full ${shadowColor} bg-opacity-90 ${currentSize.shadowTop} left-[15%] origin-center -z-10 blur-sm`}
variants={shadowVariants}
initial="initial"
animate="animate"
/>
<motion.div
className={`absolute ${currentSize.shadow} rounded-full ${shadowColor} bg-opacity-90 ${currentSize.shadowTop} left-[45%] origin-center -z-10 blur-sm`}
variants={shadowVariants}
initial="initial"
animate="animate"
transition={{ delay: 0.2 }}
/>
<motion.div
className={`absolute ${currentSize.shadow} rounded-full ${shadowColor} bg-opacity-90 ${currentSize.shadowTop} right-[15%] origin-center -z-10 blur-sm`}
variants={shadowVariants}
initial="initial"
animate="animate"
transition={{ delay: 0.3 }}
/>
</div>
);
};
// Demo component showing different variations
export default function Demo() {
return (
<div className="h-screen w-full bg-white flex flex-col items-center justify-center gap-16 p-8">
<div className="text-center">
<CustomizableBouncingBalls
ballColor="bg-blue-500"
size="small"
speed={0.4}
/>
</div>
</div>
);
}







