🍁 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!
-
You should have a web browser open to: https://editor.p5js.org/
-
The link to the slide can be found here: https://go.compclub.org/autumn-slides-day-1
-
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()anddraw()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
| Function | What 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 changing220to0(black) or255(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 (
rectfor 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
| Function | What it does | Example |
|---|---|---|
rect(x, y, w, h) | Draws a rectangle. x/y is the top-left corner | rect(50, 50, 200, 150) |
fill(r, g, b) | Sets the fill colour using RGB values | fill(255, 0, 0) |
stroke(r, g, b) | Sets the outline colour | stroke(0, 0, 0) |
strokeWeight(n) | Sets the outline thickness in pixels | strokeWeight(6) |
noStroke() | Removes the outline entirely | noStroke() |
Mondrian’s Colour Palette
| Colour | RGB values |
|---|---|
| Red | fill(214, 0, 0) |
| Blue | fill(0, 68, 170) |
| Yellow | fill(255, 214, 0) |
| White | fill(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()andstroke()before callingrect().
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(), andblue()
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
| Function | When 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
| Function | What it does | Example |
|---|---|---|
color(r, g, b) | Creates a colour value you can store in a variable | let c = color(255, 0, 0) |
fill(c) | Applies a stored colour as the fill | fill(c) |
red(c) | Extracts the red channel from a colour | red(c) → 255 |
green(c) | Extracts the green channel | green(c) |
blue(c) | Extracts the blue channel | blue(c) |
random(min, max) | Returns a random number between min and max | random(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 insetup(). 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 (usebackground(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()vscircle())
Reference
- p5.js reference —
noLoop() - p5.js reference —
mousePressed() - p5.js reference —
keyPressed() - p5.js reference —
color() - p5.js web editor
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:
| Variable | What it represents |
|---|---|
y | The ball’s vertical position on the canvas |
vy | The ball’s vertical velocity (how fast it’s moving up or down) |
Each frame, we:
- Increase
vyby a smallgravityvalue (speeding up the fall) - Add
vytoy(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
| Function | When 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
vybygravity - Each frame, update
yusingvy
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
vyand reduce how strong it is using thebouncevariable
Dragging
Add code to the mouse functions to handle dragging:
- In
mousePressed()if the mouse is on the ball, setdraggingtotrue - In
mouseDragged()ifdraggingistrue, updatexandyto follow the mouse - In
mouseReleased()setdraggingtofalse - In
draw()only apply gravity whendraggingisfalse
Hints
💡 Use
dist(mouseX, mouseY, x, y)to check if the mouse is on the ball.
💡 The
draggingboolean tracks whether the ball is being dragged, so check it before applying gravity.
💡 When the ball hits the floor, make sure you also reset
yto 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
vxso 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
vxslightly 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
pmouseXandpmouseYto draw lines - Manipulate these values to make symmetry
- Respond to keyboard input with
keyPressed() - Work with p5.js colour values using
color(),red(),green(), andblue()
Background
Key Functions
| Function | When 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
| Function | What it does | Example |
|---|---|---|
color(r, g, b) | Creates a colour value you can store in a variable | let c = color(255, 0, 0) |
fill(c) | Applies a stored colour as the fill | fill(c) |
red(c) | Extracts the red channel from a colour | red(c) → 255 |
green(c) | Extracts the green channel | green(c) |
blue(c) | Extracts the blue channel | blue(c) |
random(min, max) | Returns a random number between min and max | random(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!!
- The feedback form can be found at: Feedback Day 2