SOURCE

console 命令行工具 X clear

                    
>
console
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

'floor|random|round|abs|sqrt|PI|atan2|sin|cos|pow|max|min'
  .split('|')
  .forEach(function(p) { window[p] = Math[p]; });

var TAU = PI*2;

function r(n) { return random()*n; }
function rrng(lo, hi) { return lo + r(hi-lo); }
function rint(lo, hi) { return lo + floor(r(hi - lo + 1)); }
function choose() { return arguments[rint(0, arguments.length-1)]; }
function choose1(args) { return args[~~r(args.length)]; }

/*---------------------------------------------------------------------------*/

var W, H, frame, time;
var DPR = devicePixelRatio || 1;

function dpr(n) { return n * DPR; }

function resize() {
  var w = innerWidth;
  var h = innerHeight;
  
  canvas.style.width = w+'px';
  canvas.style.height = h+'px';
  
  W = canvas.width = w * DPR;
  H = canvas.height = h * DPR;
}

function loop(t) {
  frame = requestAnimationFrame(loop);
  draw();
  time++;
}

function pause() {
  cancelAnimationFrame(frame);
  frame = frame ? null : requestAnimationFrame(loop);
}

function reset() {
  cancelAnimationFrame(frame);
  resize();
  ctx.clearRect(0, 0, W, H);
  init();
  time = 0;
  frame = requestAnimationFrame(loop);
}

/*---------------------------------------------------------------------------*/

function Point(a, r) {
  this.a = a;
  this.r = r;
}

Object.defineProperties(Point.prototype, {
  x: { get: function() { return this.r * cos(this.a); }},
  y: { get: function() { return this.r * sin(this.a); }}
});

function Blob(a, r, rr) {
  Point.call(this, a, r);
  this.rr = rr;
}

Blob.prototype = Object.create(Point.prototype);

Blob.prototype.contains = function(p) {
  var x = this.x;
  var y = this.y;
  
  return Math.hypot(x - p.x, y - p.y) <= this.rr;
};

function Thing(n, r) {
  this.n = n;
  this.points = new Array(n);
  this.blobs = [];
  for (var i = 0; i < n ; i++) {
    this.points[i] = new Point(TAU * i / n, r);
  }
}

Thing.prototype.draw = function() {
  var p = this.points[0];
  ctx.beginPath();
  ctx.moveTo(p.x, p.y);
  for (var i = 1; i < this.n; i++) {
    p = this.points[i];
    ctx.lineTo(p.x, p.y);
  }
  ctx.closePath();
  ctx.stroke();
};

Thing.prototype.grow = function(factor) {
  for (var i = 0; i < this.n; i++) {
    var p = this.points[i];
    p.r += factor;
  }
  
  for (var i = 1; i < this.n - 1; i++) {
    var a = this.points[i-1];
    var b = this.points[i];
    var c = this.points[i+1];
    b.r = (a.r + 3*b.r + c.r) / 5;    
  }
  
  
  var a = this.points[this.n - 1];
  var b = this.points[0];
  var c = this.points[1];
  var d = this.points[this.n - 2];
  b.r = (a.r + 3*b.r + c.r) / 5;  
  a.r = (d.r + 3*a.r + b.r) / 5;
  
};

Thing.prototype.addBlob = function(a, r) {
  var nearestIndex = floor(this.n * a / TAU) % this.n;
  var nearest = this.points[nearestIndex];
  this.blobs.push(new Blob(nearest.a, nearest.r - r/2, r));
};

Thing.prototype.growBlobs = function(factor) {
  var didGrow = false;
  if (this.blobs.length === 0) return false;
  
  for (var i = this.blobs.length - 1; i >= 0; i--) {
    var blob = this.blobs[i];
    var grown = false;
    for (var j = 0; j < this.n; j++) {
      var p = this.points[j];
      if (blob.contains(p)) {
        p.r += factor;
        grown = didGrow = true
      }
    }
    if (!grown) {
      this.blobs.splice(i, 1);
    }
  }
  
  return didGrow;
};

/*---------------------------------------------------------------------------*/

var thing;
var paint = false;

function init() {
  ctx.translate(W/2, H/2);

  thing = new Thing(1000, dpr(20));
  thing.addBlob(r(TAU), dpr(10));
}

var N = 0;

function draw() {
  var factor = dpr(0.5);
  var blobbing = false;
  
  if (thing.blobs.length) {
    thing.growBlobs(factor);
    blobbing = thing.blobs.length !== 0;
    if (!blobbing) {
      time = 0;
      paint = true;
      N++;
    }
  }
  
  if (blobbing) {
    thing.draw();
    return;
  }
  
  thing.grow(factor);
  
  if (time && (time % 5 === 0) && (time % 10 !== 0)) {
    paint = !paint;
  }
  
  if (paint && time && (time % 10 === 0)) {
    var n = rint(1, N);
    while (n--) {
      var theta = r(TAU);
      thing.addBlob(theta, dpr(10));
    }
  }
  
  if (paint) thing.draw();

 

}

/*---------------------------------------------------------------------------*/

document.onclick = pause;
document.ondblclick = reset;

reset();
<canvas id="canvas"></canvas>
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}