Tokens and options
2 minutes read
Every visual decision is a design token, defined once and read from CSS. tokens/names.json freezes the names; one file per group (color.json, type.json, space.json, and the rest) sets the values. Run npm run tokens after editing a group: it writes styles/tokens.css, which npm test keeps current. Never edit that CSS by hand, and never put a raw color, length, or duration in a unit's stylesheet; use var(--color-accent), var(--space-4), and the other token variables.
A site changes a token in its config, not in the theme. The site config is mizzen.yml ; the engine passes theme.options to the theme unread (the config contract), and the token overrides live under theme.options.tokens:
theme:
options:
tokens:
accent: "#0b6e4f"
canvas: "#ffffff"
text: "#222222"
font_body: '"Source Serif 4", Georgia, serif'
radius: "0.5rem"
The keys are the token names that the config maps into the theme's CSS variables: accent, canvas, text, font_body, and radius. An unset color keeps the theme's light and dark pair; a set one replaces both, so check the contrast in both modes.
The rest of theme.options is the theme's as well. Lateen reads these blocks:
theme:
options:
announcement:
id: v0-4
text: Version 0.4 is out.
href: /changelog/
editPage:
headingLinks: true
logo:
light: /assets/logo.svg
dark: /assets/logo-dark.svg
footer:
copyright: © 2026 Example
license: MIT
links:
- title: Source
url: https://github.com/example/site
pageAgent:
providers:
- title: Claude
url: "https://claude.ai/new?q=Read+{markdown}"
feedback:
endpoint: https://feedback.example.com/vote
| Option | What it changes |
|---|---|
announcement.id, announcement.text, announcement.href |
A dismissible bar above the header. text is required; the bar renders nothing without it. href links the text; http, https, mailto, and root-relative paths are shown. Dismissal is remembered per id. |
editPage.headingLinks |
true adds a per-heading "suggest an edit" issue link under the "Edit this page" link; absent or any other value leaves it out. |
logo.light, logo.dark |
The header mark. A root-relative path gets the site's base; an absolute URL is used as written. With both, the header swaps them with the theme; with one, it shows that one in both modes. |
footer.copyright, footer.license |
The two lines of the site footer. |
footer.links[] |
Footer links with title and url; only http, https, mailto, and root-relative paths are shown. |
pageAgent.providers[] |
The "Use with an agent" menu. Each provider has a title and a url; {markdown}, {url}, and {title} are filled per page. Without the block the menu offers Claude, ChatGPT, and Cursor. |
feedback.endpoint |
The address the "Was this page helpful?" buttons POST {url, helpful, source} to; source is the page's source file. Without the block the feedback widget renders nothing. |