Einleitung
Vor Kurzem entdeckte ich dank eines Facebook-Beitrags von Max de Mendizábal die JavaScript-Bibliothek p5.js (ja, ich weiß, ziemlich spät). Mit ihr lassen sich auf einfache und zugängliche Weise Kunst und interaktive Visualisierungen im Web erstellen. In diesem Artikel erkunden wir, wie p5.js für digitale Kunst eingesetzt werden kann und welchen Nutzen die Bibliothek für Kunstschaffende und Designer hat.
Inhaltsverzeichnis
Inhaltsverzeichnis
Geschichte
Im Jahr 2001 entwickelten Ben Fry und Casey Reas, Mitglieder der von John Maeda geleiteten Aesthetics and Computation Group am MIT Media Lab, Processing. Dabei handelt es sich um eine quelloffene Programmiersprache samt integrierter Entwicklungsumgebung, die auf einer vereinfachten Java-Syntax und einem für visuelle Kunstschaffende und Designer gedachten Grafikmodell beruht. Ursprünglich sollte Processing diesen Zielgruppen das Programmieren vermitteln; bald entwickelte es sich jedoch zu einer beliebten Plattform für digitale Kunst und interaktive Visualisierungen.
Aus Processing gingen mehrere verwandte und davon inspirierte Projekte hervor, darunter p5.js. Lauren McCarthy entwickelte die Bibliothek 2014 nach derselben Philosophie wie Processing, passte sie jedoch an JavaScript und das Web an. p5.js stellt leicht zugängliche Funktionen und Werkzeuge für Grafiken, Animationen und interaktive Visualisierungen bereit.
Weitere verwandte Projekte wie Processing.py und Processing for Android werden im Wikipedia-Artikel über Processing aufgeführt.
Installation und Einrichtung
Um p5.js zu verwenden, müssen wir die Bibliothek zunächst in unser Projekt einbinden. Dazu können wir sie entweder über ein CDN laden oder als npm-Abhängigkeit installieren.
Über ein CDN
Am einfachsten ist es, die Bibliothek über ein Content Delivery Network (CDN) in das HTML-Dokument einzubinden:
<!DOCTYPE html><html lang="de"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Mein erster p5.js-Sketch</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/2.3.1/p5.min.js"></script> </head> <body> <script src="sketch.js"></script> </body></html>In sketch.js schreiben wir unseren p5.js-Code. Alternativ können wir die Bibliothek von ihrer offiziellen Website herunterladen und lokal im Projekt bereitstellen.
Als npm-Abhängigkeit
Verwendet das Projekt bereits einen Bundler wie Vite, Astro oder webpack, empfiehlt es sich, p5 als Abhängigkeit zu installieren. Dadurch wird die Version in package.json festgehalten, die Website ist zur Laufzeit nicht von einem Drittanbieter abhängig und funktioniert auch offline:
npm install p5# oderbun add p5pnpm add p5yarn add p5Das Paket enthält eigene TypeScript-Typdefinitionen (p5/types/p5.d.ts); @types/p5 muss daher nicht installiert werden.
Anschließend lässt sich p5 wie jedes andere Modul importieren. Da p5 beim Laden auf window zugreift, darf der Import nur in Code erfolgen, der im Browser ausgeführt wird. In Astro oder Next.js gehört er in ein clientseitiges Skript oder einen dynamischen import(), niemals in das serverseitige Rendering:
import p5 from "p5";
new p5(p => { p.setup = () => { p.createCanvas(400, 400); }; p.draw = () => { p.background(20); p.circle(p.mouseX, p.mouseY, 40); };}, document.getElementById("container"));Das zweite Argument von new p5() ist das DOM-Element, in das der Canvas eingefügt wird. Fehlt es, hängt p5 den Canvas an das Ende von <body> an. Dieser Artikel verwendet den Instanzmodus, um die folgenden Sketches einzubetten.
Die vollständige Bibliothek ist ungefähr ein Megabyte groß. Ein dynamischer import() sorgt deshalb dafür, dass sie nur auf Seiten mit einem Sketch heruntergeladen wird.
Einführung in Creative Coding
Beim Creative Coding löst Code nicht nur eine Aufgabe: Er definiert auch ein Bild, eine Bewegung oder ein Erlebnis. Anstatt mit einem fertigen Werk zu beginnen, legen wir Regeln fest und beobachten ihre Ergebnisse. p5.js erleichtert diesen Prozess mit einem Canvas, einer Animationsschleife und einfachen Funktionen zum Zeichnen und Interagieren.
Aufbau eines Sketches
Ein einfacher Sketch besteht meist aus zwei Funktionen:
function setup() { createCanvas(600, 400);}
function draw() { background(245); circle(300, 200, 80);}setup() wird beim Start einmal ausgeführt und dient zum Erstellen des Canvas sowie zum Festlegen der Anfangskonfiguration. draw() läuft automatisch — normalerweise etwa 60-mal pro Sekunde — und zeichnet die Szene neu. background() löscht das vorherige Bild; wird die Funktion weggelassen, hinterlassen Formen Spuren, die sich gestalterisch nutzen lassen.
Koordinaten und Formen
Der Ursprung (0, 0) liegt links oben. Die x-Achse wächst nach rechts, die y-Achse nach unten. width und height enthalten die aktuellen Abmessungen des Canvas:
line(0, 0, width, height);circle(width / 2, height / 2, 100);rect(40, 60, 120, 80);triangle(300, 40, 240, 160, 360, 160);Jede Funktion erhält Koordinaten und Maße. circle(x, y, durchmesser) zeichnet beispielsweise einen Kreis mit dem Mittelpunkt (x, y). Bei rect(x, y, breite, höhe) bezeichnet (x, y) standardmäßig die linke obere Ecke.
Farbe und Stil
fill() bestimmt die Füllung, stroke() die Kontur. noFill() und noStroke() schalten sie aus; strokeWeight() verändert die Linienstärke:
background(250);fill(57, 255, 20, 140);stroke(20);strokeWeight(3);circle(200, 200, 150);Die ersten drei Werte stehen für Rot, Grün und Blau, der vierte für die Transparenz. Standardmäßig reichen alle Werte von 0 bis 255. Auch CSS-Farben sind möglich, etwa fill("#39ff14").
Bewegung und Zeit
Animation entsteht, wenn sich ein Wert von Bild zu Bild ändert. frameCount zählt die Aufrufe von draw(); Funktionen wie sin() erzeugen periodische Bewegungen:
function draw() { background(245); const x = width / 2 + sin(frameCount * 0.03) * 160; circle(x, height / 2, 50);}Für mehr Kontrolle speichern wir den Zustand in Variablen außerhalb von draw() und aktualisieren ihn schrittweise:
let x = 0;
function draw() { background(245); x = (x + 2) % width; circle(x, height / 2, 40);}Interaktion
p5.js verwaltet Variablen für Maus und Tastatur. mouseX und mouseY geben die Zeigerposition an; mouseIsPressed und keyIsPressed erlauben eine fortlaufende Zustandsabfrage:
let durchmesser = 50;
function draw() { background(245); fill(mouseIsPressed ? "#39ff14" : "#222"); circle(mouseX, mouseY, durchmesser);}
function keyPressed() { if (key === " ") { durchmesser = random(20, 100); }}Ereignisfunktionen wie mousePressed(), mouseDragged(), keyPressed() und touchStarted() ruft p5.js auf, sobald die entsprechende Aktion stattfindet.
Zufall, Wiederholung und Transformation
Schleifen und random() erzeugen gemeinsam Variationen:
function mousePressed() { background(245);
for (let i = 0; i < 100; i++) { const d = random(5, 40); circle(random(width), random(height), d); }}translate(), rotate() und scale() verändern das Koordinatensystem. Jede Transformation sollte zwischen push() und pop() stehen, damit sie die übrige Zeichnung nicht beeinflusst:
push();translate(width / 2, height / 2);rotate(frameCount * 0.01);rectMode(CENTER);rect(0, 0, 140, 40);pop();Dies sind die Grundbausteine: Zustand, Wiederholung, Variation, Zeit und Interaktion. Aus ihnen entstehen geometrische Muster ebenso wie Simulationen und generative Kunst. Die Beispiele oben verwenden den globalen Modus; im Instanzmodus wird den Funktionen und Variablen von p5.js lediglich p. vorangestellt, etwa bei p.circle() oder p.mouseX.
Ein Sketch in Aktion
Das CDN-Beispiel verwendet den globalen Modus, in dem setup() und draw() globale Funktionen sind. Damit ist nur ein Sketch pro Seite möglich. Für mehrere eingebettete Sketches nutzt dieser Artikel daher den Instanzmodus: Der Code erhält ein Objekt p, und alle p5-Funktionen werden mit dem Präfix p. aufgerufen.
Das Ergebnis läuft direkt auf dieser Seite:
p.setup = () => {
p.createCanvas(400, 400);
p.noFill();
};
p.draw = () => {
p.background(20);
for (let i = 0; i < 24; i++) {
p.stroke(150 + i * 4, 100, 255 - i * 8);
const r = 20 + i * 14 + p.sin(p.frameCount * 0.02 + i) * 10;
p.ellipse(p.width / 2, p.height / 2, r, r);
}
}; Kunst in zwei Zeilen
Rund um p5.js hat sich eine ganze Code-Golf-Subkultur entwickelt: Sketches sollen in einen Tweet passen, sodass jedes Zeichen zählt. Dieses Beispiel zeichnet in nur zwei Zeilen eine scheinbar dreidimensionale, wellenförmige Fläche:
a=(y,d=mag(k=(4+cos(i/9-t*2))*cos(i/35),e=y/7-13)+sin(e/9+t/2)-4)=>point((q=2*sin(k*3)-y/35*k*(9+k*sin(cos(e)*9-d*2+t)))+40*cos(c=d-t)+200,q*sin(c)+d*35)
t=0,draw=$=>{t||createCanvas(w=400,w);background(9).stroke(w,96);for(t+=PI/80,i=1e4;i--;)a(i/235)} Fast alle Tricks sparen Zeichen, statt die Zeichnung zu verändern: Die Standardparameter von a dienen zugleich als temporäre Variablen (d, k und e), Zuweisungen stecken direkt in Aufrufen (createCanvas(w=400,w) und cos(c=d-t)), die for-Schleife zählt rückwärts, weil i-- kürzer als ein Vergleich ist, und t||createCanvas(...) ersetzt setup(). Dahinter stehen lediglich zehntausend Punkte pro Bild, die mit Sinus und Kosinus positioniert werden, sowie eine Drehung um PI/80 Radiant bei jedem Aufruf von draw().
Möglichkeiten
p5.js zeichnet Grundformen — Linien, Kreise, Rechtecke und Polygone — sowie Bilder und Text. Hinzu kommen Werkzeuge für Farben, Transparenz und visuelle Effekte. Die draw()-Schleife erleichtert Animationen; Ereignisse reagieren auf Maus, Tastatur und Touchscreens. Videos lassen sich direkt wiedergeben und bearbeiten, während Audiofunktionen über die zusätzliche Bibliothek p5.sound bereitstehen. Der WebGL-Modus unterstützt außerdem dreidimensionale Grafiken, Beleuchtung, Kameras und Shader.
Online-Editor
Unter editor.p5js.org lässt sich p5.js-Code ohne Installation direkt im Browser schreiben und ausführen. Der Editor kann Sketches speichern und teilen und eignet sich gut zum Experimentieren und Lernen.
Fortgeschritten
Der letzte Sketch kombiniert dreidimensionale Grundkörper, Beleuchtung und hierarchische Transformationen zu einem stilisierten Vogel. Seine Flügel sind am Körper angelenkt; ihr Winkel ändert sich in jedem Bild und simuliert so den Flug. Bewegen Sie den Zeiger über die Szene, um sie aus verschiedenen Blickwinkeln zu betrachten:
p.setup = () => {
p.createCanvas(640, 400, p.WEBGL);
p.angleMode(p.RADIANS);
};
p.draw = () => {
p.background(225, 242, 250);
p.ambientLight(110);
p.directionalLight(255, 255, 255, -0.4, 0.6, -1);
const wingBeat = p.sin(p.frameCount * 0.12);
const rotationY = p.map(p.mouseX, 0, p.width, -0.35, 0.35, true);
const rotationX = p.map(p.mouseY, 0, p.height, 0.15, -0.15, true);
p.rotateX(rotationX);
p.rotateY(rotationY - 0.25);
p.rotateZ(-0.08);
// Body
p.noStroke();
p.fill(45, 62, 72);
p.push();
p.rotateZ(p.HALF_PI);
p.ellipsoid(58, 105, 52, 28, 20);
p.pop();
// Breast
p.fill(235, 238, 230);
p.push();
p.translate(24, 17, 32);
p.rotateZ(p.HALF_PI);
p.ellipsoid(38, 70, 18, 22, 14);
p.pop();
// Head, eyes, and beak
p.fill(55, 72, 78);
p.push();
p.translate(94, -25, 0);
p.sphere(42, 24, 16);
p.fill(245);
p.push();
p.translate(30, -10, 28);
p.sphere(9, 12, 8);
p.pop();
p.fill(20);
p.push();
p.translate(34, -11, 35);
p.sphere(4, 10, 6);
p.pop();
p.fill(255, 180, 35);
p.push();
p.translate(51, 4, 0);
p.rotateZ(-p.HALF_PI);
p.cone(12, 38, 4, 1);
p.pop();
p.pop();
// Articulated wings
const wing = (side) => {
p.push();
p.translate(-5, -8, side * 30);
p.rotateX(side * (0.55 + wingBeat * 0.65));
p.rotateY(side * 0.15);
p.fill(70, 92, 102);
for (let i = 0; i < 7; i++) {
p.push();
p.rotateY(side * (i - 3) * 0.055);
p.translate(-25 - i * 12, 0, side * (28 + i * 10));
p.rotateZ(p.HALF_PI + i * 0.045);
p.ellipsoid(14, 62 + i * 7, 7, 12, 8);
p.pop();
}
p.pop();
};
wing(-1);
wing(1);
// Tail
p.fill(65, 84, 92);
for (let i = -2; i <= 2; i++) {
p.push();
p.translate(-93, 12, i * 13);
p.rotateZ(p.HALF_PI + i * 0.04);
p.ellipsoid(10, 58, 7, 10, 8);
p.pop();
}
}; Fazit
Wie wir gesehen haben, ist p5.js ein leistungsfähiges Werkzeug, um unterschiedlichste Grafiken und Animationen direkt ins Web zu bringen. Zugleich besitzt es einen großen pädagogischen Wert und steht damit in der Tradition von Lernsprachen wie Logo.
