how to add some BUBBLES to your website

Shen Huang
Frontend Weekly
Published in
8 min readFeb 10, 2019

Cold winter is about to end and it is time for some warm weather to sooth in. Finally, a time when you can enjoy some beach and sunshine. In this tutorial, I will show you how to add a bubbly beach theme to your website.

A demonstration can be found here, where dragging your mouse inside the webpage will generate a trail of bubbles.

Beach Themed Bubble Demo

Now let’s get started! First of all, you will need a webpage, which I have one ready for you if you do not wish to use your own. Simply copy these code from GitHub Gist and save it as a .html file.

With that, you should be able to drag the .html file into your favorite browser and get a beach picture that scales with your browser.

Scalable Beach Theme

In this tutorial most of the animation effects will be handled by JavaScript, meaning that you will spend most of the time adding things between the <script></script> tags, below is the only CSS code you will need, which just defines a circle displaying on top of everything.

.bubble {
z-index : 999;
position : absolute;
border-radius : 50%;
}

Now let’s start working on the scripts. In order for the bubbles to be shown on top of the webpage, we need to first create a board to stick them onto. Use the following code to create the board.

var brd = document.createElement("DIV");
document.body.insertBefore(brd, document.getElementById("board"));

Now we also need an array to keep track of all the bubbles.

bubbles = [];

Then we can create a bubble with arbitrary size and color with the following function.

function newBubble(x, y, size, color)
{
var bubble = document.createElement("DIV");
bubble.setAttribute('class', 'bubble');
bubble.style = "background-color : " + color + ";";
bubble.bubbleSize = size;
bubble.style.height = bubble.bubbleSize * 2 + "px";
bubble.style.width = bubble.bubbleSize * 2 + "px";
bubble.velocity = [];
bubble.velocity.x = 0;
bubble.velocity.y = 0;
bubble.position = [];
bubble.position.x = x;
bubble.position.y = y;
bubble.style.left = bubble.position.x - bubble.bubbleSize + 'px';
bubble.style.top = bubble.position.y - bubble.bubbleSize + 'px';
brd.appendChild(bubble);
if(bubbles == null)
bubbles = [];
bubbles.push(bubble);
return bubble;
}

Noticed that the height and width are 2 times the size, in our scenario bubble.bubbleSize indicates the radius of the bubble, which is half of the width or height.

Width and Height are Twice as much as Radius

We should be able to test our code with the following code appended to the end.

newBubble(200, 200, 50, "black");

If things are going on the right track, you should be able to see this scary black hole on top of your beach theme, or whichever website you are putting the code into.

Circle Printed on Beach Theme

Don’t worry, we will eventually make it into some cute and colorful bubbles, I promise. Right now we can first make this black hole slowly float up and disappear as a bubble would.

First, we add the following code above our newBubble function.

const d = 5000;
const o = 0.7;
const r = 0.001;
const f = 0.0025;
const p = 0.00000001;

These are just a bunch of constants we will be using to animate our bubbles. Where d defines the millisecond duration bubble exists, o defines the initial opacity, r stands for the resistance where the bubbles are experiencing, f defines the amount of buoyancy that floats the bubble up, and p defines a push around factor which will be explained in the later sections.

We will also have to insert the snippet of code into our newBubble function to make sure it is instantiated with an initial duration to count down. The final newBubble function will look something shown below.

function newBubble(x, y, size, color)
{
var bubble = document.createElement("DIV");
bubble.setAttribute('class', 'bubble');
bubble.style = "background-color : " + color + ";";
bubble.bubbleSize = size;
bubble.style.height = bubble.bubbleSize * 2 + "px";
bubble.style.width = bubble.bubbleSize * 2 + "px";
bubble.time = d;
bubble.velocity = [];
bubble.velocity.x = 0;
bubble.velocity.y = 0;
bubble.position = [];
bubble.position.x = x;
bubble.position.y = y;
bubble.style.left = bubble.position.x - bubble.bubbleSize + 'px';
bubble.style.top = bubble.position.y - bubble.bubbleSize + 'px';
brd.appendChild(bubble);
if(bubbles == null)
bubbles = [];
bubbles.push(bubble);
return bubble;
}

Once done we will start our animation controller by attaching the following code to the end.

var before = Date.now();
var id = setInterval(frame, 5);

function frame()
{
var current = Date.now();
var deltaTime = current - before;
before = current;
for(i in bubbles)
{
var bubble = bubbles[i];
bubble.time -= deltaTime;
if(bubble.time > 0)
{
bubble.velocity.y += f * deltaTime;
bubble.velocity.x -= bubble.velocity.x * r * bubble.bubbleSize * deltaTime;
bubble.velocity.y -= bubble.velocity.y * r * bubble.bubbleSize * deltaTime;
bubble.position.x += bubble.velocity.x * deltaTime;
bubble.position.y -= bubble.velocity.y * deltaTime;
bubble.style.left = bubble.position.x - bubble.bubbleSize + 'px';
bubble.style.top = bubble.position.y - bubble.bubbleSize + 'px';
bubble.style.opacity = o * (bubble.time / d);
}
else
{
bubble.parentNode.removeChild(bubble);
bubbles.splice(i, 1);
}
}
}

