Metaballs: blobs that melt into each other
Round blobs that stretch, touch and merge like wax in a lava lamp. The simple math behind metaballs, a canvas starter you can run, and skills that build lava lamp and liquid chrome heroes.
Free skills to start. Pro is $79 a year for every skill, or $9.99 a month for 10. See pricing
What is a metaballs?
Metaballs are shapes defined by a field rather than an outline. Each ball gives off a strength that fades with distance, and wherever the summed strength is above a threshold, you draw solid color. Two balls far apart look like two circles; bring them close and their fields add up, so a bridge grows between them and they melt into one.
That gooey merge is the look of lava lamps, liquid metal, slime, mercury and soft brand blobs. It reads as organic and playful, and it loops well because the balls can travel on closed paths forever.
How the effect works
For each pixel, add up radius² ÷ distance² for every ball. A pixel exactly one radius away from a lone ball scores 1, so a threshold of 1 draws that ball as a circle of its own radius. Between two close balls both contribute, the sum passes 1 where neither alone would, and the gap fills in.
Coloring by how far the sum is above the threshold gives a hot core and a soft rim. In a shader the same sum runs for every pixel at once; on a 2D canvas you compute it at a low resolution and let the browser scale it up, which keeps it fast and adds a natural softness.
01
Move a few balls
Five to eight balls on sine paths with different speeds. Whole-number frequencies make the loop repeat.
02
Sum the field
Per pixel, total r² ÷ d² over all balls. This is the expensive step, so do it on a small grid or in a shader.
03
Threshold it
Above 1 is inside the goo, below is outside. Smooth the edge over a small range to avoid jaggies.
04
Shade by depth
Map how far over 1 a pixel is to a brighter core, or to a normal for lighting in 3D.
HTML
Metaballs on a 2D canvas
Six balls summed on a 160 × 90 grid and scaled up by CSS. Raise the grid size for sharper edges, or move the sum into a shader for full resolution.
<canvas id="goo" style="width:100%;aspect-ratio:16/9;background:#14081f"></canvas>
<script>
const canvas = document.getElementById('goo')
const W = 160, H = 90
canvas.width = W; canvas.height = H
const g = canvas.getContext('2d')
const img = g.createImageData(W, H)
const balls = Array.from({ length: 6 }, (_, i) => ({ r: 9 + i * 1.6, phase: i * 1.7, speed: 0.25 + i * 0.06 }))
const still = matchMedia('(prefers-reduced-motion: reduce)').matches
function frame(ms) {
const t = still ? 0 : ms / 1000
const pts = balls.map((b) => [
W / 2 + Math.cos(t * b.speed + b.phase) * W * 0.3,
H / 2 + Math.sin(t * b.speed * 1.3 + b.phase) * H * 0.3,
b.r * b.r,
])
for (let y = 0; y < H; y++) {
for (let x = 0; x < W; x++) {
let f = 0
for (const [bx, by, r2] of pts) f += r2 / ((x - bx) ** 2 + (y - by) ** 2 + 1)
const inside = Math.min(1, Math.max(0, (f - 0.9) * 5)) // soft edge from 0.9 to 1.1
const core = Math.min(1, Math.max(0, f - 1))
const i = (y * W + x) * 4
img.data[i] = 20 + inside * 235
img.data[i + 1] = 8 + inside * (90 + core * 120)
img.data[i + 2] = 31 + inside * 20
img.data[i + 3] = 255
}
}
g.putImageData(img, 0, 0)
if (!still) requestAnimationFrame(frame)
}
requestAnimationFrame(frame)
</script>A starting point written for this page, free to use in your own projects. The skills below build the finished version with checks, fallbacks and a recorded video.
What to get right on a real page
01
Count the cost
Pixels × balls is the work per frame. On a canvas, keep the grid small; for full resolution, move the sum into a WebGL fragment shader.
02
Close the loop
Give every ball a path that returns to its start at the same moment, or the loop jumps when a video restarts.
03
Keep blobs off the copy
Moving goo under text changes contrast every frame. Keep the blobs beside the headline or behind a calm area.
04
Show a frame when motion is off
Respect prefers-reduced-motion: show one finished frame instead of the loop. A visitor who turned motion off still gets the look.
Skills that build a metaballs
Two very different moods from the same math, each a finished hero with your copy, colors and a 1080p video.
- Lava Lamp HeroClaude CodeCodexCursor+3 more agents
Motion Heroes · Pro
Lava Lamp Hero
Animated WebGL hero · page + embed + 1080p video
A 1970s lava lamp beside your headline: blobs of wax rise from the warm pool, stretch, split off trailing drops, hang under the surface and sink back, lit from the bulb inside a tapered glass bottle on a brass base, with a warm halo and film grain.
Worth knowing: Warm and nostalgic by design; not for cool, minimal brands.
Needs: Node.js 18+, Chrome (or Chromium/Edge), and ffmpeg for the video
See what Lava Lamp Hero makes - Liquid Chrome HeroClaude CodeCodexCursor+3 more agents
Motion Heroes · Pro
Liquid Chrome Hero
Animated WebGL hero · page + embed + 1080p video
Liquid metal: droplets on looping paths melt into one slowly morphing shape with a ripple over its surface, reflecting a turning photo studio with a rim light in your brand color. Chrome, gold, rose gold or any tint.
Worth knowing: Devices without WebGL get a still picture.
Needs: Node.js 18+, Chrome (or Chromium/Edge), and ffmpeg for the video
See what Liquid Chrome Hero makes
Install
Build a metaballs with your agent
Each skill is a SKILL.md folder, so it installs the same way in Claude Code, Codex, Cursor and other agents. The example below uses Lava Lamp Hero; each skill page has its own prompt.
1. Paste the install prompt
Your agent runs the installer. The first time, it shows a sign-in link so you can approve it in the browser.
Install the "Lava Lamp Hero" skill from Lookbk (https://lookbk.dev/skills/lava-lamp-hero). 1. Run: curl -fsSL https://lookbk.dev/cli.js | node - add lava-lamp-hero 2. If it prints a sign-in link, show it to me. When I say I approved it, run the same command again. 3. When the install finishes, read the SKILL.md it installed and tell me what you need from me to make the first result.
Or run it in a terminal
curl -fsSL https://lookbk.dev/cli.js | node - add lava-lamp-hero2. Start a new session
Agents load skills when a session starts. The installer writes the folder where your agent looks:
- Claude Code
- ~/.claude/skills/lava-lamp-hero
- Codex
- ~/.agents/skills/lava-lamp-hero
- Cursor
- ~/.agents/skills/lava-lamp-hero
3. Ask for the result
Describe it in plain words, for example:
Build a Lava Lamp hero for Slow Glow, a lamp restoration studio: aubergine wall, magenta liquid, orange wax, brass base, headline 'Warm light, slow time.', and record a 12-second loop.
Another agent? Install a skill in any agent
FAQ
Questions
Still stuck? The guides cover installing, agents and licensing in more detail.
Read the guidesWhat are metaballs?
Blobs drawn from a field instead of an outline. Each ball adds a strength that fades with distance, and everything above a threshold is filled, so nearby balls merge smoothly into one shape.
Can I make metaballs in CSS?
There is a well-known trick: blur several circles with filter: blur() and then raise the contrast so the soft overlaps snap into solid shapes. It gives a gooey look but little control over color and lighting.
How do I make a lava lamp animation?
Metaballs moving mostly up and down, slowed at the top and bottom, with warm colors and a light from below. Lava Lamp Hero adds the glass bottle, halo, grain and a seamless loop.
Are metaballs heavy on performance?
The cost grows with pixels times balls. A shader handles full HD easily; a canvas version should run on a small grid and scale up.

