<div class="nav">
<button id="toggle">change direction 😃 </button>
	</div>

<a href="https://www.creativecodingclub.com" target="_blank"><img id="logo" src="https://assets.codepen.io/32887/herman.svg" /></a>
* {
	position:relative;
}

html, body {
	width:100%;
	height:100%;
	overflow:hidden;
	
	
}

body {
	opacity:0;
	margin:0;
	/* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#87e0fd+0,53cbf1+40,0690d6+100 */
background: #87e0fd; /* Old browsers */
background: -moz-linear-gradient(top,  #87e0fd 0%, #53cbf1 40%, #0690d6 100%); /* FF3.6-15 */
background: -webkit-linear-gradient(top,  #87e0fd 0%,#53cbf1 40%,#0690d6 100%); /* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to bottom,  #87e0fd 0%,#53cbf1 40%,#0690d6 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#87e0fd', endColorstr='#0690d6',GradientType=0 ); /* IE6-9 */


}

.nav {
	position:absolute;
	z-index:10000;
	height:80px;
	background:rgba(0, 0, 0, 0.0);
	width:100%;
	display:flex;
	align-items:center;
	justify-content:center;
}


.bubble {
	position:absolute;
	width:178px;
	height:178px;
	background-image: url("https://assets.codepen.io/32887/bubble.png");
}

button {
	box-shadow: 0px 1px 0px 0px #fff6af;
	background:linear-gradient(to bottom, #ffec64 5%, #ffab23 100%);
	background-color:#ffec64;
	border-radius:6px;
	border:1px solid #ffaa22;
	display:inline-block;
	cursor:pointer;
	color:#333333;
	font-family:Arial;
	font-size:21px;
	font-weight:bold;
	padding:12px 24px;
	text-decoration:none;
	text-shadow:0px 1px 0px #ffee66;
	margin:10px;
}
button:hover {
	background:linear-gradient(to bottom, #ffab23 5%, #ffec64 100%);
	background-color:#ffab23;
}
button:active {
	position:relative;
	top:1px;
}

#logo {
	position:fixed;
	bottom:20px;
	left:20px;
}

// if you want to learn all my GreenSock tips and tricks, I got loads of training at
// https://www.creativecodingclub.com


function init() {
	let width = window.innerWidth
let height = window.innerHeight
let centerX = width/2
let centerY = height/2
let toggle_btn = document.querySelector("#toggle")
console.log(width)
let master = gsap.timeline()

CustomWiggle.create("large", { //name
  wiggles: 8, //number of wiggles/oscilations 
  type:"easeInOut" 
});

CustomWiggle.create("medium", { //name
  wiggles: 8, //number of wiggles/oscilations 
  type:"easeInOut" 
});

CustomWiggle.create("small", { //name
  wiggles: 20, //number of wiggles/oscilations 
  type:"easeInOut" 
});

let small = {
	ease:"small",
	duration:2,
	min:0.1,
	max:0.3,
	scaleEase:"none"
}

let medium = {
	ease:"medium",
	duration:4,
	min:0.4,
	max:0.6,
	scaleEase:"power2.in"
	
}

let large = {
	ease:"large",
	duration:5,
	min:0.7,
	max:1	,
	scaleEase:"power4.in"
}

let configs = [small, medium, large]


function weightedRandom(collection, ease) {
	return gsap.utils.pipe(
		Math.random,            //random number between 0 and 1
		gsap.parseEase(ease),   //apply the ease
		gsap.utils.mapRange(0, 1, -0.5, collection.length-0.5), //map to the index range of the array, stretched by 0.5 each direction because we'll round and want to keep distribution (otherwise linear distribution would be center-weighted slightly)
		gsap.utils.snap(1),     //snap to the closest integer
		i => collection[i]      //return that element from the array
	);
}

// usage:
let getRandomConfig = weightedRandom(configs, "power4.in");



function createBubbles(amount) {
	for(let i = 0; i < amount; i++){
		let bubble = document.createElement("div")
		
		let bubbleType = getRandomConfig()
		let scale = gsap.utils.random(bubbleType.min, bubbleType.max)
		let ease = bubbleType.ease
		let scaleEase = bubbleType.scaleEase
		let duration = bubbleType.duration
		let tl = gsap.timeline({repeat:-1, repeatDelay:Math.random() * 3})
		let relativeDirection = Math.random() < 0.5 ? "+=" : "-="
		//console.log(bubbleType.ease, scale)
		
		bubble.setAttribute("class", "bubble")
		document.body.appendChild(bubble)
	   tl.set(bubble, {x:gsap.utils.random(0,width), y:height+(100 * scale), xPercent:-50, yPercent:-50, scale:0})
		
		tl.to(bubble, {y:-200, duration:duration, ease:"power1.in"})
		tl.to(bubble, {duration:1, scale:scale, ease:scaleEase}, gsap.utils.random(0, 0.5))
		tl.to(bubble, {x:relativeDirection + scale * 80, ease:ease, duration:duration * 2, }, gsap.utils.random(0.3, 1.5))
		
		master.add(tl, i * 0.1)
		

		
	}
	master.timeScale(600/height)
	master.time(100000)
}

toggle_btn.addEventListener("click", () => {
	master.reversed(!master.reversed())
})


	createBubbles(100)
	gsap.to("body", {opacity:1, duration:0.2})
}


gsap.delayedCall(0.1, init)

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/gsap/3.3.1/gsap.min.js
  2. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/CustomEase3.min.js
  3. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/CustomWiggle3.min.js