Now let us test with the following code.

newBubble(210, 210, 10, "black");
newBubble(220, 220, 40, "red");
newBubble(230, 230, 30, "blue");
newBubble(240, 240, 20, "green");

We should see bubbles of different colors floating upwards. Noticed that the bigger bubble floats slower than the smaller ones because they take more resistances due to their sizes.

We have bubbles, we have colors, but what is missing? The bubbles are supposed to be pushing each other around or else they do not feel tangible, don’t they? Now let’s start working on the part making them pushing each other around.

First, let me explain the physics a little bit with the following diagram. When the bubbles are far away from each other they don’t exert any force onto each other. When the bubbles are overlapping with each other they exert force inversely proportional to the distance between them to the direction opposite to the vector defined by both of their centers.

In other words, after they touched each other, the closer they get the more they wanted to push each other away. The bigger bubble will also, of course, exert more forces than the smaller ones.

Physics behind Bubble Push Around Explained

There are more accurate physical relationships you can model with algorithms such as the Finite Element Method. But I think this simple model is enough to make the bubbles feel … … bubbly. Besides, the browser may not be able to handle too much of heavy computation.

Now to translate the physical model into code, we get the following.

function bubblePushAround(deltaTime)
{
for(i = 0; i < bubbles.length; i++)
{
for(j = i + 1; j < bubbles.length; j++)
{
var bubbleOne = bubbles[i];
var bubbleTwo = bubbles[j];
var Dx = bubbleOne.position.x - bubbleTwo.position.x;
var Dy = bubbleOne.position.y - bubbleTwo.position.y;
var D2 = Dx * Dx + Dy * Dy;
var R12 = bubbleOne.bubbleSize * bubbleOne.bubbleSize;
var R22 = bubbleTwo.bubbleSize * bubbleTwo.bubbleSize;
if(D2 < R12 + R22)
{
var D = Math.sqrt(D2);
var F1 = (D2 - (R12 + R22)) * R22;
var F2 = (D2 - (R12 + R22)) * R12;
bubbleOne.velocity.x -= F1 * p * Dx / D * deltaTime;
bubbleOne.velocity.y += F1 * p * Dy / D * deltaTime;
bubbleTwo.velocity.x += F2 * p * Dx / D * deltaTime;
bubbleTwo.velocity.y -= F2 * p * Dy / D * deltaTime;
}
}
}
}

The run-time complexity of this algorithm is actually O(n²) because for every bubble we have to calculate its exerted force for every other bubble, but it has been optimized by checking if they touch each other before the force calculation.

We also need to add the bubblePushAround function we have just created to the animation controller.

function frame()
{
var current = Date.now();
var deltaTime = current - before;
before = current;
bubblePushAround(deltaTime);
for(i in bubbles)
{
var bubble = bubbles[i];
bubble.time -= deltaTime;
if(bubble.time > 0)
{
bubble.velocity.y += f * deltaTime;
bubble.velocity.x -= bubble.velocity.x * r * bubble.bubbleSize * deltaTime;
bubble.velocity.y -= bubble.velocity.y * r * bubble.bubbleSize * deltaTime;
bubble.position.x += bubble.velocity.x * deltaTime;
bubble.position.y -= bubble.velocity.y * deltaTime;
bubble.style.left = bubble.position.x - bubble.bubbleSize + 'px';
bubble.style.top = bubble.position.y - bubble.bubbleSize + 'px';
bubble.style.opacity = o * (bubble.time / d);
}
else
{
bubble.parentNode.removeChild(bubble);
bubbles.splice(i, 1);
}
}
}

Now if we reload the webpage we should see the following.

Colorful Bubbles Floating Upwards

Our final step is to make the bubble pop out when we drag the cursor around, first we define some offset constants and the size of our bubbles.

const minbub = 10;
const maxbub = 50;
const cursorXOffset = 5;
const cursorYOffset = 0;

And then we define the mouse listeners, we want it to behave in a way where the bubbles are generated when the mouse is moving while the keys are held down. We can also add mobile support to make it work on our smartphones.

var msedwn = false;document.onmousedown = function(e) {
msedwn = true;
}
document.onmouseup = function(e) {
msedwn = false;
}
document.onmousemove = function(e) {
if(msedwn)
generateBubbles(e.pageX - brd.offsetLeft + cursorXOffset, e.pageY - brd.offsetTop + cursorYOffset);
}
document.ontouchmove = function(e) {
generateBubbles(e.touches[0].pageX, e.touches[0].pageY);
}

And last but not least we have to define our bubble generation algorithm, which generates a bubble with random size and color.

function generateBubbles(x, y)
{
var size = minbub + (maxbub - minbub) * Math.random();
var digits = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += digits[Math.floor(Math.random() * 16)];
}
newBubble(x, y, size, color);
}

And if everything goes right, we should see something like the following demo.

Complete Bubble Demo

Below I have attached a complete code. in the future, I may write more about similar special effects, or how to create a game in your webpage or console like the one shown below. Let me know if you have any special requests.

Demo of a Game Hidden in Console

I have some previous guides on similar projects.

Beginner:

Advanced:

I hope you have a great summer and have fun programming!

Appendix (Complete code of this project):

--

--