home/ modules/ first-sketches-p5-processing-core

First sketches: the p5.js/Processing drawing core

  • learner can structure a sketch with setup/draw, coordinate system, and primitive shapes with fill/stroke state
  • learner can drive repetition and branching with variables, for-loops, and if-else conditionals
  • learner can specify colour in RGB and map values between ranges to parameterise a drawing

Build an animated generative composition from scratch that loops shapes across a coordinate grid, uses variables and conditionals to vary them, and colours them via map()-driven RGB — running smoothly in the draw loop.

This module is where visuals for a live set stop being someone else’s demo and become something you can build on a blank canvas. In an audio-visual live-coding rig, p5.js or Processing is typically the projection layer: a sketch running fullscreen next to your sound engine, redrawing sixty times a second, its parameters ready to be wired to amplitude or MIDI later. Before any of that reactivity is possible, you need the drawing core — and that is the whole task here: an animated generative composition that fills the screen, varies itself, and never freezes the frame loop.

The arc starts fully supported. First exercises are static: place primitives on the canvas using the top-left-origin coordinate system, styling them with fill/stroke state (“Processing separates fill, stroke, and strokeWeight into independent state settings” is your JIT pointer when a shape inherits the wrong colour). Then motion enters via the two lifecycle functions — “setup() runs once and draw() runs every frame” — and a single variable nudged each frame. From there, scaffolding drops away: a for-loop turns one shape into a grid, conditionals make cells diverge, and “p5.js map() rescales a value from one numeric range into another” converts loop counters into RGB channels.

The required atoms gate the capstone directly: without setup/draw there is no animation, without loops no grid, without map() no parameterised colour. Supporting atoms enrich rather than gate — the frame-loop procedure atom deepens the same setup/draw material with frameRate() and trail effects, variable scope explains the classic frozen-animation bug, HSB colour modes and custom functions point toward cleaner, more expressive sketches, and the abstraction principle frames why one call can draw so much.

Walkthrough

p5.js is the other visual paradigm: where Hydra is signal-flow, p5 is imperative drawing — you place shapes, frame by frame. Paste each sketch into the p5 web editor and press Run (▶). Each step is a complete, standalone sketch.

1 — setup() and draw(). The two lifecycle functions: setup() runs once (make the canvas), draw() runs ~60×/second (paint a frame). background() clears each frame; coordinates start at the top-left, y going down ([[processing-setup-draw-loop]], [[processing-coordinate-system]]).

function setup() {
  createCanvas(400, 400);
}
function draw() {
  background(20);
  noStroke();
  fill(255, 140, 0);
  ellipse(200, 200, 120, 120);
}

2 — shapes and fill/stroke state. fill, stroke, and strokeWeight are sticky state — every shape after a fill() uses it until you change it (the classic “why is my circle the wrong colour?” bug). Place a couple of primitives and style them independently ([[processing-shape-primitives]], [[processing-stroke-fill-attributes]]).

function setup() { createCanvas(400, 400); }
function draw() {
  background(20);
  noStroke();
  fill(80, 180, 255);
  rect(60, 60, 120, 120);
  stroke(255);
  strokeWeight(3);
  fill(255, 90, 120);
  ellipse(280, 280, 120, 120);
}

3 — motion from a variable. Declare a variable outside draw(), nudge it each frame, and the shape moves. A faint background alpha leaves trails. This is animation: state that persists across frames ([[processing-variables-data-types]], [[processing-frame-loop]]).

let x = 0;
function setup() { createCanvas(400, 400); }
function draw() {
  background(20, 40);
  noStroke();
  fill(255, 140, 0);
  ellipse(x, 200, 40, 40);
  x = x + 3;
  if (x > width) x = 0;
}

4 — a for-loop makes a grid. One shape becomes many. Nested for loops walk x and y across the canvas, drawing a shape at each cell — a whole composition from four lines ([[processing-for-loop]]).

