<!DOCTYPE html>
<html lang="en-us">
<head>
  <meta charset="utf-8">
  <meta name="robots" content="noindex">
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
  <title>Poi Bounce</title>
  <style>
    html, body {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: #222;
    }
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.10.0/p5.js"></script>
<!--
  © Adam Murray 2025
  https://adammurray.link/

  Creative Commons License
  Attribution-NonCommercial-ShareAlike 4.0 International
  https://creativecommons.org/licenses/by-nc-sa/4.0/
-->
<script>
let balls = [];
let increment = 0.035;
let zoff = 0.0;
let zincrement = 0.01;

function setup() {
  const dim = Math.min(Math.min(600, windowWidth), windowHeight) - 60;
  createCanvas(dim, dim).parent("processing-canvas");
  strokeWeight(2);
  smooth();
  background(0);
  for (let i = 0; i < 20; i++) {
    balls[i] = new BouncingBall();
  }
}

function draw() {
  drawBackground();

  // the ground:
  stroke(0, 100, 0);
  strokeWeight(20);
  line(0, height - 1, width, height - 1);

  stroke(255, 120, 0, 70);
  strokeWeight(1);
  for (let i = 0; i < balls.length; i++) {
    balls[i].draw();
  }
}

function drawBackground() {
  noStroke();
  let xoff = 0.0; // Start xoff at 0
  const xinc = random(7.0) + 13;
  const yinc = random(4.0) + 14;
  for (let x = -20; x < width; x += xinc) {
    xoff += increment;
    let yoff = 0.0;
    for (let y = -20; y < height; y += yinc) {
      yoff += increment;
      const b = noise(xoff, yoff, zoff) * 255;
      const r = noise(xoff, yoff, zoff * 2) * 100;
      fill(r, 0, b, 90);
      rect(x, y, 14, 17);
    }
  }
  zoff += zincrement;
}

class BouncingBall {
  // float x, y;
  // float v, a; // velocity and acceleration
  // int d; // ball diameter
  // boolean stopped;
  // int alpha;
  // int gcolor;
  // int bcolor;

  constructor() {
    this.v = 0; // velocity
    this.a = 0.8; // acceleration
    this.d = 25; // ball diameter
    this.init();
    // create a random delay for the initial drop:
    this.stopped = true;
    this.alpha = int(random(255));
  }

  init() {
    this.x = random(width);
    this.y = -2 * this.d;
    this.stopped = false;
    this.alpha = 235;
    this.gcolor = int(random(170) + 70);
    this.bcolor = int(random(170) + 70);
  }

  draw() {
    fill(240, this.gcolor, this.bcolor, this.alpha);
    ellipse(this.x, this.y, this.d, this.d);
    this.update();
  }

  update() {
    if (this.stopped) {
      if (this.alpha > 0) {
        this.alpha--;
        return;
      }
      this.init();
    }
    this.y += this.v;
    this.x += random(1.0) - 0.5;
    this.v += this.a;
    if (this.y > height - this.d) {
      this.v -= random(3.0) + this.v / 5.0;
      if (this.v < 0) {
        this.stopped = true;
      }
      this.v *= -1;
      this.y = height - this.d;
    }
  }
}
</script>
</head>
<body>  
  <div id="processing-canvas"></div>
</body>
</html>