Frame Loop

A p5.js sketch is organized around a small set of functions that together define a frame loop—the mechanism that repeatedly updates and renders the display.

In most programming languages, execution begins at a single entry point—often a main function—and then proceeds sequentially, terminating unless the programmer explicitly defines a loop. This idea is commonly described as the program’s entry point (see: ).

p5.js follows the same principle, but adapts it to interactive graphics: instead of exposing a user-defined main, the library provides a built-in entry point that initializes the environment and repeatedly calls draw() for you.

Conceptually, a p5.js sketch behaves as if it were driven by an internal main loop:

// conceptual model (not actual p5.js code)

function main() {
  setup()            // run once
  while (true) {     // animation loop
    draw()           // render next frame
  }
}

You never write this loop yourself—p5.js manages it internally. Your task is simply to define what happens per frame.

Core frame-loop functions

  • setup() – Runs once, acting as the sketch’s initialization entry point.
  • draw() – Runs continuously, defining the sketch’s frame-by-frame behavior.

Additional sketch functions

  • Interactive functions – Triggered by user events such as mouse, keyboard, or touch.
  • Custom functions – Reusable helpers for drawing or organizing logic.

Here’s a minimal frame-loop structure in p5.js:

function setup() {
  // Set up the canvas and initialize variables
}

function draw() {
  // Frame loop: update and render each frame
}

// Interactive functions (mouse, keyboard, touch)

function mouseClicked() {
  // Read mouseX and mouseY to capture click position
  // Respond to the click
}

// Custom functions

function drawCircle(x, y, size, color) {
  // Draw a circle with the given parameters
}

Setup

The setup() function runs once at the start of the program. It is used to:

  • Define the canvas size with createCanvas(width, height).
  • Initialize variables and objects used throughout the sketch.

Example:

function setup() {
  createCanvas(400, 400);
  background(220); // Light gray background
}

This creates a 400×400 canvas with a light gray background.

To load external assets like images, fonts, or sounds, define setup() as async and use await loadImage(...), await loadFont(...), etc.

Asset Loading Example

Here’s an example that loads an image and uses it as the background:

Code Explanation
let pola;

async function setup() {
  createCanvas(300, 300);
  pola = await loadImage('pola.jpg');
  background(pola);
}

Draw

The draw() function implements the frame loop: it runs continuously, typically 60 times per second, updating the sketch at each frame. Unlike setup(), which runs once, draw() maintains the sketch’s ongoing behavior.

Continuous Drawing

By default, drawings in draw() accumulate over time—previous frames remain visible unless cleared. This produces a trailing effect, as in the example below where a red circle follows the mouse:

Code Explanation
function setup() {  
  createCanvas(300, 300);  
}  

function draw() {  
  fill(0, 255, 0);  
  circle(100, 200, 80);  
  fill(0, 0, 255);  
  circle(200, 200, 80);  
  fill(255, 0, 0, 25);  
  circle(mouseX, mouseY, 80);  
}  
  • draw: The function that defines the frame loop.
  • mouseX / mouseY: Mouse position on the canvas.

Smooth Refresh

To avoid visual accumulation and redraw the scene cleanly every frame, call background() at the start of draw():

Code Explanation
function setup() {  
  createCanvas(300, 300);  
}  

function draw() {  
  background(70);  
  fill(0, 255, 0);  
  circle(100, 200, 80);  
  fill(0, 0, 255);  
  circle(200, 200, 80);  
  fill(255, 0, 0, 125);  
  circle(mouseX, mouseY, 80);  
}  
  • background() resets the frame, ensuring clean animation.
  • Without it, frames accumulate and create motion trails.

Arrays

When storing several related values—such as multiple positions—it’s more convenient to use an array than multiple separate variables.

Array — an ordered list of values accessible by index. 📄 p5.js Array · JavaScript Arrays
Code Explanation
let positions = [50, 100, 150]; // store 3 x-coordinates

function setup() {
  createCanvas(300, 300);
}

function draw() {
  background(220);
  // draw a circle for each position
  for (let i = 0; i < positions.length; i++) {
    circle(positions[i], height / 2, 20);
  }
}

Interactive Functions

Interactive functions such as mouseClicked(), mouseMoved(), and keyPressed() run automatically when their associated events occur. They complement the frame loop by reacting to user input.

Mouse and Keyboard Example

(Click anywhere to reposition the red circle; press any key to reset it.)

Code Explanation
let pola;
let redX, redY;

async function setup() {
  createCanvas(300, 300);
  pola = await loadImage('pola.jpg');
  redX = width / 2;
  redY = height / 2;
}

function draw() {
  background(pola);
  fill(0, 255, 0);  
  circle(100, 200, 80);  
  fill(0, 0, 255);  
  circle(200, 200, 80);  
  fill(255, 0, 0, 125);  
  circle(redX, redY, 80);
}

function mouseClicked() {
  redX = mouseX;
  redY = mouseY;
}

function keyPressed() {
  redX = width / 2;
  redY = height / 2;
}

Custom Functions

To organize your sketch, you can define custom helper functions:

function drawCircle(size, color, x = width / 2, y = height / 2) {
  push();
  fill(color);
  circle(x, y, size);
  pop();
}

You can call them inside the frame loop or whenever needed:

function draw() {
  background(pola);
  drawCircle(80, color(0, 255, 0), 100, 200);
  drawCircle(80, color(0, 0, 255), 200, 200);
  drawCircle(80, color(255, 0, 0, 125), mouseX, mouseY);
}

Custom functions make sketches modular, readable, and reusable.

Further Reading

📌 p5.js Reference – Learn more about the frame loop (setup() and draw()), event handling, and loading assets.