All posts

shapes

3 posts

p5.js Session 11: Custom Shapes

In Session 10 we let random() decide where, what colour, and what shape to draw. This session steps back to something more basic: shapes p5.js doesn’t already have a name for.

Building a shape from points

rect(), ellipse(), and triangle() cover a lot of ground, but not everything. Let’s build a shape p5.js has no built-in name for, one point at a time.

function setup() {
  createCanvas(600, 600);
  noLoop();
  noStroke();
  fill(250, 250, 50);
}
function draw() {
  background(0);
  beginShape();
  vertex(300, 90);
  vertex(360, 240);
  vertex(510, 240);
  vertex(390, 330);
  vertex(435, 480);
  vertex(300, 390);
  vertex(165, 480);
  vertex(210, 330);
  vertex(90, 240);
  vertex(240, 240);
  endShape(CLOSE);
}

A yellow five-point star built entirely from vertex() calls

  • beginShape() opens the shape and starts collecting points. Nothing appears on the canvas yet.
  • vertex(x, y) adds one corner. They connect in the order you call them, so the order is the drawing.
  • endShape(CLOSE) finishes the shape and joins the last point back to the first.

Ten points, and a star comes out. Move any one of them and the star becomes something else entirely, which is the appeal of building shapes this way.

splineVertex(): the same points, a curved line

Same ten points, same star, but this time the edges bend instead of running straight.

function setup() {
  createCanvas(600, 600);
  noLoop();
  noStroke();
  fill(250, 250, 50);
}
function draw() {
  background(0);
  beginShape();
  splineVertex(300, 90);
  splineVertex(360, 240);
  splineVertex(510, 240);
  splineVertex(390, 330);
  splineVertex(435, 480);
  splineVertex(300, 390);
  splineVertex(165, 480);
  splineVertex(210, 330);
  splineVertex(90, 240);
  splineVertex(240, 240);
  endShape(CLOSE);
}

The same star outline, now with curved edges instead of straight ones, using splineVertex()

  • splineVertex(x, y) replaces vertex(x, y), one call per point as before, but the line between the points curves through them instead of running straight.
  • The curve passes through every point you give it, so the ten points stay exactly where they were.
  • endShape(CLOSE) still closes the shape, this time joining the last point back to the first with a curve.

The star softens into something closer to a flower. Nothing changed but the word vertex.

One warning if you go looking for more on this. Before p5.js 2.0 the function was called curveVertex(), and it worked differently: the first and last points had to be repeated, because those calls only steered the curve and were never drawn. The same star looked like this:

function setup() {
  createCanvas(600, 600);
  noLoop();
  noStroke();
  fill(250, 250, 50);
}
function draw() {
  background(0);
  beginShape();
  curveVertex(300, 90);
  curveVertex(300, 90);
  curveVertex(360, 240);
  curveVertex(510, 240);
  curveVertex(390, 330);
  curveVertex(435, 480);
  curveVertex(300, 390);
  curveVertex(165, 480);
  curveVertex(210, 330);
  curveVertex(90, 240);
  curveVertex(240, 240);
  curveVertex(300, 90);
  curveVertex(300, 90);
  endShape(CLOSE);
}

Run that in the current editor and you get ReferenceError: curveVertex is not defined. Worth knowing, because a lot of the p5.js writing online still uses the old name.

The scripts in this session were written for p5.js 2.3.2, the version the web editor runs by default. If you are following an older tutorial, some function names will differ. The one that matters here is flagged above.


Next session, we leave shapes behind for colour itself: RGB, HSB, and how to make a sketch shift smoothly through the spectrum.

p5.js Session 3: More Shapes

The Japan flag needed just one shape. This session we draw another flag, and for that we will add three more shapes to your toolkit.

The rect() function

rect(x, y, width, height) draws a rectangle. By default, x and y are the top-left corner. Width and height set how far it stretches from there.

function setup() {
  createCanvas(400, 400);
  noLoop();
}
function draw() {
  background(220);
  fill(200, 50, 50);
  noStroke();
  rect(75, 75, 250, 150);
}

A 250 by 150 rectangle, starting 75 pixels from the left edge and 75 from the top.

A red rectangle on a grey canvas

rectMode(CENTER)

By default, rect() positions from the top-left corner. rectMode(CENTER) changes that: x and y become the centre point, the same way ellipse() works. That makes it easier to position several shapes relative to each other on the canvas. To switch back: rectMode(CORNER).

function setup() {
  createCanvas(400, 400);
  noLoop();
  rectMode(CENTER);
}
function draw() {
  background(220);
  noStroke();

  fill(255, 255, 255);
  rect(200, 100, 250, 75);

  fill(200, 50, 50);
  rect(200, 175, 250, 75);
}

Two rectangles centred on the same vertical axis. White on top, red below. The flag is starting to take shape.

Two rectangles centred on the same axis, white on top and red below

The line() function

line(x1, y1, x2, y2) draws a straight line between two points. A line has no fill, only a stroke. stroke() sets its colour and strokeWeight() sets its thickness.

function setup() {
  createCanvas(400, 400);
  noLoop();
  rectMode(CENTER);
}
function draw() {
  background(220);
  noStroke();

  fill(255, 255, 255);
  rect(200, 100, 250, 75);

  fill(200, 50, 50);
  rect(200, 175, 250, 75);

  stroke(0, 0, 0);
  strokeWeight(10);
  line(75, 60, 75, 350);
}

