← Back to gallery
SVGFeatured

Gooey Blob Construction

Two overlapping divs blurred + contrast-thresholded into a single gooey shape via an SVG filter chain (gaussianBlur → colorMatrix). Three motion archetypes: a calm pulse, a synchronized orbit, and a chaotic jitter.

gooeysvg-filterfeGaussianBlurfeColorMatrixisolationblobprefers-reduced-motion

Blob Construction / Blur Threshold Filter

Gooey Blob Construction

Overlapping authored primitives merge through an SVG blur-and-threshold filter, showing how blob construction differs from a single morphing path.

Circles · merged bridge

Primitive Cluster

Three circles converge through a shared filter region until their alpha fields fuse, then breathe back apart. Keep the filter region larger than the moving primitives so blur does not clip at the viewport edge.

  • gooey
  • feGaussianBlur
  • feColorMatrix

Capsules · side pressure

Pill Merge

Capsule-like blobs press together horizontally while a small satellite circle drifts in to demonstrate that primitives do not have to be circular. The same filter merges circles, rounded rects, or authored silhouettes as long as alpha overlaps.

  • capsule
  • alpha overlap
  • filter region

Offset blobs · calm loop

Orbiting Mass

Three satellite blobs orbit a central mass at different speeds + directions while the core silhouette breathes subtly. Useful when the blob needs continuous life without changing the central silhouette.

  • orbit
  • metaball
  • transform-only

Blob inspector

Primitive Cluster

  • gooey
  • feGaussianBlur
  • feColorMatrix

Three circles converge through a shared filter region until their alpha fields fuse, then breathe back apart. Keep the filter region larger than the moving primitives so blur does not clip at the viewport edge.

Helped you ship something? 🐟 Send my cat a churu

/* Three circles converge to fuse then breathe back apart — the filter region absorbs the blur threshold so alpha fields merge cleanly at the join. */
.gooey-blob__shape {
  transform-box: fill-box;
  transform-origin: center;
  /* per-shape animation declared in slug css; only transforms move,
     blur stdDeviation stays constant for stable performance. */
}

@keyframes gooey-cluster-... {
  /* 3.8s cycle, intensity 1.00× */
}

@media (prefers-reduced-motion: reduce) {
  .gooey-blob__shape { animation: none; }
}

How to make this

A CSS gooey blob is built from overlapping primitives passed through an SVG blur-and-threshold filter: blur fuses alpha, then feColorMatrix snaps the edge back.

html
1<div class="gooey-demo" aria-hidden="true">  <svg width="0" height="0" focusable="false">3    <filter id="gooey-construction-filter"      x="-35%" y="-35%" width="170%" height="170%">5      <feGaussianBlur in="SourceGraphic" stdDeviation="9" result="blur" />6      <feColorMatrix in="blur" mode="matrix"        values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7"        result="goo" />      <feBlend in="SourceGraphic" in2="goo" />    </filter>  </svg>  <div class="gooey-demo__layer">    <span class="gooey-demo__blob gooey-demo__blob--a"></span>    <span class="gooey-demo__blob gooey-demo__blob--b"></span>    <span class="gooey-demo__blob gooey-demo__blob--c"></span>  </div></div> <style>.gooey-demo {  position: relative;  display: grid;  place-items: center;  width: 220px;  height: 160px;  overflow: visible;  background: radial-gradient(circle, #12213b, #020617);  border-radius: 22px;}.gooey-demo__layer {  position: relative;  width: 130px;  height: 94px;34  filter: url(#gooey-construction-filter);}.gooey-demo__blob {  position: absolute;  display: block;  border-radius: 999px;  background: linear-gradient(135deg, #67e8f9, #34d399);  transform-box: fill-box;  transform-origin: center;}.gooey-demo__blob--a {  width: 68px;  height: 68px;  left: 10px;  top: 18px;  animation: gooey-construction-a 3.8s ease-in-out infinite alternate;}.gooey-demo__blob--b {  width: 58px;  height: 58px;  right: 10px;  top: 24px;  animation: gooey-construction-b 3.8s ease-in-out infinite alternate;}.gooey-demo__blob--c {  width: 38px;  height: 38px;  left: 50px;  top: 0;  animation: gooey-construction-c 3.8s ease-in-out infinite alternate;}@keyframes gooey-construction-a { to { transform: translateX(12px); } }66@keyframes gooey-construction-b { to { transform: translateX(-14px); } }@keyframes gooey-construction-c { to { transform: translateY(12px); } }@media (prefers-reduced-motion: reduce) {  .gooey-demo__blob { animation: none; }}</style>

