Skip to content

Theme ​

WayRun has two colour layers: the system palette from the desktop, and the overrides in $XDG_CONFIG_HOME/wayrun/theme.toml (default ~/.config/wayrun/theme.toml). The launcher watches both, so an edit applies live.

System palette ​

The palette follows the session.

KDE Plasma ​

On KDE Plasma the palette is the active colour scheme in ~/.config/kdeglobals. KDE merges the applied scheme's roles into that file, and writes an explicit or wallpaper-derived accent back to [General] AccentColor.

There is no mode key. The luminance of the window background decides the mode, so a light/dark switch is picked up live.

WayRunKDE, from kdeglobals
modeluminance of [Colors:Window] BackgroundNormal
primary[General] AccentColor, else [Colors:Window] DecorationFocus
fg[Colors:Window] ForegroundNormal
container[Colors:Button] BackgroundNormal
bg[Colors:Window] BackgroundNormal

DankMaterialShell ​

On a DankMaterialShell desktop the palette is the Material You palette DMS generates with matugen, in ~/.cache/DankMaterialShell/dms-colors.json. The file holds the light and dark palettes and the active mode. Switching light/dark, or changing the wallpaper, is picked up live.

WayRunDMS, from colors[mode]
primaryprimary
fgon_surface
containersurface_container_high

Precedence and fallback ​

On a KDE session the launcher reads kdeglobals, even if a DMS file is left over from another desktop. With neither source it uses the built-in dark palette, with mode = "dark".

Theme overrides ​

Every section and key is optional. An absent key keeps its default, an unparseable file is ignored, and out-of-range values are clamped. The first run writes a commented template, so the options are listed without pinning their current defaults. Uncomment only what you want to change.

Colors ​

The [colors] table sets three base roles plus the backdrop dim. A role is #rrggbb or #rgb. dim also accepts #rrggbbaa and #rgba, where the trailing pair is its alpha. An unparseable value is skipped and the default stays.

KeyDefaultMeaning
primarysystem paletteAccent: selection tint, accent bar, the action panel title in the footer.
fgsystem paletteText, icons and hint tints.
containersystem paletteCard fill.
dim#0000004dBackdrop dim; its alpha is inline.

[colors] is the shared set. [colors.dark] and [colors.light] override it per mode; see below.

Every other surface derives from a role at a fixed alpha. For example, the card fill is container at 0.72 (0.85 in dark mode), and the selected row's tint is primary at 0.15. The [surfaces] table lists the full set.

An unset key keeps following the system palette, so a matugen or DMS change still recolours it. Setting a key pins that value. A role you set stops following the palette; an unset role keeps tracking it. Omitting the section is the same as a pure dynamic theme.

Per-mode overrides ​

A hand-picked colour is static, but the system palette switches between light and dark. [colors.dark] and [colors.light] accept the same keys as [colors] and layer on top of it while that mode is active. A colour that only works in one mode can therefore differ while everything else stays shared:

toml
[colors]
primary = "#7aa2f7"          # shared by both modes

[colors.dark]
fg = "#c0caf5"

[colors.light]
fg = "#1f2430"

The active mode follows the system palette (dark when there is none), so the tables follow a live switch with no restart. A key the active table does not set keeps the [colors] value.

Surfaces ​

The [surfaces] table pins individual surfaces the renderer derives from the base roles. An entry sets color, alpha, or both. An omitted field keeps deriving, so a [colors] change or a live palette change still reaches it.

toml
[surfaces]
card = { alpha = 0.90 }                 # keep following container, more opaque
selection = { color = "#7aa2f7", alpha = 0.20 }
hairline = { color = "#ffffff" }        # keep the mode's shipped alpha

color is #rrggbb or #rgb; alpha is 0–1 and is clamped. An unparseable colour is ignored. The hairline entry also takes width in logical pixels (0–16, default 1.0; 0 hides the edge), which layers like color and alpha. dim is here as well: it layers over [colors].dim, which keeps the plain-string spelling.

