p5.js Starter Article 8

Mouse Interaction

Read mouse position and clicks to make your sketches respond to the viewer.

⏱ 15 min read mouse interaction events input

Built-in mouse variables

p5.js automatically tracks the mouse and stores its state in several global variables:

Variable Description
mouseX Current mouse x position on the canvas
mouseY Current mouse y position on the canvas
pmouseX Mouse x position in the previous frame
pmouseY Mouse y position in the previous frame
mouseIsPressed true while any mouse button is held down
mouseButton LEFT, RIGHT, or CENTER

These update automatically every frame — just read them.

A simple paint brush

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

function draw() {
  if (mouseIsPressed) {
    stroke(255, 150, 50);
    strokeWeight(4);
    // Draw a line from previous position to current — avoids gaps when moving fast
    line(pmouseX, pmouseY, mouseX, mouseY);
  }
}

The pmouseX / pmouseY trick is important. If you just draw a circle at mouseX, mouseY the user can move the mouse faster than the frame rate and leave gaps. Connecting previous and current positions with a line fills them in.

mousePressed() and mouseReleased()

For one-off actions (not held-down), use event functions:

function mousePressed() {
  // Runs once each time a mouse button is pressed
}

function mouseReleased() {
  // Runs once each time a mouse button is released
}

function mouseClicked() {
  // Runs once after a press + release (full click)
}

function doubleClicked() {
  // Runs on double-click
}

Example — add a circle on each click:

let circles = [];

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

function draw() {
  background(20);
  noStroke();
  for (let c of circles) {
    fill(c.r, c.g, c.b, 200);
    circle(c.x, c.y, c.size);
  }
}

function mouseClicked() {
  circles.push({
    x:    mouseX,
    y:    mouseY,
    size: random(20, 80),
    r:    random(100, 255),
    g:    random(50, 200),
    b:    random(100, 255)
  });
}

mouseScrolled / mouseWheel

function mouseWheel(event) {
  // event.delta is positive scrolling down, negative scrolling up
  let delta = event.delta;
  // Use delta to zoom, change size, etc.
}

Detecting hover over a region

p5.js doesn’t have built-in button components, but you can check bounds manually:

function isMouseOver(x, y, w, h) {
  return mouseX > x && mouseX < x + w &&
         mouseY > y && mouseY < y + h;
}

function draw() {
  background(20);

  let hovering = isMouseOver(200, 150, 200, 100);

  fill(hovering ? color(100, 200, 100) : color(60, 60, 80));
  rect(200, 150, 200, 100, 8);

  fill(255);
  textAlign(CENTER, CENTER);
  textSize(16);
  text('Click me', 300, 200);
}

function mouseClicked() {
  if (isMouseOver(200, 150, 200, 100)) {
    background(random(255), random(255), random(255));
  }
}

Distance-based interaction

dist(x1, y1, x2, y2) gives the distance between two points. Great for circular hover detection:

let bx = 300, by = 200;

function draw() {
  background(20);

  let d = dist(mouseX, mouseY, bx, by);
  let isNear = d < 80;

  fill(isNear ? color(255, 200, 50) : color(80, 80, 120));
  noStroke();
  circle(bx, by, 80);
}

Cursor styles

cursor(HAND);     // pointer hand
cursor(CROSS);    // crosshair
cursor(ARROW);    // default arrow
cursor(MOVE);     // move arrows
cursor(TEXT);     // text cursor
noCursor();       // hide the cursor entirely

Touch devices

On touch screens, mouseX and mouseY map to the first touch point, and mouseIsPressed is true while a finger is on the screen. For more complex multi-touch, use the touches array:

function draw() {
  background(20);
  noStroke();
  fill(255, 100, 50, 150);

  for (let t of touches) {
    circle(t.x, t.y, 60);
  }
}

Key takeaways

  • mouseX, mouseY — current cursor position (updated every frame)
  • pmouseX, pmouseY — position in the previous frame (useful for drawing smooth lines)
  • mouseIsPressed — true while a button is held
  • mousePressed(), mouseReleased(), mouseClicked() — event callbacks for one-off actions
  • dist() is the cleanest way to check circular hover areas
  • cursor() changes the cursor appearance
  • Touch screens map the first touch to the mouse variables; use touches[] for multi-touch