A while back I learned how to use p5.js for a game I was building. I decided to revisit the graphic library as I found an interest in doing something to creative and challenging — building a video for my band, Symfinity. I was not looking to make a music video but a video that could be used for live performances like many pop artists have. I can thank The Chainsmokers for their epic concert at Jones Beach for some added inspiration. They get to have cool visuals after all, so why not me?!
My main goal was to make something that clearly fits a song specifically, that changes when the music changes and maybe even depicts the lyrics a bit. The obvious choice for me was our single Everything I Know Explodes which is currently perhaps our most iconic song. At any rate, making animation requires quite a bit of logic and I thought this would be a good opportunity to talk about some animation basics.
Variables — Movement
Variables are an essential part of abstracting any sort of code. With animation, there is a LOT to abstract and a lot of values than need to change. If nothing changed, then there would be no animation after all. So plan on needing to declare many variables, typically outside the setup and draw functions because they will need to be changed outside of draw since it is constantly being called (that is how p5.js works!).
Most likely you will be creating some sort of shape such as an ellipse. An ellipse takes four values, a x-coordinate, a y-coordinate, and width and height. If you want your ellipse to move, your x and/or y values need to be variables! If you want your ellipse to change size, your width and/or height will need to be variables. Let’s say we want to move the ellipse along the x values. We first assign a variable called x a start value (how about 20?). Then inside the draw function, we need to increment x. It may seem intuitive to just add x++; or x+=10 for a faster speed. This will work but will send the ellipse to the right endlessly. What if we want to have the ellipse move back and forth? We need more variables. Make a variable called left and a variable called right. Set right equal to true since we want it to move right first and set left to false. We also need some y value too so our ellipse will show up on our canvas (we’ll set it to 5). Our variables that are declared should look like this:
Now inside our draw function, we want to increment x only if right === true.
Suppose our canvas has a width of 1280 pixels. We do not want the ellipse to leave the canvas, so we want to prevent x from going above 1280. We can do this with another if statement.
Because this now sets our variable right to false if x reaches 1280, the outer if block will never be entered and x will not increment until right === true again!
Now we can handle the case where x has reached this point and we want to send it the other direction.
This will send the ellipse back the other way unless it reaches 0. You may have noticed that when right is true, left is false and vise versa. In fact, we only need one of those two variables.
With this basic logic in place we can apply it to move any shapes around our canvas. You could swap out the x variables for y variables if you wanted to move our shape vertically for instance. And similar logic also works for size. You can set a variable which controls both growth and shrinkage.
Variables — Color
We can also change the color of shapes! Color in p5.js is set with rgb values, so color takes three arguments as integers between 0–255. But instead of hardcoding values, we can use variables to change the color dynamically. By using some sort of switch variable in the same way as we used the variable “right” above, we can tell our shape when to begin changing.
If we give color a fourth argument, we can also set and change the opacity of a color.
Speed and Tempo
One of my greatest challenges was syncing the visuals with the music. I recorded the music to a metronome so I figured since draw always draws at a consistent speed, if I could set the speed of a shape to time up with the tempo of the song, then it might make it easier to sync up certain events in the song. Prior to this, I was using a lot of guesswork and trial and error. But if I could nail down the speed of the song and somehow attach it to a variable, then I would be able to keep track of which part of the song I was in and it would always be set to a visual metronome.
I made a timer ellipse:
The width and height I set to 1 each but it does not matter. I just wanted to keep them small. The x value I made negative to ensure that this ellipse is never seen. That’s right, I made an invisible ellipse. However it was perhaps the most important shape I made. The timerEllipseY variable is really the critical one that I allowed to change, first setting it to zero. From here, with a lot of trials, I eventually came up with another variable which I named timerInterval and set to 9. This is important because this sets the speed of this ellipse. That was the distance I wanted it to move because it seemed to fit the tempo of the song perfectly.
From here, I could implement logic such as this:
Since the timerInterval is a measured unit of time where every 12 equals a bar of music, now we know that timerInterval*64 will equal 4 bars of music.
I used a few other tricks, like looping over an array that would grow to have a varying number of things on screen. For me, telling a story with the video was important. With just using predominantly ellipsis and background changes, it was definitely a challenge. While there are other shapes available, it seemed most natural based on my theme to have things that could easily exist in space and look natural.
I plan to do more videos, in part because the band can use them but there are so many other capabilities of p5.js especially with sound amplitude and frequency. For those looking at doing animation, get ready to write some juicy logic!