Genuary 2026.03: Fibonacci forever

3) Fibonacci forever

Fibonacci

This is entirely based around this Fibonacci generator function:

function makeFibber(maxValue = 1000) {
  let a = 1;
  let b = 1;
  return () => {
    let n = a + b;
    a = b;
    b = n;
    if (b > maxValue) {
      a = 1;
      b = 1;
    }
    return a;
  };
}

Make a fibber and then just keep calling it for next values.

All sorts of exciting options here!


let gui;
let params = {
  gridWidth: 10, gridWidthMin: 1, gridWidthMax: 50,
  gridHeight: 10, gridHeightMin: 1, gridHeightMax: 50,
  fibColor: true,
  fibHueStep: true,
  fibSize: true,
  fibSizeStep: true,
  circlize: true,
  enableRotation: true,
  animateScale: true,
  fibRotation: true,
  fibRadiusScale: true,
  fibPhaseOffset: true,
  persistFrames: true,
};

let hueFib, sizeFib, rotationFib, radiusFib, phaseFib;

function makeFibber(maxValue = 1000) {
  let a = 1;
  let b = 1;
  return () => {
    let n = a + b;
    a = b;
    b = n;
    if (b > maxValue) {
      a = 1;
      b = 1;
    }
    return a;
  };
}

function setup() {
  createCanvas(400, 400);
  colorMode(HSB, 360, 100, 100);
  background(0);

  gui = createGuiPanel('params');
  gui.addObject(params);
  gui.setPosition(420, 0);

  hueFib = makeFibber(360);
  sizeFib = makeFibber(100);
  rotationFib = makeFibber(360);
  radiusFib = makeFibber(50);
  phaseFib = makeFibber(10);
}

function draw() {
  if (!params.persistFrames) {
    background(0, 0, 0);
  }

  let centerX = width / 2;
  let centerY = height / 2;

  let w = width / params.gridWidth;
  let h = height / params.gridHeight;

  for (let gridY = 0; gridY < params.gridHeight; gridY++) {
    for (let gridX = 0; gridX < params.gridWidth; gridX++) {
      let x = gridX * w + w / 2;
      let y = gridY * h + h / 2;

      if (params.circlize) {
        let index = gridY * params.gridWidth + gridX;
        let angle = index * 137.5;
        let radius = sqrt(index) * (params.fibRadiusScale ? radiusFib() : width / 20);
        x = centerX + radius * cos(radians(angle));
        y = centerY + radius * sin(radians(angle));
      }

      if (params.enableRotation) {
        let dx = x - centerX;
        let dy = y - centerY;
        let r = sqrt(dx*dx + dy*dy);
        let theta = atan2(dy, dx);
        let rot = params.fibRotation ? radians(rotationFib() % 360) * 0.01 : 0.01;
        theta += rot + frameCount * 0.01;
        x = centerX + r * cos(theta);
        y = centerY + r * sin(theta);
      }

      let diameter = params.fibSize ? sizeFib() % w : w * 0.8;
      if (params.fibSizeStep && params.animateScale) {
        let phase = params.fibPhaseOffset ? phaseFib() % 10 : 0;
        diameter *= 0.5 + 0.5 * sin(frameCount / 20 + (gridX + gridY + phase) / 2);
      }

      let hue;
      if (params.fibColor) {
        hue = hueFib();
        if (params.fibHueStep) hue += frameCount;
      } else {
        hue = (x + y) % 360;
      }

      fill(hue % 360, 100, 100);
      noStroke();
      ellipse(x, y, diameter, diameter);
    }
  }
}