Track · tokens
Tokens track
The design-system vocabulary. Two layers — raw palette atoms and a semantic --ds-* API — plus a pinnable surface version so production integrations don't break on rename.
Endpoint
GET /api/v1/tokens?format=css[&layer=…&version=…]
CSS responses are public (no JWT) so hosts can load via a plain <link rel="stylesheet">. JSON index is scoped to studio:v1:use.
Layers
layer | What you get |
|---|---|
atoms | Raw palette (--obs-*, --font-*, --ease-*, --duration-*). Backward-compat — reproduces the pre-semantic output byte-for-byte. |
semantic | --ds-* surface (~60 vars) for bg / text / border / accent / status / shadow / font / motion / radius / space. Light + dark blocks under :root, @media (prefers-color-scheme: dark), and [data-theme="dark"]. |
both | Atoms, then semantic. Default. |
Version pinning
GET /api/v1/tokens?format=css&version=1.4.0
Pin in production. Supported values are echoed in the JSON catalog's supportedVersions field — currently 1.0.0, 1.1.0, 1.2.0, 1.3.0, 1.4.0. Unknown → 400 with the allow-list. The resolved version appears in the x-studio-api-version header and the first line of the CSS body.
Pinning insulates you from silent token renames — when an atom gets renamed, the previous surface is snapshotted into a frozen builder and kept callable at the old version string.
Common integrations
Default — atoms + semantic
<link rel="stylesheet"
href="https://urja.insightsbyomkar.com/api/v1/tokens?format=css&version=1.4.0" />
Semantic only — host already loads atoms separately
<link rel="stylesheet"
href="https://urja.insightsbyomkar.com/api/v1/tokens?format=css&layer=semantic&version=1.4.0" />
urja-client React
import { VisualThemeProvider } from "urja-client";
<VisualThemeProvider tokensVersion="1.4.0" tokenLayer="both">
<App />
</VisualThemeProvider>
One provider, three <link> tags injected (tokens + fonts + motion), deduped.
What the semantic layer covers
~60 tokens across 10 groups:
| Group | Example |
|---|---|
bg | --ds-bg-canvas, --ds-bg-subtle, --ds-bg-elevated, --ds-bg-overlay, --ds-bg-inverse |
text | --ds-text-strong, --ds-text-soft, --ds-text-muted, --ds-text-inverse, --ds-text-link, --ds-text-link-hover |
border | --ds-border-hairline, --ds-border-soft, --ds-border-strong, --ds-border-inverse |
accent | --ds-accent-gold, --ds-accent-gold-soft, --ds-accent-gold-medium, --ds-accent-gold-strong, --ds-accent-gold-contrast |
status | --ds-status-success, --ds-status-warning, --ds-status-danger, --ds-status-info (+ tinted backgrounds) |
shadow | --ds-shadow-xs, -sm, -md, -lg, -xl |
font | --ds-font-display, --ds-font-sans, --ds-font-mono |
motion | --ds-ease-standard, --ds-ease-emphasized, --ds-ease-soft, --ds-ease-snap; durations instant / quick / standard / long |
radius | --ds-radius-xs / sm / md / lg / xl / full |
space | --ds-space-1 / 2 / 3 / 4 / 6 / 8 / 12 / 16 |
Hosts override any var by setting it in their own :root. Every var has an inline fallback value so the semantic layer works standalone without the atoms block.
Response contract
Content-Type: text/css; charset=utf-8Cache-Control: public, max-age=86400, s-maxage=604800, immutablex-studio-api-version: <resolved version>
