Source code of plot #062 back to plot

Download full working sketch as 062.tar.gz.
Unzip, then start a local web server and load the page in a browser.

import * as E from "./lib/env.js"
import {caption} from "./lib/own/caption.js"
import * as G from "./lib/own/geo2.js"

// Sketch based on Zellyn's precise recreation of Georg Nees's Schotter
// https://zellyn.com/2024/06/schotter-2/

// Declarations below instruct build plugin to copy static files to runtime dir
// STATIC lib/texture.png

const w = 1480;    // Drawing width
const h = 2100;    // Drawing height
const margin = 200;

const s1 = 1922110153;
const s2 = 1769133315;
const xCount = 12;
const yCount = 22;

void setup();

async function setup() {
  E.initEnv(w, h);
  await draw();
}

async function draw() {

  await caption(w, h, "schotter via zellyn", "117");

  const r1 = new Random(s1);
  const r2 = new Random(s2);

  const sz = Math.min((h - 2*margin) / yCount, (w - 2*margin) / xCount);
  const top = (h-sz*yCount) / 2;
  const left = (w-sz*xCount) / 2;

  let cnt = 0;
  for (let y = top, i = 0; i < yCount; ++i, y += sz) {
    for (let x = left, j = 0; j < xCount; ++j, ++cnt, x += sz) {
      drawSquare(x, y, sz, cnt, r1, r2);
    }
  }
}

function drawSquare(x, y, sz, i, r1, r2) {

  sz *= 0.5;
  const r = sz * Math.SQRT2;
  const moveLimit = sz * i / 264;
  const twistLimit = Math.PI / 4 * i / 264;

  const yCenter = y + sz + r1.next(-moveLimit, moveLimit);
  const xCenter = x + sz + r1.next(-moveLimit, moveLimit);
  let angle = r2.next(Math.PI / 4 - twistLimit, Math.PI / 4 + twistLimit);

  const pts = [];
  for (let step = 0; step < 4; ++step) {
    pts.push(new G.Vec2(xCenter + r * Math.sin(angle), yCenter + r * Math.cos(angle)));
    angle += Math.PI / 2;
  }
  E.addPath(pts, true);
}

class Random {
  constructor(i) {
    this.i = i;
  }
  next(min, max) {
    this.i = (this.i * 5) % 2147483648;
    return this.i / 2147483648 * (max-min) + min;
  }
}