Nick

loading-balls

Component

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>
  );
}

More by Nick

View all
  • Gallery Animation

    Gallery Animation

    1K
  • MacOS dock

    MacOS dock

    202
  • 3d-card

    3d-card

    167
  • Hero-Section

    Hero-Section

    115
  • Ripple-Button

    Ripple-Button

    75
  • download-animation

    download-animation

    75
  • Animated-card

    Animated-card

    53
  • text-animation

    text-animation

    40