Typhon guides

Custom themes in Typhon

Colors, radii, spacing and fonts in one small file. How to write it, import it and restore the default appearance.

Updated October 10, 2026

Where to find it in the launcher

All themes live in Settings → Appearance. That is also where you will find:

  • theme picker — click a card. "System" switches between the built-in Light and Dark themes to follow your system setting;
  • import — the "Import" button loads a theme file from disk (a .typhontheme or .json file);
  • editor — opens under the selected theme: the name, the token values with a color picker for colors, and the "Custom CSS" field under the "Advanced" button. A live preview sits next to it;
  • export — saves the selected theme to a .typhontheme file so you can move it to another computer or share it;
  • delete — custom themes only. The built-in "Dark", "Light" and "High contrast" themes can be neither deleted nor overwritten: if you edit a built-in theme, your changes are saved as a new theme next to it.

Custom themes are stored in themes.json in the Typhon data folder: %APPDATA%\Typhon\ on Windows and ~/Library/Application Support/Typhon/ on macOS. There is no need to edit it by hand — use import and export to move themes around.

Quick start

Save the text below as dusk.typhontheme (a .json extension works too), then open Settings → Appearance → Import in the launcher and pick that file. The theme appears in the list with a "custom" tag — click it to apply.

{
  "version": 1,
  "theme": {
    "id": "dusk",
    "name": "Dusk",
    "base": "dark",
    "tokens": {
      "--bg": "#0d1117",
      "--bg-sidebar": "#0b0e13",
      "--surface": "#131922",
      "--surface-2": "#18202b",
      "--surface-3": "#202a37",
      "--surface-4": "#293444",
      "--border": "rgba(255, 255, 255, 0.08)",
      "--border-strong": "rgba(255, 255, 255, 0.14)",
      "--hover": "rgba(255, 255, 255, 0.05)",
      "--hover-strong": "rgba(255, 255, 255, 0.08)",
      "--text": "#e8edf3",
      "--text-2": "#a0abb8",
      "--text-3": "#6b7785",
      "--accent": "#2fb3a3",
      "--accent-hover": "#3cc4b3",
      "--accent-subtle": "rgba(47, 179, 163, 0.15)",
      "--accent-text": "#6fd6c8",
      "--accent-ring": "rgba(47, 179, 163, 0.5)",
      "--radius-md": "1rem",
      "--radius-lg": "1.4rem"
    },
    "css": ".sidebar { border-right: 1px solid var(--border); }"
  }
}

From here it is easiest to fine-tune the theme in the launcher's own editor: select it, change the values, check the preview and click "Save".

File format

A theme file is JSON with two top-level fields: version (currently always 1) and theme. Any extra field is an import error, so a typo in a field name does not slip through unnoticed.

FieldWhat it isRules
idTheme identifierLowercase Latin letters, digits and hyphens, up to 64 characters, starting with a letter or digit
nameName in the theme list1 to 64 characters, no control characters; repeated spaces are collapsed
baseBase palettedark or light
tokensInterface variable valuesOnly the names from the tables below
cssCustom CSSOptional, up to 32 KiB

The whole file must be no larger than 256 KiB. The builtIn and updatedAt fields that appear in an exported file are accepted on import, but the launcher sets them itself.

Importing again. If a custom theme with the same id already exists, the import replaces it, which makes it easy to update a theme you edit in an external editor. If the id matches a built-in theme (dark, light, contrast), the theme is saved under a new identifier such as dark-2 and the built-in one stays as it was.

What base does. The launcher uses it to tell whether the theme is light or dark and to pick shades of the personal accent to match. base does not fill in missing colors: a token the theme does not define is taken from the built-in dark palette. A light theme therefore has to define every color from the tables, or part of the interface will stay dark.

Tokens

A token is a CSS variable the interface is built on. A theme may set any number of them; the rest keep their built-in values. Sizes are given in rem: with the interface size at 100% (Settings → General → Interface size), 1rem equals 11 pixels, and everything defined in rem scales together with that setting.

Colors

TokenWhere it is used
--bgWindow background
--bg-sidebarSidebar background
--surfaceCards and first-level panels
--surface-2Second-level surfaces: input fields, nested blocks
--surface-3Third-level surfaces
--surface-4The most raised elements: buttons, popovers
--borderRegular borders and dividers
--border-strongProminent borders
--hoverHover highlight
--hover-strongStronger highlight on hover and press
--textPrimary text
--text-2Secondary text
--text-3Muted text: captions, hints
--accentAccent color: primary buttons, selection
--accent-hoverAccent on hover
--accent-subtlePale accent background
--accent-textAccent text and links
--accent-ringFocus ring and active field border
--success, --success-subtleSuccess and its pale background
--warning, --warning-subtleWarning and its pale background
--danger, --danger-subtleError, dangerous action and their pale background

Radii and spacing

TokenBuilt-in value
--radius-xs, --radius-sm, --radius-md, --radius-lg, --radius-xl0.4rem, 0.6rem, 0.8rem, 1.2rem, 1.6rem
--cut0.2rem — corner radius of the active sidebar item marker
--space-1 … --space-60.4rem … 2.4rem in steps of 0.4rem
--space-8, --space-10, --space-123.2rem, 4rem, 4.8rem

Layout

TokenBuilt-in value
--page-x3.6rem — page side margins
--page-max232rem — maximum content width
--prose-max76rem — maximum width of long text
--sidebar-w23.2rem — sidebar width
--topbar-h5.6rem — top bar height
--control-sm, --control-md, --control-lg3.2rem, 3.8rem, 4.4rem — button and field height

