Components
this is bouncing balls animation anyone can use this as their loader or represent thinking of modal or agent.
Loading preview...
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>
);
}