AI Agent Instructions — Verdigris Design System
This file provides context for AI coding agents generating on-brand Verdigris visuals.
How to Use This Repo
When generating UI components, pages, or visual assets for Verdigris:
- Read
tokens/color/base.json— the canonical brand palette in OKLch - Read
tokens/typography/— font families and scale - Read
foundations/docs for rationale behind decisions - Check
rules/visual-rules.ymlfor machine-enforceable constraints - Review
examples/for annotated good/bad references
When writing Verdigris content (any prose — vision docs, marketing copy, blog posts, internal comms, READMEs):
- Read
voice/USE.mdfirst. It teaches you to identify subject + form + audience + target feelings before you write. Skipping this is the most common reason voice goes wrong. - Then
voice/recipes.yamlfor the mix matching your content type (e.g.investor_update,homepage,careers_page). - Then
voice/team/*.yamlfor the individual voice profile if a specific founder or teammate’s register applies.
Quick Reference: Brand Colors
| Name | OKLch | Hex | Usage |
|---|---|---|---|
| Verdigris (primary teal) | oklch(0.753 0.1279 191.57) |
#0fc8c3 | Decorative brand color |
| Midnight Purple | oklch(0.29 0.1506 289.33) |
~#1a0a4a | Deep accent |
| Pastel Red | oklch(0.7 0.1909 24.11) |
~#e85d3a | Warm accent |
| Cyber Yellow | oklch(0.87 0.1786 92.23) |
~#d4c520 | Highlight |
Do NOT use brand teal as text on white — it fails WCAG AA (2.09:1 ratio). Use near-black (oklch(0.21 0.006 285.885)) for text.
Quick Reference: Typography
| Element | Font | Size | Weight |
|---|---|---|---|
| Body text | Inter | 1rem (16px) | 400 |
| Headings (marketing) | Lato | 4rem/3rem/2rem | 700 |
| Headings (app) | Inter | (Tailwind defaults) | 700 |
| Code/metrics | JetBrains Mono | — | 400 |
| Buttons | Inter | 1rem | 600 |
Quick Reference: Spacing
- Grid: 4px base (0.25rem increments)
- Container max-width: 80rem (1280px)
- Page padding: 2.5rem (40px), 1.5rem on mobile
- Section padding: 4rem vertical (standard), 8rem (large)
- Border radius: 0.625rem (10px) — Patina canonical
Rules for Generating On-Brand Output
Colors
- Use OKLch values from
tokens/color/base.json - Neutral scale has a zinc tint (hue ~286) — not pure gray
- Dark mode: near-black background (not pure
#000000) - Dark mode borders: semi-transparent white (
oklch(1 0 0 / 10%))
Typography
- Body: Inter, headings (marketing): Lato
- H1: 4rem with -0.02em letter-spacing and weight 700
- All body text: 1.6 line-height
- This repo is the canonical source for all visual values
Semantic Tokens (CSS Variables)
These are the CSS variable names generated by the build pipeline. Use these for all UI surfaces — they automatically adapt to light/dark mode.
| Variable | Light value | Dark value | Usage |
|---|---|---|---|
--color-semantic-background |
white | neutral.950 | Page background |
--color-semantic-foreground |
neutral.950 | neutral.50 | Body text |
--color-semantic-card |
white | neutral.900 | Card/surface background |
--color-semantic-card-foreground |
neutral.950 | neutral.50 | Card text |
--color-semantic-primary |
neutral.900 | neutral.200 | Primary buttons/actions |
--color-semantic-primary-foreground |
neutral.50 | neutral.900 | Primary button text |
--color-semantic-secondary |
neutral.100 | neutral.800 | Secondary surfaces |
--color-semantic-muted |
neutral.100 | neutral.800 | Muted backgrounds |
--color-semantic-muted-foreground |
neutral.500 | neutral.400 | Muted text |
--color-semantic-border |
neutral.200 | oklch(1 0 0 / 10%) | Borders |
--color-semantic-ring |
neutral.400 | neutral.500 | Focus rings |
--color-semantic-destructive |
status.destructive-light | status.destructive-dark | Error states |
CSS variable naming: token path color.brand.verdigris → CSS var --color-brand-verdigris (dots become hyphens, prefixed with --).
Dark mode pattern:
@import '@verdigristech/design-tokens/css/oklch';
/* :root {} block = light mode, .dark {} block = dark mode */
/* Toggle dark mode by adding class="dark" to <html> */
Components
- Use shadcn/ui + Radix UI patterns
- Dark mode via
.darkclass on<html>— CSS vars swap automatically - Radius: 0.625rem base
- Tailwind: use
bg-background,text-foreground,bg-card,text-muted-foreground, etc. (from preset) - Component guides: see
categories/web-components/for buttons, cards, modals, tables, tabs, sidebar, etc.
Animation
- Gate hover effects behind
(hover: hover) and (pointer: fine) - Always provide
prefers-reduced-motion: reducefallback - Entrance:
ease-out, 500ms. Interaction:ease, 200ms.
Accessibility
- WCAG 2.1 AA minimum
- All images need
alttext - All interactive elements need focus indicators
- Never communicate with color alone
Token Files
| File | Contains |
|---|---|
tokens/color/base.json |
Primitive palette (OKLch) |
tokens/color/semantic-light.json |
Light mode semantic mappings |
tokens/color/semantic-dark.json |
Dark mode overrides |
tokens/typography/font-family.json |
Font stacks |
tokens/typography/scale.json |
Sizes, weights, line-heights |
tokens/spacing/base.json |
4px grid scale |
tokens/spacing/layout.json |
Container, sections, hero |
tokens/motion/duration.json |
Animation durations |
tokens/motion/easing.json |
Easing curves |
tokens/radius.json |
Border radius scale |
tokens/breakpoints.json |
Responsive breakpoints |
rules/visual-rules.yml |
Machine-enforceable rules |
Patina as Reference
Patina (the application UI) is the primary source of truth. When in doubt about a design decision, default to Patina’s implementation. The www marketing site converges toward Patina, not the other way around.
Justified deviations from Patina:
- Lato as display font (Patina has no display font — marketing needs font contrast)
- Hero/marketing-specific patterns (Patina is an app dashboard)
- Ad/collateral templates (Patina has no ads)
All deviations must be documented in foundations/ docs.