Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🍁 DAY 1 - INTRO TO JAVASCRIPT 🍁

Introduction to JavaScript and p5.js

This will guide you through the basics of javascript and p5.js. Complete the tasks at your own pace!

To get started, press the right arrow button and follow the setup guide.

not sure?

Ask! Mentors are here to help you! We’d rather you ask a question than be struggling on something for way too long.

Part 1: Setting up your environment

Welcome to Day 1 of CompClub’s Autumn Workshop 🍁🍂🍁!! Today you’ll be putting all that you learnt about JavaScript and p5.js in the lecture slides into practice!

  1. You should have a web browser open to: https://editor.p5js.org/

  2. The link to the slide can be found here: https://go.compclub.org/autumn-slides-day-1

  3. Get started! Click the right arrow button on this book 🐧

tip

You can change the theme of this book by clicking the paintbrush icon in the top middle!

Shapes & the Canvas (100 Points)

What You’ll Learn

By the end of this lab you will be able to:

  • Understand how the p5.js canvas coordinate system works
  • Use setup() and draw() to structure a sketch
  • Draw basic shapes: rectangles, ellipses, lines, and triangles

Background

Every p5.js sketch has two core functions:

function setup() {
  // Runs once when the sketch starts
  createCanvas(400, 400);
}

function draw() {
  // Runs continuously 60 times per second
  background(220);
}

The canvas is a grid of pixels. The top left corner is (0, 0). X increases to the right, Y increases downward.

(0,0) ──────────────▶ x
  │
  │
  │
  ▼
  y

Common Shape Functions

FunctionWhat it draws
rect(x, y, width, height)Rectangle — x/y is the top left corner
ellipse(x, y, width, height)Ellipse — x/y is the centre
line(x1, y1, x2, y2)A straight line between two points
triangle(x1,y1, x2,y2, x3,y3)Triangle with three corner points
circle(x, y, diameter)Circle — x/y is the centre
point(x, y)A single dot

Exercises

Exercise 1 — Hello Canvas (25 Points)

Create a new sketch and paste this starter code:

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
}

Run it. You should see a grey square. This is your canvas!

💡 background(220) fills the canvas with a grey colour. Try changing 220 to 0 (black) or 255 (white).


Exercise 2 — Draw Some Shapes (25 Points)

Add the following shapes inside draw(), below background(220):

// A rectangle
rect(50, 50, 100, 80);

// An ellipse
ellipse(250, 100, 120, 80);

// A line
line(0, 200, 400, 200);

// A circle
circle(200, 300, 90);

Questions to think about:

  • What happens if you change the numbers?
  • Why does the line go all the way across?
  • Where is the centre of the canvas? (Hint: the canvas we made is 400×400.)

Exercise 3 — Build a Simple Face (25 Points)

Using only basic shapes, draw a simple face on the canvas. Your face should include:

  • A head (ellipse or circle)
  • Two eyes (circles or ellipses)
  • A nose (line or triangle)
  • A mouth (ellipse, arc, or line)

There is no single correct answer — make it your own!

Starter hint:

// Head
ellipse(200, 200, 180, 200);

// Left eye
circle(160, 170, 30);

// Right eye (add this yourself!)

// Nose (add this yourself!)

// Mouth (add this yourself!)

Exercise 4 — Challenge: A Simple Scene (25 Points)

Draw a simple outdoor scene using only shapes. It could include:

  • A sky and ground (rect for both)
  • A sun or moon (circle)
  • A house (rectangle + triangle for the roof)
  • A tree (rectangle trunk + circle top)

Try to use at least 8 shapes in total.


Reference

Lab — Recreating Mondrian-Style Paintings 🟥🟦🟨 (200 Points)

What You’ll Make

In this exercise, you’ll recreate the style of Piet Mondrian, an abstract artist known for paintings made strictly using straight black lines, rectangles, and primary colours. By the end, you will have your very own abstract digital painting in p5.js!


Learning Goals

By the end of this lab you will be able to:

  • Practise drawing rectangles with rect()
  • Set fill colours with fill(r, g, b)
  • Set outline colours with stroke()
  • Change line thickness with strokeWeight()
  • Place shapes using x and y coordinates

Background

