Skip to content

App skins

Skins swap Baudrun’s app chrome: colors, typography, radii, elevation, layout shape. Distinct from themes, which only recolor the terminal viewport. A skin is a flat map of CSS-custom-property-style values that Baudrun reads at startup (and after each Skin-picker change) and projects into the runtime token store the render code consumes. Keys begin with -- for parity with the CSS variable conventions Baudrun was designed against; values use familiar CSS syntax (hex / rgba / linear-gradient / 1px solid <color> shorthand / etc.).

Custom skins live under the user config dir, not inside the app bundle:

  • macOS: ~/Library/Application Support/Baudrun/skins/<id>.json
  • Windows: %APPDATA%\Baudrun\skins\<id>.json
  • Linux: $XDG_CONFIG_HOME/Baudrun/skins/<id>.json (usually ~/.config/Baudrun/skins/)

Drop a JSON file there manually, or use Settings → App Skin → Import which runs a native file-picker and copies it into the directory. Deleting a user skin from Settings also removes the file.

{
"id": "cobalt-pro",
"name": "Cobalt Pro",
"description": "Muted blue on slate, high-contrast accents.",
"supportsLight": true,
"vars": { "--bg-main": "#1a2333", "--fg-primary": "#e6ecf5" },
"darkVars": { },
"lightVars": { "--bg-main": "#f5f5f7", "--fg-primary": "#1d1d1f" }
}
FieldRequiredNotes
idnoStable slug. If omitted, derived from name (lowercased, hyphenated). On import, a numeric suffix (-2, -3) is appended if it clashes with an existing skin.
nameyesDisplay name shown in the Skin picker.
descriptionnoOne-line hint, reserved for future UI surfaces.
supportsLightnoDefault false. Set true if your skin has a working lightVars overlay. When false, the skin is pinned dark regardless of the user’s Appearance preference.
varsyes*Always-applied variables. Effectively the dark base, since the window material itself is pinned dark.
darkVarsnoOverlay applied when appearance = dark. Usually omitted; most dark skins put everything in vars.
lightVarsnoOverlay applied when appearance = light. Use opaque surfaces (see Light / dark handling).

* At least one of vars / darkVars / lightVars must be non-empty.

All keys must start with --. The importer rejects any skin that violates this or has an empty name / no variables.

The full list of authored tokens lives in src/skin_tokens.rs. Anything not declared in your skin falls back to the built-in default for that token. Grouped for navigation:

VariableExamplePurpose
--font-ui-apple-system, sans-serifUI body font
--font-mono"SF Mono", Menlo, monospaceTerminal + hex-view
--font-size-base13pxDefault UI text
--font-size-label11pxForm labels
--font-size-section15pxSection headers
--font-size-h124pxPage titles
--label-transformuppercase / noneForm-label casing
--label-letter-spacing0.04emForm-label tracking
--label-weight500Form-label weight
VariablePurpose
--bg-windowRoot window fill (often transparent)
--bg-sidebarLeft profile pane
--bg-mainMain content pane
--bg-panelCards / sub-panels inside sections
--bg-hoverHover state on interactive rows
--bg-activeSelected / active item highlight
--bg-inputText + select inputs
--bg-input-focusFocused input
--bg-terminalTerminal viewport fill (fallback for themes that don’t set one)
--option-bgDropdown popover background (Select component, opaque)
--shell-bgBackdrop behind floating panels (Liquid Glass light uses this)
VariablePurpose
--fg-primaryBody text, strong labels
--fg-secondarySection hints, secondary labels
--fg-tertiaryMeta info (timestamps, footnotes)
--option-fgDropdown popover option text
--option-group-fgDropdown popover group-header label text
VariablePurpose
--border-subtleSection dividers, faint lines
--border-strongEmphasized borders
--input-border-idleInput outline when unfocused
--panel-borderFull border declaration for cards (1px solid ... or none)
--sidebar-dividerLine between sidebar and main (full declaration: 1px solid <color> or none)
VariablePurpose
--accentPrimary action color, selected text
--accent-hoverPrimary on hover
--dangerErrors, destructive actions
--successOK states, connected-session dot
--warnWarnings, reconnecting pulse
VariablePurpose
--radius-smSmall inputs, swatches
--radius-mdButtons, cards
--radius-lgLarge panels, modals
--shadow-panelCard / panel shadow
--shadow-floatingElevated surfaces (modals, dropdowns)
VariablePurpose
--shell-paddingOuter padding around sidebar + main. 0 = flush, 10px = floating cards
--shell-gapGap between sidebar and main
--panel-radiusCorner radius on sidebar + main
--panel-shadowDrop shadow on sidebar + main
--titlebar-heightTitle bar height in flush-edged mode (40px is the default; the macOS-26 / Liquid Glass skin sets 0 to suppress it entirely and lets the transparent overlay take over)
--titlebar-content-insetExtra top padding inside the sidebar / main pane to clear an overlay title bar — macOS-26 sets 24px so the traffic lights don’t overlap the PROFILES header
--shadow-panelPer-pane shadow (sidebar + main), used by floating-card skins where the panes read as cards rather than meeting the window edge
--shadow-floatingShadow on transient elevated surfaces: dialogs, the right-click context menu, dropdown popovers
VariablePurpose
--scrollbar-thumbThumb fill
--scrollbar-thumb-hoverThumb on hover
VariablePurpose
--overlayApplied as body::after background. Any valid background value (images, gradients, repeating patterns). Drives CRT scanlines, Blueprint grid, etc.

