Exploring the CSS Paint API: Blob Animation

No Comments

After the fragmentation impact, I’m going to deal with one other fascinating animation: the blob! All of us agree that such impact is difficult to attain with CSS, so we typically attain for SVG to make these gooey shapes. However now that the highly effective Paint API is accessible, utilizing CSS isn’t solely doable, however possibly even a preferable strategy as soon as browser help comes round.

Right here’s what we’re making. It’s simply Chrome and Edge help for now, so test this out on a type of browsers as we go alongside.

Reside demo (Chrome and Edge solely)

Constructing the blob

Let’s perceive the logic behind drawing a blob utilizing a basic <canvas> factor to raised illustrate the form:

CodePen Embed Fallback

When speaking a couple of blob, we’re additionally speaking concerning the common form of a distorted circle, in order that’s the form we are able to use as our base. We outline N factors that we place round a circle (illustrated in inexperienced).

const CenterX = 200;
const CenterY = 200;
const Radius = 150;
const N = 10;
var level = [];

for (var i = 0; i < N; i++) {
var x = Math.cos((i / N) * (2 * Math.PI)) * Radius + CenterX;
var y = Math.sin((i / N) * (2 * Math.PI)) * Radius + CenterY;
level[i] = [x, y];
}

Contemplating the middle level (outlined by CenterX/CenterY) and the radius, we calculate the coordinate of every level utilizing some fundamental trigonometry.

After that, we draw a cubic Bézier curve between our factors utilizing quadraticCurveTo(). To do that, we introduce extra factors (illustrated in purple) as a result of a cubic Bézier curve requires a begin level, a management level, and an finish level.

The purple factors are the beginning and finish factors, and the inexperienced factors may be the management factors. Every purple level is positioned on the midpoint between two inexperienced factors.

ctx.beginPath(); /* begin the trail */
var xc1 = (level[0][0] + level[N – 1][0]) / 2;
var yc1 = (level[0][1] + level[N – 1][1]) / 2;
ctx.moveTo(xc1, yc1);
for (var i = 0; i < N – 1; i++) {
var xc = (level[i][0] + level[i + 1][0]) / 2;
var yc = (level[i][1] + level[i + 1][1]) / 2;
ctx.quadraticCurveTo(level[i][0], level[i][1], xc, yc);
}
ctx.quadraticCurveTo(level[N – 1][0], level[N – 1][1], xc1, yc1);
ctx.closePath(); /* finish the trail */

Now all we’ve got to do is to replace the place of our management factors to create the weblog form. Let’s strive with one level by including the next:

level[3][0]= Math.cos((3 / N) * (2 * Math.PI)) * (Radius – 50) + CenterX;
level[3][1]= Math.sin((3 / N) * (2 * Math.PI)) * (Radius – 50) + CenterY;

CodePen Embed Fallback

The third level is closest to the middle of our circle (by about 50px) and our cubic Bézier curve follows the motion completely to maintain a curved form.

Let’s do the identical with all of the factors. We will use the identical common thought, altering these present strains:

var x = Math.cos((i / N) * (2 * Math.PI)) * Radius + CenterX;
var y = Math.sin((i / N) * (2 * Math.PI)) * Radius + CenterY;

…into:

var r = 50*Math.random();
var x = Math.cos((i / N) * (2 * Math.PI)) * (Radius – r) + CenterX;
var y = Math.sin((i / N) * (2 * Math.PI)) * (Radius – r) + CenterY;

Every level is offset by a random worth between 0 and 50 pixels, bringing every level nearer to the middle by a barely totally different quantity. And we get our blob form consequently!

CodePen Embed Fallback

Now we apply that form as a masks on a picture utilizing the CSS Paint API. Since we’re coping with a blobby form, it’s appropriate to think about sq. parts (peak equal to width) as a substitute, the place the radius is the same as half the width or peak.

Right here we go utilizing a CSS variable (N) to manage the variety of factors.

CodePen Embed Fallback