Piet Mondrian was a Dutch artist who developed a style called Neoplasticism — paintings built entirely from horizontal and vertical black lines, filled with blocks of red, blue, yellow, and white. This style translates almost perfectly into p5.js code!

Functions You’ll Need

FunctionWhat it doesExample
rect(x, y, w, h)Draws a rectangle. x/y is the top-left cornerrect(50, 50, 200, 150)
fill(r, g, b)Sets the fill colour using RGB valuesfill(255, 0, 0)
stroke(r, g, b)Sets the outline colourstroke(0, 0, 0)
strokeWeight(n)Sets the outline thickness in pixelsstrokeWeight(6)
noStroke()Removes the outline entirelynoStroke()

Mondrian’s Colour Palette

ColourRGB values
Redfill(214, 0, 0)
Bluefill(0, 68, 170)
Yellowfill(255, 214, 0)
Whitefill(240, 240, 240)
Black (for lines)stroke(0, 0, 0)

Exercise (50 Points)

Step 1 — Set Up the Canvas

Start with this sketch:

function setup() {
  createCanvas(500, 500);
  // This painting doesn't need to animate
  noLoop();
}

function draw() {
  background(240);

  // black outlines
  stroke(0);
  // thick lines
  strokeWeight(8);

}

Run it. You should see a plain grey canvas which is ready to paint!


Step 2 — Add Your First Rectangle

Inside draw(), add a coloured rectangle:

fill(214, 0, 0);
rect(0, 0, 200, 200);

💡 The order matters — set fill() and stroke() before calling rect().


Step 3 — Build the Composition

Add more rectangles to fill the canvas. Think of the canvas as a grid divided by thick black lines. Below is an example:

// Red block
fill(214, 0, 0);
rect(0, 0, 200, 180);

// Blue block
fill(0, 68, 170);
rect(280, 300, 220, 200);

// Yellow block
fill(255, 214, 0);
rect(200, 0, 300, 120);

// White fill blocks
fill(240, 240, 240);
rect(0, 180, 200, 320);
rect(200, 120, 300, 180);
rect(200, 300, 80, 200);

💡 Don’t worry about getting it perfect straight away. Play around with the numbers until it looks balanced!


Step 4 — Refine Your Composition

Look at your painting so far. Consider:

  • Are the coloured blocks spread out, or all clustered together?
  • Do the thick black lines divide the canvas clearly?
  • Is there a good balance of colour vs. white space?

Move your rectangles around, resize them, and keep tweaking until you’re happy with the result.


Extension Tasks (50 Points)

Once your basic composition is working, push it further:

  • Add at least 6 rectangles total, and 3 coloured sections
  • Make your composition balanced and interesting. Think about how you can manipulate the size and position of your rectangles to create visual tension!

Challenge Activity (100 Points)

Make a random Mondrian generator, where the colours are randomised each time the program is run. Keep in mind you’re still constrained to red, blue, yellow, and white!

Hint: Store the colour options in an array and pick from it randomly:

// Define the Mondrian palette
let palette = [
  [214, 0, 0],
  [0, 68, 170],
  [255, 214, 0],
   // more white to make it more common
  [240, 240, 240],
  [240, 240, 240],
  [240, 240, 240],
];

// Pick a random colour from the palette
let c = random(palette);
fill(c[0], c[1], c[2]);

Click Run a few times. Does it produce interesting compositions every time?


Reference

Lab — Polka Dottys 🎨 (350 Points)

What You’ll Make

Create some simple point and click art by spawning a polka dot wherever you click! You’ll build up an interactive canvas where every click leaves a colourful dot, and by the end, you’ll have the foundations of a digital painting tool.


Learning Goals

By the end of this lab you will be able to:

  • Switch p5.js into event-driven mode using noLoop()
  • Spawn shapes in response to mouse clicks with mousePressed()
  • Use random() to vary size and colour
  • Respond to keyboard input with keyPressed()
  • Work with p5.js colour values using color(), red(), green(), and blue()

Background

Two Modes: Video vs. Event Driven

So far we’ve used p5.js in video mode. draw() runs 60 times per second like frames in a video game, and we animate by changing things each frame.

In this lab we’re switching to a different approach: even driven mode. Instead of continuously redrawing, the sketch only changes when something happens, such as a mouse click, a key press or an event.

