Learn Creative Coding (#4) - Randomness: The Secret Ingredient

What will I learn
- The difference between random() and noise();
- what Perlin noise is and why it matters;
- generating color palettes with randomness;
- controlling chaos: constrained randomness;
- when to use which type of randomness.
Requirements
- A modern web browser;
- Episodes #1-3 of this series.
Difficulty
- Beginner
Curriculum (of the Learn Creative Coding Series):
- Learn Creative Coding (#1) - What Is Creative Coding? (And Why You Should Care)
- Learn Creative Coding (#2) - Your First Sketch: Shapes, Colors, and the Canvas
- Learn Creative Coding (#3) - Movement and Time: Making Things Animate
- Learn Creative Coding (#4) - Randomness: The Secret Ingredient (this post)
Learn Creative Coding (#4) - Randomness: The Secret Ingredient
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.
random(): the dice roll
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(): the smooth alternative
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:
- Small values (0.001-0.01): very smooth, gentle hills
- Medium values (0.01-0.05): rolling landscape
- Large values (0.1-1.0): more detail, closer to random
Try changing it and see what happens. This parameter is sometimes called the frequency of the noise.
Noise in two dimensions
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.
Noise and time
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.
Constrained randomness
Raw randomness is rarely what you want. The art is in constraining it. Here are some techniques I use all the time.
Pick from a set
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.
Gaussian distribution
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().
Weighted 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.
Noise-driven color
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.
random() vs noise(): when to use which?
| 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.
Allez, wa weten we nu allemaal?
random()= independent dice rolls, uniform distributionnoise()= Perlin noise, smooth, nearby inputs give nearby outputs- The frequency parameter (that
* 0.01) controls noise smoothness noise()works in 1D, 2D, and 3D (space + time)- Constrained randomness (palettes, gaussian, weighted) looks better than raw chaos
colorMode(HSB)+ noise = beautiful color fields
Next 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
This is pure gold again Char! I am about to publish my next Python tutorial but you're already outpacing my post speed by what? 2x? 3x? 4x? LOL.
Your quality is top notch though, really insightful!
Ik ga even doortypen nog, Laterrrr..
Congratulations @femdev! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)
Your next target is to reach 40 posts.
Your next target is to reach 100 replies.
You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word
STOP