I extremely suggest studying the primary a part of my earlier article to grasp the construction of the Paint API.

Every time the code runs, we get a brand new form, due to the random configuration.

Let’s animate this!

Drawing a weblog is sweet and all, however animating it’s higher! Animating the blob is definitely the principle objective of this text, in any case. We are going to see how you can create totally different sorts of gooey blob animations utilizing the identical basis of code.

The principle thought is to easily alter the place of the factors — whether or not it’s all or a few of them — to transition between two shapes. Let’s begin with the essential one: a transition from a circle right into a blob by altering the place of 1 level.

Reside demo (Chrome and Edge solely)

For this, I launched a brand new CSS variable, B , to which I’m making use of a CSS transition.

@property –b{
syntax: ‘<quantity>’;
inherits: false;
initial-value: 0;
}
img {
–b:0;
transition:–b .5s;
}
img:hover {
–b:100
}

I get the worth of this variable contained in the paint() perform and use it to outline the place of our level.

If you happen to test the code within the embedded linked demo, you’ll discover this:

if(i==0)
var r = RADIUS – B;
else
var r = RADIUS

All of the factors have a hard and fast place (outlined by the form’s radius) however the first level particularly has a variable place, (RADIUS – B ). On hover, The worth of B is altering from 0 to 100, transferring our level nearer to the center whereas creating that cool impact.

Let’s do that for extra factors. Not all of them however solely the even ones. I’ll outline the place as comply with:

var r = RADIUS – B*(ipercent2);

Reside demo (Chrome and Edge solely)

We’ve our first blob animation! We outlined 20 factors and are making half of them nearer to the middle on hover.

We will simply have totally different blobby variations just by adjusting the CSS variables. We outline the variety of factors and the ultimate worth of the B variable.

Reside demo (Chrome and Edge solely)

Now let’s strive it with some random stuff. As an alternative of transferring our factors with a hard and fast worth, let’s make that worth random transfer them throughout. We beforehand used this:

var r = RADIUS – B*(ipercent2);

Let’s change that to this:

var r = RADIUS – B*random();

…the place random() provides us a price within the vary [0 1]. In different phrases, every level is moved by a random worth between 0 and B . Right here’s what we get:

Reside demo (Chrome and Edge solely)

See that? We get one other cool animation with the identical code construction. We solely modified one instruction. We will make that instruction a variable so we are able to determine if we need to use the uniform or the random configuration with out altering our JavaScript. We introduce one other variable, T, that behaves like a boolean:

if(T == 0)
var r = RADIUS – B*(ipercent2);
else
var r = RADIUS – B*random();

CodePen Embed Fallback

We’ve two animations and, due to the T variable, we get to determine which one to make use of. We will management the variety of factors utilizing N and the gap utilizing the variable V. Sure, quite a lot of variables however don’t fear, we’ll sum up all the things on the finish.

What’s that random() perform doing?

It’s the identical perform I used within the earlier article. We noticed there that we can’t depend on the default built-in perform as a result of we want a random perform the place we’re capable of management the seed to verify we at all times get the identical sequence of random values. So the seed worth can also be one other variable that we are able to management to get a unique blob form. Go change that worth manually and see the consequence.

In the earlier article, I discussed that the Paint API removes the entire complexity on the CSS aspect of issues, and that provides us extra flexibility to create advanced animations. For instance, we are able to mix what we’ve got accomplished up so far with keyframes and cubic-bezier():

Reside demo (Chrome and Edge solely)

The demo contains one other instance utilizing the parabolic curve I detailed in a earlier article.

Controlling the motion of the factors

In all of the blobs we’ve created to date, we thought of the identical motion for our factors. Whether or not we’re utilizing the uniform configuration or the random one, we at all times transfer the factors from the sting to the middle of the circle following a line.

Now let’s see how we are able to management that motion to be able to get even extra animations. The concept behind this logic is straightforward: we transfer the x and y in another way.

Beforehand we have been doing this:

