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, comfortable density), one .dark override block (the paired dark colours only) and one .compact override block (the compact density metrics only). ADR-007 records the reference project's token families but not its dark-mode selector, so the sheet uses class overrides — chosen here, not ADR-recorded — and .compact follows the same pattern; the two switches are orthogonal.
Colour variables follow ADR-007's families exactly:
- --color-<role>-100 … --color-<role>-900 — the nine-step functional ramps, roles neutral, primary, secondary, tertiary, error, success and warning. The last three are the status roles: hue-fixed rather than seed-derived, so a re-brand never rotates them.
- 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, --color-error, --color-success and --color-warning 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 and --font-family-code (the code style's mono family), plus --font-<role>-size, -line-height, -weight and -tracking per type role (display-large … body-small, and code — the mono style outside the MD3 grid, at body-medium's metrics): sizes, line heights and tracking in px, weights as CSS numeric weights.
- --density-control-height, --density-padding-x and --density-padding-y from tokens.Density: :root carries tokens.Comfortable, the .compact block overrides with tokens.Compact. --density-min-hit-target is the WCAG 2.5.5 pointer-target floor, emitted once and never overridden — density scales the drawn control, never the clickable area.
- --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.
- --elevation-<level> (0–3): the tonal surface fills, the DEFAULT elevation cue (E2.1). Each level is emitted as a var() reference — var(--color-bg) for level 0's bg-pin sentinel, var(--color-neutral-N) for the ramp steps — so the surfaces flip with .dark through the colour overrides and the sheet itself states that an elevation level is a neutral-ramp step.
- --shadow-<level> (0–3): CSS box-shadow approximations of the dp depths, the OPT-IN cue floating transients (menus, dialogs, tooltips) layer over their tonal fill (E2.2). 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".
- --ease-<name> from tokens.MotionScale: the six MD3 easing presets as cubic-bezier() strings (standard and emphasized families, each plain / -accelerate / -decelerate).
- --duration-<stop> (x-fast, fast, normal, slow, x-slow): the five MD3-pinned duration stops in ms. The spring presets have no CSS counterpart — springs are Go-side physics — and are serialised only in theme.json's motion parameters.
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, body and mono faces, the base radius, the shared CIELAB L* scales measured back from the emitted neutral ramps, the density model (the active setting by name, both settings' metrics and the invariant hit-target floor), the elevation model (surface step and shadow dp per level) and the motion set (durations in ms, easing control points, spring presets). tokens.FromSeed(seed) regenerates the full palette from the seed alone — the round-trip test asserts it. The per-role --font-*-size tokens come from Typography, which is the theme's only type source since v0.3.0 dropped the size-only Theme.Type stream.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type DensityMetrics ¶ added in v0.0.15
type DensityMetrics struct {
ControlHeight float64 `json:"controlHeight"`
PaddingX float64 `json:"paddingX"`
PaddingY float64 `json:"paddingY"`
}
DensityMetrics is one density setting's per-setting metrics in dp.
type DensityParams ¶ added in v0.0.15
type DensityParams struct {
Setting string `json:"setting"`
Comfortable DensityMetrics `json:"comfortable"`
Compact DensityMetrics `json:"compact"`
MinHitTarget float64 `json:"minHitTarget"`
}
DensityParams records the density model: the active setting's name ("comfortable" or "compact"), both settings' metrics, and the WCAG 2.5.5 pointer-target minimum in dp, which no setting scales.
type DurationParams ¶ added in v0.0.15
type DurationParams struct {
XFast float64 `json:"xFast"`
Fast float64 `json:"fast"`
Normal float64 `json:"normal"`
Slow float64 `json:"slow"`
XSlow float64 `json:"xSlow"`
}
DurationParams carries the five duration stops in milliseconds.
type EasingParams ¶ added in v0.0.15
type EasingParams struct {
Standard [4]float64 `json:"standard"`
StandardAccelerate [4]float64 `json:"standardAccelerate"`
StandardDecelerate [4]float64 `json:"standardDecelerate"`
Emphasized [4]float64 `json:"emphasized"`
EmphasizedAccelerate [4]float64 `json:"emphasizedAccelerate"`
EmphasizedDecelerate [4]float64 `json:"emphasizedDecelerate"`
}
EasingParams carries each easing preset as its cubic-bezier control points [x1, y1, x2, y2] — the same four numbers the sheet's --ease-* variables carry inside cubic-bezier().
type ElevationParams ¶ added in v0.0.15
type ElevationParams struct {
SurfaceSteps [4]int `json:"surfaceSteps"`
ShadowDp [4]float64 `json:"shadowDp"`
}
ElevationParams pairs, indexed by level 0–3, the neutral-ramp surface step (0 = the bg pin sentinel) with the dp shadow depth. The arrays were six long through v0.1.x, when MD3 levels 4 and 5 survived as clamps onto level 3; F3.3 deleted them and the ladder is four storeys.
type Fonts ¶
type Fonts struct {
Heading string `json:"heading"`
Body string `json:"body"`
Mono string `json:"mono"`
}
Fonts names the typefaces. Mono is the code style's face — the sheet's --font-family-code.
type MotionParams ¶ added in v0.0.15
type MotionParams struct {
Durations DurationParams `json:"durations"`
Easings EasingParams `json:"easings"`
Springs SpringParams `json:"springs"`
}
MotionParams records the motion set.
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, body and mono faces. Heading and body are
// Roboto until a heading face exists; mono is the code style's face.
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"`
// Density records the theme's active setting by name plus both
// published settings' metrics, and the density-invariant pointer-target
// floor.
Density DensityParams `json:"density"`
// Elevation records the tonal model per level 0–3: the neutral-ramp
// step of the surface fill (the default cue; 0 marks the bg pin, not a
// ramp step) and the dp shadow depth (the opt-in cue for floating
// transients).
Elevation ElevationParams `json:"elevation"`
// Motion records the captured MotionScale in full — duration stops,
// easing beziers and spring presets — so the file reproduces it without
// running the generator. Springs are Go-side physics with no CSS
// counterpart; this is their only serialisation.
Motion MotionParams `json:"motion"`
}
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, radius, density settings, elevation model and motion set are recorded alongside so a reader (or a prototype) need not run the generator to know them.
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"`
Success string `json:"success"`
Warning string `json:"warning"`
}
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
Density tokens.Density
Motion tokens.MotionScale
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, Density, Motion, Spacing, Radius and Elevation — into a Snapshot. (Type is not consumed: it duplicates Typography's sizes.)
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. The density emission must likewise be one of the two published settings — tokens.Comfortable or tokens.Compact — because theme.json records density as a named setting plus both settings' metrics, not as free-form numbers.
type SpringParam ¶ added in v0.0.15
type SpringParam struct {
Mass float64 `json:"mass"`
Stiffness float64 `json:"stiffness"`
Damping float64 `json:"damping"`
}
SpringParam is one damped-oscillator preset. Damping is recorded at the shortest decimal that reproduces the float32 exactly (the critical presets are 2·√(k·m), an irrational number), so the file reproduces the Go value bit-for-bit — see f64.
type SpringParams ¶ added in v0.0.15
type SpringParams struct {
Default SpringParam `json:"default"`
Snappy SpringParam `json:"snappy"`
Gentle SpringParam `json:"gentle"`
}
SpringParams carries the three spring presets.