The GRAIN design system
One interface. A person and an AI operate it through the same controls.
A human click and an AI decision become the same intent, flow through one door, and come back as visible edits. The AI's presence is shown, never hidden: grain is the signature of a machine at work.
Every surface on this page is one of GRAIN's own components. Open the Catalog tab, then hover anything (or tap it on a touch screen) to reveal its entry.
One rule reads instantly and everywhere: grain type means the AI is acting or a value is in transit; clean type means a human wrote it or it has committed. Same words, two typefaces, no badges to learn.
a personDraft the Thursday plan.
the AIDraft the Thursday plan.
Two hands, one thread
You (clean) and the AI (grain) in one conversation: the AI's line stays grain; provenance never evaporates into looking human.
Your optimistic action settles
- Archive last week's notesarchived
Archiving is your action: grain while in-transit, then clean once it commits. AI speech, by contrast, stays grain; only your committed data reads clean.
A real GRAIN composition, operated through the one door. Ask it something yourself, or watch the AI act: both post the same Intent to /intent and render back over SSE. There is no privileged AI → DOM path; the same page powers this demo.
- Draft the Q3 plan active
- Review the design thread done
The whole system is one closed vocabulary of verbs and surfaces (contract.ts). A human click and an AI decision are the same Intent; both flow through one door and return as RenderOps pushed over SSE. There is no privileged AI → DOM back channel.
- One vocabulary. Verbs and surfaces live in a single registry, referenced, never re-typed as strings.
- A manifest the AI reads. Each screen publishes a drift-proof, machine-readable map of what's operable at /ai/manifest, harvested from the components, so the AI is shown the page, not told about it.
- Self-documenting. Every component auto-appears in a live component catalog: the design system browses itself.
- Auditable by design. Every interaction, human or AI, is one source-tagged Intent through one server-side door, so a full human + AI interaction log is a server-side drop-in.
- Two door transports, one contract. On the live server the door is POST /intent; on a static host this page opts into the client-side door: the same vocabulary and the same ops, run in your browser with no backend. The client door is deliberately fenced: everything it loads is client-safe by contract, static-style modules only, no secrets or tokens, nothing that needs a server. Anything that does need one (real data, a real model) stays behind the server door and is simply absent here.
- No build step. Server-rendered hypermedia on BATCH: Bun, TypeScript, CSS, htmx. Ship the source.
Every theme is a pure token override: one signature accent hue, no component edits (the topbar ◆ toggle cycles these site-wide too). Pick one:
Sourdough
Warm monochrome e-ink: the default, hueless.
Baguette
Clean and crisp: near-white light, near-black dark, a soft-blue accent.
Brioche
Warm cream and honey-gold: the cozy one.