KeyDerived fromShipped alpha
cardcontainer0.72 (0.85 dark)
selectionprimary0.15
hoverprimary0.08
previewprimary0.05
hairlineblack in light, white in dark0.10 (0.12 dark)
mutedfg0.55
summaryfg0.70
footerfg0.50
accentprimary1.00
dim#0000000.30

[surfaces] is the shared table. [surfaces.dark] and [surfaces.light] take the same keys and layer on it surface by surface and field by field while that mode is active. A mode can change only the colour, only the alpha, or only the width:

toml
[surfaces]
hairline = { alpha = 0.12 }

[surfaces.dark]
hairline = { color = "#ffffff", width = 1.5 }

[surfaces.light]
hairline = { color = "#000000" }

Blur ​

The [blur] table declares the blur region. The card is translucent. On a compositor that offers ext-background-effect-v1, the compositor blurs the region behind it, which gives the frosted look. A compositor without the protocol ignores the region, so the setting has no visible effect there.

niri ​

On niri the effect needs one more step. niri auto-enables xray for a client's ext-background-effect request; xray blurs the wallpaper and ignores the windows below. To blur the content actually behind the card, add a layer rule that turns xray off:

kdl
layer-rule {
    match namespace="WayRun"
    background-effect {
        xray false
    }
}

The namespace is WayRun. Non-xray blur is recomputed whenever the content underneath changes, so it costs more than the default.

Hyprland ​

Hyprland does not implement ext-background-effect-v1, so it ignores the region. Turn on its own blur and blur the layer by namespace:

ini
decoration {
    blur {
        enabled = true
    }
}
layerrule = blur, WayRun

KWin ​

KWin implements ext-background-effect-v1, so Plasma blurs the card once the Blur desktop effect is enabled. No layer rule is needed. The launcher maps to the utility namespace, which KWin's open and close effects skip.

KeyTypeDefaultMeaning
enabledbooltrueDeclare the blur region. false declares nothing, so the backdrop stays sharp; the card's translucent fill is unchanged.

Preview ​

The [preview] table has one key.

KeyTypeDefaultMeaning
enabledbooltrueShow the split preview column for the selected row. false keeps the list full width; plugin previews are ignored.

The [footer] table has one key.

KeyTypeDefaultMeaning
enabledbooltrueShow the hint bar under the results: keys, result count and search status. It also carries the action panel's row or group title, so false hides that title too.

Layout ​

The [layout] table sets the card geometry.

KeyTypeDefaultRangeMeaning
widthfloat730.0> 0Card width in logical pixels; a narrower output shrinks it to fit.
radiusfloat16.0≥ 0Card corner radius; 0 gives square corners, and the inner radii shrink with it.
top_ratiofloat0.200–1Card top as a fraction of the output height.
alignstringcenterleft/center/rightHorizontal anchor on the output.
max_rowsint51–8Visible result rows.
fixed_heightboolfalse—Hold the card at one height once there is a query or results: a full max_rows window (448 logical pixels at the defaults). Results, split previews and the action panel no longer resize it; shorter content leaves the space below the rows blank. An untouched field with no results stays the compact search-only card; a query expands it.

An unknown align keeps the default.

Font ​

The [font] table sets the text family and the interface size in logical pixels. One size drives every role; the rest scale with it. Glyphs the family lacks fall back to the system fonts.

KeyTypeDefaultRangeMeaning
familystringsans-serif—Primary shaping family, or a generic name (serif, sans-serif, monospace).
sizefloat14.01–96A result row's title; the other roles scale from it.

Both apply live; a family change re-shapes every cached line.

Motion ​

The [motion] table has these keys.

KeyTypeDefaultRangeMeaning
reducedboolfalse—Same as WAYRUN_REDUCED_MOTION=1: turns animations off. The entrance, the card height spring and result-row motion start at their end state, and no animation frames are requested. The caret still blinks. This wins over entrance_ms.
entrance_msinteger2400–2000How long the entrance fade and rise take, in milliseconds. 0 skips the entrance; the card height spring and result-row motion still run. reduced = true still wins.

Both apply live. Lowering entrance_ms mid-fade settles it at once; raising it lets the current fade finish from when the show began.

Released under the MIT OR Apache-2.0 license.