name: p5js-creative-coding
description: Creates and iterates on p5.js (p5js) creative-coding sketches in the browser: 2D/3D canvas, animation loops, input (mouse/keyboard/touch), vectors/math utilities, and basic game-like interactions. Use when the user mentions p5, p5.js, p5js, creative coding, generative art, sketches, canvas, setup(), draw(), WEBGL, animation loops, or interactive graphics.
p5.js Creative Coding
Quick start (default: browser + CDN)
When the user wants a fast p5.js sketch that runs in the browser, generate a minimal 2-file setup:
index.html loads p5.js from a CDN and the sketch file.
sketch.js contains setup() + draw() plus any input handlers.
Use this starter as the default output (adjust names/values to the request):
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>p5.js sketch</title>
<script src="https://cdn.jsdelivr.net/npm/p5@1.9.4/lib/p5.min.js"></script>
<script defer src="./sketch.js"></script>
</head>
<body>
</body>
</html>
const CANVAS_WIDTH = 800;
const CANVAS_HEIGHT = 600;
const BACKGROUND_COLOR = 16;
let circles = [];
function setup() {
createCanvas(CANVAS_WIDTH, CANVAS_HEIGHT);
noStroke();
}
function draw() {
background(BACKGROUND_COLOR);
for (const dot of circles) {
fill(dot.color);
dot.x += dot.vx;
dot.y += dot.vy;
circle(dot.x, dot.y, dot.r);
}
}
function mousePressed() {
circles.push({
x: mouseX,
y: mouseY,
vx: random(-2, 2),
vy: random(-2, 2),
r: random(12, 48),
color: color(random(255), random(255), random(255)),
});
}
Output expectations
- Prefer copy/paste runnable code with clear file boundaries (
index.html, sketch.js, and optionally style.css).
- Use constants (canvas size, speeds, palette, counts) instead of hardcoding “magic numbers”.
- Add comments only for non-obvious intent (e.g., coordinate transforms, easing, noise usage), not narration.
Workflow for building a p5 sketch
Follow this sequence unless the user requests otherwise:
- Clarify the sketch contract: canvas size/responsiveness, 2D vs
WEBGL, target FPS, and required inputs.
- Define state: arrays of particles/entities, configuration constants, and any seeded randomness.
- Implement the loop:
setup() for one-time init
draw() for per-frame update + render
- Add interactivity via p5 handlers (mouse/keyboard/touch).
- Validate: ensure it runs without console errors; verify resizing and input behavior.
Core p5 primitives to use (most common)
- Lifecycle:
preload() (assets), setup(), draw()
- Canvas:
createCanvas(w, h), resizeCanvas(w, h), background(...)
- Drawing:
fill(...), stroke(...), noFill(), noStroke(), rect(...), circle(...), line(...)
- Animation:
frameRate(fps), deltaTime
- Randomness/noise:
random(...), randomSeed(seed), noise(...), noiseSeed(seed)
- Math/vectors:
p5.Vector, createVector(x, y), p5.Vector.add/sub/mult/limit, lerp, map, constrain
- Input:
mouseX, mouseY, pmouseX, pmouseY, key, keyCode
Input & interaction patterns
Prefer these handler names and patterns:
- Mouse:
mousePressed() for click-to-add, click-to-toggle, click-to-select
mouseDragged() for drawing/painting and dragging entities
mouseWheel(event) for zoom/scale (remember to return false to prevent page scroll when appropriate)
- Keyboard:
keyPressed() for mode toggles (pause, reset, save)
- Use a small mapping object for controls (readable + easy to extend)
- Touch:
touchStarted(), touchMoved(), touchEnded() (mobile-friendly sketches)
If the sketch needs “button UI”, prefer regular HTML buttons (accessible, keyboard-friendly) next to the canvas rather than trying to emulate buttons on the canvas.
Responsive canvas (common requirement)
If the user wants the sketch to fill the window or resize:
- Create the canvas in
setup() with windowWidth, windowHeight
- Add
windowResized() and call resizeCanvas(...)
- Keep world state independent from pixel size when possible (use normalized coordinates or recompute layout on resize)
function setup() {
createCanvas(windowWidth, windowHeight);
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
Assets (images/sound/fonts)
When loading assets, use preload() so they’re ready before setup() runs:
let spriteImage;
function preload() {
spriteImage = loadImage("./assets/sprite.png");
}
function setup() {
createCanvas(800, 600);
}
function draw() {
background(0);
image(spriteImage, 50, 50);
}
If an asset fails to load, verify relative paths from index.html and that a local server is used (not a file:// URL).
Sound (p5.sound)
If the sketch needs audio, include the additional p5.sound library in index.html and use loadSound() in preload(). Browsers often require a user gesture before audio can play, so start audio in a click/touch handler when needed (e.g., userStartAudio()).
3D sketches (WEBGL) — when to use
Use WEBGL when the user asks for 3D, depth, orbiting camera, shaders, or lighting:
createCanvas(w, h, WEBGL)
- 3D primitives:
box, sphere, torus, plane
- Lighting:
ambientLight, directionalLight, pointLight
- Camera control:
orbitControl() (simple) or camera(...) (custom)
Keep 3D starters minimal; only add lights/camera controls when requested.
Performance and stability rules of thumb
- Don’t allocate large objects inside
draw() in tight loops if it can be reused.
- Cap array growth (particles/entities) and provide a reset control (
keyPressed or button).
- If visuals look blurry on high-DPI screens, consider
pixelDensity(1) (trade-off: sharpness vs performance).
Common deliverables to produce
Depending on the user’s request, output one of these:
- Minimal runnable sketch:
index.html + sketch.js
- Sketch with assets: include
assets/ structure + preload() snippet
- Interactive mini-game: clear state machine (
mode = "menu" | "playing" | "gameOver") and input mapping
- Generative art: reproducible seed controls (
randomSeed, noiseSeed) and optional s to save (saveCanvas)
Troubleshooting checklist
If the user reports “nothing shows”:
- Ensure
createCanvas(...) is called in setup()
- Ensure
draw() isn’t throwing (check console) and that background(...) isn’t fully transparent
- Verify the p5 script is loaded before
sketch.js (use defer on sketch.js, or place scripts at the end of <body>)
If inputs feel offset:
- Check canvas position vs page scroll; use
canvas.position(...) only when necessary
- Confirm using
mouseX/mouseY (p5 space) rather than raw DOM coordinates