Résumé EN (abstract): This intermediate creative coding course builds on p5.js basics to develop more sophisticated generative systems. Students learn Perlin noise fields, object-oriented particle systems, vector field flows, data-driven visuals, and generative typography. They practice clean export workflows for print and screen, and apply structured iteration (sketch journal) to develop a cohesive body of work. The capstone project is a series of three related generative works around a single concept. Outline: Perlin noise fields → Particle systems (OOP) → Vector flow fields → Data-driven art → Generative typography → Audio-reactive sketches → Clean export workflow → Series project.
Objectifs d'apprentissage
À la fin de ce cours, l'étudiant·e sera capable de :
- Analyser (Bloom : analyzing) les propriétés du bruit de Perlin et les différencier du random pour choisir l'outil adapté à une intention.
- Concevoir (creating) un système de particules avec comportements (vitesse, force, durée de vie) en programmation orientée objet.
- Implémenter (applying) un champ de vecteurs basé sur le bruit pour générer des flux organiques.
- Construire (creating) une visualisation data art à partir d'un jeu de données réel (CSV ou JSON).
- Générer (applying) de la typographie paramétrique et animée.
- Exporter (applying) des œuvres haute résolution prêtes pour l'impression et la projection.
Module 1 — Bruit de Perlin avancé (2h)
Concept
Le bruit de Perlin, inventé par Ken Perlin pour le film Tron (1982) et formalisé dans un article SIGGRAPH en 1985, produit des valeurs aléatoires continues — les valeurs voisines sont proches, créant une texture "naturelle".
Perlin, K. (1985). An Image Synthesizer. SIGGRAPH '85, pp. 287–296. https://doi.org/10.1145/325334.325247
Trois dimensions du bruit :
noise(x): variation 1D (ex. hauteur d'une courbe)noise(x, y): variation 2D (ex. texture de terrain)noise(x, y, t): variation 3D avec le temps — le bruit évolue doucement
javascript // Cartographie d'un champ de bruit 2D let scale = 0.008; for (let x = 0; x < width; x += 4) { for (let y = 0; y < height; y += 4) { let n = noise(x * scale, y * scale); let c = map(n, 0, 1, 0, 255); fill(c); noStroke(); rect(x, y, 4, 4); } }
noiseDetail(octaves, falloff) : contrôle la finesse du bruit. Plus d'octaves = plus de détail (mais plus lent).
Lab 1.1 — Paysage de bruit
Étapes :
- Générer une image 600×400 en cartographiant
noise(x*scale, y*scale)vers la couleur - Faire varier
scaleentre 0.002 et 0.02 — observer l'effet sur la granularité - Ajouter une dimension temporelle :
noise(x*scale, y*scale, frameCount*0.005)— le paysage se transforme lentement - Mapper le bruit vers une palette de couleurs (pas juste gris) : teinte HSB, altitude → couleur
Module 2 — Programmation orientée objet : la classe Particule (2h)
Concept
La programmation orientée objet (OOP) permet de regrouper données et comportements dans une classe. En creative coding, c'est la base des systèmes complexes : chaque particule, oiseau, cellule est un objet avec son propre état.
`javascript class Particule { constructor(x, y) { this.pos = createVector(x, y); this.vel = p5.Vector.random2D().mult(random(1, 3)); this.acc = createVector(0, 0); this.vie = 255; // opacité = durée de vie this.taille = random(4, 12); this.teinte = random(30, 60); }
appliquerForce(force) { this.acc.add(force); }
update() { this.vel.add(this.acc); this.vel.limit(4); // vitesse maximum this.pos.add(this.vel); this.acc.mult(0); // reset accélération this.vie -= 2; // vieillissement }
estMorte() { return this.vie <= 0; }
afficher() { colorMode(HSB, 360, 100, 100, 255); fill(this.teinte, 80, 90, this.vie); noStroke(); ellipse(this.pos.x, this.pos.y, this.taille); } } `
Tableau de particules + nettoyage : `javascript let particules = [];
function draw() { background(0, 20); // trace semi-transparente
// Ajouter 3 particules par frame for (let i = 0; i < 3; i++) { particules.push(new Particule(mouseX, mouseY)); }
// Mettre à jour et nettoyer les mortes for (let i = particules.length - 1; i >= 0; i--) { particules[i].update(); particules[i].afficher(); if (particules[i].estMorte()) particules.splice(i, 1); } } `
Lab 2.1 — Système de particules interactif
Étapes :
- Implémenter la classe Particule ci-dessus
- Ajouter une force de gravité :
appliquerForce(createVector(0, 0.05)) - Ajouter un rebond sur les bords
- Faire varier la teinte selon la position (map x→teinte)
- Bonus : ajouter une attraction vers un point fixe (distance → force)
Module 3 — Champs de vecteurs et flux organiques (2h)
Concept
Un champ de vecteurs associe à chaque point de l'espace une direction. Les particules qui suivent le champ créent des flux organiques — rivières, vent, courant marin.
Générer le champ depuis le bruit de Perlin : javascript function directionLocale(x, y) { let scale = 0.003; let t = frameCount * 0.0006; let angle = noise(x * scale, y * scale, t) * TWO_PI * 2; return p5.Vector.fromAngle(angle); }
La particule suit le champ : javascript update() { let dir = directionLocale(this.pos.x, this.pos.y); dir.setMag(1.5); // force du courant this.appliquerForce(dir); //... reste de l'update }
Visualiser le champ (debug) : javascript function afficherChamp() { let pas = 30; for (let x = 0; x < width; x += pas) { for (let y = 0; y < height; y += pas) { let dir = directionLocale(x, y); stroke(255, 40); strokeWeight(1); let dest = createVector(x, y).add(dir.copy().setMag(15)); line(x, y, dest.x, dest.y); } } }
Lab 3.1 — Flux de particules
Étapes :
- Combiner la classe Particule (Module 2) avec le champ de vecteurs
- Partir de 500 particules distribuées aléatoirement
- Chaque particule suit le champ + vieillissement lent (vie = 3000 frames)
- Pas de
background()dansdraw()— laisser les traces s'accumuler - Générer 3 variations (changer
scaleet la vitesse d'évolution temporelle du champ)
Module 4 — Data art : charger et visualiser des données (2h)
Concept
Le data art transforme des données en formes visuelles avec une intention esthétique et narrative. p5.js permet de charger facilement des fichiers CSV ou JSON.
Charger un CSV : `javascript let table;
function preload() { // preload() s'exécute avant setup() table = loadTable('data.csv', 'csv', 'header'); }
function setup() { createCanvas(800, 600); for (let i = 0; i < table.getRowCount(); i++) { let valeur = table.getNum(i, 'population'); let nom = table.getString(i, 'ville'); // visualiser... } } `
Charger un JSON : `javascript let donnees;
function preload() { donnees = loadJSON('data.json'); } `
Choix de la forme pour la donnée :
| Type de donnée | Formes suggestives |
|---|---|
| Quantité | Taille, surface, hauteur |
| Catégorie | Couleur, forme |
| Séquence temporelle | Position x (gauche→droite) |
| Rapport | Angle, proportion |
| Densité | Nombre de points, opacité |
Lien mini-cours : Data Art : donner une forme à l'invisible — voir ce mini-cours pour un exemple complet de mapping donnée→motif.
Lab 4.1 — Visualisation d'un jeu de données réel
Étapes :
- Télécharger un dataset simple au format CSV (ex. données climatiques, démographiques) depuis https://data.gouv.fr ou https://opendata.ma
- Créer un CSV avec au moins 20 lignes et 3 colonnes
- Charger avec
loadTableet visualiser 3 variables en parallèle (ex. x = année, y = valeur, taille = autre valeur) - Ajouter labels (
text()) pour les valeurs extrêmes - Exporter en PNG
Mini-exercice : Refaire la même visualisation avec 2 encodages visuels différents. Lequel communique mieux l'information ? Lequel est plus poétique ?
Module 5 — Typographie générative (2h)
Concept
En creative coding, le texte n'est pas seulement information — c'est forme, rythme, matière. p5.js permet de traiter les lettres comme des objets graphiques.
Charger une police custom : `javascript let maPolice;
function preload() { maPolice = loadFont('fonts/Roboto-Regular.ttf'); }
function setup() { textFont(maPolice); textSize(120); } `
Obtenir les points d'un glyphe (tracé vectoriel) : `javascript // textBounds() : boîte englobante // font.textBounds(texte, x, y, taille) → {x, y, w, h}
// Récupérer les points du contour let points = maPolice.textBounds('A', 0, 0, 200); // Note : p5.js ne donne pas directement les contours vectoriels. // Pour des effets avancés sur les tracés, utiliser opentype.js // https://opentype.js.org — parser les courbes Bézier de chaque glyphe `
Effets sur le texte : `javascript // Texte qui tremble let offsetX = random(-2, 2); let offsetY = random(-2, 2); text('CREATIVE', width/2 + offsetX, height/2 + offsetY);
// Texte répété en dégradé for (let i = 0; i < 8; i++) { fill(30, 80, 90, map(i, 0, 8, 20, 200)); text('CODE', width/2, height/2 + i * 3); } `
Lien mini-cours : Typographie Arabe en Mouvement — explore le calligraphe comme compositeur du temps.
Lab 5.1 — Affiche typographique générative
Étapes :
- Choisir un mot ou une phrase courte (5–20 caractères)
- Afficher le texte à grande taille (120–200px)
- Ajouter 3 effets : variation de taille par
sin(), tremblementrandom, décalage sur les bords - Intégrer le texte dans une composition avec des formes géométriques
- Exporter en 2400×2400 avec
pixelDensity(2)
Module 6 — Audio-réactif : visualiser le son (2h)
Concept
L'audio-réactif connecte le signal sonore à des paramètres visuels. En p5.js, la bibliothèque p5.sound fournit les outils nécessaires.
p5.sound documentation : https://p5js.org/reference/#/libraries/p5.sound
FFT — Fast Fourier Transform : décompose le signal audio en fréquences. fft.analyze() retourne un tableau de 1024 valeurs (amplitude par fréquence).
Amplitude : volume global du signal.
html <!-- Ajouter dans l'HTML (avant le sketch) : --> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/addons/p5.sound.min.js"></script>
`javascript let fft, amplitude, son;
function preload() { son = loadSound('musique.mp3'); }
function setup() { createCanvas(800, 400); fft = new p5.FFT(0.8, 1024); amplitude = new p5.Amplitude(); son.loop(); }
function draw() { background(10); let spectrum = fft.analyze(); // tableau amplitude par fréquence let vol = amplitude.getLevel(); // volume global 0–1
// Visualiser le spectre en barres colorMode(HSB, 360, 100, 100); for (let i = 0; i < spectrum.length; i += 4) { let h = map(spectrum[i], 0, 255, 0, height); let teinte = map(i, 0, spectrum.length, 0, 360); fill(teinte, 80, 90); noStroke(); rect(i (width / spectrum.length) 4, height - h, width / spectrum.length * 4, h); } } `
Entrée microphone (Live input) : `javascript let mic;
function setup() { mic = new p5.AudioIn(); mic.start(); fft.setInput(mic); } `
Lab 6.1 — Visualiseur audio
Étapes :
- Créer un visualiseur avec le micro comme entrée (ou un fichier MP3)
- Visualiser le spectre FFT + l'amplitude globale
- Faire que l'amplitude contrôle un paramètre non-sonore (taille des particules, vitesse du champ)
- Créer 2 modes visuels distincts (ex. barre / radial) switchés avec la touche espace
Module 7 — Export propre et workflow de série (2h)
Concept
Un workflow d'export professionnel garantit que les sketches sont reproductibles, haute résolution et documentés.
Checklist export : `javascript function setup() { pixelDensity(2); // 2× résolution écran createCanvas(2400, 2400); // format carré haute résolution colorMode(HSB, 360, 100, 100, 100); randomSeed(SEED); // fixer le seed noiseSeed(SEED); noLoop(); }
const SEED = 137; // changer pour chaque variation `
Nommer les exports de façon traçable : javascript function keyPressed() { if (key === 's') { saveCanvas(serie-01_seed${SEED}_${year()}${month()}${day()}, 'png'); } }
Journal de sketches (sketchbook) : tenir un document avec — pour chaque sketch : date, concept, seed, ce qui a marché/pas marché, prochaine piste. C'est le journal d'atelier du creative coder.
Lab 7.1 — Série de 3 variations
Étapes :
- Prendre votre sketch préféré des modules précédents
- Identifier 2 paramètres à varier pour créer 3 œuvres distinctes de la même "famille"
- Exporter chaque variation en 2400×2400 avec seed documentée
- Écrire 3 lignes de journal pour chaque variation : intention, résultat, suite
Module 8 — L-systèmes et structures récursives (2h)
Concept
Les L-systèmes (Lindenmayer, 1968) sont des grammaires formelles qui génèrent des structures arborescentes et fractales par réécriture. En p5.js, on implémente l'interprète de l'alphabet en commandes de dessin.
Lindenmayer, A. (1968). Mathematical models for cellular interactions in development. Journal of Theoretical Biology, 18(3), 280–315.
Turtle graphics : `javascript class Tortue { constructor() { this.x = width / 2; this.y = height; this.angle = -PI / 2; // pointe vers le haut this.stack = []; }
avancer(longueur) { let x2 = this.x + cos(this.angle) longueur; let y2 = this.y + sin(this.angle) longueur; line(this.x, this.y, x2, y2); this.x = x2; this.y = y2; }
tourner(angle) { this.angle += angle; } push() { this.stack.push({x: this.x, y: this.y, a: this.angle}); } pop() { let s = this.stack.pop(); this.x = s.x; this.y = s.y; this.angle = s.a; } }
// Interpréter une chaîne L-système function interpreter(chaine, longueur, angle) { let t = new Tortue(); for (let c of chaine) { if (c === 'F') t.avancer(longueur); else if (c === '+') t.tourner(angle); else if (c === '-') t.tourner(-angle); else if (c === '[') t.push(); else if (c === ']') t.pop(); } } `
Axiome et règle pour un arbre simple : Axiome : F Règle : F → F[+F]F[-F]F Angle : 25°
Lab 8.1 — L-système paramétrique
Étapes :
- Implémenter la classe Tortue et la fonction
interpreter() - Générer 5 itérations de l'arbre simple ci-dessus
- Paramétrer l'angle (slider ou variable) — observer comment l'arbre change de 10° à 45°
- Créer votre propre règle de réécriture (2 règles différentes, lettre de dessin + lettre de saut)
- Animer l'angle en
sin()— l'arbre respire
Projet fil rouge — "Série de 3 œuvres sur un concept"
Brief
Créer une série cohérente de 3 œuvres génératives autour d'un concept unique — trois variations d'un même système, explorant différents paramètres ou états.
Contraintes
- Technologie : p5.js
- Les 3 œuvres doivent être reconnaissables comme appartenant à la même série (palette, forme, structure)
- Chaque œuvre utilise au moins un des systèmes avancés du cours (champ de vecteurs, L-système, data, typographie, audio)
- Export haute résolution pour chaque œuvre (2400×2400 min)
- Seeds documentées pour les 3 œuvres
Livrables
- 3 sketches p5.js (ou 1 sketch avec paramètres de série)
- 3 exports PNG haute résolution avec seeds
- Documentation de série (2 pages) : concept de la série, règles de cohérence, 3 fiches œuvre (titre, seed, paramètres clés)
- Journal de 3 pages : process, ce qui a été tenté, décisions finales
- Présentation (8 min) : montrer la série + argumenter les choix
Rubrique d'évaluation
| Critère | Insuffisant (1) | Satisfaisant (2) | Bon (3) | Excellent (4) |
|---|---|---|---|---|
| Maîtrise technique | < 2 systèmes utilisés, bugs | 2 systèmes, fonctionne | 3+ systèmes maîtrisés, code lisible | Systèmes combinés de façon sophistiquée |
| Cohérence de la série | 3 sketches sans lien | Palette commune | Concept commun + variations lisibles | Dialogue fort entre les 3 œuvres |
| Qualité formelle | Visuel non intentionnel | Composition lisible | Palette, équilibre, espace | Sophistication formelle, tension règle/aléatoire |
| Documentation | Absente | Seeds + titres | Fiches œuvre + concept de série | Journal de process + réflexion sur le système |
| Export | Pas d'export ou basse résolution | PNG présents | 2400+ avec seeds | 3 variations + seed + nom traçable |
Lectures & ressources
- p5.js référence : https://p5js.org/reference/
- The Nature of Code (Daniel Shiffman) — systèmes, agents, forces : https://natureofcode.com
- The Coding Train — champs de vecteurs, L-systèmes : https://youtube.com/c/TheCodingTrain
- opentype.js (tracés vectoriels de glyphes) : https://opentype.js.org
- data.gouv.fr (données ouvertes France) : https://data.gouv.fr
- opendata.ma (données ouvertes Maroc) : https://www.data.gov.ma
- Perlin, K. (1985). An Image Synthesizer. SIGGRAPH '85. https://doi.org/10.1145/325334.325247
→ Niveau suivant : Creative Coding — Niveau 3 → Formation sur mesure pour votre école ou équipe : Prendre rendez-vous
Workshop intensif (1–2 j) pour écoles, studios, musées — théorie condensée, labs guidés, accompagnement projet.
Prendre rendez-vous (30 min, gratuit) →