p5.js Starter Article 6

Color & Style

RGB, HSB, alpha transparency, fill, stroke, and the colour model that makes creative coding easier.

⏱ 15 min read color fill stroke HSB alpha

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 shapes
  • stroke(colour) — sets the outline colour
  • noFill() — 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 to background(). 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 palettes
  • fill(), stroke(), noFill(), noStroke() control how shapes look
  • background() fills the entire canvas — call it at the top of draw() to clear each frame
  • lerpColor() smoothly blends between two colours
  • Store colours in variables using color()