General
A practical reference for Kwybars config.toml.
Kwybars can run without a config file. If no file exists, it uses the built-in defaults.
The config file is split into four main sections:
| Section | What it controls |
|---|---|
[overlay] | Where the visualizer window appears, which monitor it uses, and which layer it sits on |
[visualizer] | Layout, bar shape, colors, themes, animation, and audio backend behavior |
[image_overlay] | Optional transparent image layer drawn above the visualizer |
[daemon] | Automatic start/stop behavior when audio becomes active or silent |
If you only want something that works quickly, start with Preset Configs. Use this page when you want to understand each option.
Config Path
Kwybars looks for config files in this order:
--config /path/to/config.tomlKWYBARS_CONFIG$XDG_CONFIG_HOME/kwybars/config.toml~/.config/kwybars/config.toml./kwybars.toml
The packaged example config is installed at:
/usr/share/doc/kwybars/examples/config.tomlTo run with a specific config:
kwybars-daemon --config ~/.config/kwybars/custom/my_config.tomlValid config changes are hot reloaded while Kwybars is running. If a reload fails, Kwybars keeps the current active config and logs the error.
Default Config
This is the built-in default shape. You do not need to copy all of it; copy only the keys you want to change.
[overlay]
monitor_mode = "primary"
layer = "background"
position = "bottom"
full_length = true
width = 800
height = 500
anchor_margin = 20
margin_left = 20
margin_right = 20
margin_top = 0
margin_bottom = 0
fade_in_ms = 180
fade_out_ms = 350
horizontal_alignment = "center"
vertical_alignment = "center"
[visualizer]
backend = "cava"
layout = "line"
line_mode = "continuous"
line_split_gap = 200
mirror_orientation = "horizontal"
mirror_gap = 0
wave_stroke_width = 10
wave_fill = true
wave_glow = false
wave_smoothing = 1.0
wave_motion_smoothing = 0.22
wave_amplitude = 0.8
frame_edges = ["top", "bottom"]
frame_mirror_mode = "pairs"
bars = 50
bar_width = 8
bar_corner_radius = 20
segmented_bars = false
segment_length = 14
segment_gap = 6
radial_inner_radius = 180
radial_start_angle = -90
radial_arc_degrees = 360
radial_rotation_speed = 0
center_offset_x = 0
center_offset_y = 0
polygon_sides = 3
polygon_radius = 220
polygon_bar_length = 0
polygon_rotation = -90
polygon_rotation_speed = 0
gap = 20
framerate = 60
color_mode = "gradient"
color_rgba = "rgba(175, 198, 255, 0.7)"
color2_rgba = "rgba(191, 198, 220, 0.7)"
theme_opacity = 1.0
pipewire_attack = 0.14
pipewire_decay = 0.975
pipewire_gain = 1.20
pipewire_curve = 0.95
pipewire_neighbor_mix = 0.24
[image_overlay]
enabled = false
path = ""
opacity = 1.0
fit = "contain"
width = 0
height = 0
offset_x = 0
offset_y = 0
[daemon]
enabled = true
poll_interval_ms = 90
activity_threshold = 0.035
activate_delay_ms = 180
deactivate_delay_ms = 2200
stop_on_silence = true
notify_on_error = true
notify_cooldown_seconds = 45
overlay_command = "kwybars-overlay"
overlay_args = [][overlay]
Use [overlay] to decide where Kwybars appears.
[overlay]
monitor_mode = "primary"
layer = "background"
position = "bottom"
full_length = true
height = 500
anchor_margin = 20
margin_left = 20
margin_right = 20
fade_in_ms = 180
fade_out_ms = 350| Key | Description | Default | Accepted values |
|---|---|---|---|
position | Screen edge used by normal edge-based layouts. | "bottom" | "bottom", "top", "left", "right" |
layer | Layer-shell stacking layer. | "background" | "background", "bottom", "top" |
anchor_margin | Margin on the active anchored edge. | 20 | integer pixels |
margin_left | Explicit left margin. | 20 | integer pixels |
margin_right | Explicit right margin. | 20 | integer pixels |
margin_top | Explicit top margin. | 0 | integer pixels |
margin_bottom | Explicit bottom margin. | 0 | integer pixels |
fade_in_ms | Fade duration when the overlay appears or audio becomes active again. | 180 | integer milliseconds |
fade_out_ms | Fade duration after audio has stayed silent for deactivate_delay_ms. | 350 | integer milliseconds |
full_length | Stretch along the full selected edge. | true | true, false |
width | Fixed width for horizontal overlays, or thickness for left/right overlays. | 800 | integer pixels |
height | Fixed height for vertical overlays, or thickness for top/bottom overlays. | 500 | integer pixels |
horizontal_alignment | Alignment for top/bottom overlays when full_length = false. | "center" | "left", "center", "right" |
vertical_alignment | Alignment for left/right overlays when full_length = false. | "center" | "top", "center", "bottom" |
monitor_mode | Which monitor gets an overlay. | "primary" | "primary", "all", "list" |
monitors | Connector names or 1-based monitor indices used when monitor_mode = "list". | [] | array of strings |
Per-Monitor Outputs
Use [[overlay.outputs]] when different monitors need different overlay geometry. If at least one output entry exists, Kwybars uses those entries instead of monitor_mode and monitors
[overlay]
height = 220
position = "bottom"
[[overlay.outputs]]
monitor = "DP-1"
height = 180
margin_left = 40
margin_right = 40
[overlay.outputs.visualizer]
layout = "wave"
wave_glow = true
color_mode = "solid"
color_rgba = "rgba(175, 198, 255, 0.75)"
[[overlay.outputs]]
monitor = "HDMI-A-1"
position = "top"
height = 120
[overlay.outputs.visualizer]
layout = "particle"
bar_width = 6
gap = 14
[[overlay.outputs]]
monitor = "index:3"
enabled = falseEach output starts from the main [overlay] values, then applies any keys in that output entry. monitor accepts connector names such as "DP-1", "primary", or 1-based indices such as "1" / "index:1". enabled = false skips that output entry; it does not subtract from monitor_mode because output entries replace monitor_mode selection. Supported per-output override keys are enabled, position, layer, anchor_margin, edge margins, fade_in_ms, fade_out_ms, full_length, width, height, horizontal_alignment, and vertical_alignment.
Add [overlay.outputs.visualizer] after an output entry to override render-only visualizer settings for that monitor. It supports layout, line, mirror, wave, frame, radial, polygon, bar shape, gap, segmentation, and direct color keys. Direct color overrides opt that monitor out of the global theme palette so the configured colors are visible. It intentionally does not support audio-source keys such as backend, bars, framerate, PipeWire tuning, or theme; all outputs share one audio frame stream.
Monitor Targeting
Use all monitors:
[overlay]
monitor_mode = "all"Use specific monitors:
[overlay]
monitor_mode = "list"
monitors = ["DP-1", "HDMI-A-1"]When monitor_mode = "list", unknown monitor entries are ignored. If the list has no valid entries, Kwybars falls back to the first monitor.
Layer Behavior
| Layer | Behavior |
|---|---|
"background" | Behind normal app windows. This is the default and usually the least intrusive option |
"bottom" | Above wallpaper but below normal windows, compositor dependent |
"top" | Above normal windows |
[visualizer] Basics
[visualizer] controls how the bars look and how audio frames are read.
[visualizer]
layout = "line"
bars = 50
bar_width = 8
gap = 20
framerate = 60
color_mode = "gradient"
gradient_direction = "vertical"
color_rgba = "rgba(166, 227, 161, 0.82)"
color2_rgba = "rgba(137, 180, 250, 0.82)"| Key | Description | Default | Accepted values |
|---|---|---|---|
backend | Audio frame backend. | "cava" | "auto", "cava", "pipewire", "dummy" |
layout | Visualizer layout mode. | "line" | "line", "mirror", "wave", "frame", "radial", "polygon", "particle", "floating" |
bars | Number of bars or samples used by the layout. | 50 | integer |
bar_width | Base bar thickness. | 8 | integer pixels |
bar_corner_radius | Rounded corner radius. Effective value is clamped by bar size. | 20 | number, 0 for square bars |
gap | Space between bars. | 20 | integer pixels |
framerate | Render update target. | 60 | integer |
color_mode | How colors are applied. | "gradient" | "solid", "gradient" |
gradient_direction | Gradient direction for bar layouts. vertical follows the bar growth axis. horizontal follows bar order across the layout. | "vertical" | "vertical", "horizontal" |
color_rgba | Primary bar color. | "rgba(175, 198, 255, 0.7)" | RGBA string |
color2_rgba | Secondary color used by gradient mode. | "rgba(191, 198, 220, 0.7)" | RGBA string |
theme | Optional theme name. | none | string |
theme_opacity | Alpha multiplier for theme colors. | 1.0 | 0.0..1.0 |
Color Formats
gradient_direction = "horizontal" gives line, mirror, and frame layouts a smooth layout-wide gradient. With themes, this switches from discrete palette blocks to a continuous multi-stop gradient similar to the wave layout. For radial and polygon layouts, it smooths theme colors between palette stops around bar order instead of snapping bars into six hard color blocks.
color_rgba and color2_rgba accept CSS-like and comma-separated values:
color_rgba = "rgba(31, 224, 173, 0.90)"
color_rgba = "31,224,173,0.90"
color_rgba = "0.12,0.88,0.68,0.90"RGB values can be 0..255 or normalized 0..1. Alpha is always 0..1.
For colors.toml overrides and Matugen integration, see Colors and Matugen.
Layout Options
Each layout uses the shared keys above, then adds a few layout-specific keys.
Line
Use line for the standard edge-aligned bar layout.
If you want a ready-to-copy setup, see the Line preset config.
[visualizer]
layout = "line"
line_mode = "continuous"| Key | Description | Default | Accepted values |
|---|---|---|---|
line_mode | Normal continuous line or split line with a center gap. | "continuous" | "continuous", "split" |
line_split_gap | Center gap when line_mode = "split". | 200 | integer pixels |
Split example:
[visualizer]
layout = "line"
line_mode = "split"
line_split_gap = 220Mirror
Use mirror for centered mirrored bars. horizontal mirrors bars above and below a center axis; vertical mirrors them left and right.
If you want a ready-to-copy setup, see the Mirror preset config.
[visualizer]
layout = "mirror"
mirror_orientation = "horizontal"
mirror_gap = 24| Key | Description | Default | Accepted values |
|---|---|---|---|
mirror_orientation | Mirror axis direction. | "horizontal" | "horizontal", "vertical" |
mirror_gap | Empty space between mirrored halves. | 0 | integer pixels |
line_mode | Can also split the mirrored distribution. | "continuous" | "continuous", "split" |
line_split_gap | Center split gap when line_mode = "split". | 200 | integer pixels |
center_offset_x | Horizontal offset from monitor center. | 0 | pixels, positive moves right |
center_offset_y | Vertical offset from monitor center. | 0 | pixels, positive moves down |
Wave
Use wave for a continuous smoothed line. It follows the normal edge overlay geometry from [overlay].position.
If you want a ready-to-copy setup, see the Wave preset config.
[visualizer]
layout = "wave"
wave_stroke_width = 10
wave_fill = true
wave_glow = false
wave_smoothing = 1.0
wave_motion_smoothing = 0.22
wave_amplitude = 0.8| Key | Description | Default | Accepted values |
|---|---|---|---|
wave_stroke_width | Wave line thickness. | 10 | integer pixels, minimum 1 |
wave_fill | Draws a low-opacity fill under the wave. | true | true, false |
wave_glow | Draws a soft glow behind the wave line. | false | true, false |
wave_smoothing | Curve smoothing factor. | 1.0 | number, 0 is sharper |
wave_motion_smoothing | Temporal smoothing for movement. | 0.22 | number, higher feels softer/slower |
wave_amplitude | Overall wave height multiplier. | 0.8 | number, higher is taller |
Frame
Use frame to draw bars on multiple edges in one monitor-sized overlay.
If you want a ready-to-copy setup, see the Frame preset config.
[visualizer]
layout = "frame"
frame_edges = ["top", "bottom", "left", "right"]
frame_mirror_mode = "pairs"| Key | Description | Default | Accepted values |
|---|---|---|---|
frame_edges | Edges to render on. | ["top", "bottom"] | array using "top", "bottom", "left", "right" |
frame_mirror_mode | How bars are distributed across active edges. | "pairs" | "off", "all", "pairs" |
frame_mirror_mode = "off" distributes bars across selected edges. "all" mirrors the full bar set on every selected edge. "pairs" mirrors top+bottom together and left+right together.
Radial
Use radial for a circular or arc-shaped visualizer centered in a monitor-sized overlay.
If you want a ready-to-copy setup, see the Radial preset config.
[visualizer]
layout = "radial"
radial_inner_radius = 180
radial_start_angle = -90
radial_arc_degrees = 360
radial_rotation_speed = 0| Key | Description | Default | Accepted values |
|---|---|---|---|
radial_inner_radius | Where radial bars start before growing outward. | 180 | integer pixels, minimum 1 |
radial_start_angle | Start angle in degrees. | -90 | number |
radial_arc_degrees | Arc span. 360 is a full ring, 180 is a half circle. | 360 | number |
radial_rotation_speed | Rotation speed in degrees per second. | 0 | number, negative reverses direction |
center_offset_x | Horizontal offset from monitor center. | 0 | pixels, positive moves right |
center_offset_y | Vertical offset from monitor center. | 0 | pixels, positive moves down |
Half-circle example:
[visualizer]
layout = "radial"
radial_inner_radius = 160
radial_start_angle = -180
radial_arc_degrees = 180Polygon
Use polygon to place bars around a regular polygon such as a triangle, square, or hexagon.
If you want a ready-to-copy setup, see the Polygon preset config.
[visualizer]
layout = "polygon"
polygon_sides = 3
polygon_radius = 220
polygon_bar_length = 0
polygon_rotation = -90
polygon_rotation_speed = 0| Key | Description | Default | Accepted values |
|---|---|---|---|
polygon_sides | Number of polygon sides. | 3 | integer, minimum 3 |
polygon_radius | Outer polygon radius. | 220 | integer pixels, minimum 1 |
polygon_bar_length | Maximum outward bar length. 0 keeps automatic sizing. | 0 | integer pixels |
polygon_rotation | Static polygon rotation in degrees. | -90 | number |
polygon_rotation_speed | Rotation speed in degrees per second. | 0 | number, negative reverses direction |
center_offset_x | Horizontal offset from monitor center. | 0 | pixels, positive moves right |
center_offset_y | Vertical offset from monitor center. | 0 | pixels, positive moves down |
Triangle example:
[visualizer]
layout = "polygon"
polygon_sides = 3
polygon_radius = 220
polygon_rotation = -90
polygon_rotation_speed = 18Particle and Floating
particle and floating use the normal edge overlay geometry and follow [overlay].position. They are not centered monitor-sized layouts.
If you want ready-to-copy setups, see the Particle preset config and Floating preset config.
[visualizer]
layout = "particle"
bars = 10
bar_width = 40
gap = 10[visualizer]
layout = "floating"
bars = 10
bar_width = 40
gap = 10Segmented Bars
Segmented bars split each bar into repeated blocks.
[visualizer]
segmented_bars = true
segment_length = 14
segment_gap = 6| Key | Description | Default | Accepted values |
|---|---|---|---|
segmented_bars | Enables repeated block rendering. | false | true, false |
segment_length | Length of each segment along the growth direction. | 14 | integer pixels, minimum 1 |
segment_gap | Gap between segments. | 6 | integer pixels |
Audio Backend and PipeWire Tuning
| Key | Description | Default | Accepted values |
|---|---|---|---|
backend | Audio frame backend. | "cava" | "auto", "cava", "pipewire", "dummy" |
pipewire_attack | How quickly PipeWire levels rise. | 0.14 | number |
pipewire_decay | How slowly PipeWire levels fall. | 0.975 | number |
pipewire_gain | PipeWire level gain. | 1.20 | number |
pipewire_curve | Curve applied to PipeWire levels. | 0.95 | number |
pipewire_neighbor_mix | Smoothing between neighboring bars. | 0.24 | number |
Backend fallback order:
backend | Fallback order |
|---|---|
"auto" | cava -> pipewire -> dummy |
"cava" | cava -> pipewire -> dummy |
"pipewire" | pipewire -> cava -> dummy |
"dummy" | synthetic animation only |
Tuning guidance:
- slower or softer motion: lower
pipewire_attack, for example0.08..0.14 - slower falloff: raise
pipewire_decay, for example0.975..0.99 - less low-level noise: lower
pipewire_gainor raisepipewire_curve - smoother neighboring bars: increase
pipewire_neighbor_mix, for example0.24..0.35
[image_overlay]
[image_overlay] draws one optional image above the visualizer in the same transparent overlay window. This is useful for Rainmeter-style compositions where transparent PNG artwork sits in front of bars, waves, or particles.
[image_overlay]
enabled = true
path = "~/.config/kwybars/overlays/mountain.png"
opacity = 1.0
fit = "contain"
width = 0
height = 0
offset_x = 0
offset_y = 0| Key | Description | Default | Accepted values |
|---|---|---|---|
enabled | Enable image overlay drawing. | false | true, false |
path | Image file path. Absolute paths, ~/..., and paths relative to the active config file directory are supported. | "" | string |
opacity | Image alpha multiplier. | 1.0 | 0.0..1.0 |
fit | How the image fits inside the target box. | "contain" | "contain", "cover", "stretch" |
width | Target image box width. 0 uses the current overlay width. | 0 | integer pixels |
height | Target image box height. 0 uses the current overlay height. | 0 | integer pixels |
offset_x | Horizontal offset from centered placement. | 0 | number pixels |
offset_y | Vertical offset from centered placement. | 0 | number pixels |
Notes:
- Use transparent PNG artwork if you want the visualizer to remain visible around or behind the image.
- The source image is decoded on config reload, and the scaled image is cached per overlay size so normal frames only repaint the cached pixbuf.
- Replacing the image file triggers hot reload just like config, colors, and themes.
kwybarsctl validate-configandkwybarsctl doctorreport missing image paths.
Match Overlays to Wallpapers
kwybarsctl image-overlay match updates [image_overlay] by matching a wallpaper filename stem against an overlay directory.
kwybarsctl image-overlay match --overlay-dir ~/.config/kwybars/wallpaper-overlays ~/Pictures/wallpapers/forest.jpgThis looks for forest.png, forest.webp, forest.jpg, then forest.jpeg in the overlay directory. On success it sets image_overlay.enabled = true and image_overlay.path to the matched image. If the selected config path is a symlink, the command edits the resolved target file so preset symlinks stay intact.
Use --config when the daemon or overlay is watching a non-default config path:
kwybarsctl image-overlay match --config ~/.config/kwybars/current.toml --overlay-dir ~/.config/kwybars/wallpaper-overlays ~/Pictures/wallpapers/forest.jpg[daemon]
The daemon watches audio activity and starts or stops the overlay automatically. When it launches kwybars-overlay, it passes a private frame socket so the overlay reuses the daemon audio stream instead of starting a second Cava or PipeWire helper.
The overlay fades itself based on the same audio threshold and silence delay. When stop_on_silence = true, the daemon waits overlay.fade_out_ms before terminating the overlay process so the fade can finish. Overlay exits during this managed silence shutdown are logged but do not trigger desktop error notifications.
[daemon]
enabled = true
poll_interval_ms = 90
activity_threshold = 0.035
activate_delay_ms = 180
deactivate_delay_ms = 2200
stop_on_silence = true
notify_on_error = true
notify_cooldown_seconds = 45
overlay_command = "kwybars-overlay"
overlay_args = []| Key | Description | Default | Accepted values |
|---|---|---|---|
enabled | Enables daemon runtime behavior. | true | true, false |
poll_interval_ms | Daemon activity check interval. | 90 | integer milliseconds |
activity_threshold | Peak level threshold for active audio. | 0.035 | 0.0..1.0 |
activate_delay_ms | Audio must stay active this long before overlay starts. | 180 | integer milliseconds |
deactivate_delay_ms | Audio must stay silent this long before overlay stops. | 2200 | integer milliseconds |
stop_on_silence | Stops overlay after sustained silence. | true | true, false |
notify_on_error | Enables desktop notifications for daemon/config errors through notify-send. Managed overlay stops during silence are not notified. | true | true, false |
notify_cooldown_seconds | Minimum time between repeated notifications for the same error. | 45 | integer seconds |
overlay_command | Command used to launch the overlay. | "kwybars-overlay" | command string |
overlay_args | Extra arguments for overlay_command. | [] | array of strings |
kwybars-overlay defaults to GSK_RENDERER=cairo when the variable is not already set. If you prefer GTK's GPU renderer, set the environment before starting the daemon, for example GSK_RENDERER=ngl kwybars-daemon.
For local development without installed binaries:
[daemon]
overlay_command = "cargo"
overlay_args = ["run", "-p", "kwybars-overlay"]Validate Config
kwybarsctl validate-config checks the active config file, adjacent colors.toml, and configured theme resolution.
kwybarsctl doctor reports the active config summary and, when an overlay is running, whether it is using the daemon frame socket or a direct backend stream.
kwybarsctl validate-config
kwybarsctl validate-config ~/.config/kwybars/custom/my_config.toml
kwybarsctl validate-config --config ~/.config/kwybars/current.toml
kwybarsctl doctor
kwybarsctl doctor ~/.config/kwybars/custom/my_config.toml
kwybarsctl doctor --config ~/.config/kwybars/current.tomlkwybarsctl list-themes shows available user and built-in themes with their source paths.
kwybarsctl list-themes
kwybarsctl list-themes --config ~/.config/kwybars/current.toml