---
title: "How to Create a Gooey (Metaball) Effect in Framer"
description: "Build a gooey metaball effect in Framer with SVG filters — the blur-and-contrast technique explained, a working code override, and where to use it."
canonical_url: "https://framerhub.io/blog/gooey-effect-framer"
last_updated: "2027-01-27T00:00:00.000Z"
---

The gooey effect — separate blobs that appear to merge into one liquid shape as they get close, then split apart cleanly as they move away — is one of the more technically interesting effects in web design, because it isn't actually deforming any shapes at all. It's an optical trick built entirely from an SVG filter. Here's exactly how it works and how to build it in Framer.

## The Trick Behind the Trick

The gooey effect works through a two-step SVG filter chain applied to a group of shapes:

1. **A Gaussian blur** softens the edges of every shape in the group, so shapes that are close together start to visually bleed into one another at their blurred boundaries.
2. **A contrast/alpha adjustment (via feColorMatrix)** then sharpens everything back up — but because the blurred, overlapping regions between close shapes now have higher combined alpha than the blur alone would produce elsewhere, the contrast step snaps those merged regions into one continuous shape instead of two separate blurry blobs.

The net effect: shapes that overlap or come close together fuse into a single smooth silhouette, and shapes that are far apart stay crisp and separate, exactly as if they were liquid. No shape's actual path ever changes — the entire illusion happens in the filter pipeline, which is why it's simultaneously simple to implement and hard to guess how it works by looking at the result.

This technique predates most of the current wave of "liquid UI" design trends by years — it's the same underlying filter chain that's powered gooey navigation indicators, animated blob loaders, and liquid-style buttons across the web for a long time, because it's genuinely the most efficient way to produce a convincing merge illusion in real time. Physics-based blob simulation (actually calculating fluid dynamics between shapes) exists too, but it's dramatically more expensive computationally for a visual result that, in most UI contexts, looks nearly identical to the filter-based approach at a fraction of the cost.

## Why This Matters More Than It Looks

At first glance, a gooey effect might seem like pure decoration, but it solves a real interaction design problem: continuous, connected motion communicates relationship between elements in a way that discrete, separate-shape animation doesn't. A tab indicator that gooey-merges as it slides between two menu items reads as one continuous object moving, rather than one shape disappearing and a different shape appearing — which is a subtly but genuinely different, more coherent-feeling piece of feedback for the person interacting with it.

## Building the SVG Filter

Here's the filter definition itself, which you'll reference from any shapes you want the gooey effect applied to:

```svg
<svg style={{ position: "absolute", width: 0, height: 0 }}>
  <defs>
    <filter id="goo">
      <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
      <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 -8"
        result="goo"
      />
      <feComposite in="SourceGraphic" in2="goo" operator="atop" />
    </filter>
  </defs>
</svg>
```

Two values control the feel of the effect and are worth understanding rather than copying blindly:

- **stdDeviation** on the blur — higher values create a "stickier," more liquid feel where shapes merge from farther apart. Lower values create a tighter, snappier merge that only happens when shapes nearly touch.
- **The last two numbers in the feColorMatrix values (18 -8)** — these control the alpha contrast steepness and threshold. Increasing the multiplier (18) and adjusting the offset (-8) sharpens the resharpening step; get this wrong and the merged shapes look blurry and soft instead of clean and liquid.

## Applying It in a Framer Code Component

Here's a working component using this filter to merge animated circles — a common base pattern you can adapt to buttons, navigation indicators, or decorative blobs.

```jsx
import { motion } from "motion/react"
import { addPropertyControls, ControlType } from "framer"

export default function GooeyBlobs(props) {
  const { color, blobCount, blurAmount } = props
  const blobs = Array.from({ length: blobCount })

  return (
    <div style={{ position: "relative", width: "100%", height: "100%" }}>
      <svg style={{ position: "absolute", width: 0, height: 0 }}>
        <defs>
          <filter id="goo-filter">
            <feGaussianBlur in="SourceGraphic" stdDeviation={blurAmount} result="blur" />
            <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 -8"
              result="goo"
            />
            <feComposite in="SourceGraphic" in2="goo" operator="atop" />
          </filter>
        </defs>
      </svg>
      <div style={{ filter: "url(#goo-filter)", width: "100%", height: "100%" }}>
        {blobs.map((_, i) => (
          <motion.div
            key={i}
            style={{
              position: "absolute",
              width: 80,
              height: 80,
              borderRadius: "50%",
              background: color,
            }}
            animate={{
              x: [0, 60, -40, 0],
              y: [0, -30, 40, 0],
            }}
            transition={{
              duration: 6 + i,
              repeat: Infinity,
              ease: "easeInOut",
              delay: i * 0.4,
            }}
          />
        ))}
      </div>
    </div>
  )
}

addPropertyControls(GooeyBlobs, {
  color: { type: ControlType.Color, defaultValue: "#5B5FEF" },
  blobCount: { type: ControlType.Number, defaultValue: 4, min: 2, max: 8, step: 1 },
  blurAmount: { type: ControlType.Number, defaultValue: 10, min: 4, max: 20 },
})
```