The flagpole is a vertical black line, 10 pixels wide, running along the left edge of the flag.

Two rectangles with a vertical black flagpole on the left edge

The triangle() function

triangle(x1, y1, x2, y2, x3, y3) connects three points. Each pair of numbers is one corner.

function setup() {
  createCanvas(400, 400);
  noLoop();
  rectMode(CENTER);
}
function draw() {
  background(220);
  noStroke();

  fill(255, 255, 255);
  rect(200, 100, 250, 75);

  fill(200, 50, 50);
  rect(200, 175, 250, 75);

  stroke(0, 0, 0);
  strokeWeight(10);
  line(75, 60, 75, 350);

  fill(17, 69, 126);
  noStroke();
  triangle(75, 62.5, 75, 212.5, 200, 137.5);
}

The blue wedge has three corners: top-left at (75, 62.5), bottom-left at (75, 212.5), and the tip pointing right at (200, 137.5). Almost a flag. But the pole has disappeared behind the triangle, because the triangle was drawn after it. p5.js executes draw() in sequence, top to bottom. Whatever is written last appears on top.

The flag with a blue triangle added, the flagpole hidden behind it

Draw order

Moving the line to the end of draw() puts it on top of everything else.

function setup() {
  createCanvas(400, 400);
  noLoop();
  rectMode(CENTER);
}
function draw() {
  background(220);
  noStroke();

  fill(255, 255, 255);
  rect(200, 100, 250, 75);

  fill(200, 50, 50);
  rect(200, 175, 250, 75);

  fill(17, 69, 126);
  noStroke();
  triangle(75, 62.5, 75, 212.5, 200, 137.5);

  stroke(0, 0, 0);
  strokeWeight(10);
  line(75, 60, 75, 350);
}

The pole now sits in front of the flag, exactly where it should be.

The completed Czech flag with the flagpole drawn on top

Czech flag

As scripts grow it gets easy to lose track of what each part does. Comments let you add notes directly in the code. p5.js ignores them when the sketch runs. They are there for you, not the computer. Put // before any text to make it a comment. A comment on its own line is enough to label a whole block.

function setup() {
  createCanvas(400, 400);
  noLoop();
  rectMode(CENTER);
}
function draw() {
  background(220);
  noStroke();

// White top stripe
  fill(255, 255, 255);
  rect(200, 100, 250, 75);

// Red bottom stripe
  fill(200, 50, 50);
  rect(200, 175, 250, 75);

  // Blue triangle
  fill(17, 69, 126);
  noStroke();
  triangle(75, 62.5, 75, 212.5, 200, 137.5);

  // Flagpole
  stroke(0, 0, 0);
  strokeWeight(10);
  line(75, 60, 75, 350);
}

In Session 4 we look at loops: how to repeat a shape across the canvas without writing the same line of code a hundred times.

p5.js Session 2: Your First Sketch

Session 1 set up the editor and introduced the default template. In this session you write something real: a shape, a colour, a canvas that is yours.

Canvas size

You already know the canvas is your piece of paper. Those two numbers inside createCanvas() are its width and height in pixels. Change them and the paper changes size.

function setup() {
  createCanvas(600, 300);
  noLoop();
}

function draw() {
  background(220);
}

A wider canvas, 600 pixels across and 300 tall. We need to change the default canvas size: the Japan flag we are drawing in this session is wider than it is tall. Let’s use 600 by 300.

The p5.js preview panel showing a 600 by 300 grey canvas

How coordinates work

Every point on the canvas has an x position and a y position. x goes left to right. y goes top to bottom. The top left corner is (0, 0).

Think of a grid pinned at the top left of your piece of paper. As you move right, x increases. As you move down, y increases. The centre of a 600 by 300 canvas is (300, 150).

Diagram showing the canvas coordinate system with (0,0) at the top left and axes labeled

Colour: fill and stroke

Before you draw a shape, you tell p5.js what colour to use. fill() sets the colour inside the shape. stroke() sets the colour of the outline. Both take RGB values: three numbers between 0 and 255, one for red, one for green, one for blue.

fill(220, 0, 0);   // red fill
stroke(0);         // black outline

To remove the outline entirely:

noStroke();

These settings stay in effect until you change them. Set the colour before the shape you want to colour.

Your first shape: ellipse

ellipse(x, y, w, h) draws an ellipse. x and y are the centre point. w is the width, h is the height. When width and height are equal, you get a circle.

The Japan flag is a useful shape to aim for: a red circle, centred on a white canvas. It uses everything covered above.

function setup() {
  createCanvas(600, 300);
  noLoop();
}

function draw() {
  background(255);
  fill(220, 0, 0);
  noStroke();
  ellipse(300, 150, 180, 180);
}
  • background(255) fills the canvas white.
  • fill(220, 0, 0) sets the colour to red before the ellipse is drawn.
  • noStroke() removes the outline.
  • ellipse(300, 150, 180, 180) places a 180 by 180 circle at the centre of the 600 by 300 canvas.

Run it. That is your first real sketch.

The p5.js preview panel showing the finished Japan flag sketch

Saving your sketch

File > Save, or Cmd/Ctrl + S. Give the sketch a name by clicking the pencil icon next to the title at the top. Once saved, it appears in your account under File > Open.


In Session 3 we add more shapes and look at what happens when you combine them on the canvas.