Token Pipeline

A single DTCG token source compiles through Terrazzo to produce platform-appropriate outputs. Web receives CSS variables; native receives typed TypeScript. Neither platform is a second-class citizen — both outputs derive from the same source JSON.

DTCG Token JSON core.tokens.json themes/[name].tokens.json Terrazzo Compiler single build step dist/web/themes.css oklch → CSS variables Tailwind v4 @theme [data-theme] CSS scopes React DOM dist/native/themes.ts oklch → hex/rgba at build Unistyles 3 typed RN themes Expo / RN Shared Contract @app/design-tokens: ButtonVariant, Size types

DaisyUI Semantic Vocabulary

DaisyUI semantic token names provide a shared naming contract across both platforms. The *-content pairing makes arbitrary user/server themes safe for contrast — any theme that passes validation is guaranteed to have readable foreground on every background.

Token GroupTokensPurpose
Base surfaces base-100 base-200 base-300 base-content Page backgrounds and primary text
Primary action primary primary-content Main CTA, key interactive elements
Secondary secondary secondary-content Supporting actions, secondary buttons
Accent accent accent-content Highlights, badges, per-server brand color slot
Neutral neutral neutral-content Borders, dividers, muted text surfaces
Semantic state info success warning error (+ -content each) Status indicators, toasts, callouts
Radius radius-field radius-box radius-selector Consistent border radius by component type
Content Pairing Safety

*-content is the foreground-on-color pairing that makes arbitrary user/server themes safe for contrast. Server-supplied brand colors are validated for contrast server-side before being accepted into the theme system.


Web: Component Architecture

LayerTechnologyNotes
Token source @app/design-tokens (DTCG) Single source of truth for all design decisions
CSS output Tailwind v4 @theme + [data-theme] CSS Per-theme variable scopes; no class-name conflicts
Component primitives Base UI 1.0 Headless, accessible; no styles of its own
Component library Shadcn-style owned components Copy-pasted, themed with DaisyUI vocabulary
Theme switching document.documentElement.dataset.theme = name Instant, no React re-render

Native: Component Architecture

LayerTechnologyNotes
Token source @app/design-tokens (themes.ts) Same DTCG source, typed TypeScript output
Styling Unistyles 3 Zero re-render runtime theme switching
Theme switching UnistylesRuntime.setTheme(name) No React re-render triggered
Per-server branding UnistylesRuntime.updateTheme('serverOverlay', ...) Scoped via ScopedTheme component
Component primitives @rn-primitives / react-native-reusables Accessible React Native behavior layer

Runtime Theme Switching

Web

document.documentElement.dataset.theme = name. Per-server branding via <div data-theme={serverThemeId}> or inline CSS variable overrides on a wrapper. Instant, no re-render beyond style recalc.

Native

UnistylesRuntime.setTheme(name). Per-server branding via updateTheme mutation — no React re-render. Server brand colors arrive as semantic-token JSON; validated for contrast server-side before accepting.

Zero Re-render Guarantee

Neither platform requires a React tree re-render for theme switching. Web uses CSS variable reassignment. Native uses Unistyles' native runtime. Per-server branding is scoped to a subtree without propagating to global state.


Monorepo Shape

packages/design-tokens/   tokens/*.json (DTCG) + terrazzo.config
                           → dist/web/themes.css
                           → dist/native/themes.ts
                           → dist/contract.d.ts
packages/domain/           shared pure-TS business logic
apps/web/                  Vite + TanStack Router + Tailwind v4
apps/native/               Expo + Unistyles 3

What Is NOT Shared

Rendering Code Is Not Shared

React DOM components, React Native components, platform-specific gestures, scroll behaviors, and keyboard handling are strictly not shared between platforms.

The shared boundary is explicit and narrow:


Research Links

UI Theming Frameworks (doc 06) → Shared TypeScript Domain Architecture (doc 05) →