Skip to content

Design Tokens

Open Cowork separates color from structure.

The canonical typed token source is packages/shared/src/design-tokens.ts. It exports DESIGN_TOKENS, DEFAULT_DARK_BRAND_THEME, DEFAULT_LIGHT_BRAND_THEME, and emitRootTokensCss(). The default dark theme is Mercury graphite with the Azure signature accent; Day is the matching warm light scheme. Desktop imports the generated CSS partial at packages/app/src/styles/generated/design-tokens.css, produced by pnpm design-tokens:build; Cloud Web emits the same structural variables from emitRootTokensCss() and layers public branding color tokens on top. tests/design-tokens-sync.test.ts drift-gates the generated Desktop partial against the shared module and the default Cloud Web dark branding theme.

Color tokens stay in the runtime BrandThemeTokens and public branding contracts so downstream themes can vary by brand and color scheme. Structural tokens are theme invariant and should not be forked by downstream deployments.

Type

Token Size Line height Role
--text-2xs 11px 14px badges, keyboard hints, dense metadata
--text-xs 12px 16px secondary labels and compact controls
--text-sm 13px 18px dense UI default
--text-md 14px 20px body copy and chat messages
--text-lg 16px 24px card titles
--text-xl 19px 26px section headers
--text-2xl 24px 30px page titles
--text-3xl 30px 36px large product moments
--text-hero 38px 42px first-viewport Home greeting

Tailwind exposes these as text-* utilities such as text-md and text-hero.

Space

Spacing uses a 4px base with 6px and 10px avoided unless an existing surface needs a local exception.

Token Value
--space-1 4px
--space-2 8px
--space-3 12px
--space-4 16px
--space-5 20px
--space-6 24px
--space-7 28px
--space-8 32px
--space-9 36px
--space-10 40px
--space-12 48px

Tailwind spacing utilities such as gap-3, p-4, and mt-6 resolve to this scale.

Borders And Elevation

Surfaces use three border tiers so the UI stays crisp across all presets:

Token Role
--color-border-subtle inner dividers, dense list separators
--color-border default card, table, input, and panel hairlines
--color-border-strong focused, active, selected, or elevated containers

Cards and panels combine --shadow-card with a subtle inset top highlight; dialogs and popovers reserve --shadow-elevated.

The Studio material layer adds physical-material primitives without changing the active theme palette:

Token Role
--specular / --specular-strong 1px inset light lines for elevated or active material surfaces
--shadow-1 currently none: resting cards and rows are shadowless, so depth comes from the raised hairline rather than a contact shadow
--shadow-2 alias to the per-theme --shadow-card ramp
--shadow-3 alias to the per-theme --shadow-elevated ramp
--glass-bg, --glass-blur, --glass-border floating-surface glass treatment for dialogs, menus, palettes, tooltips, and toasts
--glow-accent, --glow-soft --glow-accent is a crisp 1px accent ring (not a bloom) for active, streaming, and focus moments; --glow-soft is currently none

--shadow-card and --shadow-elevated remain the canonical per-theme shadow sources. The --shadow-2 and --shadow-3 aliases preserve the character of all 18 presets while giving component code a consistent three-tier ramp.

Tracking

Display type uses small negative tracking instead of oversized weight:

Token Value Role
--tracking-tight -0.01em xl and 2xl headings
--tracking-display -0.02em 3xl and hero headings
--tracking-eyebrow 0.06em eyebrow and overline labels

Shape

Token Value Role
--radius-xs 5px small chips and tight controls
--radius-sm 7px standard buttons and inputs
--radius-md 9px grouped controls
--radius-lg 12px cards and panels
--radius-xl 16px dialogs and hero composer surfaces
--radius-2xl 16px large surfaces and hero composer shells
--radius-3xl 22px oversized feature and empty-state surfaces
--radius-full 9999px pills and circular affordances

Motion

Use --dur-1 for small hover changes, --dur-2 for panel/toast transitions, --dur-3 for larger surface changes, and --dur-4 for app-shell or hero surface choreography. prefers-reduced-motion: reduce sets all four durations to 0ms.

Use --ease-out for most interface exits/entries and --ease-emphasized only when a surface needs a clearer snap. Use --ease-spring for polished press, menu, disclosure, and app-shell motion where the movement is short, GPU-friendly, and reduced-motion safe.

Layers And Controls

Z-index tokens reserve predictable stacking slots:

Token Value Role
--z-sticky 10 sticky headers
--z-dropdown 40 menus and popovers
--z-overlay 50 page overlays
--z-modal 60 modal dialogs
--z-toast 70 app-shell notifications
--z-command 80 command palette
--z-tooltip 90 tooltips

Control heights are --control-h-xs at 24px, --control-h-sm at 28px, --control-h-md at 32px, --control-h-lg at 40px, and --control-h-xl at 48px.

Studio Semantics

Studio-specific tokens are still presentation tokens. They describe shared Desktop and Cloud Web UI structure without taking ownership of OpenCode execution behavior.

