Learn Creative Coding Series):If sin/cos are the heartbeat of creative coding, randomness is the soul.
Every generative artwork uses randomness in some form. It's what makes each execution unique. It's what gives that "I couldn't have designed this by hand" quality. But not all randomness is created equal - and knowing which kind to use changes everything.
You've already seen random(). It gives you a uniformly distributed random number:
random(); // between 0 and 1
random(10); // between 0 and 10
random(5, 15); // between 5 and 15
Each call is completely independent. There's no relationship between one call and the next. It's like rolling a die - every roll is fresh.
function setup() {
createCanvas(500, 400);
background(20);
noStroke();
for (let x = 0; x < width; x += 4) {
let h = random(50, 350);
fill(random(150, 255), 80, random(100, 200), 150);
rect(x, height - h, 3, h);
}
}
Bars of random height and color. Every run looks different. But also... kind of chaotic? There's no flow to it. Each bar has no relationship to its neighbors. This is where noise comes in.
noise() is Perlin noise. Ken Perlin invented it in 1983 for the movie Tron, and it changed computer graphics forever.
The key difference: noise() gives you random-looking values that change smoothly. Nearby inputs produce nearby outputs. Think of it as randomness with memory.
function setup() {
createCanvas(500, 400);
background(20);
noStroke();
for (let x = 0; x < width; x += 4) {
let n = noise(x * 0.01); // input changes slowly
let h = n * 350;
fill(n * 255, 80, 200 - n * 150, 150);
rect(x, height - h, 3, h);
}
}
Same concept - bars of varying height. But now they form a smooth landscape instead of jagged chaos. The bars next to each other have similar heights because their noise inputs (x * 0.01) are close together.
That 0.01 multiplier is crucial. It controls the "zoom level" of the noise:
Try changing it and see what happens. This parameter is sometimes called the frequency of the noise.
noise() can take up to three inputs. With two inputs, you get a 2D noise field - perfect for texture:
function setup() {
createCanvas(400, 400);
loadPixels();
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
let n = noise(x * 0.02, y * 0.02);
let c = n * 255;
let index = (x + y * width) * 4;
pixels[index] = c;
pixels[index + 1] = c;
pixels[index + 2] = c;
pixels[index + 3] = 255;
}
}
updatePixels();
}
This generates a cloud-like texture. Every pixel's brightness is determined by 2D Perlin noise. It looks like smoke, marble, terrain - organic stuff that's hard to create any other way.
Add frameCount as a third dimension and the noise field starts to animate:
function setup() {
createCanvas(400, 400);
}
function draw() {
background(20);
noStroke();
for (let x = 0; x < width; x += 10) {
for (let y = 0; y < height; y += 10) {
let n = noise(x * 0.02, y * 0.02, frameCount * 0.01);
fill(n * 255, 80, 200, n * 200);
ellipse(x, y, n * 12, n * 12);
}
}
}
A grid of circles that pulse and shimmer. The time dimension makes the noise field evolve smoothly - every dot is connected to its neighbors in space AND in time.
Raw randomness is rarely what you want. The art is in constraining it. Here are some techniques I use all the time.
Instead of random RGB values (which usually look muddy), pick from a curated palette:
let palette = ['#264653', '#2a9d8f', '#e9c46a', '#f4a261', '#e76f51'];
function setup() {
createCanvas(500, 500);
background(245);
noStroke();
for (let i = 0; i < 200; i++) {
let c = random(palette); // pick a random color from the array
fill(c);
let size = random(10, 60);
ellipse(random(width), random(height), size, size);
}
}
Same random placement, but the colors always harmonize because you curated the palette. This is one of the simplest ways to make generative art look intentional.
randomGaussian() gives you values clustered around a center, with a bell curve distribution. Most values are close to the center, a few are far out.
function setup() {
createCanvas(500, 500);
background(20);
noStroke();
fill(255, 100, 150, 30);
for (let i = 0; i < 5000; i++) {
let x = 250 + randomGaussian() * 60;
let y = 250 + randomGaussian() * 60;
ellipse(x, y, 4, 4);
}
}
Five thousand dots, but they cluster naturally around the center instead of filling the canvas evenly. This looks way more organic than uniform random().
Sometimes you want one outcome to be more likely than another:
function weightedChoice() {
let r = random();
if (r < 0.6) return 'small'; // 60% chance
if (r < 0.9) return 'medium'; // 30% chance
return 'large'; // 10% chance
}
This is how generative NFT projects create rarity tiers - common traits, rare traits, legendary traits. Same principle.
One of my favorite techniques: use noise to drive hue in HSB mode.
function setup() {
createCanvas(500, 500);
colorMode(HSB, 360, 100, 100, 100);
background(0, 0, 10);
noStroke();
for (let i = 0; i < 3000; i++) {
let x = random(width);
let y = random(height);
let hue = noise(x * 0.005, y * 0.005) * 360;
let sat = 60 + noise(x * 0.01, y * 0.01) * 40;
fill(hue, sat, 80, 20);
ellipse(x, y, random(3, 12), random(3, 12));
}
}
The hue changes smoothly across the canvas because of noise, creating natural-looking color regions. Neighboring dots have similar hues. The result looks like a nebula or a watercolor wash.
Quick note on colorMode(HSB): it switches from Red-Green-Blue to Hue-Saturation-Brightness. Way more intuitive for creative work. We'll go deep on color theory in a few episodes.
| Use case | random() | noise() |
|---|---|---|
| Position scatter | Uniform spread | Clustered, flowing |
| Size variation | Jumpy, independent | Smooth transitions |
| Color | Independent per element | Smooth gradients across space |
| Animation | Jittery, flickering | Smooth, organic |
| Terrain/landscape | Never | Always |
| Shuffling/picking | Always | Never |
My rule: if things should relate to their neighbors (in space or time), use noise. If things should be independent, use random. Most generative art uses both.
random() = independent dice rolls, uniform distributionnoise() = Perlin noise, smooth, nearby inputs give nearby outputs* 0.01) controls noise smoothnessnoise() works in 1D, 2D, and 3D (space + time)colorMode(HSB) + noise = beautiful color fieldsNext episode we're doing loops and grids. Takes these randomness techniques and multiplies them by a hundred. Literally - nested for-loops are where generative art really starts to shine.
't Was plezant - tot de volgende keer!
X