To stop the draw loop, call noLoop() inside setup():

function setup() {
  createCanvas(500, 500);
  background(255);
  noLoop();
}

💡 We’re not going to use the draw() function in this lab at all. Changes happen only when the user does something!

Key Functions

FunctionWhen it runs
mousePressed()Once, every time the mouse button is clicked
keyPressed()Once, every time a key on the keyboard is pressed

Working with Colour

FunctionWhat it doesExample
color(r, g, b)Creates a colour value you can store in a variablelet c = color(255, 0, 0)
fill(c)Applies a stored colour as the fillfill(c)
red(c)Extracts the red channel from a colourred(c)255
green(c)Extracts the green channelgreen(c)
blue(c)Extracts the blue channelblue(c)
random(min, max)Returns a random number between min and maxrandom(0, 255)

Part 1 — Polka Dots

Step 1 — Set Up Event-Driven Mode (50 Points)

Start with this skeleton. Notice there is no draw() function (we won’t be using it):

function setup() {
  createCanvas(500, 500);
  background(255);
  noLoop();
}

function mousePressed() {
  // PUT YOUR CODE HERE
}

Step 2 — Spawn a Dot on Click (50 Points)

Inside mousePressed(), draw a circle where the mouse is:

circle(mouseX, mouseY, 40);

Click around the canvas. A dot should appear wherever you click!

💡 Because we used noLoop(), the background is only drawn once in setup(). Old dots aren’t erased and stay on the canvas permanently.


Step 3 — Vary the Size (50 Points)

Make each dot a random size by replacing the fixed diameter with random():

let minSize = 20;
let maxSize = 80;
circle(mouseX, mouseY, random(minSize, maxSize));

Try clicking around: each dot should now be a different size!


Step 4 — Vary the Colour (50 Points)

Write a helper function that picks and applies a random colour, then call it before drawing each dot:

function mousePressed() {
  randomColour();
  noStroke();
  circle(mouseX, mouseY, random(20, 80));
}

function randomColour() {
  fill(random(0, 255), random(0, 255), random(0, 255));
}
  • Click lots of dots
  • Try limiting the random range (e.g. random(100, 255)) to get pastel tones.

Part 2 — Extension

Step 1 — Change Base Colour with Number Keys (50 Points)

Add a global baseColour variable and a keyPressed() function that changes it when the user presses a number key:

let baseColour;

function setup() {
  createCanvas(500, 500);
  background(255);
  baseColour = color(0, 0, 0);
  noLoop();
}
function keyPressed() {
  if (key === '1') {
    baseColour = color(255, 0, 0);
  } else if (key === '2') {
    baseColour = color(0, 68, 170);
  } else if (key === '3') {
    baseColour = color(255, 214, 0);
  } else if (key === '4') {
    baseColour = color(34, 139, 34);
  } else {
    print('Controls: 1 = red, 2 = blue, 3 = yellow, 4 = green');
  }
}

💡 If the user presses a key that isn’t listed, print() sends a message to the console.


Step 2 — Show the Currently Selected Colour (50 Points)

Draw a small reference dot in a corner of the canvas so the user can always see which colour is active. We will update it every time the colour changes:

function showSelectedColour() {
  // Draw with a black outline so the reference dot is always visible
  stroke('black');
  strokeWeight(2);
  fill(baseColour);
  circle(470, 470, 40);

  // Switch back to no outline for polka dots
  noStroke();
}

Call showSelectedColour() at the end of both setup() and keyPressed() so it always stays up to date.


Step 3 — Add Colour Variance to Each Dot (50 Points)

Instead of fully random colours, add a small random offset to the channels of baseColour. This keeps dots recognisably in the right colour family while adding natural variation:

function mousePressed() {
  // how much each channel can vary
  let variance = 40;

  let r = red(baseColour) + random(-variance, variance);
  let g = green(baseColour) + random(-variance, variance);
  let b = blue(baseColour) + random(-variance, variance);

  noStroke();
  fill(r, g, b);
  circle(mouseX, mouseY, random(20, 80));

  // redraw reference dot on top
  showSelectedColour();
}

Try painting a scene using different colours in different areas — a blue sky, a green field, a yellow sun!


Challenge Activity

