# Theming System: From Matrix Green to Sunset Orange

> Building a comprehensive theme engine with OKLCH color spaces and runtime CSS variable updates

- URL: https://dantech.academy/en/blog/terminal-git/dynamic-theming-system-oklch
- Published: 2025-08-30
- Updated: 2025-08-31
- Reading time: 4 min
- Tags: css, theming, design-system, react, terminal

Creating a theming system for my [Git Command Terminal](https://github.com/dantech0xff/git-command-terminal) was more complex than changing a few colors. I wanted users to switch between radically different aesthetics - from cyberpunk Matrix green to warm Sunset orange.

Here's how I built a robust theming system that goes beyond basic color swapping.

### More Than Just Colors

A terminal theme needs to convey personality and mood:

- **Matrix**: Hacker aesthetic with bright green on black
- **Oceanic**: Calm blues suggesting deep waters
- **Sunset**: Warm oranges and yellows for a cozy feel
- **Midnight**: Rich purples for late-night coding
- **Neon**: Cyberpunk pink and cyan combinations
- **Light**: Traditional light theme for accessibility

Each theme needed to feel cohesive across the entire application, not just the terminal area.

### Design System Requirements

The theming system needed to support:

- Runtime theme switching without page reload
- Consistent color relationships across themes
- Accessibility considerations (contrast ratios)
- Easy addition of new themes
- Type safety for theme values

### Why OKLCH Over HSL/RGB

Traditional color spaces have limitations:

```css
/* HSL - perceptually uneven */
hsl(240, 50%, 50%) /* Not the same perceived lightness as */
hsl(60, 50%, 50%)  /* this yellow */

/* RGB - no intuitive relationship */
rgb(128, 128, 255) /* Hard to create harmonious variations */
```

OKLCH (Oklch Lightness Chroma Hue) provides perceptual uniformity:

```css
/* OKLCH - perceptually even lightness */
oklch(0.7 0.15 240) /* Same perceived lightness as */
oklch(0.7 0.15 60)  /* this, just different hue */
```

### Benefits for Theme Creation

**Predictable Lightness**: `0.7` lightness looks the same across all hues
**Intuitive Adjustments**: Change just the hue to create color variations
**Better Gradients**: Smoother transitions between colors
**Accessibility**: Easier to maintain contrast ratios

### Comprehensive Color Palette

Each theme defines all semantic colors:

```typescript
export interface Theme {
  id: string
  name: string
  colors: {
    background: string
    foreground: string
    card: string
    cardForeground: string
    popover: string
    popoverForeground: string
    primary: string
    primaryForeground: string
    secondary: string
    secondaryForeground: string
    accent: string
    accentForeground: string
    destructive: string
    destructiveForeground: string
    muted: string
    mutedForeground: string
    border: string
    input: string
    ring: string
  }
}
```

### Matrix Theme Example

The iconic Matrix theme using OKLCH:

```typescript
{
  id: 'matrix',
  name: 'Matrix Terminal',
  colors: {
    background: 'oklch(0.15 0.02 240)',      // Very dark blue-black
    foreground: 'oklch(0.7 0.15 145)',       // Bright matrix green
    primary: 'oklch(0.7 0.15 145)',          // Same matrix green
    primaryForeground: 'oklch(0.15 0.02 240)', // Dark background
    accent: 'oklch(0.7 0.15 45)',            // Warning yellow-green
    destructive: 'oklch(0.65 0.2 25)',       // Error red-orange
    // ... other colors
  }
}
```

### Dynamic Theme Application

Runtime theme switching updates CSS variables:

```typescript
export const applyTheme = (theme: Theme) => {
  const root = document.documentElement

  Object.entries(theme.colors).forEach(([key, value]) => {
    // Convert camelCase to kebab-case
    const cssVariable = key.replace(/([A-Z])/g, '-$1').toLowerCase()
    root.style.setProperty(`--${cssVariable}`, value)
  })
}
```

### Theme Persistence

User theme preferences persist across sessions:

```typescript
export const getCurrentTheme = (): string => {
  if (typeof window === 'undefined') return 'matrix'
  return localStorage.getItem('git-terminal-theme') || 'matrix'
}

export const setCurrentTheme = (themeId: string) => {
  if (typeof window === 'undefined') return
  localStorage.setItem('git-terminal-theme', themeId)
}
```

### Theme Handler Hook

A custom hook manages theme state and persistence:

```typescript
export function useThemeHandlers({ currentThemeId, setCurrentThemeId }: UseThemeHandlersProps) {
  useEffect(() => {
    const savedTheme = getCurrentTheme()
    setCurrentThemeId(savedTheme)
    const theme = themes.find((t) => t.id === savedTheme) || themes[0]
    applyTheme(theme)
  })

  useEffect(() => {
    const theme = themes.find((t) => t.id === currentThemeId) || themes[0]
    applyTheme(theme)
  }, [currentThemeId])

  const handleThemeChange = (themeId: string) => {
    setCurrentThemeId(themeId)
    setCurrentTheme(themeId)
    const theme = themes.find((t) => t.id === themeId)
    if (theme) {
      toast.success(strings.buildSuccessMessage('themeChanged', { themeName: theme.name }))
    }
  }

  return {
    handleThemeChange,
  }
}
```

### Color Theory in Practice

Each theme uses color theory principles:

- **Matrix Theme**: Monochromatic green with high contrast
- **Oceanic Theme**: Analogous blues and teals
- **Sunset Theme**: Warm oranges and yellows
- **Midnight Theme**: Cool purples and magentas
- **Neon Theme**: Complementary pink and cyan

## Looking Forward

Building this theming system taught me that good themes are more than collections of colors - they're cohesive design languages that affect the entire user experience. The investment in OKLCH color spaces and semantic color roles paid off with a system that's both powerful for developers and delightful for users.

The complete theming system, with all six themes and the infrastructure to support them, is available in the [Git Command Terminal repository](https://github.com/dantech0xff/git-command-terminal). It demonstrates how thoughtful color design can transform a simple terminal into an immersive, personalized experience.
