webdevpuneet.com

Canvas Metaball Blobs — Free Organic Merging Blob Field Snippet

Canvas Metaball Blobs · Animations · Plain HTML, CSS & JS · Live preview

CategoryAnimations

Copy & paste

Source Code

<div class="mb-wrap">
  <canvas id="mbCanvas" class="mb-canvas"></canvas>
  <p class="mb-hint">Move your cursor over the blobs — they merge and split with a wet, organic pull.</p>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

True scalar field metaballs
Inverse-square influence summed per sample point, not layered circles.
Threshold-based fusion
Nearby blobs visually merge once their combined field crosses 1.0.
Coarse-grid sampling
A performance/quality trade-off that keeps 60fps on a full canvas.
Glowing edge band
Field values just above threshold brighten toward the blob rim.
Cursor attraction
Blobs within 220px are gently pulled toward the pointer.
Edge-bounce physics
Blobs bounce off canvas boundaries with velocity damping.
Touch-friendly
Responds to touchmove alongside mousemove.
DPR-aware rendering
Sharp field rendering on high-density displays.

About this UI Snippet

Canvas Metaball Blobs — A Scalar Field Rendered Pixel by Pixel

Screenshot of the Canvas Metaball Blobs snippet rendered live

Metaballs are a classic technique for organic, liquid-looking shapes: instead of drawing each blob as an independent circle, every blob contributes an influence value to a shared scalar field, and the final shape is wherever that combined field crosses a threshold. This snippet implements that from scratch against ImageData, with no WebGL and no shader.

Inverse-square influence, summed per sample point

For every point on a coarse sampling grid, render() sums each ball's contribution as radius^2 / distance^2 — an inverse-square falloff, the same shape used for gravitational and electrostatic fields. A point close to one ball has a huge value from that ball alone; a point roughly equidistant between two nearby balls gets meaningful contributions from both, which is exactly what causes their fields to visually fuse into a single connected shape as they approach each other.

A grid, not per-pixel, for performance

Sampling every single device pixel with a per-ball inverse-square calculation would be far too slow at 60fps. Instead the field is computed on a coarse grid (cell px per sample) and each grid cell is filled as a small flat-colored block in ImageData — a deliberate resolution trade-off that keeps the blob edges looking soft rather than pixelated, without paying per-pixel field-evaluation cost.

Threshold and edge glow

A field value below 1.0 is treated as empty space and skipped entirely. Just above threshold, edge ramps from 0 to 1 over a narrow band, brightening the color near a blob's boundary — this soft threshold band is what gives the merged shapes a glowing, liquid rim instead of a flat silhouette.

Cursor as a soft attractor

Rather than the cursor pushing blobs away, updateBalls() nudges each ball's velocity toward the pointer when it's within 220px, with the pull strength independent of distance beyond normalizing the direction vector — a gentle, constant tug rather than an inverse-square force, which reads as playful rather than physically simulated.

Compare with canvas fluid cursor trail, which uses additive-blended gradients for a different kind of organic look without a scalar field.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSSeven drifting blobs render and begin merging and separating.
  2. 2
    Move the cursor over the canvasNearby blobs are gently pulled toward the pointer.
  3. 3
    Watch blobs approach each otherTheir fields fuse into one connected, glowing shape.
  4. 4
    Watch blobs separateThe merged shape splits back into distinct blobs.
  5. 5
    Leave the canvasBlobs drift and bounce off the edges undisturbed.
  6. 6
    Resize the windowThe sampling grid and canvas rebuild to fit.
  7. 7
    Tune itAdjust NUM_BALLS, cell size, or the threshold for a different look.

Real-world uses

Common Use Cases

Hero background layers
Add an organic, liquid ambient layer behind headline text, with blobs merging and splitting as they drift and follow the cursor.
Idle and loading screens
Provide a mesmerising distraction with no fixed endpoint, running at 60 fps thanks to coarse-grid sampling of the scalar field.
Creative agency sites
Offer a tactile, playful interactive background, with a glowing band at the edge where the field just exceeds the threshold.
Music and event pages
Reinforce a fluid, energetic mood, using inverse-square influence summed per sample point rather than blurred circles.
Graphics teaching demos
Give students a compact, readable metaball example that shows how a threshold on a shared field creates fusion.
Related: Canvas Star Trail Cursor
See the Canvas Star Trail Cursor for a related animations pattern worth pairing with this one.
Related: SVG Liquid Text Wave
See the SVG Liquid Text Wave for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

A metaball is one contributor to a shared scalar field rather than an independently drawn shape. Each ball adds an inverse-square-falloff value (radius squared over distance squared) to every point in space; the rendered shape is wherever the summed field from all balls crosses a chosen threshold, which is why overlapping influence fields visually fuse into one connected blob instead of drawing as separate overlapping circles.

Evaluating the field (a loop over every ball) at every single device pixel at 60fps would be far too expensive for a full canvas. Instead the field is sampled on a coarser grid (6px cells by default) and each cell is filled as a small flat block, trading a small amount of edge smoothness for a rendering cost low enough to sustain real-time animation.

No special-case merge logic exists at all. As two blobs move closer, the sample points between them receive growing contributions from both balls' fields simultaneously, pushing the combined value above the 1.0 threshold across a wider area. The connected region that results is a direct, automatic consequence of summing two influence fields — not a separate shape-blending step.

updateBalls() checks the distance from each ball to the pointer and, when within 220px, nudges the ball's velocity toward the pointer's direction by a small constant amount. That constant (non-inverse-square) pull was chosen deliberately over a physically accurate force falloff because it reads as a gentle, playful "wet pull" rather than a sharp snap toward the cursor.

Yes — reduce the cell size for finer sampling (at a performance cost), or keep the coarse grid but run marching-squares contour extraction on the field values to generate an actual smooth vector outline you stroke/fill instead of coloring flat blocks. The field-computation logic in render() stays identical either way; only how you turn field values into pixels changes.