The premise of Generative Grid Art was deceptively simple: a canvas that produces an endless stream of grid compositions, no two alike. The first working version was almost unwatchable.
Too much freedom is noise
With every cell free to pick any size, rotation, and color independently, the output looked like static — technically infinite variation, visually indistinguishable frame to frame. Nothing anchored the eye.
function drawCell(ctx, cell, t) {
const wobble = noise2D(cell.x * 0.02, cell.y * 0.02 + t * 0.05);
const size = lerp(cell.minSize, cell.maxSize, wobble);
ctx.save();
ctx.translate(cell.cx, cell.cy);
ctx.rotate(wobble * Math.PI * 0.15); // constrained: max ~27°, not full rotation
ctx.fillRect(-size / 2, -size / 2, size, size);
ctx.restore();
}
The fix was fewer degrees of freedom
- Rotation capped to roughly a 27° range instead of a full circle — enough to feel alive, not enough to feel random.
- Size driven by one shared Perlin noise field sampled per-cell, rather than independent randomness — neighboring cells now visibly relate to each other.
- Color locked to a single hue family per session, varying only in lightness — the composition reads as one piece instead of confetti.
Infinite variation within a tight rule set reads as alive. Infinite variation with no rule set reads as broken.
The version that shipped runs at 60fps and never repeats exactly — but every frame it produces now visibly belongs to the same family. That's the whole trick.
