<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1650 1170" width="1650" height="1170" version="1.1" >
  <!-- 
    Johan Karlsson, 2020
    https://twitter.com/DonKarlssonSan 
  -->
</svg>
body, html {
  margin: 0;
  background-color: #223;
  cursor: pointer;
}

svg {
  position: absolute;
  width: 100%;
  height: 100%;
}
/*
  Johan Karlsson, 2020
  https://twitter.com/DonKarlssonSan
  MIT License, see Details View
*/

class Circle {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.r = 10;
    this.done = false;
  }
  
  draw(groupElement) {
    this.drawCircle(groupElement, this.x, this.y, this.r * 0.92);
    
    let d = mouseVector.sub(new Vector(this.x, this.y));
    // Where's Waldo? 😉
    let direction = Math.random() > 0.95 ? -1 : 1;
    let p = d.div(d.getLength()).mult(this.r * 0.31 * direction);
    
    this.drawCircle(groupElement, this.x + p.x, this.y + p.y, this.r * 0.6);

    p.multTo(2);
    
    this.drawCircle(groupElement, this.x + p.x, this.y + p.y, this.r * 0.3);
  }
  
  drawCircle(groupElement, x, y, r) {
    let circle = createSvgElement("circle");
    circle.setAttribute("cx", x);
    circle.setAttribute("cy", y);
    circle.setAttribute("r", r);
    groupElement.appendChild(circle);
  }
}

let svg;
let w = 1650;
let h = 1170;
let margin = 0.15;
let circles;
let mouseVector;

function setup() {
  svg = document.querySelector("svg");
  svg.addEventListener("mousemove", mousemove);
  document.addEventListener("click", draw);
  document.addEventListener("keydown", onKeyDown);
}

function onKeyDown (e) {
  if(e.code === "KeyD") {
    download();
  }
}

function download() {
  let svgDoc = svg.outerHTML;
  let filename = `big-brother.svg`;
  let element = document.createElement("a");
  element.setAttribute("href", "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svgDoc));
  element.setAttribute("download", filename);
  element.style.display = "none";
  document.body.appendChild(element);
  element.addEventListener("click", e => e.stopPropagation());
  element.click();
  document.body.removeChild(element);
}

function dist(x1, y1, x2, y2) {
  return Math.hypot(x1 - x2, y1 - y2);
}

function addCircles() {
  let nrOfTries = 0;
  let wasAdded;
  do {
    wasAdded = false;
    let x = (1 - margin * 2) * Math.random() * w + w * margin;
    let y = (1 - margin * 2) * Math.random() * h + h * margin;
    if(validPos(x, y)) {
      wasAdded = true;
      let c = new Circle(x, y);
      circles.push(c);
    }
    nrOfTries++;
  } while (!wasAdded && nrOfTries < 50)
}

function validPos(x, y) {
  for(let i = 0; i < circles.length; i++) {
    let current = circles[i];
    let d = dist(x, y, current.x, current.y);
    if(d - 10 < current.r) {
      return false;
    }
  }
  return true;
}

function canGrow(circle) {
  if(circle.x - circle.r < w * margin) return false;
  if(circle.y + circle.r > h * (1 - margin)) return false;
  for(let i = 0; i < circles.length; i++) {
    let current = circles[i];
    if(circle !== current) {
      let d = dist(circle.x, circle.y, current.x, current.y);
      if(d - 4 <= circle.r + current.r) {
        return false;
      } 
    }
  }
  return true;
}

function resetCircles() {
  circles = [];
}
  
function packCircles() {
  let nrOfTries = w * h / 400;
  for(let i = 0; i < nrOfTries; i++) {
    if(i % 2 === 0) {
      addCircles();
    }
    circles.filter(c => !c.done).forEach(c => {
      if(canGrow(c)) {
        c.r += 2;
      } else {
        c.done = true;
      }
    });
  }
}
  
function drawCircles(groupElement) {
  circles.forEach(c => c.draw(groupElement));
}
  
function draw() {
  console.clear();
  
  mouseVector = new Vector((1 - margin * 2) * w * Math.random(), (1 - margin * 2) * h * Math.random());

  let group = document.querySelector("#container");
  if (group) {
    group.remove();
  }
  group = createSvgElement("g");
  group.setAttribute("id", "container");
  group.setAttribute("fill", "none");
  group.setAttribute("stroke", "white");
  group.setAttribute("stroke-linecap", "round");
  group.setAttribute("stroke-linejoin", "round");
  
  resetCircles();
  packCircles();
  drawCircles(group);

  let logo = new Logo(w * 0.89, h * 0.92, "white");
  logo.draw(group);

  svg.appendChild(group);
}
  
function mousemove(event) {
  mouseVector.x = event.clientX;
  mouseVector.y = event.clientY;
}

function createSvgElement(elementName) {
  const svgNs = "http://www.w3.org/2000/svg";
  return document.createElementNS(svgNs, elementName);
}

setup();
draw();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://codepen.io/DonKarlssonSan/pen/JreEJO.js
  2. https://codepen.io/DonKarlssonSan/pen/yLOxWGB.js