setup() runs once and draw() runs every frame, forming the animation loop
Every animated or interactive Processing/p5.js sketch is built on two lifecycle functions. setup() runs exactly once at startup: it initialises the canvas (size()/createCanvas()), frame rate, fonts, images, and one-time state. draw() then runs repeatedly — once per frame, by default around 60 frames per second — advancing state and rendering. This loop is what makes animation and real-time work possible: updating a coordinate between frames produces motion, and calling background() inside draw() clears the previous frame so motion doesn’t smear. Putting drawing code only in setup() yields a static image. Two common mistakes: (1) declaring a variable that must persist across frames inside draw(), which resets it every frame — such variables must be global, outside both functions; (2) omitting draw() when mouse/keyboard events are needed — events are only detected while the sketch is looping, so an empty draw(){} is required even with no animation. If a sketch only draws one static frame, draw() can be omitted entirely.
Examples
float y = 0.0; void setup() { size(100,100); } void draw() { background(204); ellipse(50, y, 70, 70); y += 0.5; if (y > 150) y = -50.0; }
// p5.js — circle follows mouse each frame: function setup() { createCanvas(400,400); } function draw() { background(220); circle(mouseX, mouseY, 50); }
// An empty void draw(){} is still needed so the app loops and detects mousePressed.
Assessment
Explain why a sketch that draws only in setup() still needs an empty draw() when it must detect mousePressed. Given a sketch that resets a moving shape every frame, identify the bug (variable declared inside draw()) and fix it. Predict what happens if you put background() in setup() instead of draw().