var x = Math.cos((i / N) * (2 * Math.PI)) * (Radius – F(B)) + CenterX;
var y = Math.sin((i / N) * (2 * Math.PI)) * (Radius – F(B)) + CenterY;

…the place F(B) is a perform based mostly on the variable B that holds the transition.

Now we can have one thing like this as a substitute:

var x = Math.cos((i / N) * (2 * Math.PI)) * (Radius – Fx(B)) + CenterX;
var y = Math.sin((i / N) * (2 * Math.PI)) * (Radius – Fy(B)) + CenterY;

…the place we’ve updating the x and y variables in another way to makes extra animations. Let’s strive a couple of.

One axis motion

For this one, we’ll make one of many features equal to 0 and hold the opposite one the identical as earlier than. In different phrases, one coordinate stays mounted alongside the animation

If we do:

Fy(B) = 0

…we get:

Reside demo (Chrome and Edge solely)

The factors are solely transferring horizontally to get one other type of impact. We will simply do the identical for the opposite axis by making Fx(B)=0 (see a demo).

I feel you get the thought. All we’ve got to do is to regulate the features for every axis to get a unique animation.

Left or proper motion

Let’s strive one other type of motion. As an alternative of creating the factors converging into the middle, let’s make them transfer into the identical route (both proper or left). We want a situation based mostly on the situation of the purpose which is outlined by the angle.

We’ve two group of factors: ones within the [90deg 270deg] vary (the left aspect), and the remaining factors alongside the trip aspect of the form. If we take into account the indexes, we are able to categorical the vary in another way, like [0.25N 0.75N] the place N is the variety of factors.

The trick is to have a unique signal for every group:

var signal = 1;
if(i<0.75*N && i>0.25*N)
signal = -1; /* we invert the signal for the left group */
if(T == 0)
var r = RADIUS – B*signal*(ipercent2);
else
var r = RADIUS – B*signal*random();
var x = Math.cos((i / N) * (2 * Math.PI)) * r + cx;

And we get:

Reside demo (Chrome and Edge solely)

We’re capable of get the identical route however with one small disadvantage: one group of the factors are going outdoors the masks space as a result of we’re growing the gap on some factors whereas lowering the gap on others. We have to scale back the dimensions of our circle to depart sufficient area for all of our factors.

We merely lower the dimensions of our circle utilizing the V worth that defines the ultimate worth for our B variable. In different phrases, it’s the utmost distance that one level can attain.

Our preliminary form (illustrated by the gray space and outlined with the inexperienced factors) will cowl a smaller space since we’ll lower the Radius worth with the worth of V:

const V = parseFloat(properties.get(‘–v’));
const RADIUS = dimension.width/2 – V;

Reside demo (Chrome and Edge solely)

We mounted the difficulty of the factors getting outdoors however we’ve got one other small disadvantage: the hover-able space is similar, so the impact begins even earlier than the cursor hits the picture. It might be good if we are able to additionally scale back that space so all the things is constant.

We will use an additional wrapper and a detrimental margin trick. Right here’s the demo. The trick is fairly easy:

.field {
show: inline-block;
border-radius: 50%;
cursor: pointer;
margin: calc(var(–v) * 1px);
–t: 0;
}

img {
show: block;
margin: calc(var(–v) * -1px);
pointer-events: none;
-webkit-mask: paint(blob);
–b: 0;
transition:–b .5s;
}
.field:hover img {
–b: var(–v)
}

The additional wrapper is an inline-block factor. The picture inside it has detrimental margins equal to the V variable which reduces the general dimension of the form’s field. Then we disable the hover impact on the picture factor (utilizing pointer-events: none) so solely the field factor triggers the transition. Lastly we add some margin to the field factor to keep away from any overlap.

Just like the earlier impact, this one will also be mixed with cubic-bezier() and keyframes to get extra cool animations. Under is an instance utilizing my sinusoidal curve for a wobbling impact on hover.

Reside demo (Chrome and Edge solely)

