Last time I got a little wistful at the end - I said you make something wonderful live for four minutes and then it's gone, and you probably couldn't find your way back to it tomorrow. That sting isn't just a live-coding problem. It's the whole of this craft. You seed a flow field, you nudge eight parameters, and out comes a picture that makes you gasp - and then you tweak one more thing to make it even better, and you ruin it, and the good version is nowhere. Gone. You sit there trying to remember: was it seed 41 or 42? Was the noise scale 0.08 or 0.008? Allez, today we fix that forever :-).
The tool for this is Git, and I know - the moment I say "version control" half of you picture a grumpy backend meeting about merge conflicts. Forget all that. For us, Git is not a corporate ceremony. It's a time machine for your art. It's the thing that lets you be brave with a sketch you love, because you can always walk back to exactly how it was five minutes, five days, or five months ago. That safety is the whole point, and it changes how you make things.
Before we do it properly, let me show you the pit basically everyone falls into first, because naming the pit is half of climbing out. You make a sketch you like, so you save a copy. Then another. And a week later your folder looks like this:
sketch.js
sketch-final.js
sketch-final-v2.js
sketch-final-FIXED.js
sketch-final-USE-THIS-ONE.js
sketch-good-colors-broken-motion.js
sketch-backup-tuesday.js
I lived in that folder for years, and I bet some of you are reading this from inside it right now :-). It's a disaster for one simple reason: those filenames are your memory, and your memory is a liar. Six weeks from now you will have no idea what "USE-THIS-ONE" was better than. The information you actually need - what changed, when, and why - isn't written down anywhere. Git's entire job is to store that information properly so your folder can just have sketch.js, one file, and all the history lives quietly underneath.
Getting going is genuinly tiny. In your project folder, you run three things once, and from that moment on your work has a memory. A "repository" - repo - is just your folder plus a hidden .git sub-folder where all the history is kept.
cd my-sketch-project # go into your project folder
git init # create the hidden .git history store. one time only.
git add . # stage everything in the folder as "ready to save"
git commit -m "First version of the flow field sketch" # save a snapshot!
That's it - you now have your first commit. A commit is a saved snapshot of your whole project at one moment, with a little message attached saying what it is. Think of it as a save point in a game. The magic isn't that it copied your files (any backup does that); it's that it copied them with a label and a timestamp and a place in a timeline, so you can navigate between save points later. From here on, every time you reach a state worth keeping, you take another snapshot, and Git remembers the whole chain.
# your day-to-day loop, once the repo exists:
git add . # stage the current state
git commit -m "Added Perlin noise to the particle drift" # snapshot it with a note
git log --oneline # see your whole history, newest first
The git log --oneline at the end is where it starts feeling magic. That command prints your entire creative history as a tidy list, and suddenly you're not staring at a folder of lying filenames - you're reading a diary of how the piece grew. Wich brings me to the single most underrated skill in this whole episode.
Here's the thing nobody tells beginners: the commit message is worth more than the commit. The snapshot is automatic; the message is where you record what your past self was thinking. And for art, that's gold, because the "why" behind a change is exactly the thing you forget first. Compare these two histories:
# a useless history - technically valid, tells you nothing:
# a1b2c3 update
# d4e5f6 stuff
# g7h8i9 more stuff
# j0k1l2 fix
# a history that's actually a creative journal:
# a1b2c3 Warmer palette - the cold blues felt clinical
# d4e5f6 Slowed the drift way down, feels more like ink in water now
# g7h8i9 Tried 500 particles - too busy, backing off to 200
# j0k1l2 Locked seed 42, this is THE composition
Read that second one. You can feel the piece being made. Six months from now, that history will tell you not just what the code was, but what you were chasing and what you learned - "500 particles was too busy" is a lesson you paid for once and now never have to relearn. I write these messages like little notes to a friend, because that friend is me-in-the-future, who will have completely forgotten today. Makes sense, right? Be kind to that person.
Now here's where it gets specific to our craft, and it's the bit generic Git tutorials will never teach you. For a generative piece, the code is often only half the artwork. The other half is the seed and the parameters. Remember way back in episode 24, when we made randomness reproducible with a seed? That was the seed of this whole idea (pun very much intended). A single sketch file can make a million different pictures depending on its seed and knob settings - so if you only commit the code, you haven't actually saved the picture, you've saved the machine.
So the trick is: whenever you land on a look you love, save its exact inputs to a little file right next to the code, and commit both together. Let me write a helper that captures the full state of a running sketch.
// capture EVERYTHING needed to reproduce this exact picture: the seed + every knob.
// this little object IS the artwork, as much as the code is.
function captureState(seed, params) {
return {
seed: seed, // the seed from episode 24 - reproducible randomness
params: params, // every knob: noiseScale, particleCount, palette, speed...
date: new Date().toISOString(),
note: "", // room for a human note about why this one's good
};
}
// when you hit a keeper, dump it as JSON you can save beside the code:
const keeper = captureState(42, {
noiseScale: 0.008,
particleCount: 200,
speed: 0.4,
palette: "warm-ink",
});
console.log(JSON.stringify(keeper, null, 2)); // copy this into a state file
Now you write that JSON to a file the project keeps - say states/the-good-one.json - and commit it with the code:
git add sketch.js states/the-good-one.json
git commit -m "Ink-in-water look: seed 42, noise 0.008, 200 particles"
That commit is now a complete time capsule. The code, the seed, the every-knob-setting, and a human note about why it's good, all frozen together at one point in the timeline. Bring that commit back and you don't get "a sketch that makes something like it" - you get the exact pixels, bit for bit. That's the difference between saving a recipe and saving the actual cake :-).
Capturing is only half of it; the whole point is getting it back. So the other side of the helper reads a state file and pushes those values into your sketch, so any saved moment can be re-summoned instantly.
// re-summon a saved picture: read the state file and pour it back into the sketch.
async function loadState(url, sketch) {
const res = await fetch(url); // grab the saved JSON (states/the-good-one.json)
const state = await res.json();
sketch.rng = CC.seeded(state.seed); // restore the exact randomness (episode 24!)
Object.assign(sketch.params, state.params); // restore every knob at once
sketch.restart(); // redraw from a clean start with the old inputs
return state;
}
The first time you do this it feels a bit like a card trick. You mangle a sketch beyond repair, fiddling and fiddling until it's ugly, and then you load a state from three days ago and the exact gorgeous thing snaps back onto the screen, pixel-perfect. All your ruinous fiddling, undone in a heartbeat. Once you trust that this works - really trust it - you fiddle harder, because there's no cost to wrecking things anymore. That's the whole psychological gift of version control: it makes destruction safe, and safe destruction is where the best experiments live.
Right, this is my favourite part, and it's the one that most changes how you make. A branch is a parallel timeline. You split off from your main work, go wild down a side-path, and if it turns into gold you fold it back in - and if it turns into garbage you just delete the branch and it's like it never happened. Your good main version was never even touched.
# you've got a piece you like on the main line. now you want to try something risky.
git checkout -b try-glitch-palette # make and jump onto a NEW parallel timeline
# ...now go absolutely feral. rewrite the colours, break the motion, experiment hard.
git add .
git commit -m "Trying a harsh glitchy palette + jittery motion"
# love it? bring it back to your main line:
git checkout main # hop back to the safe timeline
git merge try-glitch-palette # fold the experiment in
# hate it? just walk away and delete it. main never knew it happened:
git checkout main
git branch -D try-glitch-palette # poof. gone. no harm done.
Do you see what this gives you? Before I worked this way, every experiment carried a little tax of fear - "if I go down this road and it's bad, I have to manually undo all of it and I might not get my nice version back exactly". That fear quietly makes you experiment less, and timid experiments make timid art. Branching deletes the fear. You spin up try-something-mad, you throw the kitchen sink at it, and the worst case is you type git branch -D and you're right back where you were, unharmed. I genuinely make wilder work now than I did before I trusted branches, and that's not a technical improvement, it's a creative one.
A lovely habit is to keep a branch per direction you're exploring - warm-version, cold-version, chaos-version - all growing from the same root sketch. You hop between them, let them develop separately, and cherry-pick the winner later. It's like having three easels going at once, each a different mood of the same idea.
Because we version the inputs as JSON, something wonderful falls out for free. Git's diff command shows you exactly what changed between two snapshots, line by line - and when your parameters live in a text file, that means Git can tell you precisely what turned yesterday's look into today's.
git diff HEAD~1 states/the-good-one.json # what changed vs the previous commit?
"params": {
- "noiseScale": 0.008,
+ "noiseScale": 0.02,
- "particleCount": 200,
+ "particleCount": 340,
"speed": 0.4,
}
Look how legible that is. It's telling you, in plain numbers, "between these two versions you cranked the noise scale up and added 140 particles". That's the exact information your eyes struggle to reverse-engineer from two images side by side. When two versions look different and you can't figure out why, the diff just tells you. This is why storing parameters as flat, readable JSON (rather than, say, a binary blob) is such a quietly powerful choice - it makes your art's history diffable, and a diffable history is one you can actually learn from.
One small practical thing, because it trips everyone up. Your project folder gathers junk you do not want in your history - big rendered PNG exports, video files, the node_modules folder if you're using packages. You tell Git to ignore those with a .gitignore file:
# .gitignore - a list of stuff Git should pretend doesn't exist
node_modules/ # installed packages - huge, and re-installable, never commit these
exports/ # your rendered PNGs and MP4s - the OUTPUT, not the source
*.mp4 # any stray video files
.DS_Store # macOS folder-clutter files
The principle here is worth saying out loud, because it's a real design decision: commit the source, not the output. Your code and your seed and your params are the source - small, precious, the thing you'd cry to lose. The rendered 4K PNG is output - big, and perfectly re-creatable from the source any time you like. Keeping the heavy re-creatable stuff out keeps your history lean and fast, and it keeps the focus where it belongs: on the recipe, not the cake.
As a project grows you'll have dozens of commits, and a handful of them are special - the ones you actually exhibited, minted, or would happily put on a wall. Git lets you plant a flag on those so they're easy to find again later, called a tag.
# plant a permanent, memorable flag on a commit worth remembering:
git tag genuary-day-12 -m "The piece I posted for Genuary, day 12"
git tag exhibition-print -m "The one that went to the gallery, 60x80cm"
git tag # list all your flags - your greatest-hits shelf
git checkout genuary-day-12 # instantly time-travel to that exact piece
I love this because it turns your repo into a little curated gallery of your own milestones. Scrolling git tag is scrolling the highlights of a year of making things. And any tag is one command away from being live on your screen again - the exact code, seed and params that made that gallery print, summoned back whenever you want to reprint it or build a new piece from it.
Let me give you the actual rhythm I use, because "use Git" is useless without a sense of when. Here's the honest rule of thumb:
COMMIT when: you've reached any state you'd be a bit sad to lose.
(not "when it's finished" - way more often than that.
a good look, a bug fixed, an idea captured. commit small, commit often.)
BRANCH when: you're about to try something you're NOT sure about.
(a risky new direction, a "what if the whole thing was red" moment.
branch first, THEN go wild. the safety is the point.)
THROW AWAY when: a branch didn't work out.
(delete it without guilt. a dead-end explored is not wasted -
you learned it was a dead-end, and now it's not cluttering anything.)
That middle-and-bottom pair is the real mindset shift. Beginners hoard - they're scared to throw code away, so they keep everything "just in case", and their projects rot under the weight of it. Once Git has your back, you can be ruthless. Delete the failed branch. Bin the ugly experiment. You lost nothing, because your good stuff is safe on main and your lessons are safe in the commit messages. The freedom to throw things away cleanly is, weirdly, one of the biggest gifts Git gives an artist.
I want to end on the deeper thing, because it snuck up on me over the years and it's genuinely changed how I see my own work. When you commit little and often with honest messages, and you version your seeds and params alongside the code, you're not just backing up - you're writing the documented story of a piece as you make it. Months later you can scroll back through a finished artwork and watch it become itself, decision by decision, dead-end by dead-end, with your own notes explaining every turn.
That record is worth more than you'd think. It's how you learn your own taste - patterns show up, like "I always end up slowing the motion down" or "my first palette is always too cold". It's how you explain your process to other people, which matters more and more the more your work is seen. And it's how a piece you make today can become the seed of a piece you make next year, because you can walk right back into its guts and lift out the part that worked. A project with a good history isn't just safe - it's legible, to you and to others, and that legibility is the quiet foundation everything else in these final episodes is going to stand on.
Here's the itch this episode leaves behind. Now that your work has a memory and you can move fast without fear, a harder question starts nagging: how do you know a change didn't secretly break something? You tweak the noise function to fix one sketch and quietly wreck three others, and you don't notice for a week. A time machine lets you walk back from a break - but wouldn't it be better to catch the break the instant you make it? That's a real discipline, and it's where we head next. And a little further out, once your work is safe and trustworthy, the natural next step is making it usable by other people - which is a whole craft of its own, and one these last episodes are quietly building toward. So this week: git init one of your sketches, make five commits with real, honest messages, and try one branch you fully intend to throw away. Feel how much braver you get the second you know you can't lose the good version. That braveness is the whole gift :-).
sketch-final-USE-THIS-ONE-v2.js - filenames as memory, and memory lies. Git stores the what, when and why properly so your folder can hold one clean file with all its history underneathgit init, git add ., git commit. A commit is a labelled save point in a timeline, not just a backup - and git log --oneline turns your history into a readable diarygit branch -D it into oblivion if it's garbage. Your main version is never even touched. Timid experiments make timid art; branches delete the feargit diff tells you exactly what changed between two looks - "noise up, 140 more particles" - the thing your eyes struggle to reverse-engineer from two images.gitignore to keep heavy re-creatable renders out. The recipe is precious; the cake you can bake again anytimeSo there's the answer to last time's wistful little ache: nothing good ever has to be gone again. Seed it, commit it, branch off it, tag the winners, and let the history quietly write the story of how you got there. The wild part, as always, is how little it takes - three commands and the nerve to throw away the branches that didn't work. Do that on one real sketch this week and I promise the braveness sneaks up on you fast. Merci for reading, and go give your art a memory :-).
Sallukes! Thanks for reading.
X