Gesso
The surface system. The part of a design that decides how it feels.

6
Material axes
10
Named registers, from Paper to Brutalist
108
Contrast assertions across 12 generations
2
Export formats: CSS tokens and DTCG JSON
Why this exists at all.
Colour and type are the two things every design tool generates, and they are not what makes an interface feel like anything. Material does: radius, elevation, border policy, fill strategy, density, motion. That layer is normally assembled by hand, inconsistently, and is the first thing to drift across a build.
The decisions, and what they rule out.
Six axes, and the coherence rules are the product
Radius base, a five-step elevation ladder, border policy, fill strategy, density, motion register. Generation anchors on named registers and jitters around them, but the value is in the constraints between axes: borders and shadows trade off, glass restrains elevation, radius follows density, pills only appear once the register is already round. Random values across six axes produce noise; these rules are what make a generated surface look designed.
Dress a real wireframe, independently re-rollable
A stage of real components gets dressed by three engines, surface, colour, type, each re-rollable while the others hold. You can keep a palette you like and roll the material underneath it, which is how the decision is actually made.
The things thinking about it did not catch.
Every item below is a real defect, found by measurement, with a commit behind it. They are here because the failures are more informative than the features.
The bug that only appeared on a phone
Reviewed on a phone, not a laptop, dark-mode labels were invisible and light generations looked flat. Two separate causes: a role transposition, accent-as-text used where text-on-accent was needed, and most of the role vocabulary going unused, so generations differed in hue but not in structure.
The fix was verified across generations, not on one example
Correcting the role mapping and widening the registers, then checking 108 pixel-contrast assertions across twelve generated systems in both polarities. A single fixed example proves the example. Variety is the product here, so the verification has to cover the variety.
Deployment produced a stray project nobody asked for
A deploy created an unwanted second Vercel project named after the output directory. Small, but it is the kind of thing that quietly accumulates in an account until someone wonders what half the projects are.
- TypeScript
- Vite
- Umber engine
- Kern engine
- Live tuning against an arbitrary site, click an element, get variants in place, accept one and have it write back to source, is designed but not built. It needs the write-to-source path worked out properly rather than approximated.
Free, no account, running right now.
gesso-wheat.vercel.app