Annotated snippet

  1. Line 1The whole demo is decorative, so it is hidden from assistive technology. If the blob communicates status or progress, expose that meaning as real text outside the filtered art.
  2. Line 3The filter region is larger than the source box. Blurred alpha extends beyond the primitives, and a tight filter box clips the goo at the exact moment the merge should look soft.
    PitfallWhy is my SVG gooey filter clipped at the edges?

    The filter region is too small, or a parent has overflow: hidden. Increase the filter x/y/width/height around the moving primitives and leave visual padding around the group. The blur needs space before thresholding can produce a clean edge.

  3. Line 5feGaussianBlur spreads each primitive alpha field until neighboring blobs overlap. Blur creates the bridge, but by itself it leaves a fuzzy, low-contrast edge.
    PitfallWhat makes a gooey blob different from a blurred blob?

    The threshold step. Blur spreads alpha so shapes can overlap, but feColorMatrix raises the alpha contrast afterward, turning the soft overlap into one crisp silhouette. Without the matrix, the result is just fuzzy circles.

  4. Line 6feColorMatrix thresholds the blurred alpha channel. The 18 multiplier and -7 offset push semi-transparent blur into a hard merged silhouette.

    Blur alone makes soft circles; the threshold matrix turns the overlap into a crisp fused blob.

    PitfallWhat makes a gooey blob different from a blurred blob?

    The threshold step. Blur spreads alpha so shapes can overlap, but feColorMatrix raises the alpha contrast afterward, turning the soft overlap into one crisp silhouette. Without the matrix, the result is just fuzzy circles.

  5. Line 34Apply the filter to the shared layer, not to each blob. The primitives need to be blurred and thresholded together so their alpha fields can fuse.

    A filter applied to each blob individually keeps them as separate silhouettes — the blur and threshold run per element, never sharing alpha. Applied to the shared parent, the two alpha fields blur and threshold together, fusing where they meet.

    PitfallWhat makes a gooey blob different from a blurred blob?

    The threshold step. Blur spreads alpha so shapes can overlap, but feColorMatrix raises the alpha contrast afterward, turning the soft overlap into one crisp silhouette. Without the matrix, the result is just fuzzy circles.

  6. Line 66Only transforms animate. Keeping blur and matrix values stable avoids forcing the browser to recalculate the expensive filter recipe every frame.
    PitfallIs a gooey SVG filter expensive?

    It can be. Blur and color matrix filters touch many pixels, especially with large regions or high stdDeviation values. Keep the filtered area small, animate transform only, and avoid many independent gooey groups on the same viewport.

Other pitfalls

How should gooey blobs handle reduced motion?
Stop the primitive transforms under prefers-reduced-motion and leave a static merged shape. Do not remove the filter unless it causes contrast problems, because the filtered silhouette is the visual identity of the pattern.
Do browsers support feGaussianBlur and feColorMatrix for CSS gooey effects?
Modern Chromium, Firefox, and Safari support inline SVG filters referenced from CSS, but filter region behavior and URL references can be fragile across shadow roots or external documents. Keep the filter inline near the art and use unique ids per page.
Advanced

Color-shift each blob and blend at the overlap zones

Same three blobs, same SVG goo filter, same 3.8s drift animation that pulls the blobs apart and back together. BEFORE fills all three with one cyan-green gradient — the merged shape reads as a single flat hue. AFTER swaps to three solid hues (cyan, pink, yellow) and applies mix-blend-mode: lighten, so each pixel keeps the brighter channel from the overlapping blobs. Cyan + pink → lilac, pink + yellow → peach, all three → bright pink core. The geometry is identical; only the color story changes.

