Learn Creative Coding (#6) - Interactivity: Mouse, Keyboard, and Touch

What will I learn
- Tracking mouse position with mouseX and mouseY;
- responding to clicks and key presses;
- building a simple drawing tool;
- making sketches respond to user input in interesting ways;
- touch support for mobile devices.
Requirements
- A modern web browser;
- Episodes #1-5 of this series.
Difficulty
- Beginner
Curriculum (of the Learn Creative Coding Series):
- Learn Creative Coding (#1) - What Is Creative Coding? (And Why You Should Care)
- Learn Creative Coding (#2) - Your First Sketch: Shapes, Colors, and the Canvas
- Learn Creative Coding (#3) - Movement and Time: Making Things Animate
- Learn Creative Coding (#4) - Randomness: The Secret Ingredient
- Learn Creative Coding (#5) - Loops and Grids: Repetition as a Design Tool
- Learn Creative Coding (#6) - Interactivity: Mouse, Keyboard, and Touch (this post)
Learn Creative Coding (#6) - Interactivity: Mouse, Keyboard, and Touch
Up to now our sketches have been self-contained. The code runs, the art appears, the viewer watches. That's fine for generative prints and NFTs. But some of the most exciting creative coding is interactive - the viewer becomes a participant.
Mouse position
p5.js gives you mouseX and mouseY for free. They update every frame.
function setup() {
createCanvas(500, 500);
}
function draw() {
background(20);
noStroke();
fill(255, 100, 150);
ellipse(mouseX, mouseY, 40, 40);
}
A circle that follows your mouse. Nothing special yet. Let's make it interesting:
function setup() {
createCanvas(500, 500);
background(20);
noCursor();
}
function draw() {
// don't clear background - paint mode
noStroke();
let size = dist(mouseX, mouseY, pmouseX, pmouseY);
size = constrain(size, 2, 50);
fill(mouseX % 255, 150, mouseY % 255, 30);
ellipse(mouseX, mouseY, size, size);
}
Now we're painting. pmouseX and pmouseY are the previous frame's mouse position. The distance between current and previous tells us how fast the mouse is moving - fast movement = big brush, slow movement = tiny dots. The color shifts based on position. Move slowly and you get fine detail. Slash across the canvas and you get bold streaks.
constrain(value, min, max) keeps the size within bounds. Without it, a fast flick would draw a dot the size of the canvas.
Mouse events
Beyond tracking position, you can respond to specific events:
let shapes = [];
function setup() {
createCanvas(500, 500);
}
function draw() {
background(240);
noStroke();
for (let s of shapes) {
fill(s.c);
ellipse(s.x, s.y, s.size, s.size);
}
}
function mousePressed() {
shapes.push({
x: mouseX,
y: mouseY,
size: random(20, 80),
c: color(random(255), random(100, 200), random(150, 255), 180)
});
}
Every click adds a circle. The array grows, the canvas fills up. mousePressed() fires once per click - not continuously. For continuous drawing while the mouse is held, check mouseIsPressed inside draw:
function draw() {
if (mouseIsPressed) {
fill(255, 50);
noStroke();
ellipse(mouseX, mouseY, 20, 20);
}
}
Mouse as influence, not position
Here's where it gets creative. Instead of drawing at the mouse, use the mouse to influence the entire scene:
function setup() {
createCanvas(500, 500);
}
function draw() {
background(20);
noStroke();
let spacing = 25;
for (let x = spacing; x < width; x += spacing) {
for (let y = spacing; y < height; y += spacing) {
let d = dist(x, y, mouseX, mouseY);
let size = map(d, 0, 200, 20, 3);
size = constrain(size, 3, 20);
let brightness = map(d, 0, 200, 255, 50);
fill(brightness, 100, 200, 180);
ellipse(x, y, size, size);
}
}
}
A grid of dots that swells near the mouse, like a magnifying glass effect. The mouse creates a "field of influence" - nearby dots grow, distant dots shrink. Move the mouse around and the whole grid responds. This is much more interesting than just "draw a circle where the mouse is."
Keyboard input
keyPressed() fires when any key is pressed. Use key for the character and keyCode for special keys.
let bg = 20;
let palette = ['#ff6b6b', '#feca57', '#48dbfb', '#ff9ff3', '#54a0ff'];
let currentColor = 0;
function setup() {
createCanvas(500, 500);
background(bg);
}
function draw() {
if (mouseIsPressed) {
noStroke();
fill(palette[currentColor]);
let size = 5 + sin(frameCount * 0.1) * 3;
ellipse(mouseX, mouseY, size, size);
}
}
function keyPressed() {
if (key === 'c') {
background(bg); // clear
}
if (key === ' ') {
currentColor = (currentColor + 1) % palette.length; // cycle color
}
if (key === 's') {
saveCanvas('my-drawing', 'png'); // save!
}
}
A mini drawing app. Click and drag to paint, spacebar to change color, 'c' to clear, 's' to save. That saveCanvas() function is built into p5.js - super handy for grabbing screenshots of your work.
Combining mouse with animation
Mouse input and procedural animation work beautifully together:
let particles = [];
function setup() {
createCanvas(600, 600);
}
function draw() {
background(15, 30);
// spawn particles at mouse when pressed
if (mouseIsPressed) {
for (let i = 0; i < 3; i++) {
particles.push({
x: mouseX,
y: mouseY,
vx: random(-2, 2),
vy: random(-3, -0.5),
life: 255,
size: random(3, 8),
col: [random(150, 255), random(80, 180), random(200, 255)]
});
}
}
// update and draw particles
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.x += p.vx;
p.y += p.vy;
p.vy += 0.05; // gravity
p.life -= 3;
if (p.life <= 0) {
particles.splice(i, 1);
continue;
}
noStroke();
fill(p.col[0], p.col[1], p.col[2], p.life);
ellipse(p.x, p.y, p.size, p.size);
}
}
Click and drag to spray particles. They float up, gravity pulls them down, they fade and die. The backwards loop (i--) is important when removing elements from an array while iterating - going forward would skip elements after a splice.
We'll build a proper particle system in a later episode, but this gives you the idea.
Touch support
p5.js handles touch automatically on mobile. mouseX/mouseY map to the first touch point. For multi-touch:
function touchMoved() {
for (let t of touches) {
fill(random(255), 150, 200, 50);
noStroke();
ellipse(t.x, t.y, 30, 30);
}
return false; // prevent scrolling
}
The touches array contains all active touch points. return false prevents the default browser behavior (scrolling, zooming) so your sketch captures the touch.
If you're making work for exhibition or web, testing on mobile is worth it. Fingers are less precise than a mouse but they're more physical - people engage differently with touch.
A simple interactive piece
Let me put everything together into something that works as a standalone interactive artwork:
let trails = [];
function setup() {
createCanvas(600, 600);
background(15);
noCursor();
}
function draw() {
// slow fade instead of clear
background(15, 8);
// connection lines between recent trail points
stroke(255, 40);
strokeWeight(0.5);
for (let i = 1; i < trails.length; i++) {
let a = trails[i - 1];
let b = trails[i];
if (dist(a.x, a.y, b.x, b.y) < 100) {
line(a.x, a.y, b.x, b.y);
}
}
// draw trail points
noStroke();
for (let i = trails.length - 1; i >= 0; i--) {
let t = trails[i];
t.life -= 1;
t.x += sin(t.angle) * 0.3;
t.y += cos(t.angle) * 0.3;
if (t.life <= 0) {
trails.splice(i, 1);
continue;
}
fill(t.hue, 150, 220, t.life);
ellipse(t.x, t.y, map(t.life, 0, 200, 1, 6), map(t.life, 0, 200, 1, 6));
}
// add new points at mouse
if (frameCount % 2 === 0) {
trails.push({
x: mouseX + random(-5, 5),
y: mouseY + random(-5, 5),
life: 200,
hue: (frameCount * 0.5) % 255,
angle: random(TWO_PI)
});
}
// cursor glow
fill(255, 30);
ellipse(mouseX, mouseY, 20, 20);
}
function keyPressed() {
if (key === 's') saveCanvas('interactive-trails', 'png');
if (key === 'c') {
trails = [];
background(15);
}
}
Move your mouse around. Glowing dots trail behind and slowly drift apart, connected by faint lines. The color cycles over time. Press 's' to save, 'c' to clear. It's meditative - the kind of thing you can play with for way longer than you'd expect.
't Komt erop neer...
mouseX/mouseYtrack position,pmouseX/pmouseYgive previous framemousePressed()for clicks,mouseIsPressedfor continuous drawingkeyPressed()+keyfor keyboard input,saveCanvas()to export- Use the mouse as influence, not just position - distance fields, attraction, repulsion
dist(),map(),constrain()are your three best friends for interactive worktouchesarray for multi-touch on mobile- Remove particles backwards (
i--) when splicing during iteration
Next episode: color theory for coders. We'll leave RGB behind and learn to think in HSB - hue, saturation, brightness. Makes sense, right? Way more intuitive for choosing colors that actually look good together.
Merci en tot de volgende!
X