Your First Sketch
Understand setup(), draw(), and the animation loop that makes p5.js tick.
The two essential functions
Every p5.js sketch is built around two functions:
function setup() {
// Runs once when the sketch starts
}
function draw() {
// Runs repeatedly — around 60 times per second
}
That’s the whole skeleton. p5.js calls setup() once, then calls draw() over and over until you stop the sketch or close the tab.
Your first sketch — step by step
Open your environment of choice and replace whatever is there with this:
function setup() {
createCanvas(600, 400);
background(30);
}
function draw() {
fill(255, 100, 50);
noStroke();
circle(300, 200, 100);
}
Run it. You should see an orange circle on a dark background.
Let’s unpack every line.
createCanvas(600, 400)
This creates the drawing surface — 600 pixels wide, 400 pixels tall. Call this first inside setup(). You can only have one canvas per sketch (unless you’re doing advanced multi-canvas work).
background(30)
Fills the entire canvas with a colour. The number 30 is a grey value on a scale of 0 (black) to 255 (white). Calling background() inside setup() (not draw()) means it only runs once — the canvas gets a dark grey background that persists.
fill(255, 100, 50)
Sets the fill colour for everything drawn after this line. Three numbers = red, green, blue. We’ll cover colour properly in article 6; for now, know that fill(r, g, b) where each value is 0–255.
noStroke()
Removes the outline from shapes. By default, p5.js draws a black outline around everything. noStroke() turns that off.
circle(300, 200, 100)
Draws a circle. The arguments are circle(x, y, diameter). So this circle is centred at x=300, y=200, with a diameter of 100 pixels.
Move background() into draw()
Here is where it gets interesting. Move the background call inside draw():
function setup() {
createCanvas(600, 400);
}
function draw() {
background(30); // ← moved here
fill(255, 100, 50);
noStroke();
circle(mouseX, mouseY, 100); // ← follows the mouse
}
The circle now follows your mouse. The background() at the top of draw() clears the canvas before drawing the circle again each frame — so you only ever see one circle.
What happens without background()?
Remove it:
function setup() {
createCanvas(600, 400);
}
function draw() {
fill(255, 100, 50, 40); // 40 = slightly transparent
noStroke();
circle(mouseX, mouseY, 100);
}
Now every frame adds a new circle on top of the last. Move the mouse slowly and you get a paint trail. This technique — omitting or fading the background — is one of the simplest tricks for creating accumulative visuals.
frameRate() and frameCount
p5.js targets 60 frames per second by default. Two built-in variables are useful:
frameCount— how many frames have been drawn since the sketch started (starts at 1)frameRate()— call with no arguments to read the current FPS
function setup() {
createCanvas(600, 400);
}
function draw() {
background(30);
fill(255);
textSize(16);
text('Frame: ' + frameCount, 20, 30);
text('FPS: ' + floor(frameRate()), 20, 55);
}
You can also set the frame rate: frameRate(30) runs at 30fps. This matters for performance and for animations where you deliberately want a slower, choppier look.
noLoop() and loop()
Calling noLoop() inside setup() makes draw() run exactly once. Useful for static generative images:
function setup() {
createCanvas(600, 600);
noLoop();
}
function draw() {
background(20);
// Everything here runs once
for (let i = 0; i < 200; i++) {
fill(random(255), random(255), random(255), 150);
noStroke();
circle(random(width), random(height), random(5, 40));
}
}
Call loop() from anywhere (e.g., from mousePressed()) to restart the loop.
The global variables: width and height
After createCanvas() runs, width and height hold the canvas dimensions. Use them instead of hard-coded numbers:
function setup() {
createCanvas(600, 400);
}
function draw() {
background(30);
// Centre of the canvas, regardless of size
circle(width / 2, height / 2, 100);
}
Key takeaways
setup()runs once;draw()loops ~60 times per secondcreateCanvas(w, h)defines your drawing surface- Call
background()at the top ofdraw()to clear each frame — or omit it to accumulate widthandheightalways reflect your canvas sizenoLoop()makes the sketch run once;loop()restarts it