Sigil
Overview

A five-axis design language

Sigil isn't one style — it's five independent axes that every component picks a position on. Once you can name the axis a component is varying, most "should this look different" questions answer themselves.

The axes are tokens, tone, control registers, interaction cores, and density. They compose: a Knob is an instrument-register component using a bounded-vector core, styled through the same tone tokens as everything else.

Axis 1

Tokens

Every color in the system is a CSS variable, not a hard-coded value. A theme is just a class on <html> that overrides the same variable names — swapping theme-amber for theme-midnight repaints the whole app with zero component changes.

.theme-midnight {
--primary: oklch(0.72 0.09 220);
--background: oklch(0.16 0.02 250);
--border: oklch(0.28 0.02 250);
}

Seven themes ship today, each a distinct thermal envelope — warm near-black amber, cool blue-teal midnight, oxidized copper — but the mechanism doesn't care how many exist. A component that reaches for a raw Tailwind color instead of a token is the one thing that breaks this contract.

Axis 2

Tone

Tone is the separate, smaller vocabulary layered on top of tokens for semantic state: success, warning, destructive, info, muted, and primary for emphasis that isn't a health state. Every custom component maps its own state names onto these six — aliases like danger or active resolve to the canonical tone so generated call sites don't have to memorize exact spelling.

<Meter value={0.82} color="warning" />
<Meter value={0.82} color="danger" /> // alias for "destructive"
Axis 3

Registers

A control's register is the register of surface it belongs to: ordinary form controls, dense tweak-panel controls, or physical instrument-panel controls (knobs, faders, LEDs). The same underlying value can be edited by a Slider, a CompactSlider, or a Knob — the register says which one belongs on a given screen.

Registers don't blend freely. A form can degrade into a tweak control under space pressure, but an instrument control is chosen deliberately — a Fader never silently becomes a CompactSlider just because the viewport narrowed.

Axis 4

Interaction cores

Underneath the register, every interactive control is a projection of one of five state models.

  • Bounded vector — a value inside a domain (sliders, knobs, XY pads).
  • Relative delta — unbounded, speed-scaled scrubbing.
  • Interval — a lo/hi pair (range sliders).
  • Draft/commit — an uncommitted value layered over any core.
  • Discrete index — enumerated positions with detents.

A Knob and an XY pad look nothing alike, but they're the same bounded-vector core rendered through angular vs. planar geometry. The shared core means keyboard support, clamping, and drag handling only have to be correct once.

Axis 5

Density

Density is the responsive mechanism, not a cosmetic size prop.

One scale — lg / md / sm / xs — spans the form and tweak registers. Because every control in a density ladder shares the same interaction core, a bounded scalar can degrade from a full slider-plus-input down to a bare scrubber-style readout as space shrinks, with no behavior change underneath.