Kinetic Dots

Playful bouncing dots with squash-and-stretch deformation and expanding ripple effects. Use for engaging loading states, chat typing indicators, or anywhere a lively, energetic loader fits.

Generated using Grepped's AI UI component generator — created from scratch, not pulled from a library.

dotsbouncingloadersquash-stretchripple

Live Preview — customize or regenerate this in the workspace

Loading preview…

Design Intent

Playful bouncing dots with squash, stretch, and ripple effects for engaging loading states.

CSS

css
body { margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #0f0f0f; }
    .wrap { display: flex; gap: 1.25rem; }
    .col { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 5rem; width: 1.5rem; }
    .ball { position: relative; width: 1.25rem; height: 1.25rem; z-index: 10; }
    .ball-inner {
      width: 100%; height: 100%; border-radius: 9999px;
      background: linear-gradient(to bottom, #67e8f9, #2563eb);
      box-shadow: 0 0 15px rgba(6,182,212,0.6);
    }
    .ball-hl { position: absolute; top: 0.25rem; left: 0.25rem; width: 0.375rem; height: 0.375rem; background: rgba(255,255,255,0.6); border-radius: 9999px; filter: blur(0.5px); }
    .ripple { position: absolute; bottom: 0; width: 2.5rem; height: 0.75rem; border: 1px solid rgba(6,182,212,0.3); border-radius: 100%; opacity: 0; }
    .shadow { position: absolute; bottom: -0.25rem; width: 1.25rem; height: 0.375rem; border-radius: 100%; background: rgba(6,182,212,0.4); filter: blur(4px); }
    @keyframes gravity-bounce {
      0% { transform: translateY(0); animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1); }
      50% { transform: translateY(-40px); animation-timing-function: cubic-bezier(0.32, 0, 0.67, 0); }
      100% { transform: translateY(0); }
    }
    @keyframes rubber-morph {
      0% { transform: scale(1.4, 0.6); }
      5% { transform: scale(0.9, 1.1); }
      15% { transform: scale(1, 1); }
      50% { transform: scale(1, 1); }
      85% { transform: scale(0.9, 1.1); }
      100% { transform: scale(1.4, 0.6); }
    }
    @keyframes shadow-breathe {
      0% { transform: scale(1.4); opacity: 0.6; }
      50% { transform: scale(0.5); opacity: 0.1; }
      100% { transform: scale(1.4); opacity: 0.6; }
    }
    @keyframes ripple-expand {
      0% { transform: scale(0.5); opacity: 0; border-width: 4px; }
      5% { opacity: 0.8; }
      30% { transform: scale(1.5); opacity: 0; border-width: 0; }
      100% { transform: scale(1.5); opacity: 0; }
    }

HTML

html
<div class="wrap">
    <div class="col"><div class="ball" style="animation: gravity-bounce 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0s;"><div class="ball-inner" style="animation: rubber-morph 1.4s linear infinite; animation-delay: 0s;"></div><div class="ball-hl"></div></div><div class="ripple" style="animation: ripple-expand 1.4s linear infinite; animation-delay: 0s;"></div><div class="shadow" style="animation: shadow-breathe 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0s;"></div></div>
    <div class="col"><div class="ball" style="animation: gravity-bounce 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.15s;"><div class="ball-inner" style="animation: rubber-morph 1.4s linear infinite; animation-delay: 0.15s;"></div><div class="ball-hl"></div></div><div class="ripple" style="animation: ripple-expand 1.4s linear infinite; animation-delay: 0.15s;"></div><div class="shadow" style="animation: shadow-breathe 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.15s;"></div></div>
    <div class="col"><div class="ball" style="animation: gravity-bounce 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.3s;"><div class="ball-inner" style="animation: rubber-morph 1.4s linear infinite; animation-delay: 0.3s;"></div><div class="ball-hl"></div></div><div class="ripple" style="animation: ripple-expand 1.4s linear infinite; animation-delay: 0.3s;"></div><div class="shadow" style="animation: shadow-breathe 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.3s;"></div></div>
    <div class="col"><div class="ball" style="animation: gravity-bounce 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.44999999999999996s;"><div class="ball-inner" style="animation: rubber-morph 1.4s linear infinite; animation-delay: 0.44999999999999996s;"></div><div class="ball-hl"></div></div><div class="ripple" style="animation: ripple-expand 1.4s linear infinite; animation-delay: 0.44999999999999996s;"></div><div class="shadow" style="animation: shadow-breathe 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.44999999999999996s;"></div></div>
  </div>

Full Source

html
<!DOCTYPE html>
<html>
<head>
  <style>
    body { margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #0f0f0f; }
    .wrap { display: flex; gap: 1.25rem; }
    .col { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 5rem; width: 1.5rem; }
    .ball { position: relative; width: 1.25rem; height: 1.25rem; z-index: 10; }
    .ball-inner {
      width: 100%; height: 100%; border-radius: 9999px;
      background: linear-gradient(to bottom, #67e8f9, #2563eb);
      box-shadow: 0 0 15px rgba(6,182,212,0.6);
    }
    .ball-hl { position: absolute; top: 0.25rem; left: 0.25rem; width: 0.375rem; height: 0.375rem; background: rgba(255,255,255,0.6); border-radius: 9999px; filter: blur(0.5px); }
    .ripple { position: absolute; bottom: 0; width: 2.5rem; height: 0.75rem; border: 1px solid rgba(6,182,212,0.3); border-radius: 100%; opacity: 0; }
    .shadow { position: absolute; bottom: -0.25rem; width: 1.25rem; height: 0.375rem; border-radius: 100%; background: rgba(6,182,212,0.4); filter: blur(4px); }
    @keyframes gravity-bounce {
      0% { transform: translateY(0); animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1); }
      50% { transform: translateY(-40px); animation-timing-function: cubic-bezier(0.32, 0, 0.67, 0); }
      100% { transform: translateY(0); }
    }
    @keyframes rubber-morph {
      0% { transform: scale(1.4, 0.6); }
      5% { transform: scale(0.9, 1.1); }
      15% { transform: scale(1, 1); }
      50% { transform: scale(1, 1); }
      85% { transform: scale(0.9, 1.1); }
      100% { transform: scale(1.4, 0.6); }
    }
    @keyframes shadow-breathe {
      0% { transform: scale(1.4); opacity: 0.6; }
      50% { transform: scale(0.5); opacity: 0.1; }
      100% { transform: scale(1.4); opacity: 0.6; }
    }
    @keyframes ripple-expand {
      0% { transform: scale(0.5); opacity: 0; border-width: 4px; }
      5% { opacity: 0.8; }
      30% { transform: scale(1.5); opacity: 0; border-width: 0; }
      100% { transform: scale(1.5); opacity: 0; }
    }
  </style>
</head>
<body>
  <div class="wrap">
    <div class="col"><div class="ball" style="animation: gravity-bounce 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0s;"><div class="ball-inner" style="animation: rubber-morph 1.4s linear infinite; animation-delay: 0s;"></div><div class="ball-hl"></div></div><div class="ripple" style="animation: ripple-expand 1.4s linear infinite; animation-delay: 0s;"></div><div class="shadow" style="animation: shadow-breathe 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0s;"></div></div>
    <div class="col"><div class="ball" style="animation: gravity-bounce 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.15s;"><div class="ball-inner" style="animation: rubber-morph 1.4s linear infinite; animation-delay: 0.15s;"></div><div class="ball-hl"></div></div><div class="ripple" style="animation: ripple-expand 1.4s linear infinite; animation-delay: 0.15s;"></div><div class="shadow" style="animation: shadow-breathe 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.15s;"></div></div>
    <div class="col"><div class="ball" style="animation: gravity-bounce 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.3s;"><div class="ball-inner" style="animation: rubber-morph 1.4s linear infinite; animation-delay: 0.3s;"></div><div class="ball-hl"></div></div><div class="ripple" style="animation: ripple-expand 1.4s linear infinite; animation-delay: 0.3s;"></div><div class="shadow" style="animation: shadow-breathe 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.3s;"></div></div>
    <div class="col"><div class="ball" style="animation: gravity-bounce 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.44999999999999996s;"><div class="ball-inner" style="animation: rubber-morph 1.4s linear infinite; animation-delay: 0.44999999999999996s;"></div><div class="ball-hl"></div></div><div class="ripple" style="animation: ripple-expand 1.4s linear infinite; animation-delay: 0.44999999999999996s;"></div><div class="shadow" style="animation: shadow-breathe 1.4s cubic-bezier(0.45,0.05,0.55,0.95) infinite; animation-delay: 0.44999999999999996s;"></div></div>
  </div>
</body>
</html>

More Popular Animations