export

package
v0.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 12 Imported by: 0

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

func Write

func Write(dir string, s Snapshot) error

Write renders s into dir as the full Claude Design project layout — theme.json, styles.css, readme.md and the foundation pages under foundations/ — creating directories as needed. Existing files are overwritten: the tree is generated output, regenerated whole.

Types

type Fonts

type Fonts struct {
	Heading string `json:"heading"`
	Body    string `json:"body"`
}

Fonts names the typefaces.

type ModePins

type ModePins struct {
	Light Pins `json:"light"`
	Dark  Pins `json:"dark"`
}

ModePins carries the pinned bases for both modes.

type ModeScale

type ModeScale struct {
	Light [9]int `json:"light"`
	Dark  [9]int `json:"dark"`
}

ModeScale carries the L* scale for both modes.

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

func Capture(th theme.Theme) (Snapshot, error)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL