@phcdevworks/spectre-tokens
v4.12.0
Published
@phcdevworks/spectre-tokens is the design-token foundation of the Spectre system. It provides the shared visual values and semantic contracts used across Spectre packages and PHCDevworks applications.
Maintainers
Readme
@phcdevworks/spectre-tokens
@phcdevworks/spectre-tokens is the design-token foundation of the Spectre
system. It provides the shared visual values and semantic contracts used across
Spectre packages and PHCDevworks applications.
Maintained by PHCDevworks. It defines the visual language, semantic roles, and token contracts that downstream consumers can rely on without filling gaps with raw palette values or local token inventions. Downstream UI packages define structure; adapter packages translate Spectre contracts for specific frameworks and runtimes.
Repository Snapshot
| Field | Value |
| ---------------------- | -------------------------------- |
| Project team | project-design |
| Repository role | Spectre L1 design-token contract |
| Package/artifact | @phcdevworks/spectre-tokens |
| Current version/status | 4.12.0 |
Standard Workflow
- Read AGENTS.md, then the agent-specific guide for the task.
- Check TODO.md and ROADMAP.md for current scope.
- Make the smallest repo-local change that satisfies the task.
- Run
npm run checkwhen validation is required or practical. - Update docs and CHANGELOG.md only when behavior, public contracts, or release-relevant metadata changed.
Documentation Map
| Guide | Path | | ----------------- | -------------------------------------------- | | Agent rules | AGENTS.md | | Claude Code | CLAUDE.md | | Codex | CODEX.md | | Copilot | COPILOT.md | | Jules | JULES.md | | Grok | GROK.md | | Roadmap | ROADMAP.md | | Todo | TODO.md | | Token reference | TOKEN_REFERENCE.md | | Downstream parity | DOWNSTREAM_PARITY.md | | Changelog | CHANGELOG.md | | Security | SECURITY.md |
@phcdevworks/spectre-tokens is the design-token package of the Spectre system.
It provides a complete, UI-ready token surface for downstream Spectre packages
and compatible applications.
Maintained by PHCDevworks, it defines the visual language, semantic roles, and token contracts that downstream consumers can rely on without filling gaps with raw palette values or local token inventions. Downstream UI packages define structure; adapter packages translate Spectre contracts for specific frameworks and runtimes.
Contributing | Code of Conduct | Changelog | Token Contract | Roadmap | Security Policy
Source Of Truth
tokens/ is the source of truth. contract.manifest.json is the
machine-readable contract authority. Everything else is derived from them or
validated against them.
| Layer | Path | Rule |
| -------------------- | ---------------------------------------------- | ------------------------------------------------------------------- |
| Source token data | tokens/*.json | All token value changes start here — never anywhere else |
| Contract authority | contract.manifest.json | Governs public namespaces and required output surfaces |
| Public entry points | src/index.ts · src/types.ts · src/css.ts | Contract-authority files — changes require changelog classification |
| Generated TypeScript | src/generated/tokens.ts | Never edit directly — regenerated by npm run build |
| Generated dist | dist/ | Never edit directly — regenerated by npm run build |
After any source change: run npm run build to regenerate outputs, then
npm run check to validate the full contract.
What This Package Owns
- Visual language expressed as token data in
tokens/ - Semantic roles and token contracts consumed downstream
- Generated token outputs for JavaScript, TypeScript, CSS variables, and DTCG
- Theme and mode definitions used by downstream consumers
This package is the correct place to define token meaning.
What This Package Does Not Own
- Component structure or composition. That belongs in downstream UI packages
such as
@phcdevworks/spectre-ui. - Framework-specific delivery. Adapter packages translate Spectre contracts for specific frameworks and runtimes.
- Local redefinition of token meaning. Downstream consumers should consume these contracts rather than recreate them independently.
- Example app architecture. The
example/directory documents token usage; it is not the contract source and should not become a downstream UI layer.
When To Use This Package
- You are building a Spectre ecosystem package and need the visual language contract.
- You need design token values in JavaScript, TypeScript, CSS variables, or DTCG format.
- You want a single source of truth for semantic roles:
surface,text,component,buttons,forms,modes. - You are consuming tokens as named values, not inventing new token meaning.
When Not To Use This Package
- You need UI components or component structure — use
@phcdevworks/spectre-ui. - You need framework-specific component delivery — use the appropriate adapter package.
- You want to define your own token meaning or override Spectre semantics locally — this package is the authority; downstream consumers should consume, not redefine.
Installation
npm install @phcdevworks/spectre-tokensQuick Start
CSS import
Import the generated CSS variables:
@import '@phcdevworks/spectre-tokens/index.css';Token usage
Load the token object in JavaScript or TypeScript:
import tokens from '@phcdevworks/spectre-tokens'
const card = {
background: tokens.surface.page,
color: tokens.text.onPage.default,
maxWidth: tokens.layout.container.maxWidthProse,
padding: tokens.space['16'],
borderRadius: tokens.radii.md
}Semantic Tokens Vs Raw Palette Tokens
Semantic tokens express UI meaning. Raw palette tokens expose the fixed color ramp. Always prefer semantic tokens for UI surfaces, text, buttons, forms, and mode-aware styling.
Semantic namespaces (prefer for all UI work)
| Namespace | What it expresses |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------- |
| surface | Background roles: page, card, input, overlay, subtle, hero (gradient, hero sections only), hover, selected, active, divider |
| text | Foreground roles: default, muted, subtle, meta, on-surface, on-page |
| component | Role-specific tokens for navigation, overlays, feedback, data display, loading, forms, cards, badges, and content patterns |
| buttons | Button state tokens: default, hover, active, disabled, CTA |
| forms | Form state tokens: default, focused, error, disabled |
| link | Inline link color roles: default, hover, active, visited |
| modes | Mode-aware overrides under modes.default and modes.dark |
import tokens from '@phcdevworks/spectre-tokens'
// Semantic — always prefer this for UI
const card = {
background: tokens.surface.card,
color: tokens.text.onSurface.default
}
// Mode-aware semantic
const dark = {
background: tokens.modes.dark.surface.page,
color: tokens.modes.dark.text.onPage.default
}Raw palette (use sparingly)
The colors namespace exposes the raw palette ramp. Use it only when fixed
color access is intentional — data visualization, compatibility layers, or
tooling that inspects palette data directly.
// Raw palette — only when fixed color access is deliberate
const chart = {
series1: tokens.colors.brand[500],
series2: tokens.colors.neutral[300]
}Do not use colors as a substitute for semantic tokens in normal UI surfaces.
Consumer Usage
JavaScript and TypeScript tokens
Use the runtime token object when a consumer needs token values directly in code.
import tokens from '@phcdevworks/spectre-tokens'
const card = {
background: tokens.surface.card,
color: tokens.text.onSurface.default,
borderColor: tokens.component.iconBox.border,
maxWidth: tokens.layout.container.maxWidthProse,
padding: tokens.space['16']
}Use named exports when you need generated helpers:
import tokens, { generateCssVariables } from '@phcdevworks/spectre-tokens'
const css = generateCssVariables(tokens)Generated CSS variables
Import index.css when a downstream package or app wants the generated Spectre
CSS variable contract.
@import '@phcdevworks/spectre-tokens/index.css';
.card {
background: var(--sp-surface-card);
color: var(--sp-text-on-surface-default);
max-width: var(--sp-layout-container-max-width-prose);
}
.app-shell {
width: var(--sp-layout-sidebar-width);
}
h1 {
font-family: var(--sp-heading-h1-family);
font-size: var(--sp-heading-h1-size);
line-height: var(--sp-heading-h1-line-height);
font-weight: var(--sp-heading-h1-weight);
letter-spacing: var(--sp-heading-h1-letter-spacing);
}
body {
font-family: var(--sp-body-family);
font-size: var(--sp-body-size);
line-height: var(--sp-body-line-height);
font-weight: var(--sp-body-weight);
letter-spacing: var(--sp-body-letter-spacing);
}
.hero-title {
font-size: var(--sp-display-1-size);
line-height: var(--sp-display-1-line-height);
font-weight: var(--sp-display-1-weight);
}
.intro {
font-size: var(--sp-lead-size);
line-height: var(--sp-lead-line-height);
}
input {
background: var(--sp-form-default-bg);
color: var(--sp-form-default-text);
}The CSS entry point is intended for consumers that want the token contract as variables rather than reading values in JavaScript.
typography.heading.{h1..h6}, typography.body, typography.display.{1..6},
and typography.lead are semantic role tokens — each a complete
{ fontFamily, fontSize, lineHeight, fontWeight, letterSpacing } object
referencing typography.scale.* and typography.families.* — so downstream
consumers get a text-role contract instead of hand-picking a raw
typography.scale step per heading level. Each role emits
--sp-<role>-{family,size,line-height,weight,letter-spacing} (for example
--sp-heading-h1-size, --sp-display-1-size, --sp-lead-size).
--sp-form-default-{bg,text,placeholder} are redeclared in the
[data-spectre-theme="dark"] block from modes.dark.forms.default.*, so they
follow the active mode. Other forms.* variables, including
--sp-form-default-border, keep their :root value in every mode, except
that high-contrast mode overrides forms.valid.* and forms.invalid.*.
Color modes apply wherever the attribute is set, not only on the root.
data-spectre-theme="dark", "high-contrast", or "light" on any element
switches every mode variable for that element and its descendants, so a
section can differ from the page (light restores default values inside a
dark ancestor). data-spectre-theme="system" follows the visitor's OS setting
through prefers-color-scheme, with no script. A page with no attribute is
light.
modes.highContrast is a third mode alongside default and dark. It is
light-based, and every text pair in it meets WCAG AAA (7:1). Borders and
dividers are darkened too. Set data-spectre-theme="high-contrast" on the
root, or on a section, to apply it. Buttons, links, and the valid/invalid form states don't
change between light and dark, but high-contrast mode overrides them
(modes.highContrast.buttons, .link, and .forms.{valid,invalid}), so
those also meet 7:1.
control.{sm,md,lg} gives the shared height, inline padding, and icon size
for buttons, inputs, and selects (--sp-control-md-height,
--sp-control-md-padding-inline, --sp-control-md-icon-size), and
control.compact.* is the denser set. Any element with
data-spectre-density="compact" swaps the default sizes for the compact
ones inside it. Every height except lg is below
accessibility.minTouchTarget (44px), so on touch layouts give smaller
controls a 44px hit area (for example with padding or a pseudo-element)
rather than shrinking it to the visible height.
elevation.{flat,raised,overlay,modal} pairs a shadow with its surface and
z-index, so consumers pick one level instead of combining raw steps. The
--sp-elevation-* variables are var() references to the shadow, surface,
and z-index variables, so the surface follows the active color mode.
component.chart is the data-visualization palette: eight categorical
series colors that differ in lightness as well as hue and meet 3:1 against
chart.bg, seven-step sequential and diverging ramps, and grid,
axis, and label roles. component.selection, component.caret,
component.scrollbar, component.skeleton, and component.prose.kbd cover
text selection, caret, scrollbar, skeleton-loading, and keycap colors. All of
them are set for every mode.
Token model
The generated token object includes these namespaces:
colorsspacelayoutradiitypographyfontshadowsbreakpointszIndextransitionsanimationsopacityaspectRatiosiconsborderaccessibilitybuttonsformslinksurfacetextcomponentmodestrackingcontrolelevation
The exported runtime token object is a flattened string-based tree generated
from tokens/. Source-only wrapper fields such as value and metadata are
internal generation details and are not part of the public package contract.
See TOKEN_REFERENCE.md for the exhaustive, generated list of every token path, resolved value, and usage note.
Downstream packages building recipes on the CSS output should use
DOWNSTREAM_PARITY.md, which groups every published
--sp-* variable into the family a recipe or stylesheet consumes. Run
npm run audit:parity (optionally -- <sibling-repo>) for a checklist of the
families a checked-out downstream repo has not consumed yet.
The layout namespace includes section, stack, and container spacing tokens,
plus fixed layout width tokens for common consumer shells:
layout.container.maxWidth, layout.container.maxWidthProse,
layout.container.maxWidthWide, and layout.sidebar.width.
Layout spacing sits on one 8px grid; check:structure fails on any off-grid
step. Section padding, section gap, stack gap, and container inline padding
run sm | md | lg | xl | 2xl | 3xl | 4xl. sm–lg are fixed. xl–4xl
are responsive: the base value applies on narrow viewports and
layout.responsive.lg.* takes over at the lg breakpoint. In CSS, the
@media (min-width: 1024px) block re-points --sp-layout-*-{xl..4xl} at
--sp-layout-responsive-lg-*, so consumers keep using one variable name.
layout.hero.paddingTop and layout.hero.paddingBottom (sm | md | lg)
reference section padding steps, and their CSS variables are var()
references that follow the responsive override.
Public Contract Guarantees
contract.manifest.json is the machine-readable contract authority for this
package.
It defines:
- public namespaces
- required output surfaces for JavaScript, CSS, and DTCG
- protected semantic groups
Every contract-facing surface in this repository must match that manifest. Validation fails fast on token overwrite across files, undocumented namespaces, output drift, and README mismatch with the contract authority.
Themes and modes
The package includes mode-aware semantic tokens under modes, with default
and dark mode definitions in the generated output.
Use semantic mode-aware values when the consumer needs light/dark or mode-specific behavior without branching on raw palette values.
import tokens from '@phcdevworks/spectre-tokens'
const darkPage = tokens.modes.dark.surface.page
const darkText = tokens.modes.dark.text.onPage.default
const darkInputBg = tokens.modes.dark.forms.default.bgTop-level forms.default.{bg,text,placeholder} hold the default (light)
values; read modes.dark.forms.default.* for their dark equivalents.
Guidance:
- Prefer semantic tokens for theme-aware UI.
- Prefer
modeswhen a consumer explicitly needs mode-specific values. - Do not invent local light/dark token contracts when this package already provides the semantic path.
Protected Token Families
The following semantic groups are locked. Their values must not change without explicit approval from Bradley Potts. This applies to all contributors and all AI agents — apparent visual improvements still require human sign-off.
| Protected group | Backed by | Guarded by |
| ----------------------------------- | ------------------------------ | --------------------------------- |
| success | colors.success palette | check:locked + check:contrast |
| warning | colors.warning palette | check:locked + check:contrast |
| danger semantic roles | colors.error palette | check:locked + check:contrast |
| CTA / primary action / brand-action | colors.brand + buttons.cta | check:locked + check:contrast |
check:locked fails immediately if any protected value changes from the
recorded baseline. An intentional change requires updating the baseline as part
of an approved, classified release.
Downstream Boundaries
Downstream packages should never redefine locally:
- the meaning of
surface,text,component,buttons,forms, ormodes - protected semantic groups such as
success,warning,danger, or CTA / brand-action semantics - public namespace shape that this package already exports
Downstream packages may:
- compose UI structure on top of this contract
- map these tokens into framework-specific delivery
- use raw palette values when the usage is intentionally non-semantic
Upgrade Expectations For Consumers
Consumers should treat this package as a SemVer-governed contract.
Practical guidance:
- additive token paths are intended to be safe for existing consumers
- semantic shifts may keep the same path but still affect visual meaning
- renames and removals are breaking
- generated JS, TS, CSS, and DTCG outputs are expected to stay aligned
If a downstream package depends on specific token paths or semantic meaning:
- read
CHANGELOG.mdfor contract change classification - read
TOKEN_CONTRACT.mdfor contract rules - prefer documented public namespaces over undocumented internal assumptions
Change classification
Every contract-affecting change is classified in CHANGELOG.md [Unreleased]
with a Contract change type: line before release.
| Classification | When to use | Examples |
| ----------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------- |
| additive | New tokens, new paths, new CSS variables — existing consumers unaffected | Adding a namespace, adding a token inside an existing family |
| semantic change | Path stays the same but meaning, intent, or visual output shifts | Adjusting the role of an existing surface or text token |
| breaking | Existing consumers may need code changes | Renaming a token path, removing a namespace, changing mode names |
Renames and removals are always breaking regardless of perceived scope.
Package Exports / API Surface
Root package
@phcdevworks/spectre-tokens exports:
default/tokensgenerateCssVariables- TypeScript types including
SpectreTokens,SpectreModeTokens, andSpectreModeName
Example:
import tokens, { generateCssVariables } from '@phcdevworks/spectre-tokens'
const css = generateCssVariables(tokens, {
selector: ':root',
prefix: 'sp'
})CSS entry point
@phcdevworks/spectre-tokens/index.css
Relationship To The Rest Of Spectre
Spectre keeps responsibilities separate:
@phcdevworks/spectre-tokensdefines visual language, semantic roles, and token contracts@phcdevworks/spectre-uiturns those contracts into reusable CSS, utility tooling, and shared styling behavior- Adapter packages translate Spectre contracts for framework-specific delivery
That separation keeps token meaning centralized while letting the package system expand by responsibility.
Consumer Checklist
For downstream packages and compatible apps:
- import tokens from the package root when you need runtime values
- import
index.csswhen you need generated CSS variables - prefer semantic namespaces for UI behavior
- use raw palette values only when fixed palette access is intentional
- treat
tokens/as source of truth and generated outputs as derived - do not redefine Spectre semantic contracts locally
Development
Install dependencies, then run the package verification flow:
npm install
npm run checkThis project expects Node.js ^22.12.0 || >=24.0.0 and npm 12.0.1.
Common commands
| Command | What it does |
| ------------------------ | ------------------------------------------------------------ |
| npm run build | Regenerate all outputs — run after any token source change |
| npm run check | Full validation gate — every step must pass before commit |
| npm run lint | Run ESLint against all source files |
| npm run format | Apply Prettier formatting to all files |
| npm run generate | Regenerate src/generated/tokens.ts from token sources only |
| npm run check:manifest | Validate public namespaces against contract.manifest.json |
| npm run check:docs | Validate README and TOKEN_CONTRACT headings against manifest |
| npm run check:locked | Confirm protected color families are unchanged |
| npm run check:contrast | Confirm all paired tokens meet WCAG AA |
| npm run check:dist | Confirm dist/ artifacts are in sync with source |
Key source areas
tokens/— source token data (source of truth)src/— package entry points, CSS generation, and public typessrc/generated/— auto-generated output (do not edit directly)scripts/— build and validation scriptsexample/— usage examples and smoke consumer
The files in example/ are illustrative token demos only. They help explain the
token contract, but they are not the package contract itself and should not be
treated as downstream UI primitives.
Troubleshooting
| Failure | Cause | Fix |
| ---------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| check:regression fails | A token value changed vs the recorded baseline | Revert the unintended change, or update the baseline if the change was intentional |
| check:locked fails | A protected color family was modified | Revert unless Bradley Potts has explicitly approved the change |
| check:contrast fails | A token pair is below WCAG AA, AAA in high-contrast mode, or its minContrast | Adjust the token value or the metadata.pair reference in the source JSON |
| check:dist fails | Generated dist is out of sync | Run npm run build then re-run npm run check |
| check:manifest fails | A namespace exists in outputs but is not declared in contract.manifest.json | Add the namespace to the manifest or remove it from the source |
| check:docs fails | README or TOKEN_CONTRACT.md has drifted from the manifest | Update the doc to match the current contract |
| check:classification fails | A contract-authority file changed without a classification entry | Add Contract change type: additive, semantic change, or breaking to CHANGELOG.md [Unreleased] |
AI And Automation Boundaries
Claude Code (claude-sonnet-4-6) is the primary development agent for this
repository. Codex handles releases and production stabilization, including
cutting tagged releases and GitHub Releases. Jules handles small automated fixes
and generated-output sync. GitHub Copilot provides development support.
All AI agents with repository access (Claude Code, Codex, Copilot, Jules) have commit, push, and tag authority in this repository. Publishing to npm remains Bradley Potts's sole authority. See AGENTS.md for the full commit-policy and release-authority grant.
Protected from automated change: locked color families (success,
warning, danger, CTA/brand-action), contract.manifest.json, and
src/generated/tokens.ts. See AGENTS.md for full agent governance
and boundary rules.
Contributing
PHCDevworks maintains this package as part of the Spectre system.
When contributing:
- treat
tokens/as the source of truth - keep generated outputs derived from source data
- avoid breaking token contracts without an intentional major-version change
- run
npm run buildto regenerate outputs when sources change - run
npm run checkas the full validation gate before opening a pull request - do not modify locked semantic color families without explicit approval
- keep
README.md, generated outputs, andcontract.manifest.jsonaligned
See CONTRIBUTING.md for the full workflow.
License
MIT © PHCDevworks. See LICENSE.