Text

TokenBuilt-in value
--font-sansInter Tight Variable, Inter, Segoe UI, system-ui, sans-serif
--font-xs, --font-sm, --font-md, --font-lg, --font-xl1.3rem, 1.4rem, 1.5rem, 1.7rem, 1.9rem
--font-title3.2rem — page titles
--font-heroclamp(3.6rem, 2.6vw, 4.4rem) — not currently used in the interface
--tracking-title, --tracking-heading-0.024em, -0.012em — letter spacing of headings

Fonts come only from those installed on the system: a theme cannot load its own font file. Write font names in --font-sans without quotes, separated by commas: Segoe UI, sans-serif.

Animations and shadows

TokenBuilt-in value
--easecubic-bezier(0.2, 0.8, 0.2, 1) — the curve of all transitions
--dur, --dur-fast, --dur-panel160ms, 120ms, 180ms — transition durations
--shadow-popShadow of popup menus and tooltips
--shadow-modalShadow of modal windows

--ui-scale is not part of a theme: the interface size is controlled by a separate setting, and a theme cannot override it.

Allowed values

A token value is 1 to 120 characters from this set: Latin letters, digits, the space and # . , % ( ) / + * -. That is enough for colors (#1a2b3c, rgb(26 43 60 / 80%), hsl(210 40% 16%), color-mix(in srgb, #fff 8%, transparent)), sizes, calc(...), clamp(...) and references to other tokens via var(--accent).

Not allowed: quotes, semicolons, curly braces, !important, url(, expression( and /*.

Custom CSS

Tokens cover almost everything, but sometimes you want to change something that has no variable. For that a theme has the css field, shown in the editor as "Custom CSS" under the "Advanced" button. The launcher adds this CSS to the page on top of the built-in styles for as long as the theme is active.

Limits:

  • no more than 32 KiB;
  • @import, url(, expression(, javascript:, behavior:, -moz-binding and </style are forbidden — a theme cannot load anything from the network or from disk, so there are no images or custom fonts through CSS either. The launcher's editor checks the CSS together with its comments, so do not write these words there either;
  • --ui-scale is forbidden in CSS for the same reason as in tokens;
  • curly braces must be balanced and nested no deeper than four levels. @media and @keyframes work.

Specificity. The launcher's component styles are scoped to the components themselves, so a rule such as .sidebar { background: ... } loses to the built-in one if it changes the same property. Properties a component does not set apply as written; to override one that is set, add !important.

Class names are not a contract. The tokens in the tables above are the stable interface for themes. Class names in the markup are internal to the launcher: they can change in any version, and CSS that relies on them may stop working after an update.

An example for a light theme: the scrollbar in the built-in styles is designed for a dark background and is barely visible on a light one.

::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.14);
  background-clip: padding-box;
}

::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.24);
  background-clip: padding-box;
}

In a JSON file the CSS is written as a single line with line breaks as \n. It is easier to paste it into the "Custom CSS" field in the editor and then export the theme — the launcher writes it out correctly.

Personal accent

The Appearance section also has "Personal accent" — a color applied on top of any theme that adjusts its shades for readability. While one is selected, the theme's accent tokens (--accent, --accent-hover, --accent-subtle, --accent-text, --accent-ring) are not visible. To see the theme's own accent, choose "Theme color" in the personal accent. The personal accent is your local setting and is not included in an exported theme file.

If a theme breaks the window

Bad CSS can hide or cover the interface so that you cannot reach the settings. There are three ways to restore the default appearance:

  1. The "Reset appearance" button in the bottom right corner of the window. It is always visible while a custom theme, or a theme with custom CSS, is active, and the theme's CSS does not style it.
  2. The Ctrl+Shift+Alt+T shortcut in the launcher window.
  3. Settings → Appearance → Reset, if you can still reach the settings: the "Reset" button there asks for confirmation.

In addition, a new theme counts as a trial for its first five seconds. If the launcher closes or crashes during that time, it returns to the previous theme on the next start.

Reset deletes all custom themes, along with the personal accent and the icon tint, and restores the built-in Dark theme. The corner button and the shortcut act immediately, without asking. So export the theme you are working on to a file from time to time — after a reset you can import it back and fix whatever broke the window.

Import errors

MessageWhat to check
Invalid theme file pathThe file has the wrong extension: it must be .typhontheme or .json
The theme file exceeds the allowed sizeThe file is larger than 256 KiB
Unsupported theme file versionversion must be 1
Invalid theme idid: lowercase Latin letters, digits and hyphens
Invalid theme namename is empty, longer than 64 characters or contains control characters
Invalid theme base palettebase must be dark or light
Unknown theme token nameThe token is not in the tables above, or it is --ui-scale
Invalid theme token valueAn empty value, longer than 120 characters or a character outside the allowed set — most often quotes
The custom CSS exceeds the allowed sizeThe CSS is larger than 32 KiB
The custom CSS contains a forbidden constructThe CSS contains @import, url( or another word from the list above
Unbalanced or too deeply nested braces in the CSSAn extra or unclosed brace, or nesting deeper than four levels
Could not complete the theme actionThe file does not parse as JSON or contains an extra field

If the launcher says "Could not complete the theme action", the file most often does not parse as JSON or has an extra field. Check the commas, the quotes around field names and the names of the top-level fields.