(function() {
  var canvasBody, $,
      w = window.innerWidth,
      h = window.innerHeight,
      gui = new dat.GUI(),
      stats = new Stats(),
      tick = 0,
      pi = Math.PI,
      pi2 = pi*2,
      piD2 = pi/2,
      piD3 = pi/3,
      piD6 = pi/6,
      pi2D3 = pi2/3,
      piDeg = pi/180,
      particles = [],
      canvasStyles = {
        position: "absolute",
        top: "0px",
        left: "0px",
        "background-color": "#222",
        "z-index": -1
      },
      Mouse = new Vector2(w/2, h/2),
      mousePressed = false,
      opts = {
        bgc: "#fcfcfc",
        showFPS: false,
        color: "#75b8d4",
        amount: 30,
        thickness: 5,
        radius: 12,
        rotSpeed: 0.4,
        gravity: 0.8,
        populate: function(){
            particles = [];
            for(var i =0; i < opts.amount; particles[i++]= new Shape());
            console.log(particles)
          }
      },
      Shape = function(){
        this.vertices = Math.floor(Math.random()*5);
        this.pos = new Vector2(opts.radius/2 + Math.random()*w - opts.radius, Math.random()*h - opts.radius);
        this.angle=Math.random()*180;
        this.d=Math.random()<.5?1:-1
      }; 
  Shape.prototype = {
    update: function(){
      this.pos.y-opts.radius-opts.thickness<h?(
        this.pos.y+=opts.gravity,
        this.angle+=opts.rotSpeed*this.d
        ): 
        this.pos.set(Math.random()*w, -opts.radius);
    },
    render: function(){
      if(this.vertices>0){
        $.beginPath();
        $.moveTo(Math.cos(this.angle*piDeg)*opts.radius+this.pos.x,Math.sin(this.angle*piDeg)*opts.radius+this.pos.y);
        for(var i=1; i<this.vertices;i++){
          var a = pi2/this.vertices*i;
          var aa = this.angle*piDeg;
          $.lineTo(Math.cos(a+aa)*opts.radius+this.pos.x,
                  Math.sin(a+aa)*opts.radius+this.pos.y);
        }
        $.closePath();
        $.lineCap = "round";
        $.lineJoin = "round";
        $.lineWidth = opts.thickness;
        $.strokeStyle = opts.color;
        $.stroke();
      } else {
        $.beginPath();
        $.arc(this.pos.x, this.pos.y, opts.radius, 0,pi2);
        $.closePath();
        $.lineWidth = opts.thickness;
        $.strokeStyle = opts.color;
        $.stroke();
      }
    }
  }
  function setup(){
    createCanvas();
    addListeners();
    opts.populate();
    document.body.appendChild(stats.domElement);
    
    gui.addColor(opts, "color");
    gui.add(opts, "radius", 5, 50);
    gui.add(opts, "thickness", 1, 20);
    gui.add(opts, "amount", 1, 1000).onFinishChange(opts.populate);
    gui.add(opts, "rotSpeed", 0.01, 10, 0.01);
    gui.add(opts, "gravity", 0.1, 10);
    gui.add(opts, "populate").name("respawn");
    window.requestAnimationFrame(loop);
  }
  function loop(){
    stats.begin();
    drawBg();
    particles.map(function(S){
      S.update();
      S.render();
    })
    opts.showFPS ? stats.domElement.style["display"] = "block" : stats.domElement.style["display"] = "none";
    window.requestAnimationFrame(loop);
    stats.end();
  }
  function createCanvas() {
    var el = document.createElement("canvas"),
        ctx = el.getContext("2d");
    for (var style in canvasStyles) {
      el.style[style] = canvasStyles[style];
    }
    document.body.appendChild(el);
    canvasBody = el;
    $ = ctx;
    canvasBody.width = w;
    canvasBody.height = h;
    document.body.style["overflow"] = "hidden"
    return [el, ctx];
  }
  function drawBg() {
    $.fillStyle = opts.bgc;
    $.fillRect(0, 0, w, h);
  }
  
  function addListeners(){
    window.addEventListener("resize", resize);
    window.addEventListener("mousemove", mouseMove);
    canvasBody.addEventListener("mousedown", mouseDown);
    canvasBody.addEventListener("mouseup", mouseUp);
    canvasBody.addEventListener("touchmove", touchMove);
    canvasBody.addEventListener("touchstart", touchStart);
    canvasBody.addEventListener("touchend", touchEnd);
  }
  function resize(){
    w = canvasBody.width = window.innerWidth;
    h = canvasBody.height = window.innerHeight;
  }
  function mouseDown(event){
    mousePressed = true;
    Mouse.set(event.pageX, event.pageY);
  }
  function mouseUp(event){
    mousePressed = false;
  }
  function mouseMove(event){
    Mouse.set(event.pageX, event.pageY);
  }
  function touchMove(event){
    var touches = event.changedTouches;
    Mouse.set(touches[0].pageX, touches[0].pageY);
  }
  function touchStart(event){
    e.preventDefault();
    mousePressed = true;
    touchMove(event);
  }
  function touchEnd(event){
    mousePressed = false;
  }
  setup();
})()

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://codepen.io/Godje/pen/aBbjza.js
  2. https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.1/dat.gui.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js