Go further with your tool:

  • Add more colour keys (5, 6, 7, etc) for a richer palette
  • Add a key (e.g. c) that clears the canvas back to white (use background(255) and redraw the reference dot)
  • Make dots near the edges of the canvas smaller, and dots near the centre larger
  • Add a key that toggles between round dots and square dots (rect() vs circle())

Reference

Lab — Bouncing Ball Simulation (500)

What You’ll Make

In this exercise, you’ll create a sketch of a ball that is affected by gravity, which the user can drag with the mouse. By the end, you will have an interactive physics simulation built entirely in p5.js!


Learning Goals

By the end of this lab you will be able to:

  • Use variables to simulate velocity and gravity
  • Update position each frame to create movement
  • Detect mouse interaction with a shape
  • Control behaviour using a boolean flag

Background

Simulating Gravity with Velocity

Real gravity accelerates objects downward, meaning they speed up over time. We can simulate this with two variables:

VariableWhat it represents
yThe ball’s vertical position on the canvas
vyThe ball’s vertical velocity (how fast it’s moving up or down)

Each frame, we:

  1. Increase vy by a small gravity value (speeding up the fall)
  2. Add vy to y (moving the ball by its current speed)
// accelerate downward
vy += gravity;
// move the ball
y += vy;

Bouncing

When the ball hits the bottom of the canvas, we reverse its velocity and reduce it slightly so the bounce loses energy over time:

if (y > height - size / 2) {
  // stop it going through the floor
  y = height - size / 2;
  // bounce is -0.8, so this flips and weakens vy
  vy *= bounce;
}

Mouse Interaction Functions

FunctionWhen it runs
mousePressed()Once, the moment the mouse button is clicked
mouseDragged()Every frame the mouse moves while the button is held
mouseReleased()Once, the moment the mouse button is released

Checking if the Mouse is on the Ball

dist(mouseX, mouseY, x, y) returns the distance between the mouse and the ball’s centre. If that distance is less than the ball’s radius, the mouse is on the ball:

if (dist(mouseX, mouseY, x, y) < size / 2) {
  // mouse is inside the ball!
}

Provided Code

Start with this skeleton — do not change anything outside the marked sections:

let x = 200;
let y = 200;

let vy = 0;

let gravity = 0.5;
let bounce = -0.8678;

let size = 123;

let dragging = false;

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);

  if (!dragging) {
    // PUT YOUR GRAVITY CODE HERE

    // PUT YOUR BOUNCING CODE HERE
  }

  circle(x, y, size);
}

function mousePressed() {
  // PUT YOUR CODE HERE
}

function mouseDragged() {
  // PUT YOUR CODE HERE
}

function mouseReleased() {
  // PUT YOUR CODE HERE
}

Requirements

Gravity and Movement (100)

Add code inside draw() to make the ball fall:

  • Each frame, increase vy by gravity
  • Each frame, update y using vy

Bouncing (100)

Still inside draw(), add code to make the ball bounce:

  • When the ball hits the bottom of the canvas, flip the direction of vy and reduce how strong it is using the bounce variable

Dragging

Add code to the mouse functions to handle dragging:

  • In mousePressed() if the mouse is on the ball, set dragging to true
  • In mouseDragged() if dragging is true, update x and y to follow the mouse
  • In mouseReleased() set dragging to false
  • In draw() only apply gravity when dragging is false

Hints

💡 Use dist(mouseX, mouseY, x, y) to check if the mouse is on the ball.

💡 The dragging boolean tracks whether the ball is being dragged, so check it before applying gravity.

💡 When the ball hits the floor, make sure you also reset y to the edge of the canvas, otherwise the ball can get stuck below it.


Extension Tasks (150)

Once the ball is working, try these additions:

  • Style the ball by adding a colour, gradient effect, or face using shapes
  • Add a horizontal velocity vx so the ball also drifts sideways when released after dragging
  • Add left and right wall bouncing using the same logic as the floor bounce
  • Add friction — reduce vx slightly each frame so the ball slows down over time

Challenge Activity (150)

Add a trail effect behind the ball as it moves. The trail should fade out behind the ball and disappear when the ball is being dragged.

Hint: Try removing background(220) from draw() and instead using a semi-transparent background to create a fading trail:

// low alpha = old frames fade slowly
background(220, 40);

Reference

