Expand description
The app theme — two concrete appearances, one token set.
Colors are precomputed from an oklch-derived neutral scale (perceptually even
lightness steps; the same scale the reference Tailwind theme used) into gpui
Hsla.
Numbers drive layout, colors are paint: layout constants live in
theme/layout.rs as plain numbers and never depend on which color is painted.
§Light is designed, not inverted
Mirroring lightness produces the classic “washed-out inverted” look, for three reasons this module handles explicitly:
- Surface order flips meaning. In dark, the main content panel is the darkest plane and raised surfaces get lighter. In light, the content panel is white and the shell/sidebar goes grey — chrome recedes by getting darker, not lighter. Popovers stay white and earn separation from a border and shadow rather than from lightness.
- Elevation reverses. On dark, a faint white wash means “raised”. Its
literal translation — a faint black wash on white — means “recessed”, so
the composer read as a dent instead of a plate. Light lifts with white plus
a border and shadow (
Theme::input_bg, the elevation ladder). Fill alphas carry over unchanged (INK_FILL_SCALE); only hairlines scale, so a 1px edge survives a bright surround (INK_HAIRLINE_SCALE). - Accents must move down the scale. The dark palette’s 400-level accents
(red/amber, and whatever hue an app sets
Theme::accentto) are chosen for contrast against near-black; on white they fall to 2–4:1 and fail WCAG AA. Light mode uses the 600-level siblings at the same hue, which restores the contrast ratio the dark token had.
Text tones are chosen so each light token lands within ~0.5 of its dark
counterpart’s contrast ratio against its own background — the pairing is
verified in tests/theme.rs, not eyeballed.
Re-exports§
pub use paint::INK_FILL_SCALE;pub use paint::INK_HAIRLINE_SCALE;pub use paint::SCRIM_ALPHA_DARK;pub use paint::band;pub use paint::card_selected_bg;pub use paint::card_selected_shadows;pub use paint::content_shadows;pub use paint::current_appearance;pub use paint::frame_shadows;pub use paint::glass_selected_bg;pub use paint::glass_selected_shadows;pub use paint::hairline;pub use paint::ink;pub use paint::scrim;pub use paint::set_current_appearance;pub use paint::surface_shadows;pub use paint::theme_generation;pub use paint::user_bubble_bg;pub use paint::wash;
Modules§
- appearance
- Light/dark switching: what the user asked for, what the OS reports, and the plumbing that turns a change in either into a repaint.
Structs§
- Brand
- What an app changes about the shipped palette without redesigning it.
- Ink
- Text ink for both appearances.
- Material
Spec - The frost material, before a thickness picks its opacity.
- Metrics
- One role as it is actually set: a rung on the ladder, the leading it carries, and the weight it is set in.
- Seed
- The few colours a whole variant is grown from: a background, the text on it and an accent, with the diff and highlight colours optional.
- Surface
Spec - One surface’s numbers.
out = gain * saturated(backdrop) + tint, over a backdrop blurred atblur. - Syntax
Palette - Paint-only syntax colors. The hues follow the Git history graph’s lane palette (indigo, pink, emerald, amber, red, neutral), while light-mode variants are darkened enough to remain readable as text on white.
- TextInk
- The alpha of each text role over the palette’s ink — the colour of
Theme::textat full opacity. The shipped palettes’ ink is white in dark and black in light. - Theme
- The app theme. Two concrete instances —
Theme::darkandTheme::light. - Theme
Family - One theme family, as a file declares it:
- Tint
- A hue and how much of it, in oklch terms.
chroma: 0.0is the shipped neutral, soBrand::defaultreproduces the built-in palette exactly. - Variant
- What one variant sets: a
Seedand the tokens laid over it. A token neither sets keeps the shipped palette’s value.
Enums§
- Appearance
- Which appearance the app is painting.
- Control
Size - A control’s size — SwiftUI’s
ControlSize. A closed pair, not a scale: the two that ship are the row of a form and the chip on an overlay. - Glass
- The two shipped glasses — SwiftUI’s
Glass.regularandGlass.clear. A closed variant rather than knobs: Apple exposes no numbers on glass either, only the variant and a tint. - Highlight
Kind - The token category a highlighter paints with, mirroring
SyntaxPalettefield-for-field so classification can name a kind without knowing its color. - Material
- SwiftUI’s frost scale. Measured 2026-08-31: the five thicknesses are ONE
material at five opacities — the tone implied by
tint / (1 - gain)holds to within 9% across the scale, and the sigma does not move at all (23.1/20.2/21.0pt). So this is a knob, not five looks. - Selection
- A row’s selected state. Emphasized while the area it is in holds the
keyboard focus and unemphasized otherwise, as AppKit’s
isEmphasized. Both are neutral washes, never the accent. - Surface
Style - Which surface a caller names. Material and glass are different things with different vocabularies — a material has thickness, a glass has a variant — and they meet only at the numbers they resolve to.
- Text
Style - A role in the type ladder — SwiftUI’s
Font.TextStyle. - Vibrancy
- Whether the window composites translucent — AppKit’s vibrancy, and Mica.
Constants§
- BASE_
COLORS - The greys a UI is built on, as oklch hue and chroma.
- INK_
FILL_ SCALE - Light-mode alpha multiplier for fills (hover/active washes, chip and pill backgrounds).
- INK_
HAIRLINE_ SCALE - Light-mode alpha multiplier for hairlines (borders, dividers, rings). Opposite of fills: a 1px edge has to hold its own against a bright surround, and the dark palette’s white hairlines are deliberately faint. Scaling up keeps separators legible instead of dissolving into the panel.
- LEGIBLE
- WCAG AA for body text: the most contrast
keptasks text to keep. - LENSED
- Whether this build has the backdrop-blur primitive behind it — the lens a glass surface refracts through, and the frost a card lays over the content it covers. Metal’s and wgpu’s; it tracks the gpui in use rather than the platform, and the DirectX renderer carries no such primitive.
- SCRIM_
ALPHA_ DARK - Alpha of the standard modal backdrop in dark mode. Call sites that need a
heavier or lighter scrim pass their own dark-mode alpha to
scrim.
Traits§
- AppExt
- Configuration carried by the application. Import as
use theme::AppExt as _;. - Sizing
- The size ladder, on anything styled — SwiftUI’s
.controlSize(..), andTypeset’s shape for the metrics that come with a type role. - Theme
Ext - The carrier seam for catalog traits: any type holding a
Themeexposes it through this one method, and every component group (ui::widgets::Scaffolding, …) extends it, so group methods read the environment throughself.theme(). - Typeset
- The ladder, on anything styled.
Functions§
- band
- Recessed band behind a palette/picker header or footer strip.
- base_
text_ size - The body size in points.
TextStyle::Body’s own size paints the measured ladder. - behind_
window_ blending - Whether the compositor blends a material behind a translucent window —
AppKit’s
.behindWindowblending, and Mica on Windows. - card_
selected_ bg - Selected/keyboard-active treatment for rows and chips INSIDE a floating
card (menu rows, the picker rail, segmented chips):
--color-activeagain, tone-flipped by the palette convention so a card that is already the bright plane lifts with black at 6% rather than white. - card_
selected_ shadows - Selection outline for rows and chips INSIDE a floating card (menu rows,
the picker rail, segmented chips): the inset ring alone, in both
appearances. Card rows fill with a translucent wash
(
card_selected_bg), and a drop shadow — a filled rect painted BEHIND the element — shows straight through a translucent fill as a grey plate (the same lessonglass_selected_shadowsrecords for dark glass). The card already carries the elevation shadow; selection inside it only needs the edge. - content_
shadows - The shadow
bezel::ui::window::content’s floating card casts on the chrome around it. Its blur stays insideTheme::CONTENT_INSET, which the card’s parent may clip at. - contrast_
ratio - WCAG 2.1 contrast ratio between two opaque colors (1.0 … 21.0).
- current_
appearance - The appearance the context-free paint helpers are painting for.
- flatten
- Composite
fg(which may be translucent) over an opaquebg, returning the opaque result — the color the eye actually receives. - frame_
shadows - Centered frame shadow, with half-inset blur to leave room for its tail
inside the transparent
Theme::CLIENT_INSETband. - glass_
selected_ bg - Selected-state glass treatment (tabs, session rows, space rows):
../desktop’s--color-active— white at 12% on dark, black at 6% on light, translucent enough for the vibrancy to read through (heavier flat washes blocked the glass, user request). - glass_
selected_ shadows - The selected chip’s bright outline, as an INSET shadow: gpui paints inset shadows ON TOP of the background, edges only — a border with zero layout cost. Drop shadows are filled rects painted BEHIND the element, and behind a 5% fill they showed straight through as an opaque dark plate with a greyed ring (user report) — nothing may paint behind a glass chip.
- grey
- An exact achromatic tone from an 8-bit channel value (
grey(13)≡#0d0d0d) — for surfaces matched against reference-screenshot samples. - hairline
- Translucent hairline ink for borders, dividers and rings: a light grey on
dark, a dark grey on light at
INK_HAIRLINE_SCALEof the alpha. Never pure white or black. - hsl_
to_ rgb - HSL (gpui convention, all 0..1) → sRGB components 0..1.
- ink
- Translucent fill ink for interactive states and chip plates: soft-white on
dark, soft-black on light at
INK_FILL_SCALEof the alpha. - ink_
over - The colour to draw
textin overplate.surfaceis whattextwas coloured for: the opaquepagewith the washes under it, a highlight mark or a find match.plateis what is painted under it now, a selection or a solid caret over that surface.textwhere it reads there at the better of the contrasts itkepton the page and on the surface, else the surface’s own colour (inverse video) where that does, else whichever of black and white reads better. - kept
- The contrast
textkeeps when something is painted under it: what it has overpage, up toLEGIBLE. Faint text is held to its own contrast, not raised to body text’s. - legible
- The color to draw
text(which may be translucent) in over the opaqueplate:textwhere it reads atfloorthere, elsetextwith its lightness inverted where that does, else whichever of black and white reads better. - legible_
on - Whichever of
aandbhas the higher contrast ratio againstplate,aon a tie. - lightness
- The oklch lightness of an achromatic tone:
neutralinverted. - mix
- Linear per-component mix of two colors (paint helper for the gradient spinner).
- mix_
oklab frommovedtof the way toto(0..1) in OKLab, alpha alongside.- neutral
- A neutral (chroma 0) oklch tone as Hsla. Chroma 0 means r == g == b exactly, so this goes straight to an achromatic Hsla (skipping the hue math avoids float-noise saturation).
- oklch
- Convert an oklch color (CSS notation: L 0..1, C, H in degrees) to gpui Hsla.
- oklch_
to_ srgb - oklch → sRGB (each 0..1, clamped/gamut-clipped per channel). Reference: Björn Ottosson’s OKLab definition (the same matrices CSS Color 4 uses).
- over
- Composite
topoverunder, both of which may be translucent: the one color that paints what the two painted in that order do, over anything. - relative_
luminance - WCAG 2.1 relative luminance of an opaque color.
- rgb_
to_ hsl - sRGB (0..1 components) → HSL, all components 0..1 (gpui’s Hsla convention).
- scrim
- Modal backdrop at
alpha_dark(quoted, as everywhere, in dark-mode terms). - set_
current_ appearance - Point the context-free paint helpers at an appearance. Called by
Theme::install; exposed for tests that build a theme without anApp. - stack
layers, each of which may be translucent, painted in order over the opaquebase: the color the eye receives where they all overlap.- surface_
shadows - The elevation shadow a floating surface casts —
shadow_lg’s shape, which is where it lived until the surface moved into the material. Painted cut to outside the shape, because the same drop shadow under a translucent fill is the grey platecard_selected_shadowsrecords.SurfaceSpec::shadowsays which looks carry one. - theme_
generation - Monotonic id of the current palette.
- tint
- Re-emit an achromatic tone at
hue, carrying as muchchromaas its lightness can hold. Alpha rides through untouched. - user_
bubble_ bg - The user message bubble’s plate: the softened
washat 8% dark, 4% light. At the selection weight the bubble read too strong for settled content (user report), and an opaque plate before that read as a solid slab over glass. - wash
- Interactive-state wash: a softened
inkthat stops short of pure black or white so hover plates read as tinted glass rather than paint.