function setup() { createCanvas(400, 400); }
function draw() {
  background(20);
  noStroke();
  fill(120, 200, 255);
  for (let gx = 40; gx < width; gx += 60) {
    for (let gy = 40; gy < height; gy += 60) {
      ellipse(gx, gy, 30, 30);
    }
  }
}

5 — conditionals make cells diverge. An if / else on each cell’s position breaks the uniform grid — some cells become squares, some circles. Rule-driven variation is the seed of generative art ([[processing-if-else-conditionals]]).

function setup() { createCanvas(400, 400); }
function draw() {
  background(20);
  noStroke();
  for (let gx = 40; gx < width; gx += 60) {
    for (let gy = 40; gy < height; gy += 60) {
      if ((gx + gy) % 120 === 40) {
        fill(255, 90, 120);
        rect(gx - 15, gy - 15, 30, 30);
      } else {
        fill(120, 200, 255);
        ellipse(gx, gy, 30, 30);
      }
    }
  }
}

6 — map() for colour, animated (the capstone). map(v, a, b, c, d) rescales a value from one range to another — here a cell’s x/y into RGB channels, so the grid becomes a colour field. Drive size with sin(frameCount) and it breathes. This is the animated generative composition the capstone asks for ([[processing-rgb-color]], [[p5js-map-function]]):

function setup() { createCanvas(400, 400); }
function draw() {
  background(15);
  noStroke();
  for (let gx = 40; gx < width; gx += 50) {
    for (let gy = 40; gy < height; gy += 50) {
      let r = map(gx, 0, width, 40, 255);
      let b = map(gy, 0, height, 40, 255);
      let s = 20 + 15 * sin(frameCount * 0.05 + gx * 0.02);
      fill(r, 90, b);
      ellipse(gx, gy, s, s);
    }
  }
}

What good looks like. A composition with a clear structure (the grid), an intentional colour relationship (the map() gradient, not random per-cell noise), and motion you can follow (the gentle sin breathing, not chaos). If it looks flat, widen the colour range or add a second varying channel; if it looks busy, slow the animation or reduce the grid density — negative space reads as intentional. (Skill map: live-visualist Domain B — composition, colour, readable motion.)

Now make it yours. Change the grid spacing (+= 50) for density. Swap ellipse for rect. Drive the green channel with sin too, for shifting colour. Make the size respond to distance from the centre with dist(gx, gy, 200, 200). Slow it all down with a smaller frameCount multiplier.

Atoms in this module

Required — these gate the capstone

setup() runs once and draw() runs every frame, forming the animation loop
Concept L1 Foundations H
The Processing/p5.js canvas places the origin at the top-left with y increasing downward
Concept L1 Foundations H
Processing provides point, line, rect, ellipse, and bezier as core drawing primitives
Fact L1 Foundations H
Processing separates fill, stroke, and strokeWeight into independent state settings
Concept L1 Foundations H
Processing requires explicit data types — int, float, and boolean serve different numeric purposes
Concept L1 Foundations H
A for loop repeats a code block under init, test, and update, turning one drawing procedure into a whole pattern
Concept L1 Foundations H
Processing's if-else structures let programs branch based on relational expressions
Concept L1 Foundations H
Processing specifies colour as additive RGB values (0–255 per channel) with an optional alpha channel
Concept L1 Foundations H
p5.js map() rescales a value from one numeric range into another
Concept L1 Foundations H

Supporting — enrichment, not gating

Processing's setup() runs once and draw() repeats each frame to create animation
Procedure L2 First instrument H
Abstraction hides implementation details so programmers focus on what code does, not how
Concept L1 Foundations H
Where a variable is declared determines its scope: outside functions is global, inside is local
Concept L1 Foundations H
p5.js accepts colors as a grayscale number, an RGB triple, or a CSS color-name string
Concept L1 Foundations H
Processing maintains drawing style state until explicitly changed
Concept L2 First instrument H
Custom functions in Processing encapsulate reusable code blocks with parameters and return values
Concept L2 First instrument H