🍁 DAY 2 - ADVANCED p5.js 🍁

Advanced p5.js

This will guide you through the more advanced javascript and p5.js. Complete the tasks at your own pace!

To get started, press the right arrow button and follow the setup guide.

not sure?

Ask! Mentors are here to help you! We’d rather you ask a question than be struggling on something for way too long.

Lab — MS Paint 🎨 (500 points)

What You’ll Make

In this lab, we’ll be using some of our knowledge from the lecture and yesterday’s lab 3 to make a simple MS Paint clone!


Learning Goals

By the end of this lab you will be able to:

  • Use pmouseX and pmouseY to draw lines
  • Manipulate these values to make symmetry
  • Respond to keyboard input with keyPressed()
  • Work with p5.js colour values using color(), red(), green(), and blue()

Background

Key Functions

FunctionWhen it runs
keyPressed()Once, every time a key on the keyboard is pressed
line(startX, startY, endX, endY)When called
strokeWeight(weight)When called

Working with Colour

FunctionWhat it doesExample
color(r, g, b)Creates a colour value you can store in a variablelet c = color(255, 0, 0)
fill(c)Applies a stored colour as the fillfill(c)
red(c)Extracts the red channel from a colourred(c)255
green(c)Extracts the green channelgreen(c)
blue(c)Extracts the blue channelblue(c)
random(min, max)Returns a random number between min and maxrandom(0, 255)

Part 1 — Polka Dots

Step 1 — Set up our canvas (50 points)

Start with this base. Notice we don’t set the background every frame, because we want our lines to persist.

function setup() {
  createCanvas(500, 500);
  background(255);
}

function draw() {
    // your logic here...
}

Step 2 — Draw simple lines (50 points)

Using mouseX, mouseY, pmouseX and pmouseY, in draw(), draw a line between where the mouse was last frame and where it is this frame.


Step 3 — Change the thickness (50 Points)

Using keyPressed() and the key variable, create a function that sets the stroke weight to a random value when a key (e.g. w) is pressed. Fiddle wit the range of this value until it seems reasonable!

function keyPressed() {
    // your logic here, using `key`...
}

Step 4 — Vary the Colour (50 Points)

Like in yesterday’s lab 3, use keyPressed() to make a key that changes the color of the line we draw! You can again fiddle with the values to get something nice.


Part 2 — Extension

Step 1 — Change stroke weight (nicer) (50 points)

Instead of randomly setting the stroke weight, choose a good value for it at the start, and then make two keys that can increase and decrease it! You could also add a help message that prints to the console if the key isn’t suitable.

let weight;

function setup() {
  createCanvas(500, 500);
  background(255);
  weight = 5;
  noLoop();
}

function keyPressed() {
    // your logic here...
}

Step 2 - Mirroring (100 points)

Some paint programs have a mode where they mirror your lines vertically or horizontally. Replicate this feature! At first, just make every line mirrored.

To do the mirroring, recall that if you have a canvas of size e.g. 400 x 400, then the coordinates (x, y) will be mirrored:

  • Vertically: (x, 400 - y)
  • Horizontally: (400 - x, y)
  • Both: (400 - x, 400 - y)

Then, add extra line calls to draw these in.


Step 3 — Toggleable mirroring (150 points)

Like how we made our stroke weight variable with a global variable, make the mirroring toggleable! If you want to get really fancy, make both the horizontal and vertical mirroing toggleable independantly.

Try painting some abstract art with these features!

Challenge Activity

Add extra features as you want! Anything cool gets points as allocated by mentors.


DIY!

You can do it!

Over the course of the last two days, you’ve learnt a whole lot about p5.js. It’s time to apply those skills! Using the p5.js reference found here, make something cool and interesting using one or more functions not discussed in our lectures! The cooler and more unique your project, the more points you’ll get. Try and go for a masterwork!

Project ideas

  • Extend MS Paint with more features
  • A self portrait
  • A fancier game like Snake
  • A simulation (e.g. Fire, Boid’s algorithm for flocking birds)

Feedback

Thankyou so much for attending Day 2 of CompClub’s Autumn Workshop 🍁🍂🍁!! We would appreciate it if everyone filled in this feedback form which will help us with the improvment of future workshops!!

  1. The feedback form can be found at: Feedback Day 2