Canvas & Coordinates
How the pixel grid works, why (0,0) is the top-left corner, and how to use it.
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 downwidthandheightalways hold the canvas dimensionstranslate(),rotate(), andscale()move the coordinate system, not individual shapes- Wrap transformations in
push()/pop()to isolate them map()converts a value from one range to anotherconstrain()clamps a value within bounds