p5.js Starter Article 4

Canvas & Coordinates

How the pixel grid works, why (0,0) is the top-left corner, and how to use it.

⏱ 12 min read coordinates canvas grid

The pixel grid

The p5.js canvas is a grid of pixels. Every pixel has an address expressed as two numbers: x (horizontal position) and y (vertical position).

The origin — position (0, 0) — is the top-left corner of the canvas. x increases to the right. y increases downward. This trips up anyone with a mathematics background (where y usually increases upward), but it matches how computer screens have worked since the 1970s.

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

For a 600×400 canvas:

  • Top-left corner: (0, 0)
  • Top-right corner: (600, 0)
  • Bottom-left corner: (0, 400)
  • Bottom-right corner: (600, 400)
  • Centre: (300, 200) or (width/2, height/2)

Seeing the grid

Run this sketch and hover your mouse over the canvas:

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

function draw() {
  background(20);

  // Grid lines
  stroke(50);
  strokeWeight(1);
  for (let x = 0; x <= width; x += 50) {
    line(x, 0, x, height);
  }
  for (let y = 0; y <= height; y += 50) {
    line(0, y, width, y);
  }

  // Cursor crosshair
  stroke(255, 100, 50);
  line(mouseX, 0, mouseX, height);
  line(0, mouseY, width, mouseY);

  // Coordinates display
  fill(255);
  noStroke();
  textSize(14);
  textFont('monospace');
  text(`x: ${mouseX}  y: ${mouseY}`, 10, 20);
}

Move the mouse and watch the coordinates update.

windowWidth and windowHeight

If you want your sketch to fill the browser window:

function setup() {
  createCanvas(windowWidth, windowHeight);
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

windowResized() is called automatically whenever the browser window changes size. Calling resizeCanvas() inside it keeps your canvas in sync.

Coordinate transformations

p5.js lets you move, rotate, and scale the coordinate system itself. This is often easier than calculating transformed positions manually.

translate()

translate(x, y) moves the origin to a new position:

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

function draw() {
  background(20);

  // Without translate — circle at absolute position
  fill(100, 150, 255);
  circle(300, 200, 80);

  // With translate — origin moved to centre
  translate(width / 2, height / 2);
  fill(255, 100, 50);
  circle(0, 0, 80);  // (0,0) is now the canvas centre
}

rotate()

rotate(angle) rotates everything drawn after it around the current origin. Angles are in radians by default.

function draw() {
  background(20);
  translate(width / 2, height / 2);
  rotate(frameCount * 0.02);  // slow spin

  fill(255, 200, 50);
  noStroke();
  rect(-40, -10, 80, 20);
}

push() and pop()

Transformations accumulate. Use push() and pop() to save and restore the coordinate system:

function draw() {
  background(20);

  push();
    translate(150, 200);
    rotate(frameCount * 0.02);
    fill(100, 200, 255);
    rect(-30, -10, 60, 20);
  pop();  // back to original coordinate system

  push();
    translate(450, 200);
    rotate(-frameCount * 0.03);
    fill(255, 100, 150);
    rect(-30, -10, 60, 20);
  pop();
}

Each push()/pop() pair is completely independent.

Remapping values with map()

Often you have a value in one range and need it in another. map() handles this:

// map(value, fromMin, fromMax, toMin, toMax)
let x = map(mouseX, 0, width, 0, 255);

This converts mouseX (which ranges from 0 to width) into a value between 0 and 255. Useful for mapping mouse position to colour, size, speed, or anything else.

Practical example — mouse x controls circle size and colour:

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

function draw() {
  background(20);

  let diameter = map(mouseX, 0, width, 20, 200);
  let r        = map(mouseX, 0, width, 50, 255);
  let b        = map(mouseY, 0, height, 255, 50);

  fill(r, 80, b);
  noStroke();
  circle(width / 2, height / 2, diameter);
}

constrain()

constrain(value, min, max) clamps a value so it never goes outside a range:

let x = constrain(mouseX, 50, width - 50);

Useful for keeping objects within the canvas, or preventing values from going negative.


Key takeaways

  • (0, 0) is the top-left; x goes right, y goes down
  • width and height always hold the canvas dimensions
  • translate(), rotate(), and scale() move the coordinate system, not individual shapes
  • Wrap transformations in push() / pop() to isolate them
  • map() converts a value from one range to another
  • constrain() clamps a value within bounds