Theming
Marchyo owns every themed surface itself, all derived from the Jylhis Design System: the desktop (GTK, Hyprland, the Quickshell shell, Ghostty, fzf, bat, hyprlock, starship, the console, the Plymouth boot splash), Qt (through the GTK settings, QT_QPA_PLATFORMTHEME=gtk3), the TUI long tail (lazygit, k9s, spotify-player, gdu), and Emacs (the design system’s own jylhis themes). Most surfaces restyle at runtime via marchyo theme set/next — no rebuild.
The in-shell launcher themes itself from the design tokens at runtime (the shell’s Colors singleton), so it needs no theme registration. See Launcher.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
marchyo.theme.enable |
bool |
true |
Enable the theming system |
marchyo.theme.variant |
"dark" or "light" |
"dark" |
Theme variant preference |
marchyo.theme.scheme |
string or null |
null |
Override the base16 color scheme (a tinted-schemes catalog name) |
marchyo.theme.fontScale |
number (0.5–4.0) |
1.25 |
Global font-size multiplier applied to every text surface |
marchyo.theme.themes |
list of string or inline base16 theme |
["jylhis-dark" "jylhis-light"] |
Themes available for runtime switching (pre-built into the closure) |
marchyo.theme.themes.[].wallpapers |
list of path |
[] |
Further wallpapers of an inline theme, listed in the theme dir’s wallpapers/ (details) |
marchyo.theme.appearance.transparency |
"opaque", "transparent" or "glassy" |
"opaque" |
How see-through windows are (details) |
marchyo.theme.appearance.corners |
"theme", "sharp" or "rounded" |
"theme" |
Window corners (details) |
marchyo.theme.appearance.animations |
"auto", "on" or "off" |
"auto" |
Hyprland animations (details) |
marchyo.theme.appearance.gaps |
bool |
false |
Gaps between tiled windows and the screen edge (details) |
marchyo.theme.appearance.floatingBar |
bool |
false |
Floating pill bar (details) |
marchyo.theme.appearance.surfaceAlpha |
float (0.3–1.0) |
0.85 |
Shell surface opacity (details) |
marchyo.theme.appearance.cornerRadiusScale |
float (0.0–4.0) |
1.0 |
Shell corner-radius multiplier (details) |
marchyo.theme.appearance.uiScale |
float (0.5–4.0) |
1.0 |
Shell geometry multiplier (details) |
marchyo.theme.appearance.animationSpeed |
float (0.1–10.0) |
1.0 |
Shell animation speed (details) |
marchyo.theme.appearance.reduceMotion |
bool |
true in a VM guest |
No animations, blur or shadows (details) |
marchyo.theme.appearance.highContrast |
bool |
false |
Thicker shell separators (details) |
marchyo.theme.followWallpaper |
bool |
false |
marchyo bg set / bg next also generate a matugen theme from the new wallpaper (details) |
marchyo.theme.wallpaper.enable |
bool |
true |
Enable the generated Marchyo wallpapers where supported |
marchyo.theme.wallpaper.package |
package |
pkgs.marchyo-wallpapers |
Package providing generated Marchyo wallpaper assets |
Basic usage
Section titled “Basic usage”marchyo.theme = { enable = true; variant = "dark";};Color schemes
Section titled “Color schemes”By default the theme is the Jylhis Design System palette, derived from its DTCG tokens/:
| Variant | Palette |
|---|---|
"dark" |
Jylhis Amber (amber on terminal black) |
"light" |
Jylhis Paper (ink on warm paper) |
Paper sits on warm off-white with ink text and a red signal colour. Amber sits on near-black with an amber signal colour. Code colors are Emacs Modus Operandi (light) / Vivendi (dark), so syntax reads identically in every editor and terminal.
To use a different base16 scheme instead, set marchyo.theme.scheme to the name of a .yaml file in the tinted-theming/schemes catalog (the base16/ directory):
marchyo.theme = { variant = "dark"; scheme = "gruvbox-dark-medium"; # any tinted-schemes catalog name, e.g. "nord"};A base16 theme in runtime switching (a catalog or inline entry, or a matugen result) colours each design token from the slot that best matches its role:
| Slot | Tokens |
|---|---|
base00 |
bg |
base01 |
bg-subtle, surface, surface-raised |
base02 |
accent-subtle, selection-bg |
base03 |
text-faint, border, syn-comment |
base04 |
text-muted, contour, decorator, border-strong |
base05 |
text, accent, link, rule, chart-ink, brand |
base06 |
text-heading, accent-hover |
base08 |
status-err, destructive, syn-variable |
base09 |
syn-number |
base0A |
status-warn |
base0B |
syn-string, status-ok |
base0C |
syn-type, syn-builtin |
base0D |
syn-function |
base0E |
syn-keyword |
base0F |
syn-docstring |
Tokens with no base16 role keep the build variant’s hex: primary and its shades, cursor, the bevels, the chart colours, scrim, status-info and link-underline-hover. No token reads base07. A matugen theme additionally takes border, border-strong and accent-subtle from Material’s outline_variant, outline and primary_container when matugen emits them.
Marchyo carries the design system’s UI type roles across the system — the
fontconfig role mapping (modules/nixos/fonts.nix), the GNOME interface
fonts Qt and GTK apps resolve (modules/home/jylhis-theme.nix), and every
surface that names a family directly. The families come from the design
system’s lib.fonts. The display face (Jost) is installed but only the web
uses it as a role. The defaults are:
- Serif: DejaVu Serif (
pkgs.dejavu_fonts). - Body and UI (sansSerif): Fira Sans (
pkgs.fira-sans). - Monospace: IBM Plex Mono (
pkgs.ibm-plex).
The shell, hyprlock, Ghostty and the Emacs fixed face name BlexMono Nerd Font
(pkgs.nerd-fonts.blex-mono, IBM Plex Mono patched) directly, because they
need the icon glyphs. To change the
role mapping, override the fontconfig defaults:
fonts.fontconfig.defaultFonts.monospace = [ "JetBrainsMono Nerd Font" ];Home Manager scans ~/.nix-profile/share/fonts, and fontconfig’s per-user
cache under ~/.cache/fontconfig can outlive a generation and keep serving
fonts that left the profile. Marchyo hashes the profile font set at every
activation and rebuilds the cache when it changes
(marchyo.fonts.cleanUserCache, default on); running apps pick the fonts up
after a restart.
Font size
Section titled “Font size”marchyo.theme.fontScale is a single multiplier that resizes every text
surface at once — the interface fonts (GTK, Qt, Electron), the terminal, the
bar, notifications, the lock screen, the launcher, the TUI apps, and the TTY
console. It defaults to 1.25 (noticeably larger than upstream defaults).
Set it to 1.0 for the upstream sizes, or higher for
HiDPI-at-distance or accessibility:
marchyo.theme.fontScale = 1.5; # everything ~50% largerEach surface scales from its own base size and rounds to a whole number, so the proportions between surfaces are preserved.
Runtime theme switching
Section titled “Runtime theme switching”marchyo.theme.themes lists the themes available for runtime switching — no rebuild needed. Each listed theme’s desktop assets (Hyprland colors, Ghostty colors, wallpaper, GTK CSS + the dconf color-scheme, bat config, fzf colors, hyprlock colors, console palette, the k9s skin, lazygit, spotify-player and gdu colors, the application surfaces, the terminal, editor and browser surfaces, a wallpapers/ dir, and a palette.json token map) are pre-built into the system closure so a switch is an instant symlink swap. The default list is the Jylhis pair; add any tinted-schemes catalog name to make it switchable:
marchyo.theme.themes = [ "jylhis-dark" "jylhis-light" "nord" "gruvbox-dark-hard"];Inline catalog themes
Section titled “Inline catalog themes”An entry can also be an inline base16 theme — the catalog contract — so you
can add an arbitrary palette (an omarchy colors.toml, a matugen result, your
own) without it living in any upstream catalog. Provide the sixteen
base00..base0F slots and a polarity; every runtime surface is derived from
them, and an optional wallpaper overrides the default grid:
marchyo.theme.themes = [ "jylhis-dark" { name = "kanagawa"; variant = "dark"; slots = { base00 = "#1f1f28"; base01 = "#2a2a37"; base02 = "#223249"; base03 = "#727169"; base04 = "#c8c093"; base05 = "#dcd7ba"; base06 = "#938aa9"; base07 = "#363646"; base08 = "#c34043"; base09 = "#ffa066"; base0A = "#dca561"; base0B = "#98bb6c"; base0C = "#7fb4ca"; base0D = "#7e9cd8"; base0E = "#957fb8"; base0F = "#d27e99"; }; # wallpaper = ./kanagawa.png; # optional; defaults to the Jylhis grid # wallpapers = [ ./kanagawa-2.png ]; # optional; offered by `marchyo bg list` }];Runtime switching covers every surface except the Plymouth boot splash (it is
not on screen during a session). Qt follows the GTK swap: the session runs
QT_QPA_PLATFORMTHEME=gtk3, so Qt apps pick up the swapped gtk.css and dconf
color-scheme on next launch. Marchyo owns the effective theme: a saved selection
takes precedence over the Nix default. Activation and session startup restore
that selection, or initialize the default when no override exists. Application
assets and the desktop preference derive from the same selection; Home Manager
does not independently reset the preference while runtime theming is enabled.
A failed preference update preserves the previous selection and application
links. marchyo runtime restore reports failures with a nonzero status and
continues restoring independent overrides. --revert restores the Nix default;
--apply makes the selection declarative.
The TUI apps read their colours through the ~/.config/marchyo/current-theme
pointer. k9s restyles open sessions: marchyo theme relinks
~/.config/k9s/skins/jylhis.yaml at the new theme’s skin, and k9s watches its
skins directory. lazygit, spotify-player and gdu pick up the new theme the next
time they start. ~/.config/spotify-player/theme.toml and
~/.config/gdu/gdu.yaml link into the pointer, and lazygit loads
LG_CONFIG_FILE, which lists its main config.yml followed by the pointer’s
lazygit.yml (lazygit merges the files in order, so the theme overlay wins).
LG_CONFIG_FILE is a session variable, so it applies from the next login.
These TUI colours come from base16 slots: with marchyo.theme.scheme set, the
declarative theme’s files carry that scheme’s slots, as the build-time config
does. Off the desktop, the TUI apps keep the build-time colours.
GTK apps follow a runtime switch on next launch (newly started apps read the
swapped ~/.config/gtk-{3,4}.0/gtk.css; libadwaita apps additionally restyle
live via the dconf color-scheme). Ghostty restyles open windows live too —
its runtime include names the Jylhis pair as a ghostty light/dark theme pair
(theme = dark:…,light:…), which ghostty resolves from the system
color-scheme, so the same dconf write that flips libadwaita apps recolors
running terminals. The Quickshell bar (marchyo.shell.enable)
recolors live as well — it reads the active theme’s palette through the same
pointer — and Super+Shift+L cycles the theme from the compositor.
Application surfaces
Section titled “Application surfaces”Every theme dir also carries colours for two more applications, generated from the same base16 slots (the Jylhis pair, catalog and inline themes, and theme generate all emit them):
- tmux: see tmux. The status line, messages, pane borders and pane background follow the theme.
- fcitx5:
fcitx5-theme.confis linked as the classicui thememarchyo(~/.local/share/fcitx5/themes/marchyo/theme.conf, with the stock glyphs).marchyo.theme.enablemakes the fcitx5 module select it, and a switch reloads classicui.
Both read their files through the current-theme pointer, so the declarative reset on activation covers them.
marchyo.tmux.enable defaults to marchyo.development.enable. It turns on programs.tmux with the tmux-256color terminal and true colour, mouse, vi copy mode (v selects, y copies), windows and panes numbered from 1, no escape delay and a 50000-line history. The theme colours are baked in at build time; on a desktop the module then sources ~/.config/marchyo/current-theme/tmux.conf (source-file -q), and marchyo theme runs tmux source-file on a running server. Super+Alt+Return opens the Work session (tmux new -A -s Work).
Terminal, editor and browser surfaces
Section titled “Terminal, editor and browser surfaces”Every theme dir carries seven more files from the same base16 slots, and the build-variant dir ships each one as a templates/ placeholder file that theme generate fills.
- btop:
btop.theme. btop reads it as themarchyotheme through~/.config/btop/themes/marchyo.theme, which links into thecurrent-themepointer. - kitty:
kitty.conf, a colour block thatkitty @ set-colorsapplies andkitty.confcaninclude. - foot:
foot-theme.ini, bareRRGGBBcolours in both thecolors-darkandcolors-lightsections. Its template uses{{bare:<token>}}(the hex without#) beside{{token:<token>}}. - alacritty:
alacritty-theme.toml, imported withgeneral.import. - helix:
helix-theme.toml, selected withtheme = "marchyo". - Neovim:
nvim-theme.lua, a colourscheme file (colors/marchyo.lua) that setsbackgroundfrom the colour ofbase00. - Emacs:
emacs-theme.el, which defines and enables themarchyotheme when loaded.
Chromium, Chrome and Brave get no theme file. They follow the light/dark colour scheme that the desktop portal reports, so a runtime switch reaches them.
Only btop is configured by Marchyo itself. The other apps read their files from the places the CLI links them to, or from the theme dir directly.
Wallpaper
Section titled “Wallpaper”Generated Marchyo wallpapers are enabled by default wherever they are supported: the Jylhis grid, dots, diagonal bands and contour lines, each in a light and a dark variant (3840 by 2160, drawn from the design tokens). The grid is the default; the others appear in the wallpapers/ dir of the Jylhis theme dirs and in marchyo bg list. An inline theme adds its own with wallpapers. To disable the generated set, or to supply your own wallpaper asset package:
marchyo.theme.wallpaper = { enable = false; # skip the generated wallpaper # package = pkgs.my-wallpapers; # or swap in a different asset package};Wallpaper-derived theming (matugen)
Section titled “Wallpaper-derived theming (matugen)”marchyo theme generate <image> builds a colour scheme from a wallpaper with matugen and applies it live — no rebuild:
marchyo theme generate ~/Pictures/wall.jpg # let matugen pick the polaritymarchyo theme generate ~/Pictures/wall.jpg --light # force a light schememarchyo theme generate ~/Pictures/wall.jpg --dark # force a dark schememarchyo theme generate --revert # back to the declarative themematugen extracts a base16 palette from the image, which Marchyo maps through the same token slots the catalog schemes use. A generated theme restyles every surface a theme set does: the shell (bar, panels, toasts), the terminal (Ghostty, kitty, foot, alacritty), btop, helix, Neovim, Emacs, Hyprland window borders, GTK (plus the dconf color-scheme), bat, fzf, the hyprlock fallback lock screen, the console palette (best-effort, as for every switch), k9s, lazygit, spotify-player, gdu, the application surfaces (tmux, fcitx5), and the wallpaper itself.
The colours come from two files the build ships in the declarative variant’s theme dir: palette.json (every design token’s hex, syn-* included, and the token-to-base16-slot table) and templates/ (the GTK CSS and the terminal, editor and browser surfaces, with each colour as a token placeholder). theme generate fills each placeholder with the matugen slot for that token, and a token with no base16 slot keeps the build variant’s hex. For bat it writes a marchyo-generated.tmTheme into bat’s themes directory and runs bat cache --build.
Qt follows the runtime GTK swap on next launch (QT_QPA_PLATFORMTHEME=gtk3),
and starship styles through ANSI slot names, so it already recolors with the
terminal’s live palette. Only the Plymouth boot splash (not on screen during a
session) keeps the declarative theme until the next rebuild
(Runtime theme switching). Like marchyo bg, the generated theme is runtime-only: a rebuild (or --revert) resets to marchyo.theme.variant/scheme. Requires the desktop feature (matugen ships with it).
Follow the wallpaper
Section titled “Follow the wallpaper”An opt-in Material You mode makes the theme track the wallpaper. It is off by default; the Jylhis palette stays the declarative theme either way.
marchyo.theme.followWallpaper = true;With it set, every marchyo bg set <image> and marchyo bg next runs the theme generate path on the new image after setting it, with matugen picking the polarity as a bare theme generate <image> does. If generation fails (matugen missing, an unreadable image), the wallpaper still changes, the CLI prints a warning, and the command exits 0.
Both changes are recorded as runtime overrides, so marchyo runtime restore at login replays the wallpaper and the generated theme together. A failed generation leaves the theme override as it was, so restore replays the new wallpaper and whichever theme was live before. marchyo bg set --revert shows the active theme’s wallpaper, which under a generated theme is the image it came from; marchyo theme generate --revert and marchyo theme set return to a declarative theme as usual, and a rebuild resets everything.
Light mode
Section titled “Light mode”To use the light theme:
marchyo.theme = { variant = "light";};Shell appearance scale
Section titled “Shell appearance scale”With the Quickshell shell (marchyo.shell.enable = true), a set of
palette-independent axes adjust the shell’s geometry, corners, animation
speed, contrast, and overall shape without touching the colour palette.
The scale axes default neutral; surfaceAlpha is Caelestia-inspired and
defaults to a glass 0.85, and floatingBar is off by default.
marchyo.theme.appearance = { # floatingBar = true; # detached floating pill instead of the full-width strip # surfaceAlpha = 1.0; # opaque surfaces, no blur (default 0.85 glass) # cornerRadiusScale = 0.0; # square every corner (default 1.0) # uiScale = 1.2; # larger chrome without changing font size # animationSpeed = 2.0; # faster transitions (default 1.0) # reduceMotion = true; # no animations/blur/transparency (default on in VMs) # highContrast = true; # thicker panel/notification borders};| Option | Type | Default | Description |
|---|---|---|---|
floatingBar |
bool |
false |
true floats the bar as a detached rounded pill with gaps to the screen edges, instead of the full-width strip |
surfaceAlpha |
float |
0.85 |
Surface opacity; below 1 enables the Hyprland blur effect for the shell’s layer surfaces (glass look) |
cornerRadiusScale |
float |
1.0 |
Multiplier on corner radii (0.0 squares corners) |
uiScale |
float |
1.0 |
Geometry multiplier on top of fontScale, fonts unchanged |
animationSpeed |
float |
1.0 |
Animation speed (higher is faster) |
reduceMotion |
bool |
true in a VM guest |
No animations, blur or shadows, opaque windows, instant shell transitions |
highContrast |
bool |
false |
Thicker separators for higher-contrast chrome |
With the shell on, Hyprland also turns on short compositor animations driven by
a snappy popin bezier: windows pop in, the shell’s panels, launcher, and OSD
pop in, the bar slides from its edge, and toasts and tooltips keep their own
QML transitions. Workspace switches and border colour changes stay instant.
With the shell off, compositor animations stay disabled.
Window appearance
Section titled “Window appearance”Four further marchyo.theme.appearance options set how Hyprland draws
windows. Each also switches live, and --revert returns to the declared value.
marchyo.theme.appearance = { # transparency = "glassy"; # opaque (default) | transparent | glassy # corners = "rounded"; # theme (default) | sharp | rounded # animations = "off"; # auto (default) | on | off # gaps = true; # 5 px between windows, 10 px to the screen edge};| Option | Values | Default | Description |
|---|---|---|---|
transparency |
opaque, transparent, glassy |
opaque |
transparent makes windows translucent. glassy also blurs windows and the shell’s layer surfaces, so the bar is glass (its own opacity is surfaceAlpha). reduceMotion keeps windows opaque |
corners |
theme, sharp, rounded |
theme |
theme and sharp keep square corners; rounded rounds windows |
animations |
auto, on, off |
auto |
auto keeps the default and turns animations off at session start when systemd-detect-virt -q reports a VM |
gaps |
bool |
false |
false keeps the gapless tmux-style grid. true sets gaps_in to 5 and gaps_out to 10. Switch live with marchyo theme gaps |
The declared window appearance, together with the GTK icon theme name, is written to ~/.config/marchyo/appearance.json, which the CLI reads on --revert.
Live switches (they last until the next session or rebuild, and marchyo runtime restore replays them):
$ marchyo theme transparency glassy$ marchyo theme corners rounded$ marchyo toggle animations off$ marchyo toggle reduce-motion on$ marchyo theme corners --revertmarchyo toggle reduce-motion on sets every shell transition to 0 ms until you turn it off
(the eval-time reduceMotion option stays the default). The shell also drops to 0 ms while
Hyprland’s animations:enabled is off, and re-reads that option on every config reload.
The Appearance entry in marchyo menu groups theme, background, font,
transparency, corners, animations, window gaps and the fullscreen desktop.
Windows are excluded from blur when the shell’s glass is on and glassy is not
declared, so a live switch to glassy makes them translucent but blurs them
only after declaring glassy and rebuilding.
Window utilities
Section titled “Window utilities”marchyo window pop(Super + Alt + O) floats, centres and pins the focused tile, and puts it back on the next call. A popped window is centred again when it moves to another monitor.marchyo window close-allcloses every window and returns to workspace 1.marchyo window tiled-fullscreentoggles tiled fullscreen (Super + Ctrl + F).marchyo toggle gapsswitches between the zero-gap grid and spaced tiles.marchyo toggle fullscreen-desktophides the bar and drops gaps, borders and rounding together.
Login greeter
Section titled “Login greeter”The greetd login greeter is built in the host’s marchyo.theme.variant, so a
light host shows a light login screen. It also follows the session theme:
every marchyo theme set, next, or generate writes the active theme’s
colours to /var/lib/marchyo/greeter/theme-<user>.json, and the greeter shows
the theme of the last user who logged in, at start and whenever that file
changes. The directory is owned by root:users
with mode 1775, so session users can write their own marker but cannot
replace another user’s. The greeter accepts only #rrggbb values for colour
keys it already knows; a missing or invalid file falls back to the built-in
variant palette. A declarative rebuild does not touch the marker, so the
greeter keeps the last theme the CLI activated.