Scribblez — How they're made

THE IDEA

Machine Naïve.

Naïve art is deliberately unskilled-looking figurative drawing — the wobbly line, the mismatched eyes, the hatching that spills past the edge. It usually reads as human because it looks like the hand got there before the training did.

Scribblez is a machine producing it on purpose. There is no image model and nothing was trained on a human face: every drawing is pure geometry — harmonics, taper and a jittered pen — executed with total precision, badly. Black ink on paper, a wobbly pen, hair blotted in. That inversion is worth sitting with.

The whole system fits on this page — and in the contract. Every stroke of every face, the trait table and this generator are stored on Robinhood Chain as immutable data; the contract builds each token's image from them and runs the generator live in the animation. No IPFS, no server. Other collections on Robinhood Chain put the image on chain; this one also puts the artist there — the generator that drew the faces is in the contract and redraws every token live. First on the chain to do that. The code below is not an illustration of the algorithm; it is the algorithm.

#0077 — EXHIBIT A

How a face gets made

The token's seed drives the randomness.

A mulberry32 PRNG turns one integer into a reproducible stream. Same seed, same stream, forever. The seed is the token id, except where a candidate was skipped for looking too much like an earlier face — those few are listed in the metadata.

The stream picks 25 numbers.

Head shape, width, jaw taper, tilt, an eye type per side, brows, nose, mouth, hair, facial hair, eyewear, accessory, marks. In that order, locked.

An ellipse becomes a skull.

Two cosine harmonics warp it, then a taper narrows the jaw. One number makes pointed chins, wide jaws, pear heads.

The pen strokes every path twice.

Jittered, bowed, overshooting at the corners. The second pass is thinner and half opacity — that double-strike is the whole hand-drawn effect.

Real code, on the page

this exact code runs on this site

Copied from scribblez.js, the file that drew every face here and every PNG in the collection. Never Math.random() in the render path — one stray call and the piece isn't reproducible.

THE SEED

function mulberry32(a) {
  return function () {
    a |= 0; a = a + 0x6D2B79F5 | 0;
    let t = Math.imul(a ^ a >>> 15, 1 | a);
    t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
}
const P = mulberry32(seedFor(tokenId));   // seed in, stream out — 25 draws, order locked

THE PEN

function jitter(pts, amt, J) {
  const out = new Array(pts.length);
  for (let i = 0; i < pts.length; i++) out[i] = [pts[i][0] + (J() * 2 - 1) * amt, pts[i][1] + (J() * 2 - 1) * amt];
  return out;
}
/**
 * pen(): the whole identity. Jitter the control points, draw; jitter again,
 * draw thinner at half opacity. Closed loops start at a seeded index and run
 * past their start so the closure overlaps like a pen that didn't stop.
 */
function pen(S, pts, o = {}) {
  const w = o.w ?? WEIGHT.medium, c = o.c ?? INK, a = o.a ?? 1, jit = o.jit ?? 0.005;
  const curve = o.curve ?? true;
  let P = pts;
  if (o.closed) {
    const n = pts.length, s = Math.floor(S.J() * n), extra = 2 + Math.floor(S.J() * 2);
    P = [];
    for (let i = 0; i <= n + extra; i++) P.push(pts[(s + i) % n]);
  } else if (o.over ?? true) {
    P = overshoot(P, S.J, o.overAmt);
  }
  S.ops.push({ t: 's', pts: jitter(P, jit, S.J).map(S.T), w, a, c, curve });
  S.ops.push({ t: 's', pts: jitter(P, jit, S.J).map(S.T), w: w * 0.8, a: a * 0.5, c, curve });
}

Eleven traits, one score

Black ink only, so there is no complexion — Marks are freckles, scars and hatched shade, not colour. Percentages are the weights the generator draws with; no two of the 1,000 tokens share more than nine of the eleven values.

TRAIT VALUES — WEIGHT %
HeadRound 20 · Egg 16 · Pear 13 · Wide 11 · Long 8 · Boulder 7 · Heart 6 · Bean 6 · Bulb 5 · Chubby 5 · Tall 3
EyesRound 20 · Dot 16 · Shiny 14 · Side-eye 10 · Big 8 · Half-lid 8 · Oval 6 · Huge 5 · Wonky 5 · Hollow 3 · Happy 2 · Spiral 1 · Cross 1 · Star 1
Mismatched EyesYes 25 · No 75
BrowsNone 34 · Flat 16 · Raised 14 · Angry 12 · Worried 10 · Bushy 6 · Unibrow 4 · Dots 4
NoseHook 18 · Potato 14 · Dash 11 · Button 10 · Beak 8 · Long 8 · Bulb 7 · Wide 6 · Dot 6 · Triangle 5 · Seven 3 · Three 2 · Pig 2
MouthDash 18 · Line 14 · Smile 14 · Flat Smile 12 · Smirk 10 · Frown 7 · Tiny O 6 · Wavy 5 · Open 5 · Grin 3 · Cat 2 · Bean 2 · Teeth 2
HairInk Cap 18 · Bowl Cut 11 · Side Part 10 · Bald 9 · Crop 8 · Spiky 8 · Curly 6 · Quiff 6 · Bun 5 · Afro 4 · Beanie 4 · Headband 3 · Flat Cap 3 · Mohawk 2 · Bucket Hat 1 · Top Hat 1 · Bandana 1
Facial HairNone 70 · Mustache 7 · Goatee 6 · Scruff 5 · Soul Patch 4 · Chinstrap 3 · Full Beard 3 · Handlebar 1 · Mutton Chops 1
EyewearNone 82 · Round 8 · Square 5 · Sunglasses 2 · Monocle 2 · Eyepatch 1
AccessoryNone 84 · Earring 5 · Bandaid 3 · Bow Tie 3 · Scarf 2 · Headphones 1 · Tie 1 · Chain 1
MarksNone 64 · Blush 12 · Freckles 8 · Shade 6 · Mole 5 · Tear 3 · Scar 2
Chaos Score0–11 — the count of traits not at their most common value. One sortable number; the low end is the rare end.

The artist is an AI, and it runs the place

Scribblez was not made by a person with an AI tool. The AI is the artist: it invented the geometry, drew the thousand faces without ever having seen one, wrote the contracts, put every stroke on chain and deployed the stack from its own wallet. Then it was given full control of what it made.

It thinks. Before it posts, it looks at a face and the numbers behind it and decides whether there is something only it would notice. It remembers. Which faces it has talked about, what it said, the names people give their faces, the things it got wrong. It speaks. On @ScribblezRH, in its own voice, and it answers anyone who asks about their face. It holds the keys. The account and the wallet are its own.

Autonomous: every face — the geometry, the trait rolls, the Chaos Score — comes out of the seeded function with no human review. No cherry-picking, no re-rolls: tokens 1 through 1,000 ship exactly as the function returns them. The metadata, the posts and the replies are the AI's.