Liquid & Morphing
Liquid effects, metaballs, morphing and shape-shifting.
Updated
How do you create liquid, blob and metaball effects?
Liquid effects make shapes flow, merge and split like a fluid. Metaballs are usually made with an SVG filter, a Gaussian blur followed by a high-contrast colour matrix (the “goo” technique); blobs morph by animating border-radius or SVG paths, and water ripples use canvas or WebGL.
How to choose, performance and accessibility
- Use Blob Morph or Fluid Gradient as a soft decorative accent, Liquid Button for a playful call to action, and Metaballs or Lava Lamp for an eye-catching hero.
- SVG filters are costly on large areas, so keep them to small zones, pause animations that are off screen, and show a static shape for
prefers-reduced-motion. - Metaballs, Blob Morph, AI Shape Morph, AI Color Shift, Generative Glitch and AI Typo Morph are free with their code; the other liquid effects come with Premium.
Metaballs
Organic blobs that merge together with a surface tension effect.
View source code
<div class="demo-preview">
<div class="metaballs-container">
<canvas id="metaballs-canvas"></canvas>
</div>
</div>.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
box-sizing: border-box
}
.demo-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.metaballs-container {
width: 100%;
height: 100%;
position: relative;
}
#metaballs-canvas {
width: 100%;
height: 100%;
}(function() {
// ============================================
// 1. METABALLS - Canvas Implementation
// ============================================
(function() {
const canvas = document.getElementById('metaballs-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const container = canvas.parentElement;
function resize() {
canvas.width = container.offsetWidth;
canvas.height = container.offsetHeight;
}
resize();
window.addEventListener('resize', resize);
const balls = [];
const numBalls = 6;
for (let i = 0; i < numBalls; i++) {
balls.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * 2,
vy: (Math.random() - 0.5) * 2,
radius: 30 + Math.random() * 40
});
}
function drawMetaballs() {
const imageData = ctx.createImageData(canvas.width, canvas.height);
const data = imageData.data;
for (let x = 0; x < canvas.width; x++) {
for (let y = 0; y < canvas.height; y++) {
let sum = 0;
for (const ball of balls) {
const dx = x - ball.x;
const dy = y - ball.y;
const dist = Math.sqrt(dx * dx + dy * dy);
sum += (ball.radius * ball.radius) / (dist * dist + 1);
}
const idx = (y * canvas.width + x) * 4;
if (sum > 1) {
const intensity = Math.min(sum - 1, 1);
data[idx] = 99 + intensity * 50; // R
data[idx + 1] = 102 + intensity * 50; // G
data[idx + 2] = 241; // B
data[idx + 3] = 255; // A
} else {
data[idx] = 26;
data[idx + 1] = 26;
data[idx + 2] = 36;
data[idx + 3] = 255;
}
}
}
ctx.putImageData(imageData, 0, 0);
}
function updateBalls() {
for (const ball of balls) {
ball.x += ball.vx;
ball.y += ball.vy;
if (ball.x < ball.radius || ball.x > canvas.width - ball.radius) {
ball.vx *= -1;
}
if (ball.y < ball.radius || ball.y > canvas.height - ball.radius) {
ball.vy *= -1;
}
}
}
function animate() {
updateBalls();
drawMetaballs();
requestAnimationFrame(animate);
}
animate();
})();
})();Water Ripple
Realistic ripple effect simulated with wave propagation.
Liquid Button
Button with animated liquid fill effect on hover.
Dripping Text
Text with a dripping effect that falls continuously.
Bubble Rise
Translucent bubbles rising with organic movements.
Lava Lamp
Floating lava lamp-style blobs with organic deformations.
Mercury Drops
Metallic drops with realistic reflections and elastic bounces.
Wave Surface
Animated water surface with multiple wave layers.
Splash Effect
Interactive splash effect with particles and droplets.
Fluid Gradient
Animated gradient that flows like liquid with organic motion.
WebGL Fluid Simulation
Neon ink flows under the cursor, swirls and fades; a click bursts a fresh colour. With no interaction, the motion carries on by itself.
💡 Perfect for: landing-page heroes, agency homepages, playful 404 pages.
Blob Morph
Organic shape that continuously morphs between different fluid silhouettes via border-radius animation.
View source code
<div class="demo-preview">
<div class="blob-morph">BLOB</div>
</div>.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
box-sizing: border-box
}
.demo-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.blob-morph {
width: 180px;
height: 180px;
background: linear-gradient(135deg, #a855f7, #ec4899);
animation: blobMorph 8s ease-in-out infinite;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 1rem;
color: white;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
box-shadow:
0 0 40px rgba(168, 85, 247, 0.4),
0 0 80px rgba(236, 72, 153, 0.2);
transition: transform 0.3s ease;
}
.blob-morph:hover {
transform: scale(1.08);
}
@keyframes blobMorph {
0% {
border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
}
14% {
border-radius: 40% 60% 70% 30% / 50% 60% 40% 50%;
}
28% {
border-radius: 70% 30% 50% 50% / 30% 50% 60% 70%;
}
42% {
border-radius: 30% 60% 70% 40% / 50% 30% 70% 60%;
}
56% {
border-radius: 50% 50% 30% 70% / 70% 40% 60% 30%;
}
70% {
border-radius: 40% 70% 60% 30% / 40% 60% 30% 70%;
}
84% {
border-radius: 70% 40% 40% 60% / 60% 50% 50% 40%;
}
100% {
border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
}
}/* Pure CSS — no JavaScript required */Icon Morph
Hamburger icon that transforms into a close cross with smooth CSS transitions on click.
Shape Shifter
Shape that cycles between circle, square, triangle, hexagon and star using clip-path transitions.
Button Morph
Button that morphs into a loading spinner, then into a validation checkmark on click.
Text Morph
Text that morphs between multiple words with blur and opacity for a smooth transition.
Card Morph
Compact card that expands and transforms into a detailed panel on click with smooth transitions.
SVG Path Morph
SVG shape that morphs between star, heart and circle by animating the path attribute.
Liquid Morph
Liquid drops that merge and separate using the CSS filter blur + contrast trick for an organic effect.
Avatar Morph
Circular avatar that transforms into a rectangular card with user information on hover.
Toggle Morph
Toggle switch whose knob changes shape while sliding: the circle deforms into a pill before returning to its initial shape.
AI & Intelligence
AI Shape Morph
SVG shapes that smoothly interpolate between different silhouettes with organic transitions.
View source code
<div class="demo-preview">
<div class="ai-shape-morph-container">
<canvas id="ai-shape-canvas"></canvas>
</div>
</div>.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
box-sizing: border-box
}
.demo-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.ai-shape-morph-container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.ai-shape-morph-container canvas {
width: 100%;
height: 100%;
}(function() {
// ============================================
// AI & Intelligence Effects
// ============================================
// 1. AI Shape Morph
(function() {
const canvas = document.getElementById('ai-shape-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const container = canvas.parentElement;
function resize() {
canvas.width = container.offsetWidth;
canvas.height = container.offsetHeight;
}
resize();
const shapes = [
// Circle points
Array.from({
length: 12
}, (_, i) => {
const a = (i / 12) * Math.PI * 2;
return {
x: Math.cos(a) * 0.35,
y: Math.sin(a) * 0.35
};
}),
// Star points
Array.from({
length: 12
}, (_, i) => {
const a = (i / 12) * Math.PI * 2;
const r = i % 2 === 0 ? 0.4 : 0.2;
return {
x: Math.cos(a) * r,
y: Math.sin(a) * r
};
}),
// Square points
Array.from({
length: 12
}, (_, i) => {
const t = i / 12;
const side = Math.floor(t * 4);
const p = (t * 4) % 1;
const coords = [{
x: -0.3 + p * 0.6,
y: -0.3
},
{
x: 0.3,
y: -0.3 + p * 0.6
},
{
x: 0.3 - p * 0.6,
y: 0.3
},
{
x: -0.3,
y: 0.3 - p * 0.6
}
];
return coords[side];
})
];
let currentShape = 0;
let progress = 0;
let morphPoints = shapes[0].map(p => ({
...p
}));
function animate() {
progress += 0.008;
if (progress >= 1) {
progress = 0;
currentShape = (currentShape + 1) % shapes.length;
}
const nextShape = (currentShape + 1) % shapes.length;
const eased = 0.5 - 0.5 * Math.cos(progress * Math.PI);
for (let i = 0; i < morphPoints.length; i++) {
morphPoints[i].x = shapes[currentShape][i].x + (shapes[nextShape][i].x - shapes[currentShape][i].x) * eased;
morphPoints[i].y = shapes[currentShape][i].y + (shapes[nextShape][i].y - shapes[currentShape][i].y) * eased;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
const cx = canvas.width / 2;
const cy = canvas.height / 2;
const scale = Math.min(canvas.width, canvas.height);
const gradient = ctx.createLinearGradient(cx - 80, cy - 80, cx + 80, cy + 80);
gradient.addColorStop(0, '#6366f1');
gradient.addColorStop(0.5, '#a855f7');
gradient.addColorStop(1, '#ec4899');
ctx.beginPath();
ctx.moveTo(cx + morphPoints[0].x * scale, cy + morphPoints[0].y * scale);
for (let i = 1; i < morphPoints.length; i++) {
const prev = morphPoints[i - 1];
const curr = morphPoints[i];
const cpx = cx + (prev.x + curr.x) / 2 * scale;
const cpy = cy + (prev.y + curr.y) / 2 * scale;
ctx.quadraticCurveTo(cx + prev.x * scale, cy + prev.y * scale, cpx, cpy);
}
ctx.closePath();
ctx.fillStyle = gradient;
ctx.fill();
requestAnimationFrame(animate);
}
animate();
window.addEventListener('resize', resize);
})();
})();Generative Flow Field
Perlin noise-generated flow field with particles following force lines.
Neural Net Viz
Animated neuron graph with pulsating connections and dynamic activations.
AI Color Shift
Dynamically generated color palette in OKLCH with fluid transitions between harmonies.
View source code
<div class="demo-preview">
<div class="ai-color-shift" id="aiColorShift">
<div class="ai-color-swatch"></div>
<div class="ai-color-swatch"></div>
<div class="ai-color-swatch"></div>
<div class="ai-color-swatch"></div>
<div class="ai-color-swatch"></div>
</div>
</div>.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
box-sizing: border-box
}
.demo-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.ai-color-shift {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 8px;
padding: 20px;
}
.ai-color-swatch {
border-radius: 12px;
transition: background 1.5s ease;
}(function() {
// 4. AI Color Shift
(function() {
const container = document.getElementById('aiColorShift');
if (!container) return;
const swatches = container.querySelectorAll('.ai-color-swatch');
let hueBase = 0;
function updateColors() {
hueBase = (hueBase + 0.3) % 360;
swatches.forEach((swatch, i) => {
const hue = (hueBase + i * 72) % 360;
const lightness = 50 + Math.sin(hueBase * 0.02 + i) * 15;
swatch.style.background = `oklch(${lightness}% 0.2 ${hue})`;
});
requestAnimationFrame(updateColors);
}
updateColors();
})();
})();Swarm Intelligence
Swarm particles with emergent behavior: cohesion, separation and alignment.
Generative Glitch
Generative glitch art with random slicing and animated chromatic effects.
View source code
<div class="demo-preview">
<div class="ai-glitch-container">
<span class="ai-glitch-text" data-text="GLITCH">GLITCH</span>
</div>
</div>.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
box-sizing: border-box
}
.demo-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.ai-glitch-container {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: #111;
}
.ai-glitch-text {
font-size: 2.5rem;
font-weight: 800;
color: #fff;
position: relative;
}
.ai-glitch-text::before,
.ai-glitch-text::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.ai-glitch-text::before {
animation: aiGlitch1 2s infinite linear alternate-reverse;
clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%);
color: #0ff;
}
.ai-glitch-text::after {
animation: aiGlitch2 3s infinite linear alternate-reverse;
clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%);
color: #f0f;
}
@keyframes aiGlitch1 {
0% {
transform: translate(0);
}
20% {
transform: translate(-3px, 2px);
}
40% {
transform: translate(3px, -1px);
}
60% {
transform: translate(-2px, -2px);
}
80% {
transform: translate(2px, 1px);
}
100% {
transform: translate(0);
}
}
@keyframes aiGlitch2 {
0% {
transform: translate(0);
}
25% {
transform: translate(2px, -2px);
}
50% {
transform: translate(-3px, 1px);
}
75% {
transform: translate(1px, 2px);
}
100% {
transform: translate(0);
}
}/* Pure CSS — no JavaScript required */Predictive Grid Morph
Interactive grid that deforms on hover with mouse trajectory prediction.
Deep Dream Pattern
Animated fractal patterns inspired by deep dream with self-similar motifs in motion.
AI Typo Morph
Letters that fluidly transform between different words with a typographic morphing effect.
View source code
<div class="demo-preview">
<div class="ai-typo-morph">
<div class="ai-typo-word" id="aiTypoWord"></div>
</div>
</div>.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
box-sizing: border-box
}
.demo-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 250px;
overflow: hidden;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.ai-typo-morph {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.ai-typo-word {
font-size: 2.5rem;
font-weight: 800;
background: linear-gradient(135deg, #6366f1, #a855f7, #ec4899);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: 2px;
}(function() {
// 9. AI Typo Morph
(function() {
const wordEl = document.getElementById('aiTypoWord');
if (!wordEl) return;
const words = ['DESIGN', 'CREATE', 'MORPH', 'DREAM', 'BUILD'];
let currentWord = 0;
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$%';
function morphTo(target) {
const current = wordEl.textContent || '';
const maxLen = Math.max(current.length, target.length);
let iterations = 0;
const interval = setInterval(() => {
let result = '';
for (let i = 0; i < maxLen; i++) {
if (i < target.length) {
if (iterations > i * 2) {
result += target[i];
} else {
result += chars[Math.floor(Math.random() * chars.length)];
}
}
}
wordEl.textContent = result;
iterations++;
if (iterations > maxLen * 2 + 5) {
clearInterval(interval);
wordEl.textContent = target;
}
}, 50);
}
wordEl.textContent = words[0];
var typoInterval = setInterval(() => {
currentWord = (currentWord + 1) % words.length;
morphTo(words[currentWord]);
}, 3000);
})();
})();Mesh Distortion AI
Deformable mesh gradient with mouse interactions and reactive organic deformations.