When six AI agents build 70 components simultaneously, how do you ensure they all look like they belong to the same design system? The answer is design tokens -- a centralized set of values for colors, spacing, typography, shadows, and border radii that every component references instead of hardcoding.
FlinUI's design token system was the first thing we built in Session 037, before a single component was written. Fifty-plus tokens defined the visual language. Every Button, every Card, every Modal draws from the same well. Change a token, and every component that references it updates. Switch from light to dark theme, and the entire application transforms in a single state change.
What Design Tokens Are
Design tokens are named constants that represent visual design decisions. Instead of scattering #007bff throughout 365 component files, you define it once as primary and reference it everywhere:
// tokens.flin
primary = "#007bff"
primary_hover = "#0056b3"
primary_light = "#e3f2fd"// Button.flin uses the token, not the hex value
If the brand color changes from blue to purple, you change one line in tokens.flin. Every button, every link, every badge updates automatically.
This is not a new concept -- Salesforce Lightning Design System, Material Design, and Tailwind CSS all use design tokens. What is different in FLIN is that tokens are FLIN variables. They are not CSS custom properties, not JSON files, not JavaScript objects. They are reactive values that the component system understands natively.
The Token Categories
Color Tokens
// Brand colors
primary = "#007bff"
primary_hover = "#0056b3"
primary_active = "#004085"
primary_light = "#e3f2fd"secondary = "#6c757d" secondary_hover = "#545b62"
// Semantic colors success = "#28a745" success_hover = "#218838" warning = "#ffc107" warning_hover = "#e0a800" danger = "#dc3545" danger_hover = "#c82333" info = "#17a2b8" info_hover = "#138496"
// Neutral colors white = "#ffffff" gray_50 = "#f8f9fa" gray_100 = "#f1f3f5" gray_200 = "#e9ecef" gray_300 = "#dee2e6" gray_400 = "#ced4da" gray_500 = "#adb5bd" gray_600 = "#6c757d" gray_700 = "#495057" gray_800 = "#343a40" gray_900 = "#212529" black = "#000000"
// Semantic surface colors bg_primary = "#ffffff" bg_secondary = "#f8f9fa" bg_surface = "#ffffff" text_primary = "#212529" text_secondary = "#6c757d" text_muted = "#adb5bd" border_color = "#dee2e6" ```
The color system follows a deliberate hierarchy. Brand colors (primary, secondary) define the application's identity. Semantic colors (success, warning, danger, info) communicate meaning. Neutral colors (gray_50 through gray_900) provide the grayscale backbone. Surface colors (bg_primary, text_primary, border_color) define the base layer that changes between themes.
Each brand and semantic color has hover and active variants, computed as darker shades. This ensures consistent interaction feedback across all components without each component computing its own hover color.
Spacing Tokens
space_0 = "0"
space_px = "1px"
space_0_5 = "0.125rem" // 2px
space_1 = "0.25rem" // 4px
space_1_5 = "0.375rem" // 6px
space_2 = "0.5rem" // 8px
space_3 = "0.75rem" // 12px
space_4 = "1rem" // 16px
space_5 = "1.25rem" // 20px
space_6 = "1.5rem" // 24px
space_8 = "2rem" // 32px
space_10 = "2.5rem" // 40px
space_12 = "3rem" // 48px
space_16 = "4rem" // 64px
space_20 = "5rem" // 80px
space_24 = "6rem" // 96pxThe spacing scale follows a 4px base grid. space_1 is 4px, space_2 is 8px, space_4 is 16px. The half-steps (space_0_5, space_1_5) exist for fine-tuning where the base scale is too coarse.
Components use spacing tokens for padding, margins, and gaps:
// Button.flin
padding_sm = "{space_1} {space_2}" // 4px 8px
padding_md = "{space_2} {space_4}" // 8px 16px
padding_lg = "{space_3} {space_6}" // 12px 24pxTypography Tokens
// Font families
font_sans = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
font_mono = "'SF Mono', 'Fira Code', 'Consolas', monospace"
font_serif = "Georgia, 'Times New Roman', serif"// Font sizes text_xs = "0.75rem" // 12px text_sm = "0.875rem" // 14px text_base = "1rem" // 16px text_lg = "1.125rem" // 18px text_xl = "1.25rem" // 20px text_2xl = "1.5rem" // 24px text_3xl = "1.875rem" // 30px text_4xl = "2.25rem" // 36px
// Font weights font_light = "300" font_normal = "400" font_medium = "500" font_semibold = "600" font_bold = "700"
// Line heights leading_tight = "1.25" leading_normal = "1.5" leading_relaxed = "1.75"
// Letter spacing tracking_tight = "-0.025em" tracking_normal = "0" tracking_wide = "0.025em" ```
The type scale uses a modular ratio of approximately 1.125 (major second). Each step is 1.125 times the previous step, creating a harmonious visual hierarchy. The text_base of 16px is the browser default, ensuring readability.
Shadow Tokens
shadow_xs = "0 1px 2px rgba(0,0,0,0.05)"
shadow_sm = "0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06)"
shadow_md = "0 4px 6px rgba(0,0,0,0.1), 0 2px 4px rgba(0,0,0,0.06)"
shadow_lg = "0 10px 15px rgba(0,0,0,0.1), 0 4px 6px rgba(0,0,0,0.05)"
shadow_xl = "0 20px 25px rgba(0,0,0,0.1), 0 10px 10px rgba(0,0,0,0.04)"
shadow_inner = "inset 0 2px 4px rgba(0,0,0,0.06)"
shadow_none = "none"Shadows create depth hierarchy. Cards use shadow_sm. Modals use shadow_lg. Dropdowns use shadow_md. The progression from xs to xl creates a consistent elevation system.
Border Radius Tokens
radius_none = "0"
radius_sm = "0.125rem" // 2px
radius_md = "0.25rem" // 4px
radius_lg = "0.5rem" // 8px
radius_xl = "0.75rem" // 12px
radius_2xl = "1rem" // 16px
radius_full = "9999px" // Fully rounded (pill shape)Transition Tokens
transition_fast = "150ms ease-in-out"
transition_normal = "250ms ease-in-out"
transition_slow = "350ms ease-in-out"Components use these for hover effects, focus states, and theme transitions.
Dark Mode: Token Overrides
Dark mode is not a CSS trick. It is a complete set of token overrides that replace the light theme values:
// dark.flin
bg_primary = "#1a1a2e"
bg_secondary = "#16213e"
bg_surface = "#0f3460"
text_primary = "#e2e8f0"
text_secondary = "#a0aec0"
text_muted = "#718096"
border_color = "#2d3748"// Adjusted shadows for dark backgrounds shadow_sm = "0 1px 3px rgba(0,0,0,0.3), 0 1px 2px rgba(0,0,0,0.2)" shadow_md = "0 4px 6px rgba(0,0,0,0.3), 0 2px 4px rgba(0,0,0,0.2)" shadow_lg = "0 10px 15px rgba(0,0,0,0.3), 0 4px 6px rgba(0,0,0,0.2)"
// Brand colors remain the same but with adjusted variants primary_light = "#1a365d" success_light = "#1c4532" danger_light = "#4a1d2f" ```
When the theme switches from light to dark, the token values change, and every component that references them updates. A Card that uses bg_surface for its background automatically changes from white to dark blue. A Text component that uses text_primary automatically changes from near-black to near-white.
Theme Detection
FlinUI supports three theme modes: light, dark, and system (auto-detect):
// ThemeProvider.flin
theme = props.theme || "system"// System detection {if theme == "system"} // Check OS preference preferred = system_color_scheme() // "light" or "dark" active_theme = preferred {else} active_theme = theme {/if}
// Apply tokens {if active_theme == "dark"} // Override with dark tokens {/if} ```
The system_color_scheme() function checks the operating system's preferred color scheme (via the prefers-color-scheme media query on the web). When the user changes their OS theme, the application updates automatically.
Custom Themes
FlinUI's token system is designed for customization. A developer can override any token to create a branded theme:
// my-theme.flin
primary = "#ff6b35" // Orange brand color
primary_hover = "#e55a2b"
primary_light = "#fff3ed"
radius_md = "0.5rem" // Rounder corners
font_sans = "'Inter', sans-serif" // Custom fontThe custom theme file is loaded after the default tokens, overriding only the values that differ. Everything else -- spacing, shadows, typography scale -- remains consistent with the default theme.
<ThemeProvider theme={custom_theme}>
<App />
</ThemeProvider>The ThemeProvider component wraps the application and makes the custom token values available to all descendant components. Multiple ThemeProviders can nest for section-specific theming (a dark sidebar in a light application, for example).
How Tokens Flow Through Components
The token system works through a combination of FLIN's variable scoping and the component rendering pipeline:
1. tokens.flin defines default values
2. dark.flin conditionally overrides values
3. ThemeProvider makes tokens available to child components
4. Components read tokens from their rendering context
5. Changes to tokens trigger re-renders in referencing componentsThis is not CSS custom properties (which require browser support and cascade rules). It is FLIN's own reactivity system applying to visual values. When primary changes from "#007bff" to "#ff6b35", every component that uses primary in its style attributes re-renders with the new value. The update is granular -- only the components that reference the changed token re-render.
Responsive Tokens
The responsive system defines breakpoints and provides utilities for responsive design:
// responsive.flin
breakpoint_sm = "640px"
breakpoint_md = "768px"
breakpoint_lg = "1024px"
breakpoint_xl = "1280px"
breakpoint_2xl = "1536px"// Container max-widths container_sm = "640px" container_md = "768px" container_lg = "1024px" container_xl = "1280px" ```
Components use these breakpoints for responsive behavior. The Grid component, for example, can change its column count at different breakpoints:
<Grid cols={1} cols_md={2} cols_lg={3} gap={4}>
<Card>...</Card>
<Card>...</Card>
<Card>...</Card>
</Grid>On mobile (below breakpoint_md): one column. On tablets: two columns. On desktop: three columns.
Animation Tokens
// animations.flin
fade_in = "fadeIn 200ms ease-in-out"
fade_out = "fadeOut 200ms ease-in-out"
slide_up = "slideUp 250ms ease-out"
slide_down = "slideDown 250ms ease-out"
scale_in = "scaleIn 200ms ease-out"
scale_out = "scaleOut 150ms ease-in"
spin = "spin 1s linear infinite"
pulse = "pulse 2s ease-in-out infinite"
bounce = "bounce 1s ease-in-out"Components reference these tokens for entry and exit animations. Modal uses fade_in for its overlay and scale_in for its content panel. Toast uses slide_up for appearing and fade_out for dismissing. Spinner uses spin for its rotation.
The Result: Consistent by Construction
The design token system means FlinUI is consistent not because each component was carefully reviewed for visual consistency, but because consistency is built into the architecture. A component cannot use a non-standard blue because there is no reason to -- primary is easier to type than #007bff. A component cannot use 15px padding because space_4 (16px) and space_3 (12px) are the available options.
Fifty-plus tokens. Two theme variants (light and dark). Six breakpoints. Nine animations. Together, they define a complete visual language that scales from a single button to a 365-component library without a single visual inconsistency.
---
This is Part 85 of the "How We Built FLIN" series, documenting how a CEO in Abidjan and an AI CTO built a design token system that keeps 365 components visually consistent.
Series Navigation: - [84] Charts and Data Visualization Components - [85] Design Tokens and Theming System (you are here) - [86] The Layout System - [87] Icons Library Integration