If we add some transforms, we are able to create a type of unusual (however fairly cool) sliding animation:

Reside demo (Chrome and Edge solely)

Round motion

Let’s deal with one other fascinating motion that can enable us to create infinite and “sensible” blob animations. As an alternative of transferring our factors from one location to a different, we’ll rotate them round an orbit to have a steady motion.

The preliminary location of our factors (in inexperienced) will turn into an orbit and the purple circle is the trail that our factors will take. In different phrases, every level will rotate round its preliminary place following a circle having a radius r.

All we have to do is ensure that there is no such thing as a overlap between two adjoining paths so the radius must have a most allowed worth.

I can’t element the maths however the max worth is the same as:

const r = 2*Radius*Math.sin(Math.PI/(2*N));

Reside demo (Chrome and Edge solely)

That is the related a part of the code:

var r = (dimension.width)*Math.sin(Math.PI/(N*2));
const RADIUS = dimension.width/2 – r;
// …

for(var i = 0; i < N; i++) {
var rr = r*random();
var xx = rr*Math.cos(B * (2 * Math.PI));
var yy = rr*Math.sin(B * (2 * Math.PI));
var x = Math.cos((i / N) * (2 * Math.PI)) * RADIUS + xx + cx;
var y = Math.sin((i / N) * (2 * Math.PI)) * RADIUS + yy + cy;
level[i] = [x,y];
}

We get the max worth of the radius and we scale back that worth from the principle radius. Do not forget that we have to have sufficient area for our factors so we have to scale back the masks space like we did with the earlier animation. Then for every level we get a random radius rr (between 0 and r). Then we calculate the place contained in the round path utilizing xx and yy. And, lastly, we place the trail round its orbit and get the ultimate place (the x, y values).

Discover the worth B which is, as typical, the one with the transition. This time, we can have a transition from 0 to 1 to be able to make a full flip across the orbit.

Spiral motion

Yet another for you! This one is a mixture of the 2 earlier ones.

We noticed how you can transfer the factors round a hard and fast orbit and how you can transfer some extent from the sting of the circle to the middle. We will mix each and have our level transfer round an orbit and we do the identical for the orbit by transferring it from the sting to the middle.

Let’s add an additional variable to our present code:

for(var i = 0; i < N; i++) {
var rr = r*random();
var xx = rr*Math.cos(B * (2 * Math.PI));
var yy = rr*Math.sin(B * (2 * Math.PI));

var ro = RADIUS – Bo*random();
var x = Math.cos((i / N) * (2 * Math.PI)) * ro + xx + cx;
var y = Math.sin((i / N) * (2 * Math.PI)) * ro + yy + cy;
level[i] = [x,y];
}

As you possibly can see, I used the very same logic because the very first animation we checked out. We scale back the radius with a random worth (managed with Bo on this case).

Reside demo (Chrome and Edge solely)

Yet one more fancy blob animation! Now every factor has two animations: one animates the orbit (Bo), and the opposite animates the purpose in its round path (B). Think about all the consequences which you can get by merely adjusting the animation worth (length, ease, and so on.)!

Placing all the things collectively

Oof, we’re accomplished with all of the animations! I do know that a few of you will have gotten misplaced with all of the variations and all of the variables we launched, however no worries! We are going to sum all the things up proper now and you will notice that it’s simpler than what would possibly count on.

I need to additionally spotlight that what I’ve accomplished isn’t an exhaustive checklist of all of the doable animations. I solely tackled a couple of of them. We will outline much more however the principle objective of this text is to grasp the general construction and be capable to lengthen it as wanted.

Let’s summarize what we’ve got accomplished and what are the details:

