Pause and Reset buttons in p5.js sketches


Pretty cool right? Here's how you do it:

0. Starting out with a simple script

Lets begin with the following very simple p5 sketch.
It's the example above but without the pause and reset buttons, all it does is:

  • move a circle across the screen,
  • move it up and down according to a sine wave,
  • and draw the background with 10 alpha, so a slight trace of the circle remains

If you add this script to a html page, you get something like this.
You would have minimal control over where your script is in your document, and you can't really pause the sketch or reset it (without reloading the entire page).

So how do you fix this?

// A simple p5.js script
// Just a ball moving across the canvas
let ballX = 0;
let ballSpeed = 1;

function setup() {
	// put setup code here
	createCanvas(240, 120);
	background(51);
}
  
function draw() {
	// put drawing code here
	background(51,10);
	stroke(255);
	strokeWeight(10);
	translate(0, height/2);
	let ang = 2*PI*(ballX/width);
	let ballY = sin(ang) * height/2.5;
	circle(ballX, ballY, 10);
	ballX = (ballX + ballSpeed) % width;
}

The sketch simple_script.js

1. Namespacing your script

// A namespaced p5.js script
function ballMovingSketch(p){
	let ballX = 0;
	let ballSpeed = 1;

	p.setup = function() {
		// put setup code here
		p.createCanvas(240, 120);
		p.background(51);
	}
	  
	p.draw = function() {
		// put drawing code here
		p.background(51,10);
		...

The sketch, now namespaced! Find it here: namespaced_simple_script.js

To namespace our sketch, we want to wrap everything in a function, with an argument of a p5Canvas object p.
We won't need to run this function, p5.js will handle that for us, we just need to worry about the namespacing.

If you notice in the code above in Chapter 0 , keywords and functions from p5.js were highlighted as such:
draw, background(...), stroke(...)

These terms are all linked to the canvas, so when we want to namespace according to the p5Canvas object p, we will need to namespace all of these terms by simply adding a
p.<term> for each term, so the example above will be
p.draw, p.background(...), p.stroke(...)

Finally, since the sketch is now entirely contained within the function ballMovingSketch(p), we need to actually add the sketch to the page. All we need is the following line after writing the function:
let mysketch = new p5(ballMovingSketch, 'sketchDiv');

This will add a p5Cavas (mysketch) running the sketch from the function ballMovingSketch to the element with the id sketchDiv. I prefer to place sketches in divs but they can be placed wherever.
With such namespacing, you can achieve pages that give you control over how the sketch is displayed in your document, and even how many times it's displayed, like this very basic example.
If your sketch doesn't need interactivity, something like generative art in the background, or a sketch without a draw function that only uses dom elements, you only really needs this modular function wrapping to achieve your goals.

But if we want to pause and reset the sketch, we're gonna need to add a few more things.

2. Adding a Reset button

Resetting a sketch can mean many different things, like simply blanking the canvas by splashing it with its background colour, or setting the sketch as though the entire page was just refreshed, or somewhere in between.

Dan Shiffman of the Coding Train has a great video on implementing a simple reset button for a p5 sketch.
It's a great tutorial if your page is just a standalone p5 sketch, however our implementation shall be slightly different, since we don't necessarily want the button to be attatched to the sketch itself, and we want to use our function namespacing for greater control of our sketch.

Here's how we do that.

We can create a method that (re)initialises the sketch. For this example that means (re)setting initial values for our two variables, and drawing the background.

Let's call that method p.initialiseSketch, importantly with the namespacing, since we will want to call this externally when we reset the sketch.

Then our entire setup function should just be creating the canvas, and then calling this initialising method.
If there are additional dom elements declared in the sketch in setup, those declaraions should stay in setup, since calling it during a reset would duplicate those elements. That is also why we shouldn't call setup or p.createCanvas in our reset method, since that would call p.createCanvas again, which could be unsafe.
// The sketch is wrapped in a function
function ballMovingSketch(p){
  
	// Sketch variables, uninitalised
	let ballX;
	let ballSpeed;
  
	// This defines the initial state of the sketch,
	// like variable initalisation and canvas actions
	p.initialiseSketch = function(){
		ballX = 0;
		ballSpeed = 1;
		p.background(51);
	}

	// We only need to create the canvas here,
	// everything else goes in initaliseSketch
	p.setup = function() {
		// put setup code here
		p.createCanvas(240, 120);
		p.initialiseSketch();
	}
Now we simply add a button in our HTML document that calls this reset method on an event. In our example we used a button's onclick event, but this can be any event.
<!-- within index.html -->
<button
	id="resetButton" onclick="mysketch.initialiseSketch();"
	style="width: 75px; font-size:12px">
		Reset
</button>

And bam we have a reset button!

3. Adding a Pause button

We're gonna take the main ideas from our reset button implementation to create our pause button, with a few extra bits thrown in.

	// Flag to pause the sketch
	let paused = false;
	// Function to read the pause flag externally
	p.isPaused = function(){
		return paused
	}
  
	// This simply toggles the pause flag
	// used to control the sketch's pause state
	p.pauseToggle = function(){
		paused = !paused;
	}
	p.draw = function() {
		// If pause flag is true, do nothing in draw
		if(paused){
			return;
		}
		// put drawing code here
    ...

Within our ballMovingSketch function, we add a flag paused, initially set to false since we want the sketch to start unpaused (there are many cases where a sketch would instead be paused from the start).
We want to limit external control over the value of this flag, so we create two functions, a getter p.isPaused, which simply returns the flag, and a toggle p.pauseToggle, which switches the flag between true and false for our p5Canvas object p.
This will allow the flag to be controlled from outside the sketch function, in a controlled way.

In the draw method, if the pause flag is set to true, do not proceed with the method. There are many ways this can be implemented, our method has draw continuously being called even when paused. There may be a way to have the draw method only be called while the sketch is not paused, but for the most part this is fine as is.

// This pauses a given sketch from a button press
let pauseButtonToggle = function(button, sketch){
  if(sketch.isPaused()){
    button.innerText = "Pause";
  }else{
    button.innerText = "Play";
  }
  sketch.pauseToggle();
}
<button id="pauseButton"
	onclick="pauseButtonToggle(this, mysketch)" 
	style="width: 75px; font-size:12px">
		Pause
</button> 

Outside of the sketch's function, we add a method to pause via buttons pauseButtonToggle(button, sketch), which, given the button pressed and the sketch to (un)pause, relabels the button and toggles the pause flag in the sketch.

We can then assign this to a button's onclick event, with the argument for the button being this to refer to the button itself, and we're done!

A more simple type of button could also have onclick="mysketch.pauseToggle()". This wouldn't change the looks of the button, but it would function the same otherwise.

And that's it! You're done!