Kwybars is a GTK4-based desktop audio visualizer for GNU/Linux (Wayland) that renders real-time audio bars on your screen.
Think of it like cava... but instead of living in the terminal, it becomes a transparent overlay on your desktop. Place visualizer on any screen edge: top, bottom, left, right or center and watch your music bounce in real time. Kwybars are highly customizable with multiple layouts, segmented bars, gradients, themes, and extensive configuration options.
demo.mp4
- Place visualizer on any screen edge
top | bottom | left | right - Multi-monitor support: show bars on primary, all, or selected monitors
- Control window layer:
background,bottom,top - Custom overlay size + alignment
- Solid or gradient bar colors
- Segmented bar style (oldschool split blocks)
- Radial layout (circular)
- Frame layout for top+bottom, left+right, or all monitor edges at once
- Polygon layout for triangle, square, hexagon, and similar shapes
- Hot reload config changes (no restart needed)
- Built-in themes and optional custom theme palettes (
~/.config/kwybars/themes/*.toml) - Optional but recommended
kwybars-daemonthat auto starts/stops overlay based on audio activity
Note
Kwybars are not heavily tested on all Wayland compositors yet. If you encounter issues, please open an issue and provide details what distro and Wayland compositor you are using.
yay -S kwybars-bin
# or build the latest git commit from source
yay -S kwybars-gitStart the daemon after install:
kwybars-daemon(Optional) Run with a specific config file:
kwybars-daemon --config ~/.config/kwybars/custom/my_config.tomlStart the daemon on boot (Hyprland):
# Recommended (if you use UWSM):
exec-once = uwsm app -- kwybars-daemon
# If you are not using UWSM
exec-once = kwybars-daemonIf you prefer systemd service:
systemctl --user enable --now kwybars-daemon.serviceInstall dependencies:
sudo pacman -S --needed rust gtk4 gtk4-layer-shell pipewire cava
# optional: desktop error notifications
sudo pacman -S --needed libnotifycargo build --workspace
cargo run -p kwybars-overlayRun daemon mode (auto launch on audio):
cargo run -p kwybars-daemonRun with a specific config path:
cargo run -p kwybars-daemon -- --config ~/.config/kwybars/custom/my_config.tomlKwybars looks for config files in this order:
--config /path/to/config.tomlKWYBARS_CONFIGenvironment variable$XDG_CONFIG_HOME/kwybars/config.toml~/.config/kwybars/config.toml(recommended)./kwybars.toml
config files auto reload while the app is running
If no config file exists, Kwybars uses the built-in defaults.
Default example config:
/usr/share/doc/kwybars/examples/config.toml
colors.tomlin the same directory as the activeconfig.toml.- Example default path:
~/.config/kwybars/colors.toml. - Precedence:
colors.tomloverridesconfig.tomlforcolor_rgbaandcolor2_rgbaonly when those keys are present incolors.toml. Useful for customizing appearance with your own colorscheme using matugen
You can place a colors.toml next to your config file.
Example:
[visualizer]
color_rgba = "rgba(122, 162, 247, 0.95)"
color2_rgba = "rgba(187, 154, 247, 0.95)"color_rgba and color2_rgba accept:
- CSS-like string:
"rgba(31, 224, 173, 0.90)" - plain comma string:
"31,224,173,0.90"or"0.12,0.88,0.68,0.90"
Change bars colors color_rgba and color2_rgba with Matugen
- Create a new file
kwybars-colors.tomlin~/.config/matugen/templates - Add the following content to
kwybars-colors.toml:
[visualizer]
color_rgba = "{{colors.primary.default.rgba | set_alpha: 0.7}}"
color2_rgba = "{{colors.secondary.default.rgba | set_alpha: 0.7}}"- Then add the following to your matugen config file
~/.config/matugen/config.toml:
[templates.kwybars]
input_path = '~/.config/matugen/templates/kwybars-colors.json'
output_path = '~/.config/kwybars/colors.toml'- Active theme is selected with
themeinconfig.toml(optional). theme_opacitymultiplies the theme alpha for all bars.
Theme lookup order for <theme>.toml:
~/.config/kwybars/themes/<theme>.toml(or next to your activeKWYBARS_CONFIG)/usr/share/kwybars/themes/<theme>.toml(installed package themes)<cwd>/assets/themes/<theme>.toml(source checkout fallback)
Available built-in themes:
ayu-darkcatppuccin-mochadraculaeverforestgruvboxnordrose-pinetokyo-night
Custom theme example (~/.config/kwybars/themes/your-theme.toml):
name = "your-theme"
red = "#ea6c73"
green = "#7fd962"
yellow = "#f9af4f"
blue = "#53bdfa"
magenta = "#cda1fa"
cyan = "#90e1c6"Enable one in your config:
theme = "catppuccin-mocha"
theme_opacity = 0.85[overlay]
monitor_mode = "primary"
layer = "background"
position = "bottom"
full_length = true
height = 500
anchor_margin = 20
margin_left = 20
margin_right = 20
[visualizer]
layout = "line"
bar_corner_radius = 20
bars = 50
bar_width = 8
gap = 20
framerate = 60
color_mode = "gradient"
color_rgba = "rgba(175, 198, 255, 0.7)"
color2_rgba = "rgba(191, 198, 220, 0.7)"
# By default daemon is already enabled and configured for you.
# Use in your config only if you need to customize.
[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]
position: overlay edge:bottom|top|left|right.layer: stacking layer:background|bottom|top.anchor_margin: margin on the anchored edge.margin_left: extra left margin.margin_right: extra right margin.margin_top: extra top margin.margin_bottom: extra bottom margin.full_length: stretch across full edge length.width: fixed width for horizontal overlays or thickness for vertical overlays.height: fixed height for vertical overlays or thickness for horizontal overlays.horizontal_alignment: alignment for top/bottom whenfull_length=false:left|center|right.vertical_alignment: alignment for left/right whenfull_length=false:top|center|bottom.monitor_mode: monitor targeting:primary|all|list(default:primary)monitors: monitor selector list (connector names likeDP-1or 1-based indices like"1"), used whenmonitor_mode="list". (monitors = ["DP-1", "HDMI-A-1"])
[visualizer]
layout: layout mode:line|frame|radial|polygon.bars: number of bars.bar_width: base bar thickness in pixels.bar_corner_radius: bar corner radius in pixels (0= square bars).segmented_bars: split each bar into repeated segments (true|false).segment_length: segment size in pixels along bar growth direction.segment_gap: empty spacing in pixels between segments.radial_inner_radius: inner circle radius in pixels forlayout="radial".frame_edges: selected edges forlayout="frame"(["top", "bottom"]by default).frame_mirror_mode: frame edge mirroring:off|all|pairs(pairsby default).offsplits bars across selected edges,allmirrors the same motion on every selected edge,pairsmirrorstop+bottomtogether andleft+righttogether.radial_start_angle: arc start angle in degrees forlayout="radial"(-90starts at the top).radial_arc_degrees: arc span in degrees forlayout="radial"(360= full ring,180= half circle).radial_rotation_speed: rotation speed in degrees per second forlayout="radial"(0= static, negative reverses direction).center_offset_x: horizontal center offset in pixels for centered layouts (radialandpolygon), positive moves right.center_offset_y: vertical center offset in pixels for centered layouts (radialandpolygon), positive moves down.polygon_sides: number of polygon sides forlayout="polygon"(3= triangle,4= square,6= hexagon).polygon_radius: outer polygon radius in pixels forlayout="polygon".polygon_rotation: polygon rotation in degrees forlayout="polygon"(-90points a triangle upward).polygon_rotation_speed: polygon rotation speed in degrees per second forlayout="polygon"(0= static, negative reverses direction).gap: gap between bars in pixels.framerate: render update rate (default:60).color_mode:solid|gradient(default:gradient). Solid color mode usescolor_rgba, gradient mode uses bothcolor_rgbaandcolor2_rgba.color_rgba: primary bar color (default:rgba(175, 198, 255, 0.7))color2_rgba: secondary color for gradient mode (default:rgba(191, 198, 220, 0.7))theme: optional theme name to load from~/.config/kwybars/themes/<theme>.tomlor built-in themes. Available themes:ayu-dark,catppuccin-mocha,dracula,everforest,gruvbox,nord,rose-pineandtokyo-night(default:none).theme_opacity: theme alpha multiplier0.0..1.0(default:1.0).
Example half-circle radial layout:
[visualizer]
layout = "radial"
radial_inner_radius = 160
radial_start_angle = -180
radial_arc_degrees = 180
center_offset_x = 0
center_offset_y = 0Example frame layout on all sides:
[visualizer]
layout = "frame"
frame_edges = ["top", "bottom", "left", "right"]
frame_mirror_mode = "off"Example frame layout on top and bottom only:
[visualizer]
layout = "frame"
frame_edges = ["top", "bottom"]Example mirrored frame layout:
[visualizer]
layout = "frame"
frame_edges = ["top", "bottom", "left", "right"]
frame_mirror_mode = "all"Example paired frame mirroring:
[visualizer]
layout = "frame"
frame_edges = ["top", "bottom", "left", "right"]
frame_mirror_mode = "pairs"Example triangle/polygon layout:
[visualizer]
layout = "polygon"
polygon_sides = 3
polygon_radius = 220
polygon_rotation = -90
polygon_rotation_speed = 18
center_offset_x = 0
center_offset_y = 0Example square layout:
[visualizer]
layout = "polygon"
polygon_sides = 4
polygon_radius = 220
polygon_rotation = 0
polygon_rotation_speed = 0
center_offset_x = 0
center_offset_y = 0[daemon]
enabled: run daemon logic (true|false).poll_interval_ms: daemon poll period in milliseconds.activity_threshold: peak level threshold0.0..1.0for "audio active".activate_delay_ms: active signal must stay above threshold for this long before launch.deactivate_delay_ms: active signal must stay below threshold for this long before stop.stop_on_silence: iftrue, daemon stops overlay after silence delay.notify_on_error: enable desktop notifications (notify-send) for important runtime errors.notify_cooldown_seconds: minimum seconds between repeated notifications for the same error.overlay_command: command used to launch overlay (kwybars-overlayby default).overlay_args: optional command arguments list.
Config parse errors include line numbers (for example: line 42: unknown overlay key: ...).
For local development without installing binaries:
[daemon]
overlay_command = "cargo"
overlay_args = ["run", "-p", "kwybars-overlay"]kwybarsctl switch-config lets you swap the active config file atomically so a running
kwybars-daemon or kwybars-overlay can reload it without a restart.
Default behavior:
- updates the normal active config path (
~/.config/kwybars/config.tomlor your XDG equivalent) - replaces that path with a symlink to the selected config
- creates a one-time backup of an existing regular
config.tomlasconfig.toml.bak
Examples:
kwybarsctl switch-config ~/.config/kwybars/custom/my_radial_config.tomlIf overlay/daemon is watching a different active path, use --active:
Recommended workflow:
- keep one stable active file such as
~/.config/kwybars/current.toml - put your real presets in
~/.config/kwybars/custom/*.toml - start the daemon against the stable active file
- switch presets by repointing that active file with
kwybarsctl
Example:
kwybars-daemon --config ~/.config/kwybars/current.toml
kwybarsctl switch-config --active ~/.config/kwybars/current.toml ~/.config/kwybars/custom/my_radial_config.toml
kwybarsctl switch-config --active ~/.config/kwybars/current.toml ~/.config/kwybars/custom/my_line_top_config.toml
kwybarsctl switch-config --active ~/.config/kwybars/current.toml ~/.config/kwybars/custom/my_segmented_config.tomlExample Hyprland binds:
bind = SUPER ALT, 1, exec, kwybarsctl switch-config --active ~/.config/kwybars/current.toml ~/.config/kwybars/custom/my_radial_config.toml
bind = SUPER ALT, 2, exec, kwybarsctl switch-config --active ~/.config/kwybars/current.toml ~/.config/kwybars/custom/my_line_top_config.toml
bind = SUPER ALT, 3, exec, kwybarsctl switch-config --active ~/.config/kwybars/current.toml ~/.config/kwybars/custom/my_segmented_config.toml- Both
kwybars-overlayandkwybars-daemonwrite logs to stderr and to a file. - Default log files:
~/.local/state/kwybars/overlay.log~/.local/state/kwybars/daemon.log- (
$XDG_STATE_HOME/kwybars/*.logifXDG_STATE_HOMEis set)
- You can set log level with
KWYBARS_LOG(orRUST_LOG), for example:KWYBARS_LOG=debug cargo run -p kwybars-daemon
- Override log file location with
KWYBARS_LOG_FILE=/path/to/kwybars.log
If you see a solid panel or background behind the bars instead of a transparent overlay, try checking the following:
- Compositor rules – Look for blur, shadow, opacity, or layer-surface rules that might be targeting
kwybars. - Custom GTK themes – Kwybars already removes the GTK
backgroundclass from its overlay widgets and applies a high-priority transparent CSS rule. However, very aggressive theme or compositor settings can still override this behavior. Check your theme or~/.config/gtk-4.0/gtk.cssfor overrides. Broad rules like.background { background-color: ... }can force a visible background.