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 widgetData 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:
| Dot | Color | Theme |
|---|---|---|
| Navy dot | #0A0F1A with blue radial tint | navy |
| Zinc dot | #3f3f46 | zinc |
| Light dot | #F5F0EB with stone border | light |
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 versionsConsuming 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.