Object.getOwnPropertyNames(Math).map(function(p){ window[p] = Math[p]; }); var N_DOTS = 16, DOT_RADIUS = 2, BASE_RADIUS = 40, AMPLITUDE = 22.5, N_ANI_LOOPS = 3, N_HUE_LOOPS = 3, K = 2/3, c = document.querySelector('.c'), w, h, ctx = c.getContext('2d'), dots = [], t = 0, ts = 8, r_ID; var Dot = function(idx) { var hue, hsla; this.idx = idx || 0; this.angle = idx*2*PI/N_DOTS; hue = ~~(idx*360/N_DOTS*N_HUE_LOOPS + t); this.draw = function(ctx) { var x, y, r; r = BASE_RADIUS + AMPLITUDE*sin( t/ts + this.angle*N_ANI_LOOPS ); x = ~~(r*cos(this.angle)); y = ~~(r*sin(this.angle)); this.drawTrails(ctx); hsla = 'hsla(' + hue + ', 99%, 65%, 1)'; ctx.fillStyle = hsla; ctx.beginPath(); ctx.moveTo(x + DOT_RADIUS, y); ctx.arc(x, y, DOT_RADIUS, 0, 2*PI); ctx.closePath(); ctx.fill(); }; this.drawTrails = function(ctx) { var x, y, r, rd, f; hsla = 'hsla(' + hue + ', 99%, 65%, .2)'; ctx.fillStyle = hsla; ctx.beginPath(); for(var i = 0; i < AMPLITUDE; i++) { f = i/AMPLITUDE; rd = (1 - f)*DOT_RADIUS; r = BASE_RADIUS + AMPLITUDE*sin( t/ts + this.angle*N_ANI_LOOPS - K*f*PI ); x = ~~(r*cos(this.angle)); y = ~~(r*sin(this.angle)); ctx.moveTo(x + rd, y); ctx.arc(x, y, rd, 0, 2*PI); } ctx.fill(); }; }; var init = function() { var s = getComputedStyle(c); if(r_ID) { dots = []; cancelAnimationFrame(r_ID); r_ID = null; } w = c.width = ~~s.width.split('px')[0]; h = c.height = ~~s.height.split('px')[0]; ctx.translate(~~(w/2), ~~(h/2)) for(var i = 0; i < N_DOTS; i++) { dots.push(new Dot(i)); } ani(); }; var ani = function() { ctx.clearRect(-w/2, -h/2, w, h); for(var i = 0; i < N_DOTS; i++) { dots[i].draw(ctx); } t++; r_ID = requestAnimationFrame(ani); }; setTimeout(function() { init(); addEventListener('resize', init, false); }, 15); var svg = Snap("#paper"); var circ = svg.circle(0,4,2) .attr({fill:"rgba(25,25,25,.3)"}) .pattern(0,0,8,8) .attr({patternTransform: "rotate(45)"}); svg.rect(0,0,'100%','100%').attr({fill: circ});