Writing · Build Notes
I recreated 34 pages of my sketchbook as deterministic generative SVG — a study in original vs. code
I have a sketchbook full of dense, art-brut pen drawings — eyes that explode into seed-pods, figures dissolving into their own scribble, block-letter protest slogans.
I have a sketchbook full of dense, art-brut pen drawings — eyes that explode into seed-pods, figures dissolving into their own scribble, block-letter protest slogans. I scanned 34 pages and asked a strange question: could I rebuild each one in code — not copy the pixels, but regenerate the drawing from a small spec and a seeded random number generator?
The result is a scrolling gallery that puts each original scan beside its generative-SVG recreation, so you can read the two against each other. It turned into a quiet meditation on what's lost and what's kept when a hand-drawn thing becomes an algorithm.
Deterministic, or it's not a recreation
The core rule: each piece must render identically every time. A recreation that looks different on every reload isn't a recreation, it's a slot machine. So there's no Math.random() anywhere — every piece is driven by a small seeded xorshift PRNG:
function rng(seed) {
let s = (seed * 2654435761) >>> 0;
return function () {
s ^= s << 13; s >>>= 0;
s ^= s >> 17;
s ^= s << 5; s >>>= 0;
return s / 4294967296;
};
}Same seed → same drawing, forever. The "randomness" is really fixed texture — controlled wobble, not chaos.
A drawing as data
Each page is a tiny spec, hand-derived from looking hard at the original: which generative motif to use, a palette (dominant ink first), the legible text fragments on the page, and a short reading of the piece.
{ id: 3, file: "o3.jpg", title: "THXHT — The Seed-Eye", motif: "eye",
pal: ["#e8721c", "#111111", "#0a7d3c", "#c0224a", "#1668c4"],
texts: ["THXHT"],
desc: "An orange ellipse cradles a black starburst iris that detonates outward in pen-strokes — half eye, half exploding seed-pod." }motif picks the drawer (eye, creature, face, grid…); the palette and seed do the rest. The renderer emits a pure SVG string with no DOM, so the exact same code runs in the browser and in Node — I use the Node path to rasterize the pieces into desktop wallpapers.
Making code look hand-drawn
The hardest part was fighting the machine's own neatness. A straight <line> reads as "computer"; a real pen wavers. So strokes are built as slightly-perturbed polylines, then smoothed into a wobbly bezier path:
// a wandering polyline through points -> a smooth, hand-drawn "d"
function smooth(pts) {
let d = `M ${pts[0][0]} ${pts[0][1]}`;
for (let i = 1; i < pts.length; i++) {
const p0 = pts[i - 1], p1 = pts[i];
const mx = (p0[0] + p1[0]) / 2, my = (p0[1] + p1[1]) / 2;
d += ` Q ${p0[0]} ${p0[1]} ${mx} ${my}`; // quadratic through the midpoints
}
return d;
}Add a little seeded jitter to each point and the line breathes. That single function — perturb, then smooth — is most of what separates "SVG" from "sketch."
The second view: motifs as a graph
Once every page is data, patterns fall out of the whole book. The same shapes recur — eyes, roots, cages, block text — across drawings made months apart. So there's a second view, "Entanglement Field," that graphs the pages as nodes and draws edges between ones that share motifs, lighting up the "hot threads" running through the sketchbook. The book stops being 34 separate pages and becomes one connected obsession.
What I learned
- Deterministic seeding is the whole game in generative art. The moment you can reproduce a piece exactly, it becomes something you can compose and ship, not just stumble into.
- Turning art into a spec is itself an act of reading. Writing the
descand choosing themotiffor each page forced me to actually see what I'd drawn — the recreation was a side effect of the analysis. - The gap is the point. The code versions are cleaner, calmer, more legible than the frantic originals. Setting them side by side says more about both than either would alone.
A build-story · see the live project → · more writing →