Last time we spent the whole episode building with other people -- the translator's job, the shared contract, the graceful fallback when your partner's feed drops. And right at the end I told you there's one more way the knowledge in your head wants to travel, and it's maybe the most lasting of all: handing the craft to someone who's standing exactly where you stood when you started. That's today. This is the episode about teaching creative coding -- running a workshop, building a little curriculum, and meeting a nervous beginner in a way that turns them into someone who can't stop making sketches. It's the circle closing, in a way. Everything this series taught you, you're now going to learn to pass on.
I'll be honest, teaching wrecked a lot of my assumptions. The first workshop I ran in Antwerp, I walked in with sixteen slides of theory and a beautiful shader demo, and I watched half the room go glassy-eyed in ten minutes. I thought teaching was showing how much I knew. It isn't. Teaching is the exact opposite -- it's finding the smallest thing that makes their eyes light up, and getting out of the way. So this episode is less about clever rendering and more about the shape you give a lesson so a real human can climb it. Allez, let's learn to teach.
Here's the thing nobody tells you: the person in front of you is not "a beginner". That word is useless. It hides everything you need to know. Do they already code but have never drawn a pixel? Are they an artist who's terrified of the terminal? Have they done a bit of p5.js and hit a wall? Each of those is a completely diffrent person who needs a completely diffrent first hour. So, exactly like everywhere in this arc, I start by turning the fog into data -- an honest record of who's actually in the room:
// "beginner" hides everything. capture who they ACTUALLY are before you teach a thing.
const learner = {
name: "anonymous",
codesAlready: false, // do they know a loop and a variable?
drawsAlready: true, // are they comfortable with visual thinking?
goal: "make a moving thing to project at a gig",
fear: "the blank editor -- doesn't know where to type",
};
Look at that fear field. That is the most important line in the whole object, and it's the one every curriculum ignores. If their fear is the blank editor, no amount of noise-function theory helps them -- you have to solve the blank editor first. Writing down what the learner brings and what scares them, in their own words, is what stops you teaching the lesson you wish you'd had instead of the lesson they actually need. Serve the person in the chair, not the syllabus in your head.
Now, the syllabus itself. Beginners think a curriculum is a straight line -- topic one, topic two, topic three. It isn't. It's a graph: some ideas simply cannot be learned before others, because they lean on them. You can't teach particle systems before you've taught a loop and a coordinate. So I model a little curriculum the same way we modelled a network back in the graph-visualisation episode -- concepts as nodes, prerequisites as edges:
// concepts aren't a line, they're a graph. each one needs its prerequisites first.
const concepts = {
"canvas": [],
"shapes": ["canvas"],
"color": ["shapes"],
"loops": ["shapes"],
"grids": ["loops", "color"],
"randomness": ["shapes"],
"motion": ["loops"],
"particles": ["motion", "randomness"],
};
Once it's a graph, you can ask it questions no straight-line list could answer. The most useful one is: given where a learner already is, what can they safely learn next? A concept is teachable only when every one of its prerequisites is already known:
// what can this learner tackle next? only concepts whose prerequisites are all met.
function teachableNext(concepts, known) {
return Object.entries(concepts)
.filter(([name]) => !known.includes(name)) // not already learned
.filter(([, needs]) => needs.every((p) => known.includes(p)))
.map(([name]) => name);
}
console.log(teachableNext(concepts, ["canvas", "shapes", "color", "loops"]));
// -> ["grids", "randomness", "motion"] : any of these is a safe next step
That little function is a teacher's compass. It never lets you drop someone into particles before they've got motion and randomness under their fingers -- which is exactly the mistake I made in that first workshop, jumping to the shiny thing before the floor was built. Respect the graph and your learner never feels lost, because every new idea rests on something they already own.
Remember that learner's fear -- the blank editor. Here's the single most powerful move in all of teaching creative coding, and it took me years to trust it: never start from nothing. A blank file is a cliff. Instead you hand them a tiny sketch that already runs and already makes something on screen, and you let them poke it. Working code they can break is a hundred times less scary than an empty page they have to fill:
// NEVER hand a beginner a blank file. hand them this -- it runs, and it already moves.
function starterSketch(ctx, t) {
ctx.fillStyle = "#111";
ctx.fillRect(0, 0, 400, 400); // dark background
const x = 200 + Math.sin(t) * 120; // <-- tell them to change the 120
ctx.fillStyle = "tomato";
ctx.beginPath();
ctx.arc(x, 200, 40, 0, Math.PI * 2); // a circle that slides side to side
ctx.fill();
}
The teaching trick is the comment. You don't explain sin, you don't explain the render loop, you don't explain any of it yet. You say: "See that 120? Change it to 40. Now change it to 300. What happened?" And they do it, and the circle's travel changes, and suddenly they're not a spectator -- they're driving. That first tiny edit, that one number they changed and saw move, is where a creative coder is actually born. Everything else is built on the confidence of that first successful poke.
The most common way a workshop fails is greed -- the teacher tries to cover everything and the room drowns. Human working memory is tiny, and a beginner's is tinier still because half of it is busy just being nervous. So I hard-limit every session to one new idea, and I build the plan as data so I can see when I've overloaded it:
// one new concept per session. more than that and the room drowns. enforce it.
function lessonPlan(concept, minutes) {
return {
concept, // the ONE new thing
hook: `show a finished piece that uses ${concept}`,
play: "let them edit a working starter for 10 min",
explain: "only NOW give the why, once they've felt it",
make: "they build their own tiny version",
minutes,
};
}
const plan = lessonPlan("randomness", 45);
Notice the order: hook, play, explain, then make. The explanation comes third, not first -- and that inversion is the whole secret. This series itself was built on the same rule, one focused topic per episode, because I learned it the hard way in these rooms. If you catch yourself writing a plan with two new concepts in it, split it into two sessions. Nobody ever complained that a workshop moved too gently.
That explain step above is delicate. Beginners don't want the theory up front -- it's abstract and it slides off. But the moment after they've felt something work, they're suddenly hungry for why. That's the teachable moment, and it's narrow. So I keep my explanations tiny and tied to the thing they just did, never a lecture:
// give the "why" AFTER they feel it, in one breath, tied to what they just changed.
const whyBank = {
randomness: "that random() gives a diffrent number each run -- " +
"that's why your sketch is never twice the same.",
motion: "we redraw 60 times a second, nudging things a little each time -- " +
"your eye fills the gaps and calls it movement.",
color: "colour is just three numbers, red green blue -- " +
"you're not picking paint, you're mixing light.",
};
function explainNow(concept) {
return whyBank[concept] ?? "let's just play with it first.";
}
One sentence. That's the dose. If they want more they'll ask, and then you go deeper -- but you follow their curiosity, you don't front-load it. The ?? "let's just play with it first" fallback is deliberate: if I haven't got a crisp one-liner for a concept, that's a sign I don't understand it well enough to teach it yet, and the honest move is to play instead of waffle. Teaching a concept is the fastest way to discover the holes in your own understanding of it.
Here's something that surprised me: the most valuable minutes in any workshop are not when things work -- they're when something breaks. A beginner's instinct when they hit an error is shame and panic. Your job is to model the opposite: calm, curiosity, and a process. So I teach debugging as a tiny ritual, out loud, every single time:
// beginners panic at errors. teach the ritual out loud, every time, until it's theirs.
function debugRitual(error) {
return [
`1. read the message: "${error.message}"`,
`2. what LINE? -> ${error.line}`,
`3. what did you change last? undo just that.`,
`4. print the value -- console.log(it) -- don't guess.`,
`5. still stuck? explain it out loud to me (or a rubber duck).`,
];
}
That step five is not a joke. Half the time, the learner solves their own bug in the middle of explaining it to me, because saying it slowly forces them to actually read what they wrote instead of what they meant to write. We call it rubber-duck debugging for a reason. When you teach the ritual instead of just fixing the bug for them, you're handing over the one skill that makes them independent of you -- and that, honestly, is the whole point of teaching. A learner who can debug is a learner who no longer needs the teacher.
At some point they show you what they made, and how you respond in that moment matters more than any code you'll ever write. Vague praise ("nice!") teaches them nothing. Harsh critique crushes a beginner before they've built any armour. What works is feedback with a shape: name something real that's good, offer one concrete thing to try next, and always leave the door open:
// "nice!" teaches nothing, harsh critique crushes. give feedback a kind, useful shape.
function feedback(piece) {
return {
seen: `the way your particles slow near the edges -- that's a lovely touch`,
oneThing: `try mapping their colour to their speed and see what happens`,
invite: `what were you hoping it would feel like?`, // let THEM lead
};
}
That oneThing field is capped at one on purpose. Dump five suggestions on a beginner and they freeze; give them one clear next experiment and they'll go try it tonight. And the invite question hands the direction back to them -- because it's their piece, their vision, and your job is to help them get where they want to go, not where you would have gone. The best feedback I ever got wasn't a fix, it was a question that made me see my own work more clearly.
A workshop with mixed experience is the hardest room to run, and pretending everyone's the same is how you lose both ends -- the beginners drown while the confident ones get bored. So I plan branches. Same core exercise, but with an easier on-ramp and a harder extension ready, and I route each learner to the version that fits them:
// mixed room = plan branches. same exercise, gentler on-ramp, harder extension.
function routeExercise(learner) {
if (!learner.codesAlready) {
return "edit the starter: change 3 numbers, describe what each does";
}
if (learner.known?.includes("particles")) {
return "extension: add a force field the particles react to";
}
return "core: build a 20-particle system from the starter";
}
The gentle on-ramp keeps the nervous ones moving instead of stuck, and the extension keeps the fast ones stretched instead of bored and disruptive. Everybody's working at the edge of their own ability, which is the only place real learning happens. It's more prep for you, but a room where nobody is drowning and nobody is bored is worth every extra minute you spent planning the branches.
Beginners badly underestimate their own progress -- they compare their week-two sketch to some master's finished piece and feel like failures. Part of teaching is holding up a mirror to how far they've actually come. So I keep a tiny log of what each learner has unlocked, and I make a point of showing it to them:
// beginners can't SEE their own progress. log it, then show them the climb.
function markLearned(learner, concept) {
const known = new Set([...(learner.known ?? []), concept]);
return { ...learner, known: [...known] };
}
function progress(learner, concepts) {
const total = Object.keys(concepts).length;
const done = (learner.known ?? []).length;
return `${done}/${total} concepts -- ${(done / total * 100).toFixed(0)}% of the map`;
}
When you show someone "hey, three weeks ago you couldn't draw a circle, and look -- you've got eight concepts now and you built a particle system", something shifts in them. The abstract feeling of "I'm bad at this" turns into a concrete number that's clearly going up. That reframe, from a vague wound into a visible climb, is the same trick we used on our own submission funnel last week -- and it works just as well pointed at a nervous learner as it did pointed at ourselves.
There's one last idea I want to leave you with, and it's the quiet reason teaching matters at all. Everything you struggled to figure out -- every wall you hit, every night you spent confused about why your loop wouldn't animate -- you can hand to the next person as a starting point. They don't have to bleed for it the way you did. That's not you losing an edge. That's the whole craft moving forward:
// what cost you a week of pain becomes their five-minute head start. that's the point.
function handOff(hardWonLesson) {
return {
tookMe: hardWonLesson.myStruggleDays, // what it cost me to learn
givesThem: "a five-minute head start", // what it costs them now
net: "the craft moves forward by one person",
};
}
const lesson = handOff({ myStruggleDays: 7, whatILearned: "always redraw the bg" });
I used to worry, in a small ungenerous way, that teaching people would somehow use me up -- that giving away what I knew left me with less. It's the exact opposite. Every person I've taught has come back and shown me something I'd never have found alone, and the ones who started in my workshops are making work now that genuinly humbles me. You don't shrink by teaching. You become the root of a whole tree of makers, and that is a far bigger thing to be than the best coder in an empty room.
teachableNext check keeps you from ever dropping someone into particles before they own motion and randomnessSo that's the real shape of teaching, and you'll notice again how little of it was about clever code. The code was the easy half -- a dependency graph, a starter sketch, a debugging ritual. The hard and beautiful half is human: reading a nervous person well enough to find the one small thing that lights them up, then being generous enough with your patience that they walk out wanting to make more. Get that right and you don't just make art anymore -- you make artists, and they go on making long after your workshop ends.
Here's the thread forward. Teaching one person, or one room, is intimate and slow and wonderful. But you're not the only one out there doing this, and the makers you teach don't stay in your workshop -- they go looking for others like them. There's a whole living world of people who make things with code, sharing, challenging, and lifting each other, and finding your place in it changes everything about how you keep going. That's where we head next time. 't Was plezant to teach the teachers today :-).
Sallukes! Thanks for reading.
X