Series: Gestalt Color System - Core and Flow
Copy
╔═══════════════════════════════════════════════════════════════════════════════╗
│ │
│ THEMEMANAGER INTEGRATION │
│ │
│ How Core & Flow Colors Flow Through the Theme System │
│ From CSS Variables to Monaco Editor and Beyond │
│ │
│ Theme Switching = Gravity Field Reconfiguration │
│ │
╚═══════════════════════════════════════════════════════════════════════════════╝
Theme Switching as Field Reconfiguration
Physical Metaphor for Theme Changes
Each theme defines a “Core gravity field” with a specific Hue center. When you switch themes, you are reconfiguring the entire gravity field.Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ THEME SWITCHING = GRAVITY FIELD RECONFIGURATION │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ applyTheme("dracula") │
│ │ │
│ v │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ OLD GRAVITY FIELD --> NEW GRAVITY FIELD │ │
│ │ │ │
│ │ Core Hue: 230 (Blue) Core Hue: 265 (Purple) │ │
│ │ * * │ │
│ │ /│\ /│\ │ │
│ │ / │ \ / │ \ │ │
│ │ / │ \ Frame Drag / │ \ Frame Drag │ │
│ │ o o o o o o │ │
│ │ │ │
│ │ All Flow Colors All Flow Colors │ │
│ │ dragged toward Blue dragged toward Purple │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ GESTALT PRINCIPLE: SIMILARITY │
│ ───────────────────────────── │
│ │
│ When the gravity field changes, all colors are "dragged" toward the │
│ new Core, creating visual unity through shared hue direction. │
│ │
│ "Elements with similar color are perceived as related" │
│ --> All UI elements share the new Core's gravitational influence │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
ThemeManager Class Architecture
File Structure Overview
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ FILE ANALYSIS: theme-manager.ts (708 lines) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ IMPORTS: │
│ ├── readDir, readTextFile, exists (Tauri FS plugin) │
│ └── BaseDirectory (AppData access) │
│ │
│ CONSTANTS: │
│ └── THEME_CONSTANTS (modes, defaults) │
│ │
│ INTERFACES: │
│ ├── ThemeConfig (theme metadata) │
│ └── MonacoTokenRule (syntax highlighting) │
│ │
│ CLASS ThemeManager: │
│ ├── Properties (state variables) │
│ ├── constructor() (theme map init) │
│ ├── init() (initialization) │
│ ├── loadCustomThemes() (custom theme loading) │
│ ├── applyTheme() (theme application) │
│ ├── getCurrentTheme() (getter) │
│ ├── getAvailableThemes() (list themes) │
│ ├── setModeTheme() (dark/light theme set) │
│ ├── setMode() (mode switch) │
│ ├── handleSystemThemeChange() (system theme sync) │
│ ├── emitThemeChange() (event dispatch) │
│ ├── applyThemeToMonaco() (Monaco integration) │
│ ├── forceMonacoSync() (force sync) │
│ ├── getMonacoSyntaxColors() (syntax colors) │
│ ├── registerTheme() (register new theme) │
│ └── toggleMode() (toggle dark/light) │
│ │
│ EXPORTS & GLOBALS: │
│ ├── export themeManager (singleton) │
│ └── window.themeManager (global access) │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Class Structure
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ THEMEMANAGER CLASS ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────────────────────┐ │
│ │ ThemeManager (Singleton) = GRAVITY FIELD CONTROLLER │ │
│ │ ════════════════════════════════════════════════════ │ │
│ │ │ │
│ │ PRIVATE STATE: │ │
│ │ ┌─────────────────────┬──────────────────────────────────────────────┐ │ │
│ │ │ themes │ Map<string, ThemeConfig> - All gravity fields│ │ │
│ │ │ currentTheme │ string - Active gravity field name │ │ │
│ │ │ currentMode │ string - "dark" or "light" (field polarity) │ │ │
│ │ │ darkTheme │ string - Theme for dark mode │ │ │
│ │ │ lightTheme │ string - Theme for light mode │ │ │
│ │ │ initialized │ boolean - Init status │ │ │
│ │ │ pendingMonacoTheme │ object │ null - Deferred Monaco theme │ │ │
│ │ └─────────────────────┴──────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ PUBLIC METHODS: │ │
│ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ Gravity Field Control (Theme Application) │ │ │
│ │ │ ├── init() --> Initialize gravity field │ │ │
│ │ │ ├── applyTheme(name) --> Activate new gravity field │ │ │
│ │ │ ├── toggleMode() --> Switch field polarity (dark/light) │ │ │
│ │ │ └── setMode(mode) --> Set specific polarity │ │ │
│ │ │ │ │ │
│ │ │ Field Queries │ │ │
│ │ │ ├── getCurrentTheme() --> Get active field name │ │ │
│ │ │ ├── getCurrentMode() --> Get current polarity │ │ │
│ │ │ ├── getAvailableThemes()--> List all fields │ │ │
│ │ │ └── isThemeActive(name) --> Check if field is active │ │ │
│ │ │ │ │ │
│ │ │ Monaco Integration (External System Sync) │ │ │
│ │ │ ├── applyThemeToMonaco()--> Sync gravity field to Monaco Editor │ │ │
│ │ │ └── forceMonacoSync() --> Force Monaco sync │ │ │
│ │ │ │ │ │
│ │ │ System Integration │ │ │
│ │ │ ├── setSystemSync() --> Enable/disable OS theme sync │ │ │
│ │ │ └── isSystemSyncEnabled()--> Check sync status │ │ │
│ │ └───────────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Theme Configuration Structure
ThemeConfig Interface
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ THEME CONFIG STRUCTURE │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ ThemeConfig: │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ name: Theme display name (e.g., "monolex-night") │ │
│ │ type: 'file' | 'builtin' | 'custom' | 'hybrid' │ │
│ │ path: File path or identifier │ │
│ │ mode: 'dark' | 'light' │ │
│ │ themeType: 'ansi' | 'standard' (optional) │ │
│ │ │ │ │
│ │ ├──► 'ansi' = 16-color terminal palette │ │
│ │ └──► 'standard' = full color palette │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ MonacoTokenRule: │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ token: Syntax token type (e.g., "keyword", "string") │ │
│ │ foreground: Color value (hex or oklch) │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────────┘
Copy
// Theme configuration type
interface ThemeConfig {
name: string;
type: 'file' | 'builtin' | 'custom' | 'hybrid';
path: string;
mode: string;
themeType?: 'ansi' | 'standard'; // ANSI or Standard theme
}
// Monaco theme rule type
interface MonacoTokenRule {
token: string;
foreground: string;
}
Built-in Theme Registry
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ THEME REGISTRY = CATALOG OF GRAVITY FIELDS │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ THEME CATEGORIES │
│ ════════════════ │
│ │
│ ├── Monolex Family (Primary Gravity Fields) ───────────────────────────────┐ │
│ │ │ │
│ │ LIGHT MODE (Low Mass) DARK MODE (High Mass) │ │
│ │ ───────────────────── ───────────────────── │ │
│ │ monolex-daylight [standard] monolex-night [standard] │ │
│ │ monolex-night-ansi [ansi] │ │
│ │ monolex-midnight-ansi [ansi] │ │
│ │ monolex-darknight-ansi [ansi] │ │
│ │ monolex-forest-ansi [ansi] │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ├── Pro Series (High Chroma Fields) ───────────────────────────────────────┐ │
│ │ orange-pro-ansi [dark] blue-pro-ansi [dark] silver-pro-ansi [dark] │ │
│ │ black-ansi [dark] │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ├── Air Series (Low Chroma Fields) ────────────────────────────────────────┐ │
│ │ space-air-ansi [dark] white-air-ansi [light] gold-air-ansi [light] │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ├── Classic Themes (External Gravity Fields) ──────────────────────────────┐ │
│ │ solarized-light [light] solarized-dark [dark] dracula [dark] │ │
│ │ cacio-e-pepe [light] │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ THEME TYPES: │
│ ───────────── │
│ [ansi] --> Uses ANSI 16-color palette (Core Colors for terminal) │
│ Limited gravity wells, strong discrete attraction │
│ [standard] --> Uses full color palette (Semantic Core Colors) │
│ Continuous gravity field, smooth attraction │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Theme Initialization Flow
The init() Method
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ THEME INITIALIZATION FLOW = GRAVITY FIELD BOOT SEQUENCE │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────┐ │
│ │ init() called │ │
│ │ "Boot gravity field"│ │
│ └───────────┬──────────┘ │
│ │ │
│ v │
│ ┌──────────────────────┐ │
│ │ Already initialized? │ │
│ └───────────┬──────────┘ │
│ │ │
│ ┌───────────┴───────────┐ │
│ YES NO │
│ │ │ │
│ v v │
│ [Return] ┌──────────────────────────┐ │
│ │ Load localStorage: │ │
│ │ * darkModeTheme │ │
│ │ * lightModeTheme │ │
│ │ * themeMode │ │
│ └───────────┬──────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────┐ │
│ │ Determine Current Mode (Polarity):│ │
│ │ │ │
│ │ 1. Check savedMode │ │
│ │ 2. Check legacyTheme (migrate) │ │
│ │ 3. Check systemSync │ │
│ │ 4. Default to 'dark' (high mass) │ │
│ └───────────┬───────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────┐ │
│ │ applyTheme(themeToApply) │ │
│ │ "Activate gravity field" │ │
│ │ │ │
│ │ themeToApply = mode === 'dark' │ │
│ │ ? darkTheme │ │
│ │ : lightTheme │ │
│ └───────────┬───────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────┐ │
│ │ Register system theme listener │ │
│ │ matchMedia('prefers-color-...') │ │
│ │ "External field synchronization" │ │
│ └───────────┬───────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────┐ │
│ │ loadCustomThemes() (async) │ │
│ │ --> AppData/themes/custom/*.json │ │
│ │ "Load additional gravity fields" │ │
│ └───────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Theme Application Process
applyTheme() Method - Activate New Gravity Field
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ THEME APPLICATION FLOW = GRAVITY FIELD ACTIVATION SEQUENCE │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ applyTheme("monolex-midnight-ansi") │
│ "Activate new gravity field with Core Hue at 230 (Blue)" │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ STEP 1: DEACTIVATE OLD FIELD (Clean Slate) │ │
│ │ ────────────────────────────────────────── │ │
│ │ │ │
│ │ Remove existing theme classes: │ │
│ │ document.body.className.replace(/\b(light-mode│theme-[\w-]+)\b/g, '')│ │
│ │ │ │
│ │ Remove existing theme stylesheets: │ │
│ │ document.querySelectorAll('link[data-theme]').forEach(link.remove()) │ │
│ │ │ │
│ │ Old gravity field collapsed, colors in free space │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ STEP 2: SET FIELD POLARITY (Mode Class) │ │
│ │ ─────────────────────────────────────── │ │
│ │ │ │
│ │ if (theme.mode === 'light') { │ │
│ │ document.body.classList.add('light-mode'); │ │
│ │ } │ │
│ │ │ │
│ │ This triggers [data-theme="light"] CSS selectors in variables.css │ │
│ │ --> Light theme Core Colors are activated │ │
│ │ │ │
│ │ Set field polarity (dark = high mass, light = low mass) │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ STEP 3: LOAD NEW GRAVITY FIELD (Theme CSS) │ │
│ │ ────────────────────────────────────────── │ │
│ │ │ │
│ │ const link = document.createElement('link'); │ │
│ │ link.rel = 'stylesheet'; │ │
│ │ link.href = 'themes/monolex-midnight-ansi.css'; │ │
│ │ link.dataset.theme = 'monolex-midnight-ansi'; │ │
│ │ document.head.appendChild(link); │ │
│ │ │ │
│ │ Theme CSS overrides Core Color variables: │ │
│ │ --oklch-primary: oklch(60% 0.18 210); /* theme-specific */ │ │
│ │ │ │
│ │ New gravity field activated with specific Core Hue │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ STEP 4: APPLY FIELD IDENTIFIER (Theme Class) │ │
│ │ ──────────────────────────────────────────── │ │
│ │ │ │
│ │ document.body.classList.add('theme-monolex-midnight-ansi'); │ │
│ │ │ │
│ │ Enables theme-specific CSS selectors: │ │
│ │ .theme-monolex-midnight-ansi { ... } │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ STEP 5: PROPAGATE FIELD CHANGE (Emit Event & Sync Monaco) │ │
│ │ ───────────────────────────────────────────────────────── │ │
│ │ │ │
│ │ this.emitThemeChange(themeName); │ │
│ │ --> window.dispatchEvent(new CustomEvent('themechange', {...})); │ │
│ │ │ │
│ │ this.applyThemeToMonaco(themeName, mode); │ │
│ │ --> Monaco Editor gets synced Core Colors │ │
│ │ │ │
│ │ GESTALT: Similarity principle activated │ │
│ │ All colors now share the same gravitational influence (Core Hue) │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ═══════════════════════════════════════════════════════════════════════════ │
│ │
│ CORE COLOR FLOW (Frame Drag Effect): │
│ ───────────────────────────────────── │
│ │
│ 1. variables.css defines default Core Colors (--oklch-primary, etc.) │
│ 2. Theme CSS overrides specific Core Colors (new gravity center) │
│ 3. Flow Colors (--oklch-primary-hover) auto-update via color-mix() │
│ --> Frame Drag: All Flow Colors "dragged" toward new Core │
│ 4. Components using var() get new values automatically │
│ --> Gestalt Similarity: Visual unity through shared Hue direction │
│ │
│ "Core Colors define identity. Flow Colors handle everything in between." │
│ "The new Core Hue becomes the center of gravity for all colors." │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Monaco Editor Integration
CSS Variable to Editor Color Mapping
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ MONACO EDITOR: CSS VARIABLE TO EDITOR COLOR MAPPING │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Monaco Editor is an external system that must be synchronized │
│ with the current gravity field. The Core Hue influence propagates │
│ through CSS variables to Monaco's color configuration. │
│ │
│ CSS VARIABLE --> MONACO COLOR KEY │
│ ══════════════════════════════════════════════════════════════════════════════ │
│ │
│ CORE COLORS (from variables.css) - Gravity Field Anchors │
│ ───────────────────────────────────────────────────────── │
│ --color-bg-primary --> editor.background │
│ --color-text-primary --> editor.foreground │
│ --color-accent --> editorCursor.foreground │
│ --color-bg-secondary --> editorWidget.background │
│ --color-bg-tertiary --> editor.lineHighlightBackground │
│ --color-border --> editorWidget.border │
│ │
│ SEMANTIC CORE COLORS - Status Identities │
│ ───────────────────────────────────────── │
│ --color-success --> editorGutter.addedBackground │
│ --color-warning --> editorGutter.modifiedBackground │
│ --color-danger --> editorGutter.deletedBackground │
│ --color-danger --> editorError.foreground │
│ --color-warning --> editorWarning.foreground │
│ --color-info --> editorInfo.foreground │
│ │
│ TEXT HIERARCHY - Gestalt Proximity │
│ ─────────────────────────────────── │
│ --color-text-primary --> editorLineNumber.activeForeground │
│ --color-text-secondary --> editorLineNumber.foreground │
│ │
│ ══════════════════════════════════════════════════════════════════════════════ │
│ │
│ TRANSPARENCY SUFFIX PATTERN (FLOW) - Frame Drag with Transparency │
│ ───────────────────────────────────────────────────────────────── │
│ │
│ toHex(--color-selection-bg) + '60' --> editor.selectionBackground │
│ │ │
│ └── '60' = 37.5% opacity in hex │
│ │
│ toHex(--color-accent) + '40' --> editor.findMatchBackground │
│ │ │
│ └── '40' = 25% opacity in hex │
│ │
│ This is the "Flow" pattern applied to Monaco: │
│ Core Color + Transparency Suffix = Flow Color for Monaco │
│ │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ NOTE: Monaco uses HEX+opacity suffix, not color-mix() │ │
│ │ This is a Monaco API limitation, not a Core & Flow deviation │ │
│ │ The gravitational influence (Core Hue) is still preserved │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Monaco Syntax Colors
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ MONACO SYNTAX COLORS: THEME-SPECIFIC CORE COLORS │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ GESTALT: FIGURE/GROUND │
│ Each syntax token type is a CORE identity - it defines what that element IS. │
│ The syntax colors are the "figure" that stands out from the "ground" (bg). │
│ │
│ ├── Dracula Theme (Purple Gravity Field) ───────────────────────────────────┐ │
│ │ │ │
│ │ Token │ Color │ Visual │ │
│ │ ──────────┼─────────┼───────────────────────────────────────────────── │ │
│ │ comment │ #6272A4 │ === Muted purple-gray (low contrast) │ │
│ │ string │ #F1FA8C │ === Bright yellow (high visibility) │ │
│ │ keyword │ #FF79C6 │ === Pink (attention) │ │
│ │ number │ #BD93F9 │ === Purple (Core Hue influence) │ │
│ │ type │ #8BE9FD │ === Cyan │ │
│ │ variable │ #F8F8F2 │ === White (neutral) │ │
│ │ function │ #50FA7B │ === Green │ │
│ │ constant │ #BD93F9 │ === Purple (same as number - Frame Drag) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ├── Solarized Dark (Warm Gravity Field) ────────────────────────────────────┐ │
│ │ │ │
│ │ Token │ Color │ Visual │ │
│ │ ──────────┼─────────┼───────────────────────────────────────────────── │ │
│ │ comment │ #586E75 │ === Gray (background-aligned) │ │
│ │ string │ #2AA198 │ === Cyan (Core Hue influence) │ │
│ │ keyword │ #859900 │ === Green │ │
│ │ number │ #D33682 │ === Magenta │ │
│ │ type │ #B58900 │ === Yellow (warm) │ │
│ │ variable │ #839496 │ === Base color │ │
│ │ function │ #268BD2 │ === Blue │ │
│ │ constant │ #CB4B16 │ === Orange (warm, Core influence) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ├── Monolex Night (Blue Gravity Field) ─────────────────────────────────────┐ │
│ │ │ │
│ │ Token │ Color │ Visual │ │
│ │ ──────────┼─────────┼───────────────────────────────────────────────── │ │
│ │ comment │ #6A737D │ === Muted gray │ │
│ │ string │ #9DB1C5 │ === Light blue-gray (Core Hue influence) │ │
│ │ keyword │ #F97583 │ === Coral red (contrast) │ │
│ │ number │ #79B8FF │ === Light blue (Core Hue) │ │
│ │ type │ #B392F0 │ === Purple │ │
│ │ variable │ #E1E4E8 │ === Light gray │ │
│ │ function │ #B392F0 │ === Purple (same as type) │ │
│ │ constant │ #79B8FF │ === Light blue (same as number - Frame Drag) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ These are CORE COLORS for syntax - they define the identity of each theme. │
│ They are NOT derived via color-mix() but defined explicitly per theme. │
│ Each theme creates its own "syntax gravity field" with distinct token colors. │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Theme Change Event System
Event Propagation - Gravity Wave Broadcast
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ THEME CHANGE EVENT PROPAGATION = GRAVITY WAVE BROADCAST │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ User clicks theme: "Dracula" │
│ "Requesting gravity field transition to Purple Hue" │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ ThemeManager.applyTheme("dracula") │ │
│ │ "Activating Dracula gravity field" │ │
│ │ │ │
│ │ 1. Load dracula.css --> Core Colors change (new Hue center) │ │
│ │ 2. this.emitThemeChange("dracula") │ │
│ │ "Broadcasting gravity wave" │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ │ window.dispatchEvent('themechange') │
│ │ "Gravity wave propagating..." │
│ │ │
│ ├──────────────────────────────────────────────────────────────────────┤
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ ThemeColorSystemAutoUnique │ │
│ │ ─────────────────────────────────── │ │
│ │ │ │
│ │ Listens for: 'themechange', 'theme-changed', 'hybrid-theme-applied' │ │
│ │ │ │
│ │ Action: this.updateCSSVariables() │ │
│ │ --> Regenerates agent colors based on new background │ │
│ │ --> Uses isDarkTheme() and getBackgroundColorHSL() │ │
│ │ --> Injects new CSS with agent-color-* classes │ │
│ │ │ │
│ │ Agent colors re-calculated with new gravity field │ │
│ │ GESTALT: Similarity - agents share new Core influence │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ ThemeColorSystemCodeSyntax │ │
│ │ ─────────────────────────────────── │ │
│ │ │ │
│ │ Listens for: 'themechange', 'theme-changed', 'hybrid-theme-applied' │ │
│ │ │ │
│ │ Action: this.updateCSSVariables() │ │
│ │ --> Regenerates syntax colors based on new theme │ │
│ │ │ │
│ │ Syntax tokens align with new gravity field │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ Monaco Editor (via applyThemeToMonaco) │ │
│ │ ────────────────────────────────────── │ │
│ │ │ │
│ │ 1. Read CSS variables via getComputedStyle() │ │
│ │ 2. Convert to Monaco color format │ │
│ │ 3. monaco.editor.defineTheme('monolex-dynamic', ...) │ │
│ │ 4. monaco.editor.setTheme('monolex-dynamic') │ │
│ │ │ │
│ │ External system synchronized with gravity field │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ═══════════════════════════════════════════════════════════════════════════ │
│ │
│ FLOW COLOR RECALCULATION (Zero JavaScript - CSS Cascade Only): │
│ ─────────────────────────────────────────────────────────────── │
│ │
│ When Core Colors change via theme switch: │
│ │
│ OLD (Blue Field): NEW (Purple Field): │
│ --oklch-primary: oklch(55% 0.15 230) --> --oklch-primary: oklch(50% 0.20 265)│
│ │
│ FLOW COLORS AUTO-UPDATE (via CSS cascade - Frame Drag effect): │
│ --oklch-primary-hover: color-mix(in oklch, var(--oklch-primary), white 15%) │
│ --oklch-primary-muted: color-mix(in oklab, var(--oklch-primary), transparent 80%)│
│ │
│ Zero JavaScript needed for Flow Color recalculation! │
│ The CSS var() reference causes automatic Frame Drag toward new Core. │
│ │
│ GESTALT: SIMILARITY - All Flow colors now share the Purple Hue influence │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Mode Switching
Dark/Light Mode Toggle - Gravity Field Polarity Inversion
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ MODE SWITCHING: GRAVITY FIELD POLARITY INVERSION │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ setMode('light') │
│ "Inverting field polarity from high-mass (dark) to low-mass (light)" │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ STORED PREFERENCES │ │
│ │ ═════════════════════ │ │
│ │ │ │
│ │ darkTheme: "monolex-midnight-ansi" (stored in localStorage) │ │
│ │ lightTheme: "monolex-daylight" (stored in localStorage) │ │
│ │ │ │
│ │ When mode = 'light': │ │
│ │ themeToApply = "monolex-daylight" │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ │ applyTheme("monolex-daylight") │
│ │ "Activating light-mode gravity field" │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ CORE COLOR TRANSITION (Field Polarity Inversion) │ │
│ │ ════════════════════════════════════════════════ │ │
│ │ │ │
│ │ DARK MODE (before) LIGHT MODE (after) │ │
│ │ High Mass Field Low Mass Field │ │
│ │ ───────────────── ──────────────── │ │
│ │ │ │
│ │ --color-bg-primary: #000000 --color-bg-primary: #ffffff │ │
│ │ --color-text-primary: #93a1a1 --color-text-primary: #1a1a1a │ │
│ │ --color-border-primary: #151d26 --color-border-primary: #e0e0e0 │ │
│ │ │ │
│ │ SEMANTIC COLORS (may or may not change): │ │
│ │ --oklch-primary: oklch(55% 0.15 230) --> (theme-dependent) │ │
│ │ │ │
│ │ Background luminance inverted, Core Hue may shift │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ FLOW COLORS AUTO-ADAPT (Frame Drag with new polarity) │ │
│ │ ═════════════════════════════════════════════════════ │ │
│ │ │ │
│ │ All Flow Colors using color-mix() with var() automatically adapt: │ │
│ │ │ │
│ │ --color-overlay-light-1: color-mix(in oklab, var(--color-text-primary), transparent 92%)│
│ │ │ │ │
│ │ DARK: color-mix(in oklab, #93a1a1, transparent 92%) │ │
│ │ LIGHT: color-mix(in oklab, #1a1a1a, transparent 92%) │ │
│ │ │ │ │
│ │ Same 8% opacity, but adapted to new text color! │ │
│ │ │ │
│ │ GESTALT: CONTINUITY - Smooth perceptual transition │ │
│ │ The overlay remains visually consistent despite polarity change. │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ "When Flow moves from Core to Core, OKLAB's linear interpolation │
│ prevents muddy transitions during polarity inversion." │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Custom and Hybrid Themes
Theme Type Architecture
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ CUSTOM THEME ARCHITECTURE = USER-DEFINED GRAVITY FIELDS │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ THEME TYPES │
│ ═══════════ │
│ │
│ ├── 'file' (Standard Gravity Field) ────────────────────────────────────────┐ │
│ │ Location: /themes/{name}.css │ │
│ │ Format: CSS file with :root variables │ │
│ │ Loading: <link rel="stylesheet" href="..."> │ │
│ │ Example: themes/dracula.css │ │
│ │ │ │
│ │ Core Colors defined via CSS: │ │
│ │ :root { --oklch-primary: oklch(50% 0.20 265); } │ │
│ │ │ │
│ │ Pre-configured gravity field with fixed parameters │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ├── 'custom' (User-Defined Gravity Field) ──────────────────────────────────┐ │
│ │ Location: AppData/themes/custom/{name}.json │ │
│ │ Format: JSON with color definitions │ │
│ │ Loading: Parsed and converted to CSS │ │
│ │ │ │
│ │ { │ │
│ │ "name": "my-theme", │ │
│ │ "displayName": "My Custom Theme", │ │
│ │ "isDark": true, │ │
│ │ "colors": { │ │
│ │ "background": "#1a1a2e", │ │
│ │ "foreground": "#eaeaea", │ │
│ │ "accent": "#0f3460" │ │
│ │ } │ │
│ │ } │ │
│ │ │ │
│ │ User can define their own gravity field parameters │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ├── 'hybrid' (Composite Gravity Field) ─────────────────────────────────────┐ │
│ │ Location: Database or combination sources │ │
│ │ Format: Mixed CSS + JSON + DB │ │
│ │ Loading: applyHybridTheme() │ │
│ │ │ │
│ │ Hybrid themes can combine: │ │
│ │ - Base theme from 'file' (base gravity field) │ │
│ │ - User overrides from JSON (local perturbations) │ │
│ │ - Dynamic values from database (runtime modifications) │ │
│ │ │ │
│ │ Multiple gravity sources combine into resultant field │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ├── 'builtin' (Embedded Gravity Field) ─────────────────────────────────────┐ │
│ │ Location: Embedded in variables.css │ │
│ │ Format: No additional CSS needed │ │
│ │ Loading: Just apply mode class │ │
│ │ │ │
│ │ Used for default dark/light without theme file │ │
│ │ │ │
│ │ Minimal gravity field, just polarity (dark/light) │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
THE CENTER
How ThemeManager Enables Consistent Information Flow
The ThemeManager is the central orchestrator that ensures color-coded information flows consistently through theme changes:Copy
Connection to Core-Flow:
├── Theme Switching preserves semantic meaning
│ * Success (green) always means positive across ALL themes
│ * Danger (red) always means error across ALL themes
│ * The HUE of green/red may shift, but the MEANING is preserved
│
├── Monaco Editor receives consistent color mapping
│ * Error squiggles use danger colors
│ * Success indicators use success colors
│ * Syntax highlighting uses theme-appropriate colors
│
├── Event System broadcasts changes to all color-dependent systems
│ * Agent color system recalculates unique identifiers
│ * Syntax color system recalculates token colors
│ * All systems maintain semantic consistency
│
└── Zero JavaScript color calculation during theme switch
* CSS cascade handles all Flow derivation
* Theme switch takes < 0.1ms
* Human perceives instant, consistent color change
Integration Flow Summary
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ COMPLETE THEME INTEGRATION FLOW = GRAVITY FIELD ORCHESTRATION │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ USER ACTION │ │
│ │ (Select theme, toggle mode) │ │
│ │ "Request gravity field change" │ │
│ └─────────────────────┬────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ THEMEMANAGER │ │
│ │ "Gravity Field Controller" │ │
│ │ │ │
│ │ 1. Remove old theme CSS/classes (deactivate old field) │ │
│ │ 2. Load new theme CSS file (activate new field) │ │
│ │ 3. Add theme class to body (apply field identifier) │ │
│ │ 4. Save to localStorage (persist field state) │ │
│ │ 5. Emit 'themechange' event (broadcast gravity wave) │ │
│ │ 6. Sync Monaco Editor (external system sync) │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┼───────────────────────────┐ │
│ │ │ │ │
│ v v v │
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ CSS CASCADE │ │ EVENT LISTENERS │ │ MONACO EDITOR │ │
│ │ "Frame Drag" │ │ "Gravity Waves" │ │ "External Sync" │ │
│ │ │ │ │ │ │ │
│ │ Core Colors change │ │ AutoUnique system │ │ applyThemeToMonaco │ │
│ │ │ │ │ updates agent │ │ reads CSS vars │ │
│ │ v │ │ colors │ │ defines theme │ │
│ │ Flow Colors auto- │ │ │ │ │ │
│ │ update via │ │ CodeSyntax system │ │ │ │
│ │ color-mix() │ │ updates syntax │ │ │ │
│ │ │ │ colors │ │ │ │
│ │ Zero JS required! │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ GESTALT: │ │ GESTALT: │ │ GESTALT: │ │
│ │ Similarity │ │ Common Fate │ │ Figure/Ground │ │
│ │ │ │ │ │ │ │
│ └─────────────────────┘ └─────────────────────┘ └─────────────────────┘ │
│ │ │ │ │
│ └──────────────────────────┼───────────────────────────┘ │
│ │ │
│ v │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ RENDERED UI │ │
│ │ │ │
│ │ All components using var(--core-*) and var(--flow-*) │ │
│ │ automatically reflect the new theme │ │
│ │ │ │
│ │ All colors now orbit the new Core Hue gravity center │ │
│ │ GESTALT: Pragnanz achieved - ordered visual unity │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ═══════════════════════════════════════════════════════════════════════════ │
│ │
│ "Core Colors define identity. Flow Colors handle everything in between." │
│ "applyTheme() activates a new Core gravity field, and all colors Frame Drag │
│ toward the new center, creating visual unity through Gestalt Similarity." │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Decision Flow
When to use Core vs Flow: The five decision rules