Documentation
¶
Overview ¶
Package export serialises a theme.Theme emission into the project layout claude.ai/design consumes: theme.json, the machine-readable generative parameters; styles.css, the token sheet; readme.md, the project's front door; and the foundation pages under foundations/. Capture collects the first emission of each Theme observable into a Snapshot; Write renders the whole tree into a target directory. cmd/vg-tokens is the command-line front door.
The token sheet ¶
styles.css carries one :root block (the light scheme plus every mode-invariant scale) and one .dark override block (the paired dark colours only). ADR-007 records the reference project's token families but not its dark-mode selector, so the sheet uses a .dark class override — chosen here, not ADR-recorded.
Colour variables follow ADR-007's families exactly:
- --color-<role>-100 … --color-<role>-900 — the nine-step functional ramps, roles neutral, primary, secondary, tertiary and error.
- Pinned bases and the semantic layer: --color-accent is the Primary pin (the reference project's .btn-primary consumes --color-accent, per ADR-007), with --color-on-accent its on-colour; --color-secondary, --color-tertiary and --color-error are the other role pins with their --color-on-* companions; --color-bg, --color-text are the pinned background and body text; --color-surface and --color-divider are the semantic layer's ramp-resolved card and separator colours.
The remaining families, all emitted in :root only because they do not change with the scheme:
- --font-family, plus --font-<role>-size, -line-height, -weight and -tracking per type role (display-large … body-small): sizes, line heights and tracking in px, weights as CSS numeric weights.
- --space-<key> from tokens.SpacingScale, keys as the Go scale names them (0, 1, 2, … 24), in px.
- --radius-<key> from tokens.RadiusScale in Tailwind naming (none, sm, base, md, lg, xl, 2xl, 3xl, full), in px; Base is also theme.json's base radius parameter.
- --shadow-<level> (0–5): CSS box-shadow approximations of tokens.ElevationScale. Each level's dp depth d becomes "0 <d>px <2d>px 0 rgba(0, 0, 0, 0.2)" — y-offset the depth, blur twice it, no spread, black at 20% — and level 0 is "none". E2.1 remaps elevation to surface roles and E5.1 re-emits it.
The foundation pages ¶
foundations/color.html, type.html and layout.html render the scales at real sizes, and readme.md is the file a human or an agent reads first. The pages are static HTML that reads only from the emitted sheet: every styled colour, size, radius, shadow and font value is a var() reference into ../styles.css, so regenerating the sheet from another seed reflows every page. Literal token values appear only as annotation text — hexes, px numbers, and the measured APCA Lc and WCAG 2 ratio of each text pair — printed for both modes (labelled L and D) because text cannot flip with a class the way painted specimens do. Each page carries a light/dark toggle flipping the .dark class on the root element. The page test enforces the no-hard-coded-values rule: no hex colours or px lengths in any style context, and every referenced variable declared by the sheet.
The generative parameters ¶
theme.json records what reproduces the theme: the seed (hex plus its OKLCh hue and sat), the pinned role hexes per mode, the heading and body faces, the base radius, and the shared CIELAB L* scales measured back from the emitted neutral ramps. tokens.FromSeed(seed) regenerates the full palette from the seed alone — the round-trip test asserts it. Density and the motion set are E5.1's; they are deliberately absent, as is Theme.Motion from the sheet. Theme.Type is not consumed either: the per-role --font-*-size tokens come from Typography, which carries the same sizes.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Parameters ¶
type Parameters struct {
// Seed is the brand seed as lowercase #rrggbb; Hue and Sat are its
// OKLCh hue (degrees, 2 decimals) and chroma (4 decimals), recorded for
// the reader — regeneration starts from the hex.
Seed string `json:"seed"`
Hue float64 `json:"hue"`
Sat float64 `json:"sat"`
// Pins are the pinned role bases per mode.
Pins ModePins `json:"pins"`
// Fonts names the heading and body faces. Both are Roboto until a
// heading face exists.
Fonts Fonts `json:"fonts"`
// Radius is the base radius in dp — tokens.RadiusScale.Base, the sheet's
// --radius-base.
Radius float64 `json:"radius"`
// Scale is the shared CIELAB L* lightness scale per mode, steps
// 100–900, measured back from the emitted neutral ramps. It documents
// the generator's fixed scale (ADR-007); it is not itself an input —
// FromSeed carries it.
Scale ModeScale `json:"scale"`
}
Parameters is theme.json's shape: the generative parameters that reproduce the theme. tokens.FromSeed(Seed) regenerates every ramp and pin — the round-trip test asserts it — so the file alone rebuilds the palette; the pins, scales, fonts and radius are recorded alongside so a reader (or a prototype) need not run the generator to know them.
Density and the motion set join in E5.1; they do not exist yet.
type Pins ¶
type Pins struct {
Bg string `json:"bg"`
Text string `json:"text"`
Accent string `json:"accent"`
Secondary string `json:"secondary"`
Tertiary string `json:"tertiary"`
Error string `json:"error"`
}
Pins records one mode's pinned bases as lowercase #rrggbb hexes. Accent is the primary pin — the sheet's --color-accent.
type Snapshot ¶
type Snapshot struct {
// Seed is the brand seed the colour schemes derive from — the light
// scheme's pinned Primary, which FromSeed guarantees is the seed
// byte-for-byte.
Seed stdcolor.NRGBA
// Light is the colour scheme the theme emitted; Dark is its paired
// scheme, FromSeed(Seed)'s dark half.
Light, Dark tokens.ColorTokens
Typography tokens.Typography
Spacing tokens.SpacingScale
Radius tokens.RadiusScale
Elevation tokens.ElevationScale
}
Snapshot is one resolved theme: the first emission of each theme.Theme observable, with the paired dark colour scheme and the seed recovered from the light scheme's primary pin. It is the input Write serialises.
func Capture ¶
Capture collects the first emission of each observable a serialisation needs — Color, Typography, Spacing, Radius and Elevation — into a Snapshot. (Type duplicates Typography's sizes and Motion is E5.1's, so neither is consumed.)
The colour emission must be a seed-derived light scheme: FromSeed pins the light primary base to the seed exactly, so Capture recovers the seed from the emission's Primary and regenerates the pair. An emission FromSeed cannot reproduce — a dark scheme, or hand-assembled tokens — is an error, because theme.json could not honestly claim to reproduce it.