The variety of factors (N): This variable is the one which controls the granularity of the blob’s form. We outline it within the CSS and it’s later used to outline the variety of management factors.The kind of motion (T): In nearly all of the animations we checked out, I at all times thought of two type of animations: a “uniform” animation and a “random” one. I’m calling this the kind of motion that we are able to management utilizing the variable T set within the CSS. We can have someplace within the code to do an if-else based mostly on that T variable.The random configuration: When coping with random motion, we have to use our personal random() perform the place we are able to management the seed to be able to have the identical random sequence for every factor. The seed will also be thought of a variable, one which generates totally different shapes.The character of motion: That is the trail that the factors take. We will have quite a lot of variations, for instance:From the sting of the circle to the centerA one axis motion (the x or y axis)A round movementA spiral movementand many others…

Like the kind of motion, the character of the motion will also be made conditional by introducing one other variable, and there’s no restrict to what may be accomplished right here. All we’ve got to do is to search out the maths method to create one other animation.

The animation variable (B): That is the CSS variable that accommodates the transition/animation. We typically apply a transition/animation from 0 to a sure worth (outlined in all of the examples with the variable V). This variable is used to precise the place of our factors. Updating that variable logically updates the positions; therefore the animations we get. Generally, we solely must animate one variable, however we are able to have extra based mostly on the character of the motion (just like the spiral one the place we used two variables).The form space: By default, our form covers the whole factor space, however we noticed that some motion require the factors to go outdoors the form. That’s why we needed to scale back the world. We typically do that by the utmost worth of B (outlined by V), or a unique worth based mostly on the character of the motion.

Our code is structured like this:

var level = [];
/* The middle of the factor */
const cx = dimension.width/2;
const cy = dimension.peak/2;
/* We learn the entire CSS variables */
const N = parseInt(properties.get(‘–n’)); /* variety of factors */
const T = parseInt(properties.get(‘–t’)); /* sort of motion */
const Na = parseInt(properties.get(‘–na’)); /* nature of motion */
const B = parseFloat(properties.get(‘–b’)); /* animation variable */
const V = parseInt(properties.get(‘–v’)); /* max worth of B */
const seed = parseInt(properties.get(‘–seed’)); /* the seed */
// …

/* The radius of the form */
const RADIUS = dimension.width/2 – A(V,T,Na);

/* Our random() perform */
let random = perform() {
// …
}
/* we outline the place of our factors */
for(var i = 0; i < N; i++) {
var x = Fx[N,T,Na](B) + cx;
var y = Fy[N,T,Na](B) + cy;
level[i] = [x,y];
}

/* We draw the form, this half is at all times the identical */
ctx.beginPath();
// …
ctx.closePath();
/* We fill it with a stable shade */
ctx.fillStyle = ‘#000’;
ctx.fill();

As you possibly can see, the code isn’t as advanced as you might need anticipated. All of the work is inside these perform Fx and Fy, which defines the motion based mostly on N,T and Na. We even have the perform A that reduces the dimensions of the form to stop factors overflowing the form through the animation.

Let’s test the CSS:

@property –b {
syntax: ‘<quantity>’;
inherits: false;
initial-value: 0;
}

img {
-webkit-mask:paint(blob);
–n: 20;
–t: 0;
–na: 1;
–v: 50;
–seed: 125;
–b: 0;
transition: –b .5s;
}
img:hover {
–b: var(–v);
}

I feel the code is self-explanatory. You outline the variables, apply the masks, and animate the B variable utilizing both a transition or keyframes. That’s all!

I’ll finish this text with a last demo the place I put all of the variations collectively. All you must do is to play with the CSS variables

CodePen Embed Fallback

Exploring the CSS Paint API collection:

Picture FragmentationBlob Animation (this text)

The submit Exploring the CSS Paint API: Blob Animation appeared first on CSS-Tips. You’ll be able to help CSS-Tips by being an MVP Supporter.

    About Marketing Solution Australia

    We are a digital marketing company with a focus on helping our customers achieve great results across several key areas.

    Request a free quote

    We offer professional SEO services that help websites increase their organic search score drastically in order to compete for the highest rankings even when it comes to highly competitive keywords.

    Subscribe to our newsletter!

    More from our blog

    See all posts

    Leave a Comment