Skip to content

Instantly share code, notes, and snippets.

@shenhuang
Last active February 12, 2019 15:52
Show Gist options
  • Save shenhuang/ea55e1f0098a58f3a8cdd622eeaebe93 to your computer and use it in GitHub Desktop.
Save shenhuang/ea55e1f0098a58f3a8cdd622eeaebe93 to your computer and use it in GitHub Desktop.
A beach themed website where dragging your mouse will leave a trial of bubbles.
<!--Copyright to Shen Huang, you can reach me out at shenhuang@live.ca-->
<!DOCTYPE html>
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
<html>
<head>
<title>BUBBLE DEMO</title>
<style>
body {
background-color : #a3d2ff;
}
html, body {
max-width: 100%;
overflow-x: hidden;
overflow-y: hidden;
}
.bubble {
z-index : 999;
position : absolute;
border-radius : 50%;
}
sand {
z-index : 0;
position : absolute;
top : 60%;
left : -10%;
width: 110%;
border-bottom : 300px solid #ffedc6;
border-left : 100px solid transparent;
}
water {
z-index : 1;
position : absolute;
top : 45%;
left : -30%;
height : 60%;
width : 100%;
background-color : #84abff;
border-radius : 50%;
}
skymask {
z-index : 2;
position : absolute;
top : 30%;
left : -10%;
height : 30%;
width : 80%;
background-color : #a3d2ff;
}
boat {
z-index : 3;
position : absolute;
top : 90%;
left : 20%;
width: 70px;
border-top : 10px solid #ffd6f9;
border-left : 5px solid transparent;
border-right : 5px solid transparent;
}
mast {
z-index : 4;
position : absolute;
top : -70px;
left : 50px;
height : 60px;
width : 5px;
background-color : #efeded;
}
sail {
z-index : 3;
position : absolute;
top : -70px;
left : 10px;
width : 5px;
border-bottom : 50px solid #ffffff;
border-left : 40px solid transparent;
}
tree {
z-index : 2;
position : absolute;
top : 55%;
left : 80%;
}
branch {
z-index : 2;
position : absolute;
top : 0px;
left : 0px;
height : 90px;
width : 40px;
border : 1px;
border-color : #7f6048;
border-style : solid;
background-color : #bc8e6b;
border-radius : 50%;
-webkit-clip-path : polygon(20px -30px, 70px 0px, 35px 80px, 10px 80px, 30px 55px);
clip-path : polygon(20px -30px, 70px 0px, 35px 80px, 10px 80px, 30px 55px);
}
leaf1 {
z-index : 2;
position : absolute;
top : -5px;
left : -55px;
height : 15px;
width : 70px;
border : 1px;
border-color : #527c51;
border-style : solid;
background-color : #6fad6b;
border-radius : 50%;
-webkit-clip-path : ellipse(40px 25px at 60px 30px);
clip-path : ellipse(40px 25px at 60px 30px);
transform : scaleX(1.2) rotate(0deg);
}
leaf2 {
z-index : 2;
position : absolute;
top : -15px;
left : -35px;
height : 15px;
width : 70px;
border : 1px;
border-color : #527c51;
border-style : solid;
background-color : #6fad6b;
border-radius : 50%;
-webkit-clip-path : ellipse(40px 15px at 60px 20px);
clip-path : ellipse(40px 15px at 60px 20px);
transform : scaleX(0.7) rotate(15deg);
}
leaf3 {
z-index : 2;
position : absolute;
top : 5px;
left : -35px;
height : 15px;
width : 70px;
border : 1px;
border-color : #527c51;
border-style : solid;
background-color : #6fad6b;
border-radius : 50%;
-webkit-clip-path : ellipse(40px 15px at 60px 20px);
clip-path : ellipse(40px 15px at 60px 20px);
transform : scaleX(0.7) rotate(-10deg);
}
leaf4 {
z-index : 2;
position : absolute;
top : -7px;
left : 30px;
height : 15px;
width : 70px;
border : 1px;
border-color : #527c51;
border-style : solid;
background-color : #6fad6b;
border-radius : 50%;
-webkit-clip-path : ellipse(40px 25px at 60px 30px);
clip-path : ellipse(40px 25px at 60px 30px);
transform : scaleX(-1.2) rotate(0deg);
}
leaf5 {
z-index : 2;
position : absolute;
top : -20px;
left : 10px;
height : 15px;
width : 70px;
border : 1px;
border-color : #527c51;
border-style : solid;
background-color : #6fad6b;
border-radius : 50%;
-webkit-clip-path : ellipse(40px 15px at 60px 20px);
clip-path : ellipse(40px 15px at 60px 20px);
transform : scaleX(-0.7) rotate(20deg);
}
leaf6 {
z-index : 2;
position : absolute;
top : 5px;
left : 15px;
height : 15px;
width : 70px;
border : 1px;
border-color : #527c51;
border-style : solid;
background-color : #6fad6b;
border-radius : 50%;
-webkit-clip-path : ellipse(40px 15px at 60px 20px);
clip-path : ellipse(40px 15px at 60px 20px);
transform : scaleX(-0.7) rotate(-10deg);
}
coconut1 {
z-index : 3;
position : absolute;
top : 1px;
left : 10px;
height : 15px;
width : 15px;
border : 1px;
border-color : #827d5d;
border-style : solid;
background-color : #a59f78;
border-radius : 50%;
}
coconut2 {
z-index : 3;
position : absolute;
top : -1px;
left : 21px;
height : 15px;
width : 15px;
border : 1px;
border-color : #827d5d;
border-style : solid;
background-color : #a59f78;
border-radius : 50%;
}
coconut3 {
z-index : 3;
position : absolute;
top : 5px;
left : 15px;
height : 15px;
width : 15px;
border : 1px;
border-color : #827d5d;
border-style : solid;
background-color : #a59f78;
border-radius : 50%;
}
</style>
</head>
<body>
<div id = "board"></div>
<sand></sand>
<water></water>
<skymask></skymask>
<boat>
<mast></mast>
<sail></sail>
</boat>
<tree>
<branch></branch>
<leaf1></leaf1>
<leaf2></leaf2>
<leaf3></leaf3>
<leaf4></leaf4>
<leaf5></leaf5>
<leaf6></leaf6>
<coconut1></coconut1>
<coconut2></coconut2>
<coconut3></coconut3>
</tree>
</body>
<script>
var brd = document.createElement("DIV");
document.body.insertBefore(brd, document.getElementById("board"));
bubbles = [];
const d = 5000;
const o = 0.7;
const r = 0.001;
const f = 0.0025;
const p = 0.00000001;
const minbub = 10;
const maxbub = 50;
const cursorXOffset = 5;
const cursorYOffset = 0;
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;
}
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);
}
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);
}
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;
}
}
}
}
var before = Date.now();
var id = setInterval(frame, 5);
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);
}
}
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment