The concise nature of p5.js makes it a very easy library to learn. But don’t let this simplicity trick you into believing that p5.js has limited capabilities. p5.js has an impressive amount of functionality, history, and community behind it to make it a valuable learning investment if you ever wanted to create art, design, motion or interactive pieces using code. A p5.js program can be anywhere from a few lines of code to thousands.
You can use p5.js to build intricate data visualizations:
See the Pen p5.js data visualization by Engin Arslan (@enginarslan) on CodePen.
Or, generative art:
See the Pen p5.js generative art by Engin Arslan (@enginarslan) on CodePen.
I will also assume some level of familiarity with computer graphics so that concepts like coordinate systems or color modes don’t require too much explanation. But in case if anything is not clear, feel free to reach out to me and I will do my best to clarify things.
You can follow along with this write-up either using the p5.js editor on your operating system or use an online code editor. Here is a pen that can serve as a template for your p5.js projects.
Let’s get started!
Part One: p5.js Basics
setup & draw functions
Most p5.js scripts contain two function declarations called setup and draw. You will be writing all of your p5.js related code inside these two functions and p5.js will execute these functions for you in particular ways. It is important to understand how these functions are executed by p5.js since they form the backbone of any p5.js program.
The setup function is where you will be writing code that is related to initialization of your program. Anything that is written inside the setup function gets executed once and it gets executed at the beginning of the program.
The draw function is where you will be writing most of the drawing related functionality. draw function gets executed after the setup function and it gets executed continuously (close to 60 times, frames, a second by default) which lets you create all kinds of interactive and animated visuals using this library.
Given draw and setup functions are pretty essential to the workings of p5.js, this is the boilerplate code that you would need to use for almost every p5.js code you write.
See the Pen book-cover-step-01 by Engin Arslan (@enginarslan) on CodePen.
If you don’t explicitly instruct it, p5.js creates a canvas (the drawing area inside the web page that you will be using) using a default size which is probably too small for your purposes. That’s why you are calling the createCanvas function which creates a canvas explicitly using the given x and y dimensions. You are also calling the background function inside the draw function to be able to set a color for the canvas as well. This might not be necessary for boilerplate purposes but it helps with seeing the created canvas.
Colors & Shapes in p5.js
Color setting functions in p5.js, like the background function you are using here, works with either one, two, three or four arguments. A single argument creates a solid color using the given value for the R, G, and B (Red, Green, Blue) components. Calling a color setting function with a single value is same as calling it with the same value as three separate arguments. These two declarations below would create the same result:
background(150, 150, 150);
A fourth argument, when provided, sets the alpha (transparency) for the color. A second argument, when is used as the last argument also controls the alpha of the color and hence the alpha of the shapes that you draw after it. Talking of shapes, let’s create a shape. Here is a rectangle, drawn by using the rect function.
See the Pen book-cover-step-02 by Engin Arslan (@enginarslan) on CodePen.
The first two arguments to the rect function set the position of the rectangle and the last two arguments are for setting the size. Notice how when used with the arguments 0 and 0, the rectangle is drawn to the top-left of the screen. 0, 0 is the origin point for the canvas and it resides at the top-left corner. Rectangle shapes are drawn from their top-left corner by default in p5.js. If you wanted to change this behavior, you can declare a function called rectMode with the p5.js variable CENTER to change the rectangle drawing mode. It makes sense to place this declaration inside the setup function since you will only have to do it once for the lifetime of a program.
See the Pen book-cover-step-03 by Engin Arslan (@enginarslan) on CodePen.
If you wanted to draw this rectangle right in the middle of the screen, you have a couple of options. You could provide it with the value 700/2 so that it would be using half of the width and half of the height. But hard-coding values like this is not a good programming practice. You could try sharing variables among the rect function and the setup and draw functions. But luckily, since placing things relative to the width and height of the canvas is a common operation, p5.js provides you with a shortcut. You can use the p5.js variables width and height to be able to get the current width and height of the canvas. Divide these variables by two to use them for the placement of the rectangle.
See the Pen book-cover-step-04 by Engin Arslan (@enginarslan) on CodePen.
So far, you know how to set the color for the background but haven’t seen how to set the color for the shapes yet. There are two functions that allow you to do so. One of them is the fill function that sets the fill color for the shapes that comes after this function declaration and then there is the stroke function that sets the color for the stroke.
How color functions work might feel bit unintuitive since they affect the shapes that come after the declaration and not before. To understand how they operate, you can think of calling these functions as setting the active color for the consecutive drawing operations.
Another related function is strokeWidth, which sets the width of the stroke of the shapes. You will be using all these three functions to create a transparent rectangle with white borders.
See the Pen book-cover-step-05 by Engin Arslan (@enginarslan) on CodePen.
You will also create a text in the middle of the screen. For this purpose, you will be using the text function. text function takes 3 inputs, the text to be drawn to the screen and the x and the y position for the text placement. You can also use the textFont function to set the desired font for the text.
See the Pen book-cover-step-06 by Engin Arslan (@enginarslan) on CodePen.
There are a couple of things to fix here. First of all, notice how the text is not center aligned. As you can guess by now, there is a function to set how text is aligned, called the textAlign function. You will be using the textAlign function in the setup function since you won’t be changing this property again. You will provide it with two arguments: CENTER, CENTER. This will make the text drawings to be horizontally and vertically aligned.
The second thing to notice is that the text shape is being affected by the fill and stroke values of the rectangle above but you probably don’t want to use these values when drawing the text. Let’s set new values before drawing the text to get rid of the previous values.
See the Pen book-cover-step-07 by Engin Arslan (@enginarslan) on CodePen.
To be able to adjust the stroke, you could have either make the stroke color to be transparent or set the strokeWeight to be 0. There is also a noStroke function that is used here which gets rid of the stroke altogether. It doesn’t really matter which one you choose in my opinion, they all have the same effect in this use case.
You will now adjust the shape of the rectangle to encompass this text a bit better. Also, you will make the background black for legibility purposes.
See the Pen book-cover-step-08 by Engin Arslan (@enginarslan) on CodePen.
Currently, the text and the rectangle is too small. You already know how to scale up the rectangle. To be able to change the size of the text you could be using a function called textSize. But you will instead use a p5.js transformation function, scale, to handle the scaling since it will allow you to control the scale for the rectangle and the text together in a more straightforward manner. Unfortunately, transformations are not very intuitive when working with p5.js so they require a further explanation.
p5.js transformation functions
Transformations in p5.js happen relative to the origin point. There is a scale function that you can use which would scale the shapes that come after itself by the given amount, but things will get scaled from the origin point (the top-left corner of the screen). This is rarely desirable. When working with shapes, you would generally want to scale them relative to their center point.
Notice how calling the scale function makes everything bigger but also displaces them since scaling is happening relative to the top-left corner.
See the Pen book-cover-step-09 by Engin Arslan (@enginarslan) on CodePen.
If only the shape was at the origin point then this scaling operation would have worked for our purposes. Luckily there is a way to achieve that. For this, you should be using the scale function alongside with the translate function. Here is how it works:
See the Pen book-cover-step-10 by Engin Arslan (@enginarslan) on CodePen.
You have set the x and y position for both the rectangle and the text to be 0. This moves the shapes to the origin point. Then you call the translate transformation function to move the shapes to their initial position at width/2 and height/2. This works because translate function actually doesn’t move the shapes, it moves the entire coordinate system. Now that the origin of the coordinate system is in the middle of the screen, you can call the scale function, which would do the scaling from this desired point.
Now if this sounds a bit convoluted to you, let me assure that you are not alone. Moving the entire coordinate system to transform a shape is not only an overkill for what you are trying to achieve but can also be impractical since it means that anything else that comes after these shapes will need to use this newly transformed coordinate system which adds a lot of complexity to the process. Let’s see it in an example by drawing a new shape.
See the Pen book-cover-step-10-B by Engin Arslan (@enginarslan) on CodePen.
As you can see, you are now drawing a circle using the ellipse function at the x and y coordinates of 120 and 0. But the problem is that even though the provided y value is at 0, you can clearly see that the circle is not at top of the screen but in the middle, which happens to be the new 0 value for the y-axis. This would be highly undesirable for most circumstances but luckily there is a way in p5.js to deal with it. Enter the push and pop functions!
push & pop
The p5.js push function allows you to create a new state and pop function restores the state to the previous conditions. This allows you to have completely different settings applied to individual objects without worrying those settings to affect the shapes that come after as long as you do everything in between a push and a pop call. Here is how it works:
See the Pen book-cover-step-11 by Engin Arslan (@enginarslan) on CodePen.
Perfect! All that transformation changes you are doing right now remains localized in between the push and pop function calls. It is important to note that you should always call push and pop functions together. Using one but not the other doesn’t make any sense. Now that you fixed the problems regarding transformations, you can get rid of the circle shape. One final thing you will be adding before finalizing this text on the screen is to add a bit of an animation to it. Let’s scale it up a little bit for the first 200 frames of the animation to add a bit more dynamism to the visual. For this purpose, you can use the frameCount p5.js variable. frameCount p5.js variable keeps track of the number of times the draw function is called during the lifetime of a p5.js program.
See the Pen book-cover-step-12 by Engin Arslan (@enginarslan) on CodePen.
The following code snippet is added to the program. If the frameCount is less than 200 it adds 1/400 of the current frameCount value to the current scale. The reason why you are using the number 400 is that when the frameCount is 200 you would like to have 0.5 added to the total scale. But this is not the most elegant or scalable way of tackling this problem.