Color
Our color system uses OKLCH — a perceptually uniform color space that ensures consistent lightness across hues. Colors are defined as CSS custom properties and mapped to Tailwind utility classes via shadcn's token layer.
Brand Palette
Three signature hues embody our duality. Green for Life, violet/pink for Virtual, and blue as the Bridge between them. These appear in our gradient title, wavy background, and accent moments.
Semantic Tokens (Dark Mode)
Semantic tokens are the bridge between brand colors and component usage. They are defined as CSS custom properties and consumed through shadcn's Tailwind mapping. Every component references semantics, never raw values.
| Token | Preview | OKLCH Value | Tailwind Class | Usage |
|---|---|---|---|---|
| --background | oklch(0.21 0.04 266) | bg-background | App canvas, main content area | |
| --foreground | oklch(0.93 0.013 256) | text-foreground | Primary body text | |
| --card | oklch(0.28 0.04 260) | bg-card | Card surfaces (used at /10 opacity) | |
| --primary | oklch(0.68 0.158 277) | bg-primary | Primary buttons, active states, links | |
| --secondary | oklch(0.34 0.033 261) | bg-secondary | Secondary buttons, less prominent actions | |
| --muted | oklch(0.24 0.038 260) | bg-muted | Subdued backgrounds, disabled fields | |
| --muted-foreground | oklch(0.71 0.019 261) | text-muted-foreground | Secondary text, placeholders, captions | |
| --accent | oklch(0.37 0.031 260) | bg-accent | Hover highlights, sidebar active bg | |
| --destructive | oklch(0.64 0.208 25) | bg-destructive | Delete actions, error states | |
| --border | oklch(0.45 0.026 257) | border-border | Card edges, dividers, input borders | |
| --ring | oklch(0.68 0.158 277) | ring-ring | Focus rings on interactive elements | |
| --sidebar | oklch(0.21 0.04 266) | bg-sidebar | Navigation sidebar, title bar, status bar |
Semantic Tokens (Light Mode)
Light mode tokens are applied via the html.light class. They maintain the same semantic names
but shift values for readability on light backgrounds. Primary colors become darker; surfaces become lighter.
| Token | Preview | OKLCH Value | Tailwind Class | Usage |
|---|---|---|---|---|
| --background | oklch(0.97 0.005 265) | bg-background | App canvas, main content area | |
| --foreground | oklch(0.18 0.04 265) | text-foreground | Primary body text | |
| --card | oklch(0.95 0.005 265) | bg-card | Card surfaces | |
| --primary | oklch(0.52 0.20 277) | bg-primary | Primary buttons, active states, links | |
| --secondary | oklch(0.90 0.010 260) | bg-secondary | Secondary buttons, less prominent actions | |
| --muted | oklch(0.94 0.008 260) | bg-muted | Subdued backgrounds, disabled fields | |
| --muted-foreground | oklch(0.40 0.04 257) | text-muted-foreground | Secondary text, placeholders, captions | |
| --accent | oklch(0.92 0.008 260) | bg-accent | Hover highlights, sidebar active bg | |
| --destructive | oklch(0.55 0.22 25) | bg-destructive | Delete actions, error states | |
| --border | oklch(0.78 0.015 257) | border-border | Card edges, dividers, input borders | |
| --ring | oklch(0.52 0.20 277) | ring-ring | Focus rings on interactive elements | |
| --sidebar | oklch(0.94 0.018 272) | bg-sidebar | Navigation sidebar, title bar, status bar |
Status Colors
Status colors are consistent across modes — they're designed to be accessible on both dark and light
backgrounds. In light mode, darker variants (--success, --warning) are used
for better contrast against white surfaces.
| Status | Dark | Dark OKLCH | Light | Light OKLCH |
|---|---|---|---|---|
| Success | oklch(0.723 0.219 150) | oklch(0.45 0.18 150) | ||
| Error | oklch(0.64 0.208 25) | oklch(0.55 0.22 25) | ||
| Warning | oklch(0.828 0.189 84) | oklch(0.65 0.18 84) | ||
| Info | oklch(0.68 0.158 277) | oklch(0.52 0.20 277) |
Surface Scale
Surfaces layer from darkest (canvas) to lightest (elevated card) in dark mode, and from lightest to elevated in light mode. Each step is subtle — about 7% lightness change — creating depth without hard edges.
| Surface | Dark | Dark OKLCH | Light | Light OKLCH | Usage |
|---|---|---|---|---|---|
| Surface 0 | oklch(0.13 0.04 265) | oklch(0.97 0.005 265) | Canvas | ||
| Surface 1 | oklch(0.21 0.04 266) | oklch(0.94 0.018 272) | Background / Sidebar | ||
| Surface 2 | oklch(0.28 0.04 260) | oklch(0.90 0.010 260) | Card | ||
| Surface 3 | oklch(0.34 0.03 261) | oklch(0.86 0.012 261) | Elevated |
Typography
Our type system uses TT Rounds Neue — a geometric rounded sans-serif by TypeType Foundry — as the primary typeface. It pairs with a monospaced face for technical precision and a serif for rare prose moments. The system supports theme-level font overrides.
Plus Jakarta Sans → system-ui → sans-serif.
Licensing: TT Rounds Neue is free for personal/trial use. Commercial deployment requires a license from TypeType Foundry.
--font-sans is the single source of truth.
The default VirtualLife theme uses TT Rounds Neue; other themes fall back to Plus Jakarta Sans.
Cascadia Code → Fira Code → ui-monospace → monospace.
Georgia → Times New Roman → serif.
Type Scale
Base size is 0.825rem (~13.2px) — slightly smaller than the browser default to increase
information density without sacrificing readability. The scale uses --text-scaling for user
preferences and Tailwind's built-in classes.
Prose Headings (Rich Content)
| Element | Size | Weight | Margin |
|---|---|---|---|
| h1 | 1.5em | 700 (Bold) | 0.67em top/bottom |
| h2 | 1.3em | 600 (Semibold) | 0.83em |
| h3 | 1.17em | 600 | 1em |
| h4 | 1em | 600 | 1.33em |
| p | inherit | 400 | 0.5em |
Spacing
Spacing follows Tailwind's 4px base grid. We favor a constrained set of values for consistency: the 4-8-12-16-24-32-48 scale handles virtually all layout needs.
0.25rem
0.5rem
0.75rem
1rem
1.5rem
2rem
3rem
Spacing Usage Guidelines
| Context | Tailwind | Value | When to Use |
|---|---|---|---|
| Inline element gap | gap-2 | 8px | Icon + text, badge contents, tight groups |
| Form field gap | gap-2 | 8px | Label to input, switch to label |
| Card internal padding | p-4 | 16px | Standard card content padding |
| Section vertical gap | gap-4 | 16px | Between cards, between form groups |
| Page padding | px-4 pt-4 | 16px | Section wrapper padding |
| Grid image gap | gap-4 | 16px | Gallery grid, catalog grid |
| Dialog padding | p-6 | 24px | Modal dialogs and popovers |
| Toolbar compact | px-3 py-1 | 12px × 4px | Status bar, compact toolbar rows |
Border Radius
Rounded corners are fundamental to VirtualLife's soft, approachable feel. The base radius
(--radius: 0.625rem) ripples through the system via calc() expressions.
Themes can override the base to shift the entire system's roundness.
Radius Assignment
| Element | Radius | Tailwind |
|---|---|---|
| Buttons (default) | md | rounded-md |
| Input fields | md | rounded-md |
| Cards | xl | rounded-xl |
| Dialogs | lg | rounded-lg |
| Badges / Pills | full | rounded-full |
| Images (generated) | lg or xl | rounded-lg |
| Main content inset | 2xl (top-left only) | border-top-left-radius: 16px |
| Radial menu buttons | full | rounded-full |
| Status dots | full | rounded-full |
| Tab list | lg | rounded-lg |
| Scrollbar thumb | 4px | Custom CSS |
Elevation
Elevation is communicated through shadow depth and backdrop blur. In dark mode, shadows are more subtle and surface lightness shifts do most of the layering work. The glass effect replaces heavy drop shadows for most surfaces.
| Level | Used For | Shadow |
|---|---|---|
| 0 | Flat surfaces, inline elements | none |
| 1 (sm) | Buttons, cards at rest, inputs | 0 1px 2px oklch(0 0 0/0.15) |
| 2 (md) | Toasts, popovers, dropdowns | 0 4px 12px oklch(0 0 0/0.15) |
| 3 (lg) | Image tiles on hover, dialogs | 0 15px 40px -10px oklch(0 0 0/0.50) |
| 4 (xl) | Image tile active hover, fullscreen overlay | Multi-layer composite |
Glass & Transparency
Glass morphism is VirtualLife's signature surface treatment. Translucent backgrounds combined with backdrop blur create depth and visual interest while letting the wavy background pattern breathe through the interface.
Glass Light
The standard card surface. Most of the background shows through, with just enough blur to maintain text legibility.
bg-card/10 backdrop-blur-smGlass Medium
For interactive panels, filter bars, overlays on images. More opacity means more contrast for denser content.
bg-card/40 backdrop-blur-mdGlass Heavy
For sticky headers, group labels, badges on images. Nearly opaque but still part of the glass family.
bg-card/80 backdrop-blur-smGlass Recipes
| Recipe | Opacity | Blur | Border | Used For |
|---|---|---|---|---|
| Glass Light | bg-card/10 | backdrop-blur-sm | border-border/50 | Standard cards (VLCard) |
| Glass Medium | bg-card/40 | backdrop-blur-md | border-border | Image overlays, filter panels, edit panels |
| Glass Heavy | bg-card/80 | backdrop-blur-sm | border-border/50 | Sticky headers, group labels |
| Glass Scrim | bg-black/50 | none | none | Image status overlays (loading/error) |
| Glass Overlay | bg-black/80 | none | none | Dialog backdrop, fullscreen overlay |
backdrop-filter: blur() is GPU-accelerated in Chromium (Electron's renderer)
but can cause compositing overhead on dense grids. Use backdrop-blur-sm (4px blur) as the default; reserve
backdrop-blur-md (12px blur) for surfaces that overlay rich content like images.
Wavy Background
The wave pattern is VirtualLife's most distinctive visual element. It represents the flowing connection between human and AI creativity — organic curves rendered with digital precision.
Anatomy
| Property | Value | Purpose |
|---|---|---|
| Curves | 11 cubic Bézier paths | Fan from edges, converge tightly at center |
| Gradient direction | Vertical (top → bottom) | Blue → Pink → Green |
| Stroke width | 3px | Thin enough to be texture, not distraction |
| Opacity ramp | 0.11 → 1.00 | Builds density toward center of fan |
| SVG opacity | 0.3 (base) × 0.6 (img layer) | Subtle background presence |
| Dark mode blend | mix-blend-mode: lighten | Waves glow against dark surface |
| Light mode blend | mix-blend-mode: darken | Waves deepen against light surface |
| Positioning | background-size: cover | Always fills the content area fully |
Theming
VirtualLife supports swappable themes that override the semantic token layer without changing component structure. Each theme is a JSON file with light/dark CSS variable overrides plus optional font and radius changes.
Theme Architecture
{
"name": "Clean Slate",
"cssVars": {
"theme": { // Shared (fonts, radius)
"--font-sans": "TT Rounds Neue, sans-serif",
"--radius": "0.5rem"
},
"light": { // Light mode overrides
"--background": "oklch(0.98 0.003 248)",
"--primary": "oklch(0.59 0.204 277)"
},
"dark": { // Dark mode overrides
"--background": "oklch(0.21 0.04 266)",
"--primary": "oklch(0.68 0.158 277)"
}
}
}
Available Themes
bg-primary.
This guarantees every theme works with every component.
Light & Dark Mode
Dark mode is the primary design surface — optimized for immersive creative work where generated images
pop against deep backgrounds. Light mode is a first-class alternative, not an afterthought. The
.dark class on <html> toggles the active variable set. Each theme
provides both dictionaries.