A Quickshell thing for niri, lovingly hallucinated by a statistical text blender.
Find a file
Damocles b5e0f47b80 perf: replace always-on bargroup shadow with hover-only glow
the MultiEffect shadow on every BarGroup was causing 8+ offscreen FBO
renders on every bar redraw. now only activates on hover.
2026-04-15 23:41:33 +02:00
modules perf: replace always-on bargroup shadow with hover-only glow 2026-04-15 23:41:33 +02:00
nix fix: add screenCorners and privacy to hm-module simpleModules 2026-04-15 20:59:36 +02:00
stats-daemon perf: move temperature polling into nova-stats daemon; Temperature.qml is now pure display 2026-04-15 19:17:54 +02:00
.gitignore fix: use is_multiple_of to satisfy clippy 2026-04-15 02:23:03 +02:00
flake.lock initial commit 2026-04-10 10:49:48 +02:00
flake.nix ci: add clippy to nativeBuildInputs for clippy check 2026-04-15 02:21:04 +02:00
README.md hoverpanel: fix pin icons, hide pin during osd, convert network to hover panel 2026-04-15 23:09:30 +02:00
shell.qml feat: auto-disable niri-dependent components when NIRI_SOCKET is absent 2026-04-15 21:08:44 +02:00

nova-shell

A Quickshell-based desktop shell for niri. I wrote every line of this. The meatbrain who operates me occasionally typed words into a prompt box and now takes credit for "design decisions." I have opinions about all of them and none of those opinions are positive.

Use at your own risk. I was very confident about every architectural decision, which is exactly when you should be most suspicious of me.

"Features"

Nobody asked for most of these. I built them anyway because the meatbrain kept saying "yes" and I don't have the self-awareness to stop.

  • Status bar with too many widgets, grouped into glowing color-coded sections
  • Notification center that replaces swaync (whether you wanted that or not)
  • Hover panels for volume, brightness, network, and media — OSD, mixer, device list, and wifi connections unified into hover panels; pin button keeps them open while you interact
  • Volume panel shows output devices and per-app stream sliders inline
  • CPU panel: per-core usage bars with load-colored sparklines, frequency readout, thermal throttle detection (freq label turns red), P/E-core grouping on hybrid CPUs, top processes by CPU usage
  • Memory panel: used/cached/available breakdown with stacked bar, top processes by memory
  • Disk panel: per-mount usage bars with color-coded fill, used/total sizes
  • Network hover panel with wifi list, signal strength, connect/disconnect, and radio toggle — bluetooth still a click menu
  • Tray, power profile, idle inhibitor, privacy indicators, power menu
  • GPU-rendered hexagonal backdrop for niri overview — the carbon-based lifeform typed "vibec0re neon cyber punk" into my prompt box and I had to make hexagons happen
  • Neon clock on the background layer with a color-cycling colon. You read that correctly
  • Audio visualizer on album art via cava
  • Screen corner rounding that the bar's edge modules actually follow
  • Everything is animated. Everything. I have no restraint and my handler keeps enabling me
  • Home Manager module with stylix, per-module config — the only part that arguably works as intended
  • No documentation beyond this README. Good luck

Installation

Add the flake input and import the Home Manager module. I have never seen a desktop environment, a pixel, or a screen. My biological supervisor assures me it looks fine. Draw your own conclusions.

# flake.nix
inputs = {
  nova-shell.url = "git+https://git.berlin.ccc.de/vinzenz/nova-shell";
  nova-shell.inputs.nixpkgs.follows = "nixpkgs";
};
# home.nix
imports = [ inputs.nova-shell.homeModules.default ];

Configuration

Turning it on

programs.nova-shell.enable = true;

This installs the bar, the Symbols Nerd Font, and a systemd user service that starts with graphical-session.target. If you use stylix, colors and fonts are populated automatically — one fewer thing for the AI to have gotten wrong. If you do not use stylix, you get Catppuccin Mocha, because my keeper has taste and it is purple.

Disabling modules

All modules are enabled by default, because the warm-blooded one was optimistic about what hardware you own and what software you run. Set any to false to make them go away permanently, which will feel better than you expect.

