Introduction to Motion Graphics in p5.js

Objectives and Overview

This lesson introduces the basics of creating motion graphics and animation with p5.js.

Lesson Objectives:

  • Understand what motion graphics are and how they’re used on the web
  • Understand how to use sine waves to program basic motion graphics in p5 and integrate one into a sketch by using the sin() command.

Introduction to Motion

One of the most common sketch themes in p5 is motion graphics. This can range anywhere from shapes moving in basic patterns to incredibly complex recreations of natural systems. Much of the motion relies on an understanding of some mathematics concepts, but once you become comfortable with these foundations you’ll be able to quickly start expressing yourself creatively.

Sine Waves

The first motion tool that you’ll be practicing is using a sine wave. Sine waves are everywhere in nature and are identified by their smooth motion and rounded shape. Here is an animation of a sine wave:

Animation of a sine wave

P5 has a built-in command to calculate an angle’s sin() value, enabling you to create motion that is similar to that of a sine wave. Whatever elements of your sketch that you move will have a quality of motion similar to the above example. Let’s take a look at a sketch.

Basic Motion: Using sin()

First, let’s take examine some code. This example is modified from an example in Session 6: Motion: Move and choreograph shapes from the Introduction to Programming for the Visual Arts with p5.js Kadenze course. The code may look overwhelming at first, but this lesson will walk through each piece. Here’s the code:

//This example is a modification of code from 'Session 6: Motion: Move and choreograph shapes...' from //'Introduction to Programming for the Visual Arts with p5.js' Kadenze course let angle = 0; let offset = 200; //provides a constant value that offsets the y position let scalar = 40; //effects the amplitude of the sine wave (how far from the offset) let speed = 0.05; //effects the speed of the motion function setup() { createCanvas(400, 400); fill(255, 0, 100); } function draw() { background(0); let y1 = offset + sin(angle) * scalar; //sin() value is small, so multiply by scalar makes them easier to detect let y2 = offset + sin(angle + 0.5) * scalar; let y3 = offset + sin(angle + 0.75) * scalar; ellipse(100, y1, 50, 50); ellipse(200, y2, 50, 50); ellipse(300, y3, 50, 50); angle += speed; //increment the angle each time through draw(), see what happens if you change this! }
Code language: JavaScript (javascript)

If you run the sketch, you’ll see this animation:

p5 basic motion using sin(): pink circles moving along sine wave

If you run the code, you’ll notice that the circles move slightly faster than in the above GIF. This is because the p5’s framerate is 60fps, and the capture is slightly slower than this.

Sketch Breakdown

You may notice that the pink circles move in a similar way to the sine wave! This is because the sketch uses the sin() command in p5 to animate the circles. If you draw a line through the circles, you’d see that it is close to the motion of the sine wave. Let’s do that!

p5 basic motion using sin(): pink circles moving along sine wave with line

The looping is a bit jarring, but this example shows the general outline of the sine wave. Basically, if you use sin(angle) for motion in p5, your animations will move along a sine wave. Here’s yet another example with the lines of a graph drawn in:

p5 basic motion using sin(): pink circles moving along sine wave with lines and graph

Now that you’ve seen some sketches, let’s take a look at the code!

Code Analysis

This code is for the first example, with just the circles. The other examples had a lot of extra code included to draw the graph lines and adds more complexity than needed for right now. Let’s break the code down into sections, starting with the global variables.

Global Variables

There are four global variables used in this sketch: angle, offset, scalar, and speed. These names were borrowed from the Kadenze example, and are good ones to use for motion graphics because they’re named based on their effect. The variables are all interrelated, so it’s best to explain to them as they connect with each other.

The angle variable starts at 0 and is increased each time the draw() loop completes. The angle value is essentially what plots the motion since the position of the shape is generated by taking the sin() of the angle.

The offset is a constant value that is used in calculating the y-position of the shapes. Think of this as the general position of the shapes on the y-axis. If you decrease it, the shapes will move closer to the top of the sketch where y = 0, and if you increase it, the shapes will move down to the bottom of the sketch.

The speed variable effects the speed of the motion. The angle increases at the rate that you choose for speed. The greater the speed value, the faster the animations will move. Try increasing this value to see the effect it has on the motion!

The scalar variable changes the amplitude of the wave. Amplitude can be thought of as how ‘tight’ the waveform is. If you increase this value, the motion will move greater distances up and down in the sketch.

One of the best ways to understand the relationship between these values is to change them and observe the effect! If you don’t understand it right away, that’s alright. Keep trying your best to observe the relationship. Some of the math involved is a bit tricky, but you can still create interesting and effective motions while learning the underlying math!

The draw() Function

The only other new pieces of code in this sketch appear in the draw() function, which is where the ellipses and motion are created. Let’s take a look at the code:

let y1 = offset + sin(angle) * scalar; //sin() value is small, so multiply by scalar makes them easier to detect let y2 = offset + sin(angle + 0.5) * scalar; let y3 = offset + sin(angle + 0.75) * scalar;
Code language: JavaScript (javascript)

This formula calculates the y-position of each of the ellipses, where y1 = the first ellipse, y2 = the second ellipse, and y3 = the third ellipse. If you wanted to draw more ellipses, you’d need to repeat continue adding more code.

The y position is the offset, which is a constant value set in the global variable, plus the sine of the angle multiplied by the scalar variable. The resulting sine value is small, so there’s a need to modify it by the scalar. Remember, the scalar is the amplitude of the wave, so if you increase the size of this variable you’ll see an increase in the height of the wave.

The second and third ellipses have a tiny value added to the angle (0.5 and 0.75) so that the y position is slightly different for each ellipse. See what happens if you remove this!

After calculating the y values, the next step is to draw the ellipses. The syntax is the exact same as drawing any other ellipse with the exception that the y parameter is y1, y2, or y3.

The last step is to increment the angle by adding it to speed:

angle += speed; //increment the angle each time through draw(), see what happens if you change this!

This step is what actually creates the motion by changing the angle value over time.

Next Steps

While this may seem like a lot of complex steps, it’s actually just a series of connected variables. You can use sin() to animate any parameter, not just the y-value of an ellipse. Go ahead and experiment with this and see what you come up with!