Gooey Blobs in Flutter with CustomPainter

Rutvik Tak
5 min readJul 12, 2024

--

Have you ever seen these gooey blobs on the internet?

They look kinda cool, right! Ever thought creating something like this in Flutter would be really cool?

So a couple of days back, Twitter user @double__glitch showed how to create such gooey blobs in Figma. Seeing his technique reminded me how the steps represent drawing something on a canvas which led to me thinking about CustomPainter and I thought, bet it can do that! Somehow.

Let’s dig in and see how we can create these gooey blobs in Flutter…

Why CustomPainter?

Well, as I said earlier, the technique shown by @double__glitch is like drawing on a canvas and CustomPainter serves exactly that purpose. It provides you with set of apis ranging from drawing shapes on a canvas to adding layer composite effects combining image filters, blend modes, etc.

If you aren’t aware, Flutter under the hood converts your widget layers into a set of canvas painting instructions as part of the rendering pipeline and somewhere down the line, these instructions are rendered on the screen. An interesting fact to know there!

Before diving in, here’s something that you’ll need on our journey of creating gooey blobs in Flutter 🗡️

saveLayer:

saveLayer allows you to create composite effects on canvas. Normally each canvas instruction is painted individually, thus applying composite effects on a group of shapes for e.g. isn’t possible directly. With saveLayer, you can group those shapes and apply an effect on those as one single layer on the canvas.

canvas.saveLayer(Rect.fromLTWH(0, 0, size.width, size.height), paint);

// drawing instructions here are grouped together.

canvas.restore();

Pieces snippet link

saveLayer takes in the size of the layer and a Paint object. Any canvas instructions called after calling saveLayer will be grouped, and once you call, canvas.restore that group will be flattened out into a layer on which the Paint objects image filters and blend modes will be applied.

Now back to creating our gooey blobs…

Adding blurred Circles:

We’ll use the canvas.drawCircle() to draw two circles on the canvas and add a blur filter to the layer using saveLayer.

import 'dart:ui';

import 'package:flutter/material.dart';
class BlobsView extends StatefulWidget {
const BlobsView({super.key});
@override
State<BlobsView> createState() => _BlobsViewState();
}
class _BlobsViewState extends State<BlobsView> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CustomPaint(
painter: _BlobsPainter(),
size: MediaQuery.of(context).size,
),
),
);
}
}
class _BlobsPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final blackCirclesPainter = Paint()
..color = Colors.black
..style = PaintingStyle.fill;
final blurLayerPaint = Paint()
..color = const Color(0xff808080)
..style = PaintingStyle.fill
..imageFilter = ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
tileMode: TileMode.decal,
);
canvas.saveLayer(Rect.fromLTWH(0, 0, size.width, size.height), blurLayerPaint);
canvas.drawCircle(Offset(size.width / 2 - 50, size.height / 2), 70, blackCirclesPainter);
canvas.drawCircle(Offset(size.width / 2 + 50, size.height / 2), 60, blackCirclesPainter);
canvas.restore();
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}

Pieces snippet link

And here’s how it looks. Nothing fancy as of right now.

Adding colorDodge layer:

Next, we’ll add certain layers on top of our canvas with specific blend mode applied to them. The blend mode will specify how the layer should be composited with its background. In this article, we won’t dive deep into how these blend modes work but if you’re curious, I would recommend reading this w3 docs on different blend modes mentioned in this article and how they function.

First is the colorDodge layer. We’ll achieve this by creating a rectangle, giving it a bright color like Color(0xff808080), and setting its blend mode to BlendMode.colorDodge.

This will go right after the canvas.restore call,

canvas.drawRect(
Rect.fromCenter(center: Offset(size.width / 2, size.height / 2), width: size.width, height: size.height),
Paint()
..color = const Color(0xff808080)
..style = PaintingStyle.fill
..blendMode = BlendMode.colorDodge,
);

Pieces snippet link

Now we get something…interesting.

colorDoge is one of the blend modes that can be used to brighten the destination image(our canvas in this case) wrt to the source image(blend mode layer). It basically brightens the brighter areas, adds more contrast and saturation to them. In our case, it helps create sharper outlines for our circles replacing the blurred outlines. Darker areas of the destination image aren’t affected as much as the brighter areas.

Adding colorBurn layer:

Now we’ll add a colorBurn layer on top of our whole canvas. Similar to how we did this earlier, we’ll create a rectangle, give it a black color this time, and set its blend mode to BlendMode.colorBurn.

canvas.drawRect(
Rect.fromCenter(center: Offset(size.width / 2, size.height / 2), width: size.width, height: size.height),
Paint()
..color = Colors.black
..style = PaintingStyle.fill
..blendMode = BlendMode.colorBurn,
);

Pieces snippet link

Getting close we are!

colorBurn is basically the opposite of colorDodge. It darkens the destination image wrt the source image. With this, the inside blurred areas of the circles become completely black creating a sharp gooey shape.

Adding gradient layer:

Same like before, we’ll add a gradient layer with a blend mode set to screen. Setting blend mode to screen will compose this layer as an overlay on top of our gooey shapes excluding the white areas of the canvas.

canvas.drawRect(
Rect.fromCenter(center: Offset(size.width / 2, size.height / 2), width: size.width, height: size.height),
Paint()
..style = PaintingStyle.fill
..shader = const RadialGradient(
colors: [Colors.yellow, Colors.pink],
).createShader(
Rect.fromCenter(
center: Offset(size.width / 2, size.height / 2),
width: size.width,
height: size.height,
),
)
..blendMode = BlendMode.screen,
);

Pieces snippet link

And with that, we’ve our gooey blobs ready🎉

Final version after adding drag controls.

We finally have gooey blobs in Flutter and that wasn’t crazy hard to do. But very interesting how using composite effects with various blend modes can help you create some interesting visuals like this.

Use these blobs cautiously though :)

Conclusion:

You can find the src code for these gooey blobs here among some of my other creative work. Feel free to poke around and play with them :)

--

--