The Gooey effect is one of the most interesting techniques in modern UI design. When used subtly, it can add an organic and fluid quality to interfaces.
One of the best ways to understand and experiment with the Gooey effect is by creating Metaball animations - where shapes smoothly blend and interact with each other like liquid mercury.
This article was inspired by William Candillon's tutorial about the Headspace Player.
GitHub Repo
Are you in a hurry? You can find the complete code below:
YouTube Tutorial
Want to follow along with a video? Check out the step-by-step tutorial on my YouTube channel:
Getting Started
To get started, you'll need to start an Expo Go project:
Look what we've done so far, isn't it beautiful?
Yep, you can't do much with a simple circle, but we'll fix that in the next step.
The interactive Circles
Have you tried to interact with the circle? Bad news, it's not interactive.
This seems like a good opportunity to learn how to interact with a Skia Canvas. Unfortunately, there is no gesture handler for the Canvas component, so if you want to manage gestures you'll need to get creative.
There are two options:
You can create a "fake" transparent circle and use gesture-handler with Reanimated (docs)
Let's be honest, if you don't know what's the trick behind this animation you'll feel like you're in front of magic. I've always been fascinated by this kind of animation, and I've always wanted to build one.
The fun part is that it's crazy simple to build. It just requires two ingredients:
A Blur
A ColorMatrix
Start with a Paint
To use the ingredients mentioned above, we need to set up our pot. Well, in this case I'm talking about a Paint object.
It seems like nothing has changed, but we've just set up our pot.
Now we can start adding the ingredients.
The Blur
...
const layer =useMemo(()=>{
return(
<Paint>
<Blurblur={30}/>
</Paint>
);
},[]);
...
And that's the output.
The ColorMatrix
If you try moving around the circle, you'll see that actually with the blur applied it seems that we're very close to the final result.
If only we could focus things again without losing the fluid effect given by the blur.
Luckly, we can do that with a ColorMatrix.
...
const layer =useMemo(()=>{
return(
<Paint>
<Blurblur={30}/>
<ColorMatrix
matrix={[
// R, G, B, A, Position
1,0,0,0,0,
0,1,0,0,0,
0,0,1,0,0,
0,0,0,60,-30,
]}
/>
</Paint>
);
},[]);
...
The metaball effect creates a fluid, organic connection between shapes using a combination of blur and color matrix transformations. Here's how it works:
Core Formula
The effect is based on this transformation:
α_new = alphaMultiplier × α - alphaThreshold
Key Parameters
alphaMultiplier (default: 60)
Controls the edge sharpness of the metaball
Higher values (e.g., 80) = Sharper edges
Lower values (e.g., 40) = Softer edges
Must be positive
alphaThreshold (default: 30)
Controls the connection area size
Higher values = Smaller connection area
Lower values = Larger connection area
How It Works
First, the blur spreads out the alpha values of both circles, creating a gradient falloff
The color matrix then applies the transformation:
Areas where α < (threshold ÷ multiplier) become transparent
Areas where α > (threshold ÷ multiplier) become visible
The transition point occurs at α = 0.5 (with default values)
Why don't you try to play with the parameters?
Note: by setting the alpha to 1 and the threshold to 0 you'll get the blurred effect.
Conclusion
I hope you enjoyed this tutorial and that you learned something new. I'm really excited to see what you will create with this technique and I'm looking forward to seeing your creations. Feel free to share them with me on Twitter.