Last active
February 12, 2019 15:52
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--Copyright to Shen Huang, you can reach me out at [email protected]> | |
<!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