Baudrun observes the OS appearance and re-applies the active skin live whenever the system flips Light / Dark — no relaunch required. Authors set a base vars block plus an optional lightVars overlay; when the user is in light mode (or auto with the OS in light mode), the two are merged with lightVars winning on conflicts.

{
"supportsLight": true,
"vars": {
"--bg-main": "#1a1a1c",
"--fg-primary": "#e5e5e7"
},
"lightVars": {
"--bg-main": "#ffffff",
"--fg-primary": "#1d1d1f"
}
}

For skins that only make sense dark (CRT, synthwave), set "supportsLight": false and omit lightVars. The applier pins dark for those regardless of the user’s Appearance preference.

  1. Element-specific styling beyond the documented tokens. The render code reads a fixed set of typed fields off the SkinTokens struct. If a value isn’t in skin_tokens.rs today, your skin can’t influence it. Open an issue with the use case if you’re hitting a gap.
  2. Window chrome below the title bar. macOS traffic-light positioning, the system min/max/close glyphs, and the window- manager’s own decorations on Windows / Linux are owned by the OS and the gpui platform layer. The --titlebar-height, --titlebar-content-inset, and --shell-bg tokens give a lot of leverage over how the chrome reads from inside the window, but the OS-side chrome itself isn’t customizable from JSON.
  3. Appearance modes beyond light / dark. Only lightVars and darkVars overlays are honored. No sepia, high-contrast, etc. beyond what one of those can express.

For a complete working skin with every option set and a per-field comment on what it does, see:

The annotated file is the recommended starting point: read it, copy the stripped version, rename the id and name, and tweak the values you care about.

A solid-color dark skin with a cyan accent. Save as ocean.json in the skins directory:

{
"name": "Ocean",
"supportsLight": false,
"vars": {
"--bg-window": "#0b1b28",
"--bg-sidebar": "#0e2133",
"--bg-main": "#12283c",
"--bg-panel": "#193249",
"--bg-hover": "rgba(255, 255, 255, 0.05)",
"--bg-active": "rgba(78, 205, 196, 0.25)",
"--bg-input": "#0e2133",
"--bg-input-focus": "#143050",
"--option-bg": "#0e2133",
"--option-fg": "#d8e9f5",
"--fg-primary": "#d8e9f5",
"--fg-secondary": "#8ba9c0",
"--fg-tertiary": "#5a7a92",
"--border-subtle": "rgba(255, 255, 255, 0.06)",
"--border-strong": "rgba(255, 255, 255, 0.12)",
"--sidebar-divider": "1px solid rgba(255, 255, 255, 0.08)",
"--accent": "#4ecdc4",
"--accent-hover": "#6ed8d1",
"--danger": "#ff6b6b",
"--success": "#4ecdc4",
"--warn": "#ffd93d",
"--radius-sm": "4px",
"--radius-md": "6px",
"--radius-lg": "10px",
"--shell-padding": "0",
"--shell-gap": "0",
"--panel-radius": "0",
"--panel-shadow": "none",
"--titlebar-height": "38px"
}
}

Re-import via Settings (or restart the app) and pick “Ocean” from the Skin dropdown.

  • Iterate by editing the JSON. Save changes; in Settings → App Skin pick a different skin and switch back to your skin (or restart Baudrun). The new values apply on the next render without rebuild. Settings → App Skin → Reveal in finder opens the skins directory so you can keep your editor next to the picker.
  • Start from a built-in. Read the JSON for each built-in skin in resources/builtin_skins.json — copy the variable block of the one closest to what you want, rename id + name, and tweak. The macOS-26 / Liquid Glass entry is the most complete demonstration of every authored variable; flush-edged skins like Baudrun-default show the minimum viable set.
  • Test both appearances if you set supportsLight: true. The Appearance dropdown in Settings flips modes without reload.
  • Skins vs. themes. The terminal viewport is styled by the active theme, not the skin. --bg-terminal is only a fallback; themes override it.

Skins are plain JSON. Sharing is email, gist, or paste; no registry. Recipients drop the file into their skins directory or use Settings → Import.