- Published on
Theming System: From Matrix Green to Sunset Orange
- Authors
- Name
- Dan Tech
- @dan_0xff
Creating a theming system for my 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:
/* 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:
/* 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:
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:
{
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:
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:
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:
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. It demonstrates how thoughtful color design can transform a simple terminal into an immersive, personalized experience.