p5.js Reference
p5.js is a creative coding library for drawing, animation, data visualization, physics simulations, and interactive canvas experiences.
Imports and React setup
import p5 from "p5";
p5 manages its own canvas and animation loop. Mount it into React with a ref, create the p5 instance inside useEffect, and always clean it up on unmount.
import * as React from "react";
import p5 from "p5";
function P5Canvas() {
const containerRef = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
if (!containerRef.current) return;
const sketch = (p: p5) => {
p.setup = () => {
p.createCanvas(containerRef.current!.clientWidth, 400);
};
p.draw = () => {
p.background(30);
p.fill(255);
p.noStroke();
p.circle(p.mouseX, p.mouseY, 40);
};
};
const instance = new p5(sketch, containerRef.current);
return () => instance.remove();
}, []);
return <div ref={containerRef} className="w-full" />;
}
Responsive canvas
Use the container width rather than hardcoded pixels, and implement windowResized when the canvas should track layout changes.
const sketch = (p: p5) => {
p.setup = () => {
p.createCanvas(containerRef.current!.clientWidth, 400);
};
p.windowResized = () => {
p.resizeCanvas(containerRef.current!.clientWidth, 400);
};
p.draw = () => {
p.background(240);
p.circle(p.width / 2, p.height / 2, 100);
};
};
React state bridge
React state changes do not recreate the p5 sketch. Keep changing values and callbacks in refs, then read them inside draw() or event handlers.
const valuesRef = React.useRef(values);
React.useEffect(() => {
valuesRef.current = values;
}, [values]);
const sketch = (p: p5) => {
p.draw = () => {
const data = valuesRef.current;
const barWidth = p.width / data.length;
p.background(255);
for (let i = 0; i < data.length; i++) {
const height = p.map(data[i], 0, 100, 0, p.height);
p.rect(i * barWidth, p.height - height, barWidth - 2, height);
}
};
};
For callbacks, update a callback ref and call it from p5.
const onScoreRef = React.useRef(onScore);
React.useEffect(() => {
onScoreRef.current = onScore;
}, [onScore]);
p.mousePressed = () => {
score += 10;
onScoreRef.current(score);
};
Drawing and interaction
Common drawing APIs include canvas creation, background, fill, stroke, shapes, text, and transforms.
p.createCanvas(width, height);
p.background("#1e293b");
p.fill(59, 130, 246);
p.noStroke();
p.circle(x, y, 40);
p.rect(x, y, width, height, 8);
p.line(x1, y1, x2, y2);
p.textSize(16);
p.textAlign(p.CENTER, p.CENTER);
p.text("Hello", p.width / 2, p.height / 2);
p.push();
p.translate(x, y);
p.rotate(p.radians(45));
p.pop();
setup() runs once and draw() runs continuously. Use p.frameRate(), p.noLoop(), p.loop(), p.redraw(), p.frameCount, and p.deltaTime when controlling timing. Mouse handlers cover touch input in p5 v2; inspect p.touches for multitouch. Prefer p.key over deprecated key codes in keyboard handlers.
Simulation patterns
Use p5 math helpers such as p.map(), p.constrain(), p.lerp(), p.dist(), p.random(), p.noise(), trigonometry helpers, and vectors for simulations.
const sketch = (p: p5) => {
let x = 0;
let y = 50;
let vx = 2;
let vy = 0;
const gravity = 0.5;
const bounce = 0.8;
const radius = 20;
p.setup = () => p.createCanvas(containerRef.current!.clientWidth, 400);
p.draw = () => {
p.background(15, 23, 42);
vy += gravity;
x += vx;
y += vy;
if (y + radius > p.height) {
y = p.height - radius;
vy *= -bounce;
}
if (x - radius < 0 || x + radius > p.width) {
vx *= -1;
x = p.constrain(x, radius, p.width - radius);
}
p.fill(59, 130, 246);
p.noStroke();
p.circle(x, y, radius * 2);
};
};
Use p.noise() for organic motion and particle systems for generative effects. Remove dead particles and cap arrays in long-running sketches.
Best practices
Always use instance mode, always return instance.remove() from useEffect, bridge React state through refs, size the canvas from its container, isolate drawing state with p.push() and p.pop(), use p.map() for data-to-visual conversions, use Perlin noise for smooth natural variation, and use p.deltaTime for frame-rate-independent physics when precision matters.