Color & Style
RGB, HSB, alpha transparency, fill, stroke, and the colour model that makes creative coding easier.
How p5.js represents colour
p5.js supports multiple ways to specify a colour. The default is RGB (Red, Green, Blue), but HSB (Hue, Saturation, Brightness) is often far more useful for creative work.
RGB mode
Each channel is 0–255:
fill(255, 0, 0); // pure red
fill(0, 255, 0); // pure green
fill(0, 0, 255); // pure blue
fill(255, 255, 0); // yellow
fill(128, 0, 255); // purple
fill(0); // black (single value = grey)
fill(255); // white
fill(128); // mid grey
Alpha (transparency)
Add a fourth argument for transparency — 0 is fully transparent, 255 is fully opaque:
fill(255, 100, 50, 100); // orange, ~40% transparent
fill(0, 0, 0, 50); // dark overlay, mostly transparent
Hex colours
You can use CSS hex strings:
fill('#ff6432');
fill('#3b82f6');
background('#0d0d14');
Named colours
CSS colour names also work:
fill('coral');
fill('steelblue');
fill('limegreen');
Switching to HSB mode
HSB is often the better choice for creative coding because:
- Hue controls what colour (0–360, cycling through the spectrum)
- Saturation controls how vivid (0 = grey, 100 = full colour)
- Brightness controls how dark or light (0 = black, 100 = full brightness)
This makes it easy to cycle through colours, fade things in/out, and create harmonious palettes.
To enable HSB, call colorMode() in setup():
function setup() {
createCanvas(600, 400);
colorMode(HSB, 360, 100, 100, 100);
// Arguments: mode, hue range, sat range, bri range, alpha range
}
Now colour values work differently:
fill(0, 100, 100); // pure red
fill(120, 100, 100); // pure green
fill(240, 100, 100); // pure blue
fill(60, 100, 100); // yellow
fill(0, 0, 100); // white (no saturation)
fill(0, 0, 0); // black
fill(200, 60, 80); // soft blue
Rainbow animation using HSB — impossible to do as cleanly in RGB:
function setup() {
createCanvas(600, 100);
colorMode(HSB, 360, 100, 100);
noStroke();
}
function draw() {
for (let x = 0; x < width; x++) {
let hue = map(x, 0, width, 0, 360);
fill(hue, 90, 90);
rect(x, 0, 1, height);
}
}
Cycling hue over time:
function draw() {
background(0, 0, 10);
let hue = (frameCount * 0.5) % 360;
fill(hue, 80, 95);
circle(width / 2, height / 2, 200);
}
fill() and stroke()
fill(colour)— sets the fill colour for shapesstroke(colour)— sets the outline colournoFill()— shapes have no fill (transparent)noStroke()— shapes have no outline
// Filled circle, no outline
fill(200, 50, 255);
noStroke();
circle(200, 200, 100);
// Outline only, no fill
noFill();
stroke(200, 50, 255);
strokeWeight(3);
circle(400, 200, 100);
background()
background() accepts the same colour arguments as fill():
background(20); // dark grey
background(20, 30, 60); // dark navy
background('#1a1a2e'); // hex
background(0, 0, 10); // near-black in HSB
Fading trick: call background with a low alpha value to leave a ghostly trail instead of clearing completely:
function draw() {
background(20, 20, 20, 20); // note: requires alpha support
// ...
}
In RGB mode with
colorMode(RGB, 255, 255, 255, 255)you can pass alpha tobackground(). Without explicitly setting the alpha range this may not work on all platforms — test it.
The color() object
Store colours in variables using color():
let c1 = color(255, 100, 50);
let c2 = color('#3b82f6');
fill(c1);
circle(200, 200, 80);
fill(c2);
circle(400, 200, 80);
lerpColor() — blending two colours
let from = color(255, 50, 50); // red
let to = color(50, 50, 255); // blue
for (let i = 0; i <= 10; i++) {
let inter = lerpColor(from, to, i / 10);
fill(inter);
rect(i * 50, 150, 50, 100);
}
lerpColor(c1, c2, amount) — amount 0 gives c1, amount 1 gives c2, 0.5 is halfway.
Reading colour components
If you need to extract individual channels:
let c = color(200, 50, 255);
print(red(c)); // 200
print(green(c)); // 50
print(blue(c)); // 255
print(alpha(c)); // 255 (fully opaque by default)
Key takeaways
- Default colour mode is RGB (0–255 per channel) with an optional fourth alpha value
colorMode(HSB, 360, 100, 100)switches to HSB — better for cycling, gradients, and palettesfill(),stroke(),noFill(),noStroke()control how shapes lookbackground()fills the entire canvas — call it at the top ofdraw()to clear each framelerpColor()smoothly blends between two colours- Store colours in variables using
color()