View explanation and full code10 lines

The base recipe runs three blobs through the same monochromatic gradient, fused by the SVG goo filter — the merged shape reads as one flat hue. Real production examples (Stripe pricing graphics, Apple keynote intros) give each blob a distinct chromatic identity and use mix-blend-mode: lighten so overlap zones produce NEW colors per channel: cyan+pink→lilac, pink+yellow→peach, all three→bright pink core. The filter still fuses the alphas, so the geometry stays gooey; only the color story changes. isolation: isolate on the layer keeps the blend scoped.

Append these rules inside the <style> block from the base snippet above.

css
/* Advanced: color-shift + lighten blend at overlap — extends the base recipe. */.gooey-demo__layer {  isolation: isolate;}.gooey-demo__blob {  mix-blend-mode: lighten;}.gooey-demo__blob--a { background: #19c6e6; } /* cyan   */.gooey-demo__blob--b { background: #ff3d8b; } /* pink   */.gooey-demo__blob--c { background: #ffc21f; } /* yellow */

Notes

Overview

SVG gooey blob effects merge two or more overlapping shapes into a single fluid silhouette via an SVG filter that blurs the alpha channel and then thresholds it back to a hard edge. The primitives stay div-or-circle simple; the filter does the work. Pair the technique with mix-blend-mode or a colored gradient and the result passes for true metaball math without any WebGL or per-frame JS.

When to use it

Reach for gooey for loading indicators, ambient hero accents, or any place where two shapes need to feel related (a navigation dot that absorbs into the next dot, drops of liquid coalescing, a marker that splits when reaching a divider). Skip it for content layout — the filter region creates a stacking context that traps clicks and can break form layouts beneath. Skip it under transparent backgrounds; the threshold matrix depends on opaque alpha to find an edge.

How it works

The filter is a two-step pipeline: feGaussianBlur stdDeviation="9" smudges the alpha channel of overlapping shapes into one blurry mass, then feColorMatrix multiplies the alpha by ~18 and subtracts ~7 so the smooth blur snaps back to a hard edge wherever the alpha crossed a threshold. Shapes that were too far apart to overlap during the blur step stay separate; shapes that overlapped fuse. Apply the filter to a parent<g> or div containing the primitives. Animate the underlying shapes’ transform or cx/cy — the goo follows.

In practical search terms, feColorMatrix values are the whole trick. A matrix tail like 18 -7 means “multiply the blurred alpha by 18, then subtract 7,” which crushes the soft blur into a crisp edge. A stronger tail like 21 -7 tightens the threshold and makes the gooey bridge appear later; a lower multiplier makes blobs merge sooner but look mushier. Tune the multiplier and the feGaussianBlur stdDeviation together instead of copying one magic matrix into every SVG gooey effect.

Production gotchas

Filter region defaults to a small bounding box; set x="-35%" y="-35%" width="170%" height="170%" on the filter so blur near the edges does not clip into a hard line. The created stacking context blocks pointer-events on anything underneath the filtered region; if a form sits beneath, use pointer-events: none on the gooey wrapper or move the form out of the filter region. On Safari iOS the colorMatrix multiplier > 20 can banding-artifact — stay in the 17-19 range. Animating the shapes with filter: blur already applied is double work; use a single SVG filter, not two.

Accessibility

The gooey region is decorative; wrap it in aria-hidden="true" and ensure focusable content sits outside the filtered region (the stacking context can make focus rings render wrong against the filter). Under prefers-reduced-motion: reduce freeze the underlying shape positions; the goo itself is fine because the filter is decorative geometry, not motion.

References

Implementation depth

The blur and threshold are a coupled pair. feGaussianBlur decides how far neighboring shapes bleed into each other, while feColorMatrix decides where that soft overlap snaps back into a hard gooey edge.

Tune matrix values against the actual blob size. A value such as 18 -7 can feel soft at one stdDeviation and too sticky at another; a value such as 21 -7 delays the bridge and needs enough overlap to avoid flicker.