Vauban Docs
Design System

Technical Architecture

VDL Technical Architecture

How the Vauban Design Language is implemented, distributed, and consumed across the ecosystem.

Package Structure

packages/
  design-tokens/              # Source of truth for VDL v5.0
    src/
      tokens.css              # CSS custom properties (reference + semantic layers)
      tailwind-v4.css         # Tailwind v4 @theme mapping
      bridge.css              # Legacy variable mapping (Bastion compat)
      motion.css              # Keyframes, easing, animation utilities
      prose.css               # Markdown/Tiptap rendering styles
      patterns.css            # SVG backgrounds, glass effects
      tokens.json             # W3C DTCG programmatic access
      versions/               # Frozen version snapshots
        v3.0.css
    logos/                    # Brand logo SVGs (mark, wordmark, lockup × 4 variants)
    favicons/                 # Favicon files (ico, png, manifest)
    icons/                    # 70 SVG icons across 7 categories
    scripts/
      generate-scales.mjs     # OKLCH → hex scale generator (culori)
      vdl-version.sh          # Version manager CLI
    CHANGELOG.md              # Detailed version history
    VERSION                   # Current active version number

  ui/                         # Shared React components
    src/
      VThemeProvider.tsx       # next-themes wrapper (navy/zinc/light)
      VThemeSwitcher.tsx       # Three-dot theme selector widget

Data Flow

tokens.css (Reference + Semantic layers)

     ├──► tailwind-v4.css (@theme mapping)
     │         │
     │         ├──► @theme { --color-vdl-base: var(--vdl-bg-base) }
     │         │         │
     │         │         └──► Tailwind classes: bg-vdl-base, text-vdl-primary
     │         │
     │         └──► @custom-variant dark (&:is([data-theme="navy|zinc"] *))

     ├──► bridge.css (legacy --background, --surface, etc.)
     │         │
     │         └──► Bastion Web (gradually migrating to --vdl-*)

     ├──► motion.css (keyframes + utility classes)

     ├──► VThemeProvider (React context)
     │         │
     │         └──► Sets data-theme="navy|zinc|light" on <html>
     │                   │
     │                   └──► CSS selectors activate correct theme block

     └──► External repos (copy of tokens.css)
               ├──► command-center/dashboard/
               └──► glacis-protocol/dashboard/

Three-Tier Token Architecture

Layer 1: Reference (Static)

Raw 12-step scales derived from OKLCH source values. Theme-agnostic.

/* OKLCH source → hex output */
--vdl-slate-1: #050810;   /* oklch(0.135 0.019 264) */
--vdl-indigo-9: #6366F1;  /* oklch(0.585 0.204 277) */

Layer 2: Semantic (Theme-Reactive)

Purpose-bound tokens that reference scale tokens. These change per theme.

:root {
  --vdl-bg-void: var(--vdl-slate-1);  /* Navy: #050810 */
}
[data-theme="light"] {
  --vdl-bg-void: var(--vdl-stone-1);  /* Light: #F5F0EB */
}

Layer 3: Component (Scoped)

Defined per-component, not in tokens.css. Example:

.card {
  --card-bg: var(--vdl-bg-surface);
  --card-border: var(--vdl-border-default);
}

Theme Switching Mechanism

1. Provider

VThemeProvider wraps next-themes with VDL-specific configuration:

<VThemeProvider defaultTheme="navy">
  <App />
</VThemeProvider>

It sets the data-theme attribute on <html>, which activates the corresponding CSS selector block in tokens.css.

2. Switcher

VThemeSwitcher renders three colored dots:

DotColorTheme
Navy dot#0A0F1A with blue radial tintnavy
Zinc dot#3f3f46zinc
Light dot#F5F0EB with stone borderlight

Active dot has a glowing ring and 1.15x scale. Click any dot to switch. Click active dot to cycle to the next theme.

3. Persistence

Theme choice persists in localStorage under the key vdl-theme. The provider reads it on mount and applies instantly (no flash of wrong theme thanks to disableTransitionOnChange).

Tailwind v4 Integration

The integration layer (tailwind-v4.css) maps VDL tokens into Tailwind's utility system via the @theme directive:

@theme {
  --font-display: 'Geist', system-ui, sans-serif;
  --font-heading: 'Inter', system-ui, sans-serif;
  --color-vdl-base: var(--vdl-bg-base);
  --color-indigo-9: var(--vdl-indigo-9);
  /* ... */
}

This generates utility classes like bg-vdl-base, text-vdl-primary, border-vdl-border, text-indigo-9.

Dark Variant

@custom-variant dark (&:is([data-theme="navy"] *, [data-theme="zinc"] *));

Creates a unified dark: variant matching both dark themes. Usage: bg-white dark:bg-vdl-surface.

Legacy Bridge

bridge.css maps 40+ legacy CSS variables to VDL tokens:

:root {
  --background: var(--vdl-bg-base);
  --surface: var(--vdl-bg-surface);
  --brand-primary: var(--vdl-brand-500);
}

Apps that haven't fully migrated import bridge.css after tokens.css. New code should use --vdl-* variables directly.

Version Management

VDL versions are managed via the CLI tool at packages/design-tokens/scripts/vdl-version.sh:

./scripts/vdl-version.sh list       # List available versions
./scripts/vdl-version.sh switch 5.0 # Switch to a specific version
./scripts/vdl-version.sh snapshot 6.0  # Snapshot current as new version
./scripts/vdl-version.sh diff 4.0 5.0  # Compare two versions

Consuming VDL in a New App

Step 1: Import tokens + Tailwind layer

@import "tailwindcss";
@import "@vauban/design-tokens/tokens.css";
@import "@vauban/design-tokens/tailwind-v4.css";
/* Optional: */
@import "@vauban/design-tokens/motion.css";
@import "@vauban/design-tokens/prose.css";

Step 2: Add the theme provider (React/Next.js)

import { VThemeProvider, VThemeSwitcher } from '@vauban/ui';

export default function Layout({ children }) {
  return (
    <VThemeProvider defaultTheme="navy">
      {children}
      <VThemeSwitcher />
    </VThemeProvider>
  );
}

Step 3: Set the zone accent

:root {
  --vdl-zone-rgb: 245, 158, 11; /* Citadel = Amber */
}

Step 4: Use tokens in code

// Tailwind utilities
<div className="bg-vdl-surface text-vdl-primary border-vdl-border">
  <h1 className="font-display text-indigo-9">Title</h1>
  <span className="font-mono vdl-data-num">{amount}</span>
</div>

// CSS custom properties
.custom-element {
  background: var(--vdl-bg-surface);
  color: var(--vdl-text-primary);
  font-family: var(--vdl-font-display);
}

View Transitions

The integration layer includes a CSS-native circular reveal animation for theme switches:

::view-transition-new(root) {
  animation: vdl-reveal 0.5s cubic-bezier(0.2, 0, 0, 1);
}

The reveal originates from the click position (--vdl-reveal-x, --vdl-reveal-y). It degrades gracefully -- prefers-reduced-motion disables all animations.