Skip to content

Themes

Magia is fully themeable. It ships 24 built-in themes and supports loading custom themes from a directory on disk. Changes to theme files are picked up automatically without restarting.

The following themes are bundled with Magia and available in Settings → Appearance:

Magia, Stone Rose, Midnight, Brutalist, Dracula, Solarized, Nord, Monokai, Catppuccin, Gruvbox, Tokyo Night, One Dark, Rose Pine, Ayu, GitHub, Kanagawa, Everforest, Palenight, Vesper, Synthwave, Cyberpunk, Poimandres, Flexoki, Modus Vivendi.

Stone Rose is the default theme. Its values are baked into the CSS file, so selecting it clears any inline overrides rather than re-applying colors.

Every theme defines both a dark and a light color map. The active map is chosen based on your Appearance setting:

  • Dark — always use the dark map.
  • Light — always use the light map.
  • System — follow the OS dark/light preference.

If a theme only defines modes.dark, Magia falls back to the dark map for light mode as well.

Place .json theme files in ~/.magia/themes/. Magia loads all .json files from that directory at startup and adds them to the theme picker alongside the built-ins.

The directory is created automatically on first launch.

{
"name": "My Theme",
"author": "your-name",
"version": 1,
"modes": {
"dark": {
"background": "20 14.3% 4.1%",
"foreground": "0 0% 95%",
"primary": "346.8 77.2% 49.8%",
"..."
},
"light": {
"background": "0 0% 100%",
"foreground": "20 14.3% 4.1%",
"..."
}
},
"shape": {
"radius": "0.5rem",
"shadows": {
"shadow-sm": "0 1px 2px 0 rgb(0 0 0 / 0.05)"
}
},
"fonts": {
"ui": "Inter",
"mono": "JetBrains Mono"
}
}

The file name (without .json) becomes the theme’s ID. For example, my-theme.json has ID my-theme.

All color values use the HSL channel format without the hsl() wrapper: "<hue> <saturation>% <lightness>%". This matches the shadcn/ui convention and allows the CSS variable system to apply opacity modifiers.

The full set of color tokens:

TokenRole
background / foregroundMain app surface and text
card / card-foregroundCard surfaces
popover / popover-foregroundDropdowns and tooltips
primary / primary-foregroundPrimary action color
secondary / secondary-foregroundSecondary surfaces
muted / muted-foregroundSubtle backgrounds and de-emphasized text
accent / accent-foregroundHover states and highlights
destructive / destructive-foregroundErrors and destructive actions
borderDefault border color
inputInput field border
ringFocus ring
chart-1 through chart-5Data visualization colors
sidebar / sidebar-foregroundSidebar surface and text
sidebar-primary / sidebar-primary-foregroundActive sidebar items
sidebar-accent / sidebar-accent-foregroundSidebar hover states
sidebar-border / sidebar-ringSidebar borders and focus

shape.radius sets the CSS --radius variable used for border radii throughout the UI. Use any valid CSS length, for example "0.5rem" or "0px" for a flat look.

shape.shadows is optional. It overrides the four shadow levels shadow-sm, shadow-md, shadow-lg, and shadow-xl.

fonts.ui and fonts.mono override the UI and monospace fonts respectively. Values are CSS font-family strings. Both fields are optional — omitting them leaves the defaults in place (Noto Sans and Noto Sans Mono).

The Rust backend (ThemeWatcher) watches ~/.magia/themes/ using the notify crate. Any create, modify, or delete event triggers a debounced themes:changed Tauri event (500 ms debounce). The frontend listens for this event and reloads all external themes automatically. There is no need to restart Magia after editing or adding a theme file.

Themes are applied by writing CSS custom properties to :root via applyTheme(theme, mode). This sets all color, shape, and font variables as inline styles. Selecting Stone Rose calls clearTheme() instead, which removes all inline overrides and lets the CSS defaults take over.