The critical structural detail here: the `filter: "url(#goo-filter)"` is applied to the **wrapping container**, not to each individual blob — the filter needs to process all the blobs together as one composited source for the merge illusion to work between them. Applying the filter to each blob individually would just blur and resharpen each shape on its own, with no merging behavior at all.

## Common Mistakes

- **Applying the filter to individual shapes instead of their shared container.** As noted above, this is the single most common reason a first attempt doesn't produce any merging — each shape gets processed in isolation.
- **Using the filter on shapes containing text or images.** The blur-then-resharpen pipeline blurs everything inside the filtered container indiscriminately, including any text or image content, producing a distracting halo effect around content that should stay crisp.
- **Too aggressive a blur without a matching contrast adjustment.** If you increase `stdDeviation` for a stickier effect, you generally need to also increase the `feColorMatrix` multiplier to keep edges sharp outside the merge zones — the two values are meant to move together, not independently.
- **Forgetting feComposite at the end.** Without compositing the goo result back with `SourceGraphic`, you can lose the original shape's color/opacity fidelity in the final render, especially with semi-transparent fills.

## Where This Effect Fits

Gooey effects are a strong fit for:

- **Animated background decoration** — soft, organic blobs drifting behind hero content, adding movement without competing with foreground text.
- **Interactive cursor followers** where a trailing blob merges into a cursor dot as it catches up.
- **Loading and transition states** — playful liquid-merge loaders instead of a standard spinner.
- **Navigation indicators** that stretch and merge as they slide between menu items, a well-known pattern from native app tab bars.

It's a poor fit for anything requiring crisp, precise edges (icons, product imagery) or performance-constrained contexts, since the SVG filter pipeline is meaningfully more expensive to render than a standard shape.

If you're exploring gooey navigation as a specific pattern — merging pill indicators sliding between tabs or menu items — it pairs particularly well with a spring-based motion curve rather than a linear or ease-based one, since the slight overshoot a spring produces makes the merge-and-separate motion feel more genuinely liquid than a mechanically precise linear transition would. Adjust `stiffness` and `damping` on the underlying motion values (if you're driving position with `useSpring` rather than keyframe `animate` arrays as shown above) until the blob's movement has a small amount of natural give at the end of each transition.

## Performance Considerations

SVG filters, particularly `feGaussianBlur`, are GPU-intensive relative to standard CSS or canvas rendering, and the cost scales with both the blur radius and the size of the filtered area. Keep the filtered container reasonably sized (a decorative background element or a small interactive widget, not a full-viewport effect) and limit the number of animated blobs — beyond 6-8 simultaneously animating shapes inside one goo filter, the frame cost starts to add up on lower-powered devices. If the effect needs to run continuously in the background of a page rather than triggered by interaction, test it specifically on a throttled mobile CPU profile before shipping.

A practical mitigation if performance is tight: trigger the effect only on interaction (a hover state, a tab change) rather than running the blob animation continuously and indefinitely in the background. A continuously running filter costs frame budget on every single frame for the entire time a visitor is on the page, whether they're looking at that section or not, while an interaction-triggered version only spends that budget during the brief window it's actually being seen and appreciated.

## Pairing With Other Motion

Gooey blobs read best as a supporting background element rather than the primary focal point of a section — pair them with static or gently animated foreground content (a headline, a card) rather than another equally busy motion effect competing for the same visual attention, the same principle covered in our [Framer animations and hover effects guide](/blog/framer-animations-hover-effects) for motion generally. If you're assembling a hero section with several moving parts, our broader [component library](/components) and the [Components plugin](/plugins/framer-components) have background and decorative effects designed to sit behind foreground content without overwhelming it, which is worth a look if hand-tuning an SVG filter isn't the best use of a given project's time budget.

## FAQ

**What is a gooey or metaball effect?**
It's a visual effect where separate shapes appear to merge into one another like liquid blobs as they get close, rather than simply overlapping. It's built using an SVG filter combining Gaussian blur with a contrast adjustment, not by literally deforming the shapes.

**Is the gooey effect the same as a blob animation?**
Related but not identical. A blob animation typically morphs a single shape's path over time. A gooey/metaball effect is about how multiple separate shapes visually merge and separate as they move relative to each other — the SVG filter trick covered in this guide is specifically for the merging behavior.

**Does the gooey effect work well on mobile?**
The SVG filter itself works on mobile browsers, but it's more GPU-intensive than a standard shape render, so test performance specifically on mid-range mobile devices if the effect is animating continuously rather than only on interaction.

**Can I use the gooey effect with images, not just solid shapes?**
It works best with solid-color shapes. Applying the same filter to shapes containing images or text produces distracting blur artifacts on the content itself, since the filter blurs and re-sharpens everything inside its bounding area indiscriminately.

**Why does my gooey effect look blurry instead of sharp-edged?**
This usually means the contrast (alpha threshold) value in the feColorMatrix step isn't aggressive enough to fully resharpen the edges after the blur step. Increase the matrix's alpha multiplier and adjust the offset until edges snap back to sharp outside the merge zones.
