let radiusFunc, ringFunc, thickFunc, ring0;
createCanvas(windowWidth, windowHeight);
function mouseClicked() {
let R = min(width, height);
let ringRatio = (2 * R / ring0 - 1) ** (1 / nrings);
radiusFunc = (i) => ring0 * (ringRatio ** i);
ringFunc = (r) => log(r / ring0) / log(ringRatio);
thickFunc = (i) => (radiusFunc(i + 1) - radiusFunc(i)) * 0.90;
let dring = (min(width, height) * 0.9) / (nrings + 1);
for (let i = 0; i < nrings; i++) {
let n = perimeter / segSize;
let gapAng = gap / perimeter * TAU;
let offset = random(TAU);
let angVel = random(radians(0.1), radians(0.2));
for (let ang of randomPartition(TAU, dang)) {
amax: angTotal + ang - gapAng,
function randomPartition(val = 1, minSize = 0.1, variation = 0.1) {
const partition = (val) => {
let d = 0.5 + random(-variation, variation);
if (min(val0, val1) >= minSize) return [...partition(val0), ...partition(val1)]
translate(width / 2, height / 2);
for (let brick of bricks) {
brick.offset += brick.angVel;
strokeWeight(brick.dr * 0.8);
if (brick.status === 'static' &&
falling.length < maxfalling) {
brick.status = 'falling';
if (brick.status == 'static')
arc(0,0, brick.r * 2, brick.r * 2,
brick.amin + brick.offset, brick.amax + brick.offset, OPEN,10)
for (let brick of falling) {
brick.r += brick.rincrement;
if (brick.r >= ring0) nextFalling.push(brick);
strokeWeight(thickFunc(ringFunc(brick.r)) * 0.8);
if (brick.status == 'falling') {
arc(0,0, brick.r * 2, brick.r * 2,
brick.amin + brick.offset, brick.amax + brick.offset, OPEN, 10);
brick.offset += brick.angVel;