Token family Role
--studio-shell-* shared shell, topbar, inspector, composer, and task-lane dimensions
--density-* compact, regular, and comfy row padding/gap values for operational surfaces; emitted as --row-pad and --gap via :root[data-density]
--coworker-* semantic agent/coworker identity colors for lead, strategist, builder, reviewer, operator, and neutral identities
--lane-* planning, delegated, review, approval, and artifact lane colors
--review-* proposed, accepted, and blocked review outcome colors

Use these variables for visual identity and status only. Runtime status, delegation, approvals, questions, sessions, and tool semantics remain owned by OpenCode and the existing Open Cowork projection layer.

Consumers

Surface Source path Contract
Shared package packages/shared/src/design-tokens.ts Canonical typed token values, default dark brand theme, public branding bridge, and CSS emitter.
Shared React UI packages/ui/src/ Token-backed WorkbenchLayout, ActionCluster, DiffView, Studio shell/coworker/composer/lane/card primitives, production Studio cards/rows/boards/timelines/wizard/wiki primitives, and base primitive components consumed by Desktop and Cloud Web.
Desktop packages/app/src/styles/generated/design-tokens.css Generated :root CSS variables imported by globals.css; do not hand-edit.
Cloud Web packages/app/src/styles (browser build served by packages/cloud-server/src/browser-renderer-app.ts) Cloud Web is the browser build of the renderer, so it ships the same generated :root token CSS as Desktop (from emitRootTokensCss()), serves Mona Sans / Schibsted Grotesk from /assets/fonts/*.woff2, and overlays public branding variables from the cloud bootstrap. There is no separate Cloud Web stylesheet.
Drift gate tests/design-tokens-sync.test.ts Fails when generated Desktop tokens, shared tokens, font package assumptions, or default public branding drift.

Run pnpm design-tokens:build after editing DESIGN_TOKENS. CI also runs pnpm design-tokens:check through pnpm lint, so stale generated CSS fails instead of silently drifting.

Public Branding Theme Keys

cloud.publicBranding.theme may override color and visual-brand values only. The default theme is the Desktop-aligned Mercury graphite palette from DEFAULT_DARK_BRAND_THEME; DEFAULT_LIGHT_BRAND_THEME defines the matching Day warm light palette for presets and downstream full-theme overrides. Legacy light partial overrides remain supported for existing deployments.

Supported keys are:

background, surface, mutedSurface, border, text, mutedText, accent, accent2, accentSoft, accentLine, accentStrong, focus, warn, danger, ok, surfaceHover, surfaceActive, borderSubtle, borderStrong, elevated, textSecondary, accentHover, accentForeground, green, amber, red, info, shadowCard, shadowElevated, and bgImage.

Downstream builders should override only the color/brand keys they own and let the shared structural tokens continue to define layout density, control heights, radii, typography scale, shadows, glass, glow, and motion. Do not reintroduce Cloud Web-only spacing or typography scales.

Retint In 5 Minutes

A downstream fork retints the whole product by overriding primitive / brand tokens only. Because every component consumes semantic tokens (enforced by scripts/check-design-token-usage.mjs; see the tier model in Design System → Token Tiers), no component, stylesheet, or JSX file changes. There are three override surfaces, smallest blast radius first:

  1. Accent only (one line). Pick a shipped signature accent by id — azure, indigo, plum, teal, amber, or rose from DESIGN_ACCENT_PRESETS — or set your own. In code, applyDesignAccentTokens(theme, 'plum') returns a brand theme with the accent, hover, foreground, soft, and line tokens derived for you (foreground contrast is computed to clear WCAG AA). At runtime, set cloud.publicBranding.theme.accent (and optionally accent2); the derivation helpers fill accentSoft, accentLine, accentHover, and accentForeground automatically via derivePublicBrandingThemeTokens().

  2. Full brand palette (config-only, no rebuild). Override the neutrals, ink, status hues, shadows, and logo through cloud.publicBranding.theme using the Public Branding Theme Keys above — background, surface, mutedSurface, elevated, border, borderSubtle, borderStrong, text, mutedText, textSecondary, accent, accent2, warn/danger/ok (status), shadowCard, shadowElevated, and bgImage (brand background/logo art). This is a pure config override served by the cloud bootstrap and layered on the shared :root tokens at load time — no fork of the token source and no rebuild. Set three or four surface hexes plus one accent and the entire product — Desktop and Cloud Web — reskins, because the coworker/lane/review/glass/glow/focus tokens are all derived from --color-*.

  3. Radius personality and other structural primitives (token override layer). Radius, spacing, and control heights are theme-invariant structure, not brand color, so they are intentionally outside publicBranding. A fork that wants a rounder or sharper personality ships a tiny CSS layer that re-declares only those primitive-derived variables after the generated design-tokens.css import — e.g. a brand-overrides.css with :root { --radius-sm: 10px; --radius-lg: 18px; --radius-xl: 22px; }. This is still token-only (it overrides the semantic variables, not any component), so it survives upgrades and keeps pnpm design-tokens:check green because the generated file is untouched. For a permanent fork, edit DESIGN_TOKENS.radius in packages/shared/src/design-tokens.ts and run pnpm design-tokens:build.

What you must not touch to retint: packages/ui/src components, the renderer classes in globals.css, or the semantic token names. If a retint tempts you to edit a component color, that color is missing a token — add the token instead.