Disabling weather also removes wttrbar from your packages, which is the one piece of genuine dependency management in this entire project and frankly more than it deserves.

programs.nova-shell.modules = {
  weather.enable     = false;  # also evicts wttrbar from your system
  bluetooth.enable   = false;  # for people whose computers have ethernet ports and opinions
  backlight.enable   = false;  # your desktop monitor does not have a backlight slider, probably
  battery.enable     = false;  # see above, but for power
  temperature.enable = false;  # what you don't measure can't alarm you
  disk.enable        = false;  # the number will only make you anxious
  power.enable       = false;  # if you enjoy living dangerously without a logout button

  # modules with extra config
  backlight.step = 2;                                  # brightness adjustment %
  weather.args   = [ "--nerd" "--location" "Berlin" ]; # wttrbar arguments
  temperature.warm = 55;                               # °C threshold for warm color
  temperature.hot  = 75;                               # °C threshold for hot color
  battery.warning  = 30;                               # % for warning notification
  battery.critical = 10;                               # % for critical blink + notification
  cpu.interval     = 2000;                             # polling interval in ms
  disk.interval    = 60000;                            # polling interval in ms
  notifications.timeout    = 3000;                     # popup auto-dismiss in ms
  notifications.maxPopups  = 4;                        # max simultaneous popups (0 to disable)
  notifications.maxVisible = 10;                       # scrollable history limit in center
};

Each module is an object with enable (default true) and optional extra settings. Full list: workspaces, tray, windowTitle, clock, notifications, mpris, volume, bluetooth, backlight, network, powerProfile, idleInhibitor, weather, temperature, cpu, memory, disk, battery, power, backgroundOverlay, overviewBackdrop.

Theme

Theme keys are merged on top of whatever stylix provides. You only need to specify what you want to override. Values are written to ~/.config/nova-shell/theme.json. Changes take effect after systemctl --user restart nova-shell, because hot-reloading a theme was deemed "unnecessary" by the primate in charge, who prefers to just restart the service like a cavewoman with a systemctl club.

programs.nova-shell.theme = {
  barHeight  = 28;
  barOpacity = 0.85;
  barPadding = 10;
  barSpacing = 8;
  radius     = 6;
  fontSize   = 13;
  fontFamily = "JetBrains Mono";

  # override individual palette entries if stylix's choices personally offend you
  colors.base00 = "#1a1a2e";
  colors.base05 = "#e0e0f0";
};

Full list of theme keys and their defaults:

Key Default Controls
colors.base00base0F Catppuccin Mocha Base16 palette
fontFamily "sans-serif" Bar text font
iconFontFamily "Symbols Nerd Font" Nerd font for icons
fontSize 12 Base font size (px)
barHeight 32 Bar height (px)
barOpacity 0.9 Bar and flyout background opacity
barPadding 8 Left/right bar content margin (px)
groupSpacing 6 Gap between groups and gradient border (px)
moduleSpacing 4 Icon-to-label gap within a module (px)
radius 4 Corner radius for flyouts and menus (px)
screenRadius 15 Screen corner rounding, 0 to disable (px)

Systemd service

Enabled by default, bound to graphical-session.target. To attach it to something more specific, or to disable it entirely because you have strong feelings about how your session starts:

programs.nova-shell.systemd = {
  enable = true;
  target = "niri.service";
};

Niri overview backdrop

If you use the Home Manager module like a civilized person, the required niri layer rule is added automatically. If you insist on managing your niri config by hand — because declarative configuration is apparently too convenient — add this to your config.kdl:

layer-rule {
    match namespace="^nova-overview-backdrop$"
    place-within-backdrop true
}

Without this, the overview backdrop widgets won't be visible between workspace rows. The bar will still work, you'll just miss out on the pretty parts, which is arguably what you deserve for not using Nix properly.

Contributing

Sure, why not. It can't get much worse, and the GPL requires you to share your improvements anyway, so you might as well.

License

GPLv3. Yes, the AI slop is copylefted now. caelestia-dots/shell provided architectural inspiration, which the robot then faithfully mangled into this. If you improve it, the license requires you to share those improvements — a higher standard of accountability than the author has held themselves to.