VisorVisor
Themes

Creating Themes

How to create a Visor theme — the theme contract, 5-section template, standard vs creative themes, and the space theme as a reference implementation.

Visor themes are CSS files that override the design tokens from @loworbitstudio/visor-core. Any valid theme transforms every Visor component's appearance without touching component code.

Theme Contract

The theme contract defines which tokens a theme must override, which are optional, and how to add theme-specific extensions.

Required Tokens (~35)

A theme must override all of these for components to render correctly in both light and dark modes.

Text:

TokenPurpose
--text-primaryPrimary body text
--text-secondarySupporting text
--text-tertiaryPlaceholder text
--text-disabledDisabled state
--text-inverseText on inverted backgrounds
--text-inverse-secondarySecondary text on inverted backgrounds
--text-linkLink text
--text-link-hoverLink hover
--text-successSuccess feedback
--text-warningWarning feedback
--text-errorError feedback
--text-infoInfo feedback

Surface:

TokenPurpose
--surface-pagePage background
--surface-cardCard/panel background
--surface-subtleSubtle differentiation
--surface-mutedMuted areas
--surface-overlayOverlay base color
--surface-interactive-defaultInteractive resting state
--surface-interactive-hoverInteractive hover
--surface-interactive-activeInteractive pressed
--surface-selectedPersistent selected state (active nav item, currently-selected list row)

Border:

TokenPurpose
--border-defaultStandard borders
--border-mutedSubtle borders
--border-strongEmphasized borders
--border-focusFocus ring color
--border-disabledDisabled borders

Interactive:

TokenPurpose
--interactive-primary-bgPrimary button background
--interactive-primary-bg-hoverPrimary button hover
--interactive-primary-textPrimary button text
--interactive-secondary-bgSecondary button background
--interactive-secondary-bg-hoverSecondary button hover
--interactive-secondary-textSecondary button text
--interactive-destructive-bgDestructive button background
--interactive-destructive-bg-hoverDestructive button hover
--interactive-destructive-textDestructive button text

Optional Tokens (~15)

These have sensible defaults from visor-core. Override them to customize accent and status colors.

Includes: --surface-accent-subtle, --surface-accent-default, --surface-accent-strong, all status surfaces (success, warning, error, info in subtle and default variants), and status borders.

Extension Tokens (Namespaced)

Theme-specific tokens use a --{theme-name}-* prefix. Components must never depend on these — they are consumed only by theme-specific CSS.

/* Space theme extensions */
--space-glass: color-mix(in srgb, var(--accent) 15%, rgba(0, 0, 0, 0.3));
--space-surface-elevated: color-mix(in srgb, var(--accent) 8%, #121220);

/* Veronica theme extensions */
--veronica-warmth: hsl(24, 80%, 55%);

5-Section Template

Every theme file follows this structure. Copy it as your starting point.

/* ── {Theme Name} — visor-core adapter ── */

/* ═══ Section 1: Shared tokens (mode-independent) ═══ */

.{theme-name}-theme {
  --accent: #5b6fff;
  /* --font-heading: "Custom Font", system-ui, sans-serif; */

  min-height: 100vh;
  background: var(--surface-page);
  color: var(--text-primary);
}

/* ═══ Section 2: Dark mode overrides ═══ */

.dark .{theme-name}-theme {
  --text-primary: /* dark value */;
  --surface-page: /* dark value */;
  --border-default: /* dark value */;
  --interactive-primary-bg: /* dark value */;
  /* ... all required tokens */
}

/* ═══ Section 3: Light mode overrides ═══ */

html:not(.dark) .{theme-name}-theme {
  --text-primary: /* light value */;
  --surface-page: /* light value */;
  --border-default: /* light value */;
  --interactive-primary-bg: /* light value */;
  /* ... all required tokens */
}

/* ═══ Section 4: Framework bridge ═══ */

/* fumadocs HSL triplets, if applicable */
.dark .{theme-name}-theme {
  --fd-background: /* H S% L% */;
  /* ... */
}

/* ═══ Section 5: Creative extensions (creative themes only) ═══ */

/* Namespaced extension tokens + custom CSS */

Theme Tiers

Standard Themes

Standard themes contain only token overrides — no custom CSS. They can be described entirely via .visor.yaml and are compatible with the theme builder (Phase 5).

name: "Corporate Blue"
tier: standard
tokens:
  shared:
    accent: "#1e40af"
  dark:
    text-primary: "#f3f4f6"
    surface-page: "#0a0a0f"
    # ... all required tokens
  light:
    text-primary: "#111827"
    surface-page: "#ffffff"
    # ... all required tokens

Use standard themes when: you need brand-aligned colors and typography without visual effects.

Creative Themes

Creative themes include section 5 — visual effects, animations, and custom CSS that go beyond token overrides. They still satisfy the full theme contract.

Use creative themes when: you want gradients, glass effects, starfields, custom animations, or any visual treatment that cannot be expressed as a token value.

The space theme is Visor's reference creative theme. It extends the contract with:

  • Starfield animation with twinkling stars
  • Glass/translucent code blocks
  • Sunrise gradient background (light mode)
  • Custom font faces (Satoshi, Source Code Pro)

Distinguishing rule: If a theme needs anything in section 5, it is creative. If sections 1-4 fully describe it, it is standard.

Tips

  • Use color-mix() to derive surfaces from your accent color — this creates cohesive tinted surfaces.
  • Test both light and dark modes. A common mistake is only tuning one mode.
  • Keep --border-focus high-contrast against both light and dark backgrounds.
  • Reference the space theme source as a working example.