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>