Rainbow Paintbrush in p5.js
This tutorial will show you how to make a paint canvas in p5.js with a rainbow brush (and keyboard controls)! Written for a session at CC Fest LA, this tutorial is geared towards those new to p5.js but familiar with basic coding concepts (functions, variables, conditionals).
If you get errors in your code along the way: double-check for typos, refer to one of the gists in the tutorial, or check out the solution code!
Setup
Getting set up in p5.js has never been easier thanks to the p5.js web editor! Open up the editor and identify the setup
and draw
functions:
The setup
function contains code that will just run once, at the start of your program. The draw
function will execute over and over again. Right now, the line of code background(220)
draws a light grey background repeatedly.
We don’t want our work to be constantly covered up by a light grey background, so we are going to comment out that line of code! We can comment out code by adding two slashes in front of it: //
.
The computer ignores comments; they are mostly there for us humans to read (if, for instance, we want to remember how to draw a background again).
Code so far:
Dragging the mouse
In a typical computer paint canvas, we drag our mouse on the screen and the computer leaves paint in its wake. Therefore, we need our program to recognize when the mouse is being dragged.
p5.js already has built-in functionality for this. Along with the built-in functions of setup
and draw
, there is also the mouseDragged
function.
At the bottom of your code, add in this new function:
function mouseDragged() {
}
Right now, this function has no code inside and does nothing! Inside it, we need to write what we want the computer to do when the mouse is dragged.
When the mouse is dragged, we want the computer to put paint on the screen. To get more technical, we want the computer to draw an ellipse (specifically, a circle) at the exact (x, y) location of our mouse.
p5.js has built-in variables to detect the coordinates of your mouse: mouseX
and mouseY
. Inside the mouseDragged
function, we will use those variables to draw an ellipse. Update your mouseDragged
function to include this code:
function mouseDragged() {
ellipse(mouseX, mouseY, 50, 50);
}
This code will draw a 50x50 ellipse (effectively a circle) at the (x, y) location of your mouse. Try it out and see if it works!
Woohoo!
Still, these plain circles with their black outline are not as glorious as the rainbow I promised you. Let’s fix that.
First, you can make your circles a different color using the fill
function. Insert a line of code to make the fill of your circles grey:
function mouseDragged() {
fill(220);
ellipse(mouseX, mouseY, 50, 50);
}
You may recall from when we commented out the background that 220
is the code for light grey. We’ll be doing a deep dive into colors in the next section.
Run your code and see if your circles turn light grey!
Now let’s get rid of that black outline (not super aesthetically pleasing, in my opinion). Add in a call to the noStroke
function to clean that up:
function mouseDragged() {
noStroke();
fill(220);
ellipse(mouseX, mouseY, 50, 50);
}
Now you should have a subtle light grey paintbrush!
“But Kelly,” you are saying, “I did not want a subtle light grey paintbrush. I wanted a RAINBOW!”
That is correct. Let’s add some rainbow!
Code so far:
Making the rainbow paintbrush
Before we actually add the rainbow, we need a cursory understanding of HSL colors. Although you can also tell the computer colors in formats such as hexadecimal and RGB, HSL allows you to describe the color in terms of Hue, Saturation, and Lightness.
Hue is a degree from 0–360 on the color wheel. Saturation is the vividness of the color, expressed in a percent: 0% would be grey, and 100% would be full color. Lightness is also expressed in a percent: 0% would be dark and 100% would be light.
To make a rainbow paintbrush, we need to use HSL colors because it allows us to cycle really easily through all the hues on the color wheel, from 0 to 360 over and over again.
First thing, we need to inform the computer that we are talking about colors in HSL, not RGB or hex!
Update your mouseDragged
function to use HSL by calling the colorMode
function:
function mouseDragged() {
colorMode(HSL, 360);
noStroke();
fill(220);
ellipse(mouseX, mouseY, 50, 50);
}
Now we can use HSL colors in our fill
function! Instead of 220
(for our original grey), we will need to supply three numbers. I’m going to use 0
for the hue (starting us off with red), 200
for the saturation (yes, it’s a percentage, but I like things REALLY colorful), and 200
for lightness.
Change your fill(220)
line to fill(0, 200, 200)
so that your code now looks like this:
function mouseDragged() {
colorMode(HSL, 360);
noStroke();
fill(0, 200, 200);
ellipse(mouseX, mouseY, 50, 50);
}
Now try out your paintbrush! Is it red?
Now we just need the brush to cycle through all the degrees of the color wheel, from 0 to 360 (and over again)! To do this, we’re going to create a variable to store our current hue so that we can continuously increment it.
At the very top of your code (before even the setup
function) declare a variable called hue
:
var hue;
Now, inside the setup
function, add a line that sets the hue
variable to 0:
function setup() {
createCanvas(400, 400);
hue = 0;
}
Your complete code should now look like this:
Returning the mouseDragged
function, add a line at the top that increments the hue
variable by one:
function mouseDragged() {
hue++;
colorMode(HSL, 360);
noStroke();
fill(0, 200, 200);
ellipse(mouseX, mouseY, 50, 50);
}
If you haven’t seen the syntax before, hue++
is equivalent to saying hue = hue + 1
.
Now, to use our hue
variable (it’s just incrementing in a vacuum right now), we need to use it in our fill
line.
Change your fill
line to read fill(hue, 200, 200)
so that our paintbrush constantly changes color!
Your mouseDragged
function should now read:
function mouseDragged() {
hue++;
colorMode(HSL, 360);
noStroke();
fill(hue, 200, 200);
ellipse(mouseX, mouseY, 50, 50);
}
And your paintbrush should be writing in rainbow!
Code so far:
A small catch
However, if you paint for long enough, you may notice… your paintbrush starts only writing in red!
This happens because we increment the hue
variable up to 360… and then keep going! At that point, the brush gets stuck on the hue of 360 (red).
We need to make a more sophisticated system for incrementing the hue
variable. If hue
is greater than 360, we should reset it to 0, but otherwise proceed as normal.
Replace the incrementation line, hue++
, with this conditional:
if (hue > 360) {
hue = 0;
} else {
hue++;
}
Now test out your code. Is it drawing beautiful rainbows?
Success!
Code so far:
Ternary operator (optional)
Are you in your coding panic zone right now? If so, skip to the mini-challenges!
If not… do you thirst for eloquent JavaScript syntax? You can refactor the conditional we just wrote into a beautiful single line of code using the ternary operator.
Replace your conditional with this line of code:
hue > 360 ? hue = 0 : hue++;
Translated to English, this says: “Is hue
greater than 360? If so, reset hue
to 0. Otherwise, increment it.”
Mini-challenges
Congratulations on getting the rainbow canvas up and running! (If yours isn’t working, compare your code with the latest code gist above — or just copy and paste the gist into your editor so you can play around with it.)
Can you figure out how to…
- Make the brush a different size?
- Make the colors change more quickly?
- Make the background black and the canvas the width and height of the window? (super challenge)
Mini-challenge solutions
Try to tackle at least the first two challenges before reading the solutions!
- Change the dimensions of the
ellipse
drawn on the screen in yourmouseDragged
function. Instead of a 50x50 ellipse, you could have a smaller 25x25 ellipse with this line of code:ellipse(mouseX, mouseY, 25, 25);
- Instead of incrementing
hue
by one with the codehue++
, you could increment hue by a larger number. For instance, to increment by 10 (and make the color change 10x as fast), you would write:hue = hue + 10
or simplyhue += 10
. - You have to go to the
setup
function to set the background without erasing your beautiful rainbow art. This setup function uses the built-in variableswindowWidth
andwindowHeight
to make the canvas take up the whole window and then0
as a color code for the black background:
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
hue = 0;
}
Adding keyboard controls
Our rainbow canvas is very cool, but most computer paint editors allow you to pick certain colors, like red, green, blue, etc.
We are going to add some extra functionality to change colors via the keyboard! For instance, when you press “r,” the color will turn to just red.
Just like we used the mouseDragged
function to react to the mouse dragging across the screen, we can also use the keyPressed
function to react to keyboard activity.
Add this empty function at the bottom of your code:
function keyPressed() {
}
All the keys on the keyboard have different codes associated with them. For instance, “r” is 82 — and I know this because I typed “r” in the handy key code website!
Inside our keyPressed
function, we want to check if the key code matches up to “r.” For testing purposes, I’ll have my computer give me an alert when I press the “r” key.
Update your keyPressed
function to include this code:
function keyPressed() {
if (keyCode == 82) {
alert("You typed the letter r!");
}
}
Paint a little, then type “r” and see if the alert pops up!
OK, now that we know the program is detecting our keyboard strokes, let’s make the brush turn to red when we press “r.” We can make the brush red by setting the hue
variable back to 0.
(Side note: you may noticed that in an earlier context, 0 was the code for the black. This was because we were using a shorthand for RGB colors. Here, 0 is red because we are using HSL colors.)
Instead of issuing an alert, update your keyPressed
function to change hue
to 0 when the “r” key is pressed:
function keyPressed() {
if (keyCode == 82) {
hue = 0;
}
}
Now try out your code! Paint a little rainbow, then press “r,” then paint again. What happens?
It’s still just painting rainbow! Whaaaat?!?!
If you look really closely, you’ll see that after you press “r” and paint again, the brush starts out as red — but then rapidly starts cycling through the rainbow again. How do we turn it off?
Code so far:
Turning off the rainbow
If we want our paintbrush to stay red, we need to turn off the incrementation that creates the rainbow.
To track the status of whether the rainbow functionality is on or off, we can add in a variable at the very top of code (along with the hue
variable).
At the top of your code, initialize a variable called rainbow
as true:
var rainbow = true;
By default, the rainbow functionality is on, so this variable is true.
When the “r” key is pressed, we want to turn the rainbow OFF. This will involve setting the rainbow
variable to false. Go into your keyPressed
function and make rainbow
false when you press “r.”
Your updated keyPressed
function should look like this:
function keyPressed() {
if (keyCode == 82) {
hue = 0;
rainbow = false;
}
}
Finally, we need to only increment hue
when the rainbow is on (when the rainbow
variable is true).
Returning to our mouseDragged
function, we can wrap our incrementation code in a conditional like so:
if (rainbow) {
if (hue > 360) {
hue = 0;
} else {
hue++;
}
}
Now, the incrementation code will only execute if the rainbow is on. Saying if (rainbow)
is the same as saying if (rainbow == true)
.
Try out your new code! When you press “r,” does the paintbrush stay red?
Woohoo!
Code so far:
Mini-challenges
You will need the key code site and also the HSL color picker to tackle these challenges.
- Make the brush turn green when you hit “g.”
- Make the brush turn blue when you hit “b.”
- Reset the brush to rainbow when you hit the space bar.
- Make the brush paint rainbow at a faster rate each time you hit the space bar.
Solutions
Try to tackle each challenge to the best of your ability before reading the solutions!
- The key code for “g” is 71, and a good green hue is 125. Include this conditional in the
keyPressed
function:
if (keyCode == 71) {
hue = 125;
rainbow = false;
}
2. The key code for “b” is 66, and a good blue hue is 200. Include this conditional in the keyPressed
function:
if (keyCode == 66) {
hue = 200;
rainbow = false;
}
3. The key code for the space bar is 32. Include this conditional in the keyPressed
function:
if (keyCode == 32) {
rainbow = true;
}
4. Create a variable called rate
(near the top of your code, outside any functions) to keep track of the rate of change; initialize it with the value of 1. Inside the mouseDragged
function, increment hue
by rate
rather than a static number: hue += rate;
Finally, update your conditional for key code 32 so that it doubles the rate
variable at every tap of the space bar:
if (keyCode == 32) {
rainbow = true;
rate *= 2;
}
Final product
Congratulations for building a beautiful rainbow canvas!
Here is the full solution code, complete with solutions to the mini-challenges as well.
What else can you add to the canvas? (Ideas: make key press responses for erasing the board, changing the brush size…) What else can you make with p5.js?