Object.getOwnPropertyNames(Math).map(function(p) { window[p] = Math[p]; }); var rand = function(max, min, is_int) { var max = ((max - 1) || 0) + 1, min = min || 0, gen = min + (max - min)*random(); return (is_int)?round(gen):gen; }; var makeShade = function(hsla) { var c = 'hsla('; c += round(hsla.h || rand(240, 180)) + ',' + round((hsla.s || rand(1, .5))*100) + '%,' + round((hsla.l || rand())*100) + '%,' + (hsla.a || 1).toFixed(2) + ')'; return c; }; var BASE_N = 64, c = document.querySelector('canvas'), ctx = c.getContext('2d'), w, h, min_dim, types = ['blob', 'faded', 'spark', 'plain'], n = types.length, bubbles = {}, repulsion_pt = null; var Bubble = function(type, o, r) { this.type = type || 'plain'; this.o = o || null; this.r = r || null; this.c = null; var idx = max(types.indexOf(this.type), 0); this.init = function() { var m1 = [ min_dim/4, min_dim/12, min_dim/16, min_dim/24 ], m2 = [128, 64, 32, 8]; if(!this.r) { this.r = rand(m1[idx], m2[idx], 1); } if(!this.o) { this.o = { 'x': rand(w + this.r, -this.r, 1), 'y': rand(h + this.r, -this.r, 1) }; } if(this.type == 'blob') { this.c = makeShade({ 's': rand(1 - this.o.y/h), 'l': rand(1 - this.o.y/h), 'a': rand(this.o.y/h) }); } if(this.type == 'faded') { this.c = makeShade({ 'l': rand(1, .5), 'a': rand(.32, .25) }); } if(this.type == 'spark') { this.c = makeShade({ 'l': rand(.9, .25) }); } if(this.type == 'plain') { this.c = makeShade({ 'l': rand(1, .5), 'a': rand(.9, .25) }); } }; this.draw = function(ctxt) { var g; if(this.type === 'spark') { ctxt.strokeStyle = 'rgba(255,255,255,.16)'; g = ctxt.createRadialGradient( this.o.x, this.o.y, 0, this.o.x, this.o.y, 8 ); g.addColorStop(0, this.c); g.addColorStop(.2, 'rgba(255,255,255,.1)'); g.addColorStop(1, 'rgba(255,255,255,0)'); ctxt.fillStyle = g; ctxt.filter = 'drop-shadow(1px 1px 1px) blur(1px)'; } else { ctxt.fillStyle = this.c; ctxt.strokeStyle = 'transparent'; if(this.type === 'faded') { ctxt.filter = 'blur(4px)'; } if(this.type === 'blob') { ctxt.filter = 'blur(8px)'; } } ctxt.beginPath(); ctxt.arc(this.o.x, this.o.y, this.r, 0, 2*PI); ctxt.closePath(); ctxt.fill(); ctxt.stroke(); ctxt.filter = 'none'; }; this.init(); }; var init = function() { var s = getComputedStyle(c), m, ctype; w = c.width = ~~ s.width.split('px')[0]; h = c.height = ~~ s.height.split('px')[0]; min_dim = min(w, h) for(var i = 0; i < n; i++) { ctype = types[i]; bubbles[ctype] = []; m = rand(BASE_N, BASE_N/2, 1); for(var j = 0; j < m; j++) { bubbles[types[i]].push(new Bubble(ctype)); } } draw(); }; var draw = function() { var m; for(var p in bubbles) { m = bubbles[p].length; for(var i = 0; i < m; i++) { bubbles[p][i].draw(ctx); } } }; setTimeout(function() { init(); addEventListener('resize', init, false); }, 15);