A Quickshell desktop shell for Wayland compositors (developed and tested on
Quickshell 0.3.2 / Qt 6.11). Hyprland, niri, sway, mango, labwc and Umbriel are
supported (each with a bundled config in external/), and any other
compositor runs on an experimental generic backend (docs/compositors.md). The
backend is picked from the session at start.
Documentation: anoshell.anorebel.net (stable) · anoshell-dev.anorebel.net (development) · source in docs/
- Panels and the pill: bars in several forms with attachable groups, the AnoSpot pill (faces, transients, any edge), sidebars, dock, launcher, overview, and four panel families; with the connected frame they fuse into one curved surface (overview, the pill).
- Looks and colours: Liquid, Ink, Neo-tech and Clay looks, static themes or wallpaper colours (matugen), glass, colour modes, your own looks (looks).
- Atelier: themes, looks, pieces, launcher plugins, lock screens, wallpapers (and Wallhaven) and whole-setup rices from built-in, your folders and catalogs, with previews, checksums, a code check and undo (atelier).
- Pieces (desktop widgets) in pages on a grid: clocks and clock faces, a world clock, day progress, system, weather, media, lyrics, calendar, to-do, news, screen time, the wallpaper's palette, the Bioma organisms, plus your own (pieces).
- Scratchpad & Pins: notes, to-do, clipboard and calendar in one panel that grows from the pill, pinned commands (in a terminal or the background) and a prompt for notes, to-dos, commands, web searches and AI questions (scratchpad).
- Launcher plugins: web search, files, kaomoji, unicode symbols, keybinds, windows and clipboard history, plus your own (plugins).
- Lock screen on niri with fingerprint unlock and replaceable lock screens (built-in, Minimal, Bioma Gate, your own) (lock screens).
- Reader: novels, manga and anime (resume, intro skip, Airing), fused into the frame (reader).
- System: network and NetBird VPN panel, Bluetooth, audio and EasyEffects, brightness, night light, power and performance mode, device pills, package updates, removable drives, notifications with DND (critical ones still show), inline replies and per-app rules, focus mode, a screen-share picker on Hyprland, KDE Connect, screen time with limits, screenshots (freeze-frame regions), text recognition (OCR) and screen recording, song recognition, lyrics (extras, configuration).
- anod and
ano: the companion daemon (wallpapers, hooks, keybinds, displays, backups, the Atelier, the reader backend) and its CLI:ano doctor,ano backup,ano atelier,ano keybinds(anod, CLI). - Settings for all of it, as an overlay or a standalone window, with a search over every option and previews you edit in place: drag the bar's modules, the bar, pill and dock, the lock screen's parts and the notifications; themes and looks drawn in their own colours and shapes. Ctrl+Z undoes changes made there (resets included); typing anywhere starts a search.
Shell source lives at ~/.config/quickshell/ano/. Generated state and user-writable overrides live under the anoshell namespace: ~/.config/anoshell/ (config, themes, looks, pieces, plugins, lock screens, rices, lyrics), ~/.local/state/anoshell/, ~/.cache/anoshell/.
# Get the shell where Quickshell finds it, then the daemon and CLI
git clone https://github.com/AnoRebel/AnoShell.git ~/.config/quickshell/ano
~/.config/quickshell/ano/anod/install.sh # anod + ano into ~/.local/bin
# Launch it
qs -c ano
# Check what's installed and what's missing
ano doctor
# Settings on their own
qs -n -p ~/.config/quickshell/ano/settings.qmlTo start it with your session, use the bundled compositor configs
(external/: Hyprland, niri, sway, mango, labwc, Umbriel); see
docs/installation.md.
Service singletons sit under services/ and are auto-loaded by import "services" in shell.qml. They expose state and methods that any module (and IPC handlers) can read/call. Most are dormant until referenced.
| Service | What it provides |
|---|---|
CompositorService |
One API over the compositor backends in services/compositor/ (Hyprland, niri, sway, mango, labwc, Umbriel; experimental: generic): workspaces, windows (leased), outputs, fullscreen, keyboard layout, actions. |
NiriService |
Full Niri IPC over its UNIX socket — events, window list, workspace list, focus changes. |
HyprlandKeybinds / NiriKeybinds |
Parsers for the live keybinds files. Power the cheatsheet. |
AnoSocket |
Auto-reconnecting socket helper used by NiriService. |
MinimizedWindows |
Niri-only minimize emulation registry (Niri has no native minimize concept). |
WindowMru |
Most-recently-used window order for every switcher style, from focus changes (no polling). |
PanelRegistry |
The connected frame's geometry registry: surfaces publish their bodies, the frame fuses them. |
DefaultApps |
Launches your default apps (apps.*); binds call it, so changing an app never regenerates binds. |
| Service | What it provides |
|---|---|
Audio |
PipeWire default sink/source. Volume/mute, mic mute, volume protection. |
Brightness |
Per screen: the backlight under its connector (brightnessctl; a firmware/ACPI one goes to the built-in panel; light.device overrides), else ddcutil over DDC/CI for an external monitor; a screen with neither isn't offered a slider. |
Battery |
UPower charge/health/time-remaining + auto-suspend trigger. |
KeyboardLayoutService |
Active XKB layout on both Hyprland and Niri; clicking cycles it where the backend can. |
LockKeys |
Caps Lock / Num Lock state, read on demand (no polling) for the OSD and the lock screen warning. |
EasyEffects |
EasyEffects bypass and output presets through its command line. |
Idle |
Wayland IdleInhibitor toggle (caffeine-style). |
IdleInhibitor |
Per-app inhibit registry. |
| Service | What it provides |
|---|---|
Network |
Wi-Fi state and networks read live from Quickshell.Networking (NetworkManager over D-Bus); nmcli for scans, connect/disconnect, hotspot toggle; wired & tethering links (ethernet, USB/Bluetooth tether, mobile broadband) and which carries the default route; NetworkManager VPN and WireGuard connections on/off (Settings → Services → NetworkManager VPNs). |
NetworkUsage |
rx/tx throughput polled from /proc/net/dev. Opt-in via network.usage.enable. |
VPN |
Connect/disconnect/status for tailscale, netbird, warp, wireguard, or custom providers. |
BluetoothStatus |
Adapter state + paired/connected device list. |
TrayService |
System tray entries with pinning + DBus menu support. |
Cliphist |
Clipboard history with fuzzy search. |
ResourceUsage |
CPU / RAM / swap / network from /proc. |
Privacy |
Mic-active and cam-active detection. |
GameMode |
Follows gamemoded over D-Bus (no polling) and drives performance mode (pauses animations, blur, visualisers and popups while a game runs, a window is fullscreen, or by hand). |
PowerProfilePersistence |
Restores last power-profiles-daemon profile on shell start. |
ShellExec |
Shell-runtime detection + safe exec helper. |
KdeConnect |
Paired phones over kdeconnectd's D-Bus (reachability, battery, ring, ping, clipboard, files, pairing prompts). Opt-in. |
DeviceEvents |
Bluetooth devices, USB plugs, audio output and display changes as short pills (per-kind switches). |
Drives |
Removable drives: partitions, mount/unmount, eject, and whether data is still being written. |
Downloads |
Downloads in progress in the download folder, from anod's watcher (bytes so far, rate). |
Updates |
Pending package updates (checkupdates, plus paru/yay for the AUR). Opt-in. |
PolkitAuth |
The shell's polkit agent (the password prompt is modules/polkit). |
Anod |
Client for the anod daemon's socket; without anod its features show as unavailable. |
Location |
Where you are, for weather, night light's sun schedule and sun/moon widgets. |
| Service | What it provides |
|---|---|
MaterialThemeLoader |
Watches the wallpaper-derived MD3 JSON and writes into Appearance.m3colors when source is Material You. |
StaticThemeLoader |
Loads assets/themes/<name>.json (or ~/.config/anoshell/themes/<name>.json) when source is static. Defers to Appearance.previewTokens during Settings hover-preview. |
ThemeRegistry |
Discovers + indexes all available themes (bundled + user). Exposes themes ListModel and themeContents (parsed JSON cache). |
Wallpapers |
The wallpaper folder for the picker, anod palette (hue, stills), favourites, apply via anod. |
Wallhaven |
Wallhaven search + download for the picker; API key in ~/.local/share/anoshell/secrets/wallhaven (0600). |
AntiFlashbang |
Screen shader that darkens bright screens (backends with screen shaders: Hyprland). IPC-controlled. |
ScreenFilters |
Eye-care screen filters: grayscale, sepia, high contrast, protan/deutan/tritan correction (Hyprland). |
Looks |
The switchable looks (Liquid, Ink, Neo-tech, Clay, yours): shape, material, texture, type and motion (docs/looks.md). |
Glass |
Glass material settings and the wallpaper alignment maths behind it. |
AppColorScheme |
Light/dark for your apps, independent of the shell (freedesktop color-scheme, GTK and Qt). |
PaletteThemes |
Cursor and icon themes drawn in the current palette (built on demand). |
FontService |
Installed font families (fc-list) for the Settings font pickers. |
BarStyle |
Pill or classic bar (Ano family), and moving the pill or dock to an edge. |
PillTransient |
The moments the pill morphs into (volume, brightness, mic, layout, notifications, charging, recording, devices). |
Atelier |
The shell side of anod's content store (themes, looks, pieces, plugins, lock screens, wallpapers, rices). |
LauncherPlugins / LockScreens |
Launcher plugin and lock screen packages, bundled and yours (plugins, lock screens). |
Pieces |
Desktop piece registry (bundled pieces/ + ~/.config/anoshell/pieces/, live, broken ones marked) and the per-screen layout; the layer is modules/pieces (docs/pieces.md). Off by default. |
NightLight |
wlsunset wrapper. Warm now (the toggle), or automatically from sunset to sunrise or between set times. Opt-in. |
| Service | What it provides |
|---|---|
MprisController |
Active Mpris player tracking, duplicate filtering, position polling. |
LyricsService |
Synced .lrc parsing — local files first, falls back to LRCLIB / NetEase. Opt-in. |
SpectrumService |
Cava audio spectrum, reference-counted (only runs when something subscribes). |
Screenshot |
Region, window and screen captures (grim/slurp; niri's own actions) and text recognition (screenshot ocr, tesseract), with the preview card in modules/screenshot. |
MusicRecognition |
"What's playing?" with songrec, one bounded recording of the output or the mic. Opt-in. |
Reader / ReaderNovel / ReaderManga / ReaderAnime |
The reader panels' side of anod's reader backend: novels (FreeWebNovel, NovelArrow), manga, anime (docs/reader.md). |
RecorderStatus |
Screen recording with gpu-screen-recorder, wl-screenrec or wf-recorder (fps, audio none/system/mic/both, discard, finish preview); state from its own recorder process. |
| Service | What it provides |
|---|---|
DateTime |
Formatted clock + uptime. |
Weather |
wttr.in API client with optional GPS; official warnings from anod and a rain-soon notice (bar.weather.alerts). |
Notifications |
DBus notification server with persistent storage and popup management: inline replies, per-app rules (normal / silent / blocked), Do Not Disturb that still lets critical ones pop up. |
CalendarSync |
iCal/CalDAV pull from configured URLs. Opt-in. |
Ai |
AI chat across OpenAI, Gemini, Anthropic, Mistral, OpenRouter, Ollama. Streaming + Anthropic thinking blocks. |
FocusTime |
Daemon lifecycle for the per-app usage tracker (SQLite-backed Python daemon; Hyprland and niri IPC sockets). |
Notepad / Todo |
Notepad tabs (JSON) and the to-do list (a todo.txt synced both ways). Opt-in. |
CalendarEvents / Holidays |
Your own events with recurrence and reminders; public holidays per country. |
Pomodoro |
Pomodoro, stopwatch and countdown. Opt-in. |
Chrono |
Alarms (minute-aligned check, snooze/dismiss notification, sound) and world clocks for the Clock panel; the timer and stopwatch are Pomodoro's. |
ScreenTime |
Screen time per app and title, idle-aware, with daily and per-app limits. Opt-in. |
Scratchpad |
Pinned commands (terminal or background), the prompt bar's parser, and the tabs over notes, to-do, clipboard and calendar (docs/scratchpad.md). Opt-in. |
| Service | What it provides |
|---|---|
AnoSpotState |
Aggregated state shared between the AnoSpot pill and its widgets. |
AnoSpotStash |
Manages the drag-and-drop stash directory ($XDG_RUNTIME_DIR/anoSpot or fallback) and the shelf's recent screenshots. |
All settings in config.json. GUI via Settings overlay (qs -c ano ipc call settings toggle) or standalone window (qs -n -p settings.qml). Both share the same page components and behave identically — including keyboard navigation:
| Key | Action |
|---|---|
Ctrl+K |
Open the command palette (search every config key) |
Up / Down |
Cycle nav rail (when no input is focused) |
Tab / Shift+Tab |
Cycle pages or default Tab traversal inside an input |
Ctrl+1..Ctrl+9 |
Jump to page N |
Ctrl+0 |
Jump to last page |
Esc |
Close the panel (overlay) or quit (standalone) |
Ctrl+Z |
Undo the last change made while Settings is open (resets included; up to 50), with a toast |
| any letter or digit | Start a search with it (when no field has focus) |
Search (the field at the top of the page list, or Ctrl+K). Search every setting by the words you see in Settings (card titles, control labels and descriptions) or by config key — case-insensitive, multi-word (every term must match somewhere), punctuation and spaces ignored ("wifi" finds Wi-Fi). Keys come live from the config; labels come from modules/settings/settings-index.json (generated, see Keeping settings wired below). Up/Down move the highlight, Enter jumps to the page that owns the key and scrolls to its card, Esc closes.
Ctrl+K → "event border" → anoSpot.eventBorder.holdMs → AnoSpot · Event border animation
Ctrl+K → "hotspot" → network.hotspot.password → Services · Network usage tracking
Ctrl+K → "lyrics" → lyrics.dir → Services · Lyrics
Ctrl+K → "wallpaper rot" → background.randomize → Appearance · Wallpaper Rotation
Each page also has a per-page "Reset" affordance in its header (only visible when that page has overridden any keys), and AboutPage has a global "Reset every setting" card. Both reset paths target only the user delta at ~/.config/anoshell/config.json; bundled defaults are never written to.
There are two config files:
~/.config/quickshell/ano/config.json— bundled defaults that ship with the shell. Read-only at runtime; nothing the shell does writes here.~/.config/anoshell/config.json— your per-machine delta. Sparse: only contains keys you've actually changed. The Settings UI writes here.
On startup the shell reads the bundle for defaults, then deep-merges your delta on top. This means:
- The user file is portable — copy it to another machine for an identical configuration without bringing the entire bundle along.
- Shell upgrades that bump bundle defaults reach you automatically for any keys you haven't customised.
- "Reset to defaults" (per-page or global, in Settings) deletes keys from the user file rather than writing the default value into it.
You can edit the user file directly if you prefer JSON over the GUI. The shell watches it with watchChanges: true — saves apply within ~100ms with no restart needed:
// Example ~/.config/anoshell/config.json — only the keys you've customised
{
"bar": {
"layout": { "height": 38, "radius": 16 },
"actions": { "leftClick": "settings" }
},
"anoSpot": {
"enable": true,
"position": "bottom"
},
"appearance": {
"theme": { "source": "static", "static": "tokyo-night-dark" }
},
"nightLight": { "schedule": "times", "start": "21:00", "end": "07:00", "nightTemp": 3500 }
}Semantics
- Plain objects merge recursively (your
bar.layout.heightdoesn't wipebar.actions). - Arrays and scalars replace entirely (setting
enabledPanels: [...]replaces the whole list). - A malformed JSON file fires a desktop notification with the line/column of the parse error and the last-known-good config keeps applying — the shell never crashes on a stray comma.
- Removing a key from the user file reverts that key to the bundle default on the next reload.
The Settings UI has 14 pages, opening on About, each owning a set of top-level config keys. The "Reset" header button on each page only clears keys it owns; the global "Reset every setting" card on the About page wipes the entire user delta.
| Page | Owns | What you'll find there |
|---|---|---|
| About | user |
Presets, export/import, backup & restore (through anod, same archives as ano backup), avatar picker, system info, the shell's QML errors (Errors card; their count shows on About in the page list), credits, global "Reset every setting" card |
| General | audio, battery, time, notifications, interactions, sounds.* (but theme), session |
Volume protection, battery thresholds (with ordering warning), clock/date format with live preview, notification timeout/silent/max popups and per-app rules, logout & shutdown confirmation, scroll speed |
| Modules | enabledPanels, panelFamily, osd, screenCorners, altSwitcher, apps, focusTime, taskView, media, compositor, displayManager, display.primaryMonitor, sounds.theme, bar.morphingPanels |
Searchable + categorised module enable/disable, OSD indicators, hot corners, app launcher options, compositor fallback, panel-family picker, advanced toggles |
| Bar | bar, bars, tray |
A live preview of the bar, pill and dock you drag things in; edge picker, per-group module chips, click/scroll actions, layout sliders, weather, tray pinning |
| Dock | dock |
Position, style (pill/macOS), sizing, hover-reveal, window previews, pinned apps and their order |
| Sidebars | sidebar |
Behavior toggles (instant open, keep loaded), right-sidebar widget picker with empty-state warning, quick-slider sub-toggles |
| AnoSpot | anoSpot |
Position, per-widget visibility, click bindings, event border animation, drag/drop config + custom drop actions |
| Appearance | appearance, background, animations |
Theme source (Material You / static) with hover-preview, font picker, bezel preview, animation speed, wallpaper rotation |
| Overview | overview |
AnoView layout selector (11 cards) |
| Services | ai, autostart, gameMode, performance, powerProfiles, network, vpn, nightLight, lyrics, calendar, resources, light, shell, weather |
Toggle and configure every optional service (see Optional services below) |
| Displays | cursor, icons |
Monitor arrangement, mode, scale, rotation, VRR and profiles (through anod), cursor and icon themes |
| Keybinds | keyboard |
Search, record, add, change or remove binds; keyboard layouts |
| Atelier | atelier |
Themes, looks, pieces, plugins, lock screens, wallpapers and rices: browse, preview, install, use, undo |
| Actions | actions |
Macros: build, reorder, test and run step lists; the ring on Super+Ctrl+X (see docs/actions.md) |
Settings opens via qs -c ano ipc call settings toggle, the standalone window via qs -n -p ~/.config/quickshell/ano/settings.qml (or AnoShell Settings in your app launcher: anod/install.sh writes anoshell-settings.desktop; the window's app id is anoshell-settings, floating under the bundled Hyprland and niri rules), or Super+, (Hyprland default).
Each bar has a form (full, fit, islands, notch) and groups of
modules, each in a zone (start, center, end) and attached to the bar
body or detached as its own island. Switching forms animates live. End zones
read from the screen edge inwards. Full reference:
docs/configuration.md.
{
"bar": { "style": "classic", "form": "full" },
"bars": [{
"id": "main",
"edge": "top",
"form": "full",
"groups": [
{ "id": "start", "zone": "start", "modules": ["sidebarButton", "activeWindow"], "attached": true },
{ "id": "center", "zone": "center", "modules": ["workspaces"], "attached": true },
{ "id": "end", "zone": "end", "modules": ["clock", "battery", "network", "tray"], "attached": false }
]
}]
}A bar without groups still reads its older modules.left/center/right
lists. bar.style: "pill" (the default in the Ano family) makes the pill the
bar instead. Edit groups on Settings → Bar (drag chips between groups, detach a
group) or right-click a group on the bar.
Bar modules: sidebarButton, activeWindow, workspaces, clock, weather, battery, network, bluetooth, volume, tray, media, resources, keyboard (alias keyboardLayout), notifications, idle, privacy, gameMode, plus the ones listed in the add menu (drives, downloads, updates, KDE Connect…).
Switch entire layout presets atomically. A family is the set of modules it hosts, declared in modules/common/PanelGate.qml (familyModules); switching only loads/unloads the modules that differ. Turning a module off in Settings → Modules (or its own enable key) works in every family:
| Family | Includes | Best for |
|---|---|---|
ano |
Bar + Dock + both Sidebars + HUD + AI + Overview + Focus Time + Display Manager + everything | Default daily driver |
hefty |
Same as ano minus Focus Time/Display Manager; morphing panels always on |
Maximalist visual |
clean |
Bar + Sidebars + clipboard/cheatsheet/calendar. No dock, hot corners, HUD | Focused work |
minimal |
Bar + bare overlays only. No sidebars, no dock, no HUD | Lightweight / external launchers |
Connected mode and AnoSpot are available in every family.
Set via panelFamily: "ano"|"hefty"|"clean"|"minimal" in config.json, cycle with Ctrl+Super+P, or via qs -c ano ipc call panelFamily cycle. Switching plays a configurable ripple-transition animation (familyTransitionAnimation: true).
Configurable via sidebar.right.enabledWidgets[] in any order:
| Widget | Purpose |
|---|---|
systemButtons |
Uptime + reload/settings/session row |
quickSliders |
Volume / Brightness / (optionally) Mic |
quickToggles |
WiFi / Hotspot / BT / DND / Idle / NightLight pills |
networkDetail |
Bandwidth (rx/tx) + VPN status (auto-hides when both dormant) |
media |
Compact Mpris player |
notifications |
Recent notifications |
calendar |
Month grid |
systemInfo |
CPU / RAM / Battery gauges |
The night-light pill has a chevron — tap the body to toggle, tap the chevron to expand an inline temperature slider (animated reveal).
Two color sources, switched via appearance.theme.source:
materialYou(default) —MaterialThemeLoaderderives Material 3 palette from the active wallpaper via matugen.static—StaticThemeLoaderreadsassets/themes/<name>.json(or user override~/.config/anoshell/themes/<name>.json). 75 themes ship in the bundle (dark + light variants of Catppuccin, Dracula, Nord, Tokyo Night, Gruvbox, Kanagawa, Rosé Pine, Ayu, Eldritch, Noctalia, Inir, plus Angel and Aurora, and Crystal Neuo's six materials).
Pick from Settings → Appearance → Theme grid (hover-preview, click-to-commit). Themes optionally export glass_* keys consumed by Appearance.glassTokens for translucent surfaces (RecordingOsd, AnoSpot pill, AnoSpot stash popout).
Top/bottom/left/right pill overlay aggregating now-playing (Mpris), latest notification, recording indicator (with elapsed timer), clock/weather, workspace number, and battery. Compositor-agnostic (Hyprland + Niri). Click to expand into related panels; drag from a file manager to stage files for triage actions like sending via LocalSend.
"anoSpot": {
"enable": false,
"position": "top", // top | bottom | left | right (invalid → top)
"widthPx": 420, "heightPx": 36,
// Per-widget visibility
"showMpris": true,
"showNotification": true,
"showRecording": true,
"showClockWeather": true,
"showWorkspace": true,
"showBattery": true,
"showTimer": true, // live activity: a running countdown/pomodoro/stopwatch (click opens it)
"showPrivacy": true, // live activity: camera (green) / microphone (orange) dot, app name on hover
"notificationTimeoutMs": 4000,
// Brief morphs, each switchable: volume, brightness, mic, keyboard,
// notification, charging, recording, device, download, screenshot.
// Job-done ones (recording saved, download finished, screenshot taken)
// open their file on click. Rank: one on show is only replaced by one of
// at least its rank (levels < notification/device < charging < job-done;
// the volume etc. always show at once).
"transients": { "download": true, "screenshot": true /* , … */ },
// Click bindings — each value is the IPC target opened by `qs -c ano ipc call <target> toggle`
"actions": {
"leftClick": "mediaControls",
"rightClick": "controlPanel",
"middleClick": "anoview",
"scrollOnMpris": "audio" // wheel on the Mpris widget → volume up/down
},
// Animated gradient halo that pulses on configured events
"eventBorder": {
"enable": true,
"holdMs": 1500,
"events": ["notification", "track", "recording", "workspace"]
},
// Drag-handle to reposition (release snaps to nearest screen edge)
"draggable": true,
// Drag and drop
"acceptDrops": true,
"stashDir": "", // empty = auto ($XDG_RUNTIME_DIR/anoSpot, /tmp/anoSpot-<UID> fallback)
"dropTargets": [], // user-defined custom action buttons; see below
"shelfSize": 8 // shelf: newest copies + screenshots beside the pins (0 = pins only)
}Toggle from Settings → AnoSpot. Page warns when anoSpot.position collides with bars[0].edge (visual overlap likely).
| Trigger | Default action | Configurable via |
|---|---|---|
| Left click | open Media Controls | actions.leftClick |
| Right click | open Control Panel | actions.rightClick |
| Middle click | open AnoView (overview) | actions.middleClick |
| Wheel on Mpris area | volume up/down | actions.scrollOnMpris ("" = off) |
| Click Workspace widget | open AnoView (overview) | (hard-coded discoverability shortcut) |
Each actions.* value is the IPC target name; the dispatcher invokes qs -c ano ipc call <target> toggle. Set to "" to disable.
Drop files (or any text/uri-list payload) on the pill to stage them in an ephemeral stash directory. The popout opens with a thumbnail-grid view of the staged items, per-item × removal, and an action toolbar.
Built-in actions:
| Action | Behavior | Requires |
|---|---|---|
| LocalSend | mDNS + /24 sweep for LocalSend devices, then send each staged file to the picked device | python3, curl, openssl, iproute2 (all standard) |
| Open | xdg-open each staged item with the user's default app |
xdg-utils |
| Copy path | Newline-joined absolute paths to the wl-clipboard | wl-clipboard |
| Move to… | zenity directory picker, then mv each item there |
zenity |
| Reveal | xdg-open the parent directory in the user's file manager |
xdg-utils |
| Clear all | Empty the stash and close the popout | — |
The same popout is a shelf: below the dropped files, your pins (the clipboard's pins, clipboard-pins.json; a pinned screenshot is copied in) and the shelfSize newest clipboard entries and screenshots. Click copies (wl-copy, pictures with their MIME type), drag out drops the file (text/uri-list) or the text into another app, the corner pin pins/unpins. Open it with qs -c ano ipc call shelf toggle or a click action set to "shelf".
Stash directory resolution order:
Config.options.anoSpot.stashDirif non-empty (explicit override)$XDG_RUNTIME_DIR/anoSpot(preferred — per-user, ephemeral, auto-cleaned at logout)/tmp/anoSpot-<UID>(fallback ifXDG_RUNTIME_DIRis unset)
The directory is created on first use. Originals are never moved; AnoSpot stages copies and acts on those copies.
Add user-defined buttons to the popout footer via Config.options.anoSpot.dropTargets[]. Each rule:
{
"name": "Encode for web",
"icon": "compress", // any Material Symbols name
"action": "shell", // "exec" = argv-split (safe, no shell) | "shell" = bash -c
"command": "ffmpeg -i {path} -c:v libx264 -crf 28 {dir}/{name}.web.mp4",
"perItem": true // true = invoke once per staged item; false = once with full set
}Placeholder substitution:
| Placeholder | Substituted with |
|---|---|
{path} |
First item's full absolute path |
{name} |
First item's basename |
{dir} |
First item's parent directory |
{ext} |
First item's extension (without leading dot) |
{paths} |
Newline-joined absolute paths (full set) |
{names} |
Newline-joined basenames (full set) |
Action modes:
exec— Splitscommandon whitespace, substitutes each arg individually, runs the resulting argv directly. No shell, no globs, no pipes. Safe for paths with spaces or special characters.shell— Runscommandviabash -c; pipes, redirects, and globs work. Each placeholder becomes a variable ({path}→${ANO_PATH}, alsoANO_NAME,ANO_DIR,ANO_EXT,ANO_PATHS,ANO_NAMES), so a file name is never run as shell code. Quote it ("{path}") for names with spaces.
Edit the rule list in Settings → AnoSpot → "Custom drop actions" — fields, add, remove, and a built-in placeholder cheat-sheet.
The pill renders a gradient halo behind itself that pulses when configured events fire. Subscribe/unsubscribe per event type via eventBorder.events (e.g. drop "workspace" if it's too chatty for your workflow). Hold duration controls how long the halo stays visible before fading.
Renamed from
ActivSpot. If your existingconfig.jsonstill uses the oldactivSpotkey, it is migrated automatically on first start (values copied toanoSpot, old key removed; one-shot, idempotent).
Layouts: smartgrid, justified, bands, masonry, hero, spiral, satellite, staggered, columnar, vortex, random
overview.liveThumbnails (Settings → Overview): off (default, one still frame per window), hovered (only the hovered or selected window streams) or all (the first 12 stream). Covers the overview, the task view and the Alt+Tab list, and streams only while the view is open; the fan switcher is always live.
Providers: Gemini (2.5 Flash, 3 Flash), Anthropic (Claude Sonnet 4, Haiku 3.5), OpenAI (GPT-4.1 Mini), Mistral (Medium 3), OpenRouter (dynamic free models), Ollama (local auto-detect). Commands: /model, /key, /temp, /prompt, /save, /load, /clear
All of the following are disabled by default. Enable from Settings → Services or by editing config.json directly.
| Block | Purpose | Notable keys |
|---|---|---|
gameMode.enable |
Bar indicator while a game holds GameMode | — |
performance |
Performance mode: what turns it on (onGameMode on by default, onFullscreen, apps globs) and what it pauses |
stopAnimations, stopBlur, stopVisualizers, holdPopups, stopShadows, hidePieces, slowPolling + pollInterval, manual; Hyprland: hyprAnimations, hyprBlur, hyprShadows (on), hyprGaps, hyprRounding, hyprTearing (off), restored after (docs/extras.md); IPC performance toggle|on|off|status |
sounds |
Sound effects: login, notifications, panels, alerts (all off) | volume, alertThreshold, alertGap; IPC sounds play <name> |
autostart.entries |
Startup applications anod starts once per login | [{desktopId | command, enabled, delayMs}] |
powerProfiles.restoreOnStart |
Restore last power-profiles-daemon profile on shell start |
preferredProfile (auto-populated when you change profiles) |
network.usage |
Per-interface rx/tx polling for the sidebar bandwidth panel | intervalMs, historyLength |
network.hotspot |
WiFi tethering toggle backed by nmcli device wifi hotspot |
ssid, password (auto-generated on first enable) |
vpn |
Generic VPN status + connect/disconnect for tailscale/netbird/warp/wireguard/custom | providers[], notifyOnChange |
calendar |
KHal/CalDAV pull into the calendar panel | upcomingDays, externalSync.{enable, refreshMinutes, sources[]} |
lyrics |
Synced lyric overlay in MediaControls + AnoSpot | enable, backend, dir |
nightLight |
wlsunset-backed warm-shift (Hyprland, niri, sway) | enable (on now), schedule (off/sun/times), start, end, fade (min), dayTemp, nightTemp, latitude, longitude, gamma, outputs |
lock.notifications |
Mirror notifications onto the lock screen | maxItems |
lock.osk |
On-screen keyboard for password entry | — |
lock.statusRow |
Battery + WiFi + clock chips on the lock screen | — |
lock.dim |
Auto-dim the lock background after idle | idleMs, opacity |
lock.passwordInput.expandOnFocus |
Animate the password field on focus | — |
anoSpot.showLyrics |
Swap track title for the current lyric line | requires lyrics.enable |
anoSpot.workspaceHoverPreview |
Hover the workspace pill to see live thumbnails | openDelayMs, closeDelayMs, thumbnailWidth, thumbnailHeight |
dock.previews |
Rest on a running app in the dock to see its windows as live thumbnails (up to 6); click focuses, middle-click closes | — |
appearance.theme |
Switch between dynamic Material You and bundled static themes | source (materialYou/static), name (theme name; see the bundled themes) |
appearance.theme.source = "static" activates the StaticThemeLoader, which reads assets/themes/<name>.json (or ~/.config/anoshell/themes/<name>.json to override). 75 themes ship in the bundle (Catppuccin, Dracula, Nord, Tokyo Night, Gruvbox, Kanagawa, Rosé Pine, Ayu, Eldritch, Noctalia, Aurora, Inir, Angel, Crystal Neuo's six materials — most with dark/light variants).
Every module is toggleable via the enabledPanels array (empty = all) or the Modules settings page, in every panel family. A module loads only when its family hosts it, you haven't switched it off, its own feature key (e.g. dock.enable, focusTime.enable) is on, and the compositor supports it — see modules/common/PanelGate.qml. Disabled modules are never even compiled.
- Every key lives in the schema (
modules/common/Config.qml), the bundled defaults (config.json) and is read by runtime code outsidemodules/settings/. - Runtime code changes settings only through
Config.setNestedValue("a.b", value); it is a no-op when the value doesn't change, so controls echoing their initial value never write. - Per-bar fields in
bars[]arenullto follow the global setting. - After adding or renaming a control or key, run:
python3 scripts/dev/settings-index.py # regenerate the palette label index
python3 scripts/dev/settings-audit.py # exit 1 on dead, undeclared, mismatched keys or a stale indexqs -c ano ipc call <target> <method>| Target | Methods |
|---|---|
bar |
toggle, open, close |
sidebarLeft / sidebarRight |
toggle, open, close |
anoview |
toggle [layout], open, close |
overviewWorkspacesToggle |
toggle (workspace-strip overview) |
settings / settingsStandalone |
toggle, open / open |
audio |
toggleMute, toggleMicMute, increment, decrement |
brightness |
increment, decrement, status (per screen: percent, backlight or DDC, as JSON) |
mpris |
pauseAll, playPause, previous, next |
idle |
toggle, enable, disable |
hud |
toggle, open, close |
session |
toggle, open, close |
actions |
run name (queued if one runs), list, ring (toggle) |
dock |
toggle, pin, unpin |
notifications |
toggleDnd, setDnd on, clearAll, status, list, reply id text |
config |
get key, set key json, reset key, undo (a JSON array must start with a space, ' ["a","b"]': qs ipc call splits an argument that starts with [) |
focus |
toggle, on, off, status (bar away + Do Not Disturb) |
undo |
last, list (the Undo toast after a removal) |
dropTerminal |
toggle, open, close, status (Super+Shift+T; extras) |
pieces |
add id, remove id, place id col row, move uid col row, list, grid, next, prev, page n, edit, done |
clock |
toggle, open, close, countdown seconds, stopwatch, dismiss, snooze, next |
shelf |
toggle, open, close (the pill's shelf) |
performance |
toggle, on, off (performance mode by hand), status |
sharePicker |
pick, pending, cancel (used by ano share-pick, not by hand) |
clipboard / cliphistService |
toggle, open, close / direct cliphist actions |
altSwitcher |
show, hide, next, prev, activate |
search |
toggle, open, close |
taskView |
toggle, open, close |
mediaControls |
toggle, open, close |
controlPanel |
toggle, open, close |
weatherPanel |
toggle, open, close |
calendar |
toggle, open, close |
recordingOsd |
toggle, open, close |
cheatsheet |
toggle, open, close |
lock |
lock |
wallpapers / wallpaperSelector |
apply path / toggle |
ai |
run "text or /command" |
panelFamily |
cycle, set family |
shell |
reload, quit |
screenCorners |
enable, disable, toggle |
focusTime |
toggle, open, close |
displayManager |
toggle, open, close |
antiFlashbang |
toggle, enable, disable |
niriKeybinds |
reload (re-parse KDL) |
minimize |
toggle (Niri minimize emulation) |
zoom |
zoomIn, zoomOut |
TEST_ALIVE |
(no methods — existence check) |
Source files: ~/.config/hypr/Ano/hyprland/keybinds.conf (defaults, tracked) and ~/.config/hypr/Ano/custom/keybinds.conf (user overrides, sourced after defaults). Equivalent Niri bindings live at ~/.config/niri/ano.kdl. Both are reachable via symlinks under external/{niri,hyprland}/ inside this repo.
| Key | Action |
|---|---|
Super (tap) |
Search/launcher |
Super+Tab |
Overview (AnoView) |
Super+`` |
Task view |
Super+B |
Left sidebar (AI/notifications) |
Super+N |
Right sidebar (controls) |
Super+A |
App search |
Super+I |
Control panel |
Super+, |
Settings |
Super+Shift+I |
HUD |
Alt+V |
Clipboard history |
Super+O |
Media controls |
Super+X |
Session menu |
Super+/ |
Cheatsheet |
Super+Shift+B |
Toggle bar |
Super+Shift+D |
Toggle dock |
Super+Shift+W |
Weather panel |
Super+Shift+F |
FocusTime tracker |
Super+− / Super+= |
Zoom out / in |
Ctrl+Super+D |
Display manager |
Ctrl+Super+T |
Wallpaper selector |
Ctrl+Super+B |
Anti-flashbang shader |
Ctrl+Super+P |
Cycle panel family |
Ctrl+Super+R |
Restart QuickShell |
| Key | Action |
|---|---|
Super+Shift+T |
Dropdown terminal |
Super+M |
Toggle minimized workspace |
Super+Shift+- |
Minimize/restore window |
Ctrl+Super+L |
Fetch lost windows |
| Key | Action |
|---|---|
Super+Shift+S |
Region screenshot |
Super+Shift+X |
OCR (text recognition) |
Super+Shift+G |
Google Lens search |
Super+Shift+R |
Screen recording |
Super+Shift+C |
Color picker |
Print |
Full screenshot to clipboard |
Shift+Print |
Region screenshot (swappy) |
| Key | Action |
|---|---|
Super+Space |
Toggle floating |
Super+F |
Fullscreen |
Super+S |
Toggle split |
Super+Q |
Kill active |
Super+C |
Center window |
Super+G |
Toggle group |
Super+Alt+A |
Toggle special workspace |
Super+Shift+A |
Move to special workspace |
Super+1-0 |
Switch workspace 1-10 |
Super+Shift+1-0 |
Move to workspace 1-10 |
| Key | Action |
|---|---|
Super+L |
Lock screen |
Super+Shift+L |
Suspend |
Super+Alt+F1 |
VM mode (disable keybinds) |
| Package | Purpose |
|---|---|
quickshell (tested with 0.3.2) |
Shell framework |
awww + awww-daemon |
Wallpaper engine |
matugen ≥4.0 |
Material You color generation; the Theme studio |
jq |
JSON parsing in scripts |
brightnessctl |
Screen backlight |
NetworkManager (nmcli) |
WiFi/Ethernet, USB/Bluetooth tethering, mobile broadband, VPN/WireGuard connections (a VPN plugin such as networkmanager-openvpn for its type) |
cliphist + wl-clipboard |
Clipboard, AnoSpot Copy-path action |
curl |
HTTP (weather, AI chat, AnoSpot LocalSend send) |
openssl |
Random fingerprint for AnoSpot LocalSend |
iproute2 (ip) |
Network introspection for AnoSpot LocalSend discovery; the default route (which wired/tether link carries traffic) |
libnotify |
Notifications, AnoSpot LocalSend status messages |
python3 |
Scripts (general + AnoSpot LocalSend discovery/send) |
xdg-utils (xdg-open) |
AnoSpot Open / Reveal actions |
Sway (1.12+), Mango (0.18), labwc (0.20) and Umbriel (0.1) sessions have their own backends and bundled configs (external/sway/ano.conf, external/mango/ano.conf, external/labwc/, external/umbriel/ano.toml); see docs/compositors.md. Sway needs swaymsg (part of sway), Umbriel its umbriel CLI (part of umbriel); Mango and labwc need nothing extra (labwc users with a <privilegedInterfaces> block must allow the protocols listed there).
For the Niri session specifically, niri ≥ 26.04 is required — ~/.config/niri/ano.kdl uses the background-effect { blur } and window-rule popups { … } blocks introduced in 26.04 for visual parity with Hyprland-Ano.
pyprland (minimize, lost windows), pywal (terminal colors), ddcutil (external monitors), cava (spectrum), zenity (file picker — required for AnoSpot's "Move to…" action), ydotool (paste), translate-shell (translator), wf-recorder (screen recording — drives AnoSpot's recording widget), xdg-desktop-portal-* (one of -gtk/-kde/-hyprland — file open/screenshare integration; almost always already installed by the desktop)
ffmpeg, hyprpicker, qalc (calculator), grim+slurp (screenshot), wlsunset (night light — works on any wlroots session), localsend (the GUI app — only needed on the receiving device for AnoSpot's LocalSend action; the sender side ships ready-to-use scripts in scripts/anoSpot/)
Each AnoSpot widget/action and the underlying tool that makes it work:
| Surface | Provided by |
|---|---|
| Mpris widget | Mpris D-Bus (any modern player); playerctl recommended |
| Notification widget | libnotify-emitted notifications via the QS service |
| Recording widget | a recorder: gpu-screen-recorder, wl-screenrec or wf-recorder; ffmpeg (finish thumbnail), gio (Discard to trash), pactl (system + mic mix) |
| Battery widget | UPower D-Bus (standard on every Linux desktop with a battery) |
| Workspace widget | CompositorService → Hyprland or Niri IPC |
| Clock/Weather widget | Built-in DateTime + Weather services |
| Timer activity | Built-in Pomodoro service (Clock panel, timer piece, sidebar card) |
| Privacy activity | PipeWire (Quickshell); anod for cameras opened directly |
| Download transient | anod (downloads watcher); xdg-open to open the file |
| Screenshot / recording transient | the screenshot / recorder services; xdg-open to open the file |
| Click bindings | QuickShell IPC (qs -c ano ipc call …); no external deps |
| Drag handle | Qt MouseArea; no external deps |
| Drop target | QML DropArea (Wayland data-device protocol) |
| Stash | bash + cp/rm/stat/du/mkdir/ls (coreutils) |
| Shelf | cliphist + wl-clipboard (copy, pins); drag-out via the Wayland data-device protocol |
| Action: LocalSend | bash, python3, curl, openssl, iproute2 |
| Action: Open / Reveal | xdg-utils (xdg-open) |
| Action: Copy path | wl-clipboard (wl-copy) |
| Action: Move to… | zenity (file picker) + coreutils mv |
| Action: Custom | whatever your rule's command invokes |
If any dependency is missing, the corresponding action shows a notify-send failure message but the rest of AnoSpot keeps working.
What each feature needs from the system (ano doctor checks the binaries):
| Feature | Needs | Without it |
|---|---|---|
| Apps launched in their own unit (dock, launcher, default apps) | a systemd user manager (systemd-run, systemctl), else setsid (util-linux) |
plain detached launch |
| Password prompt (polkit) | polkit (polkitd; pkaction for Details), procps-ng (pgrep, ps) for the pkexec command in Details; no other agent running (e.g. hyprpolkitagent) |
another agent answers, Settings says so |
Blur behind the polkit prompt (polkit.blur) |
the bundled Hyprland/niri layer rules for quickshell:polkit / quickshell:polkitPlain |
the compositor's own rules decide |
| Sensitive clipboard entries skipped | wl-clipboard (wl-paste --watch) + cliphist (verified with 0.7.0) |
password-manager copies land in the history |
| Privacy: microphone, PipeWire cameras | PipeWire + WirePlumber | not shown |
Volume bar module (volume), output/input device pickers (Settings → General → Audio, sidebar, control panel) |
PipeWire + WirePlumber | no volume, no devices listed |
| Privacy: cameras opened directly | anod running (inotify on /dev/video*, no packages) |
only PipeWire cameras shown |
| Privacy: screen sharing | Hyprland (screencast events); portal casts via xdg-desktop-portal + -hyprland (or -gnome on niri) and PipeWire |
not shown (a browser sharing its own tab is never visible to the desktop) |
Long-running helpers (nmcli monitor, wlsunset, cava, udevadm monitor) |
setpriv (util-linux): started with --pdeathsig TERM so they end with the shell, even a killed one |
the helper fails to start |
Network (bar network, sidebar, Network Orbit, Settings → Services → NetworkManager VPNs) |
NetworkManager running; Quickshell's Quickshell.Networking module (part of Quickshell when built with its network module, the default; reads Wi-Fi state and networks over NetworkManager's D-Bus); nmcli (scans, connect, hotspot, wired links, VPN and WireGuard profiles, nmcli monitor); ip (iproute2) for the link carrying traffic; a NetworkManager VPN plugin (e.g. networkmanager-openvpn) for that VPN type |
no networks listed; a VPN type without its plugin won't connect |
Brightness (OSD keys, sliders, brightness IPC) |
brightnessctl for backlights; ddcutil (and the i2c-dev module) for external monitors over DDC/CI |
that screen gets no slider (an external screen without DDC is left alone) |
Removable drives (bar module drives) |
udisks2 (udisksctl), util-linux (lsblk ≥ 2.37 for MOUNTPOINTS), udev (udevadm: systemd-udev or eudev), libnotify (notify-send) |
no drives listed / no notifications |
Night light (Settings → Services, bar/pill module nightlight, sidebar toggle) |
wlsunset; a compositor with wlr-gamma-control (Hyprland, niri, sway) |
the toggle does nothing |
Qt apps in the palette (appearance.theme.qt) |
qt6ct (and QT_QPA_PLATFORMTHEME=qt6ct); qt5ct for Qt 5 apps; kvantum for the default Kvantum mode |
Qt apps keep Qt's default look |
Terminal colours (appearance.theme.terminals, docs/wallpaper.md) |
the terminal (kitty, Ghostty, foot); jq; pkill (procps-ng) to recolour running kitty/Ghostty windows |
that terminal keeps its own colours; without pkill only new windows change |
Downloads (bar/pill module downloads) |
anod running (inotify on the download folder from user-dirs.dirs, else ~/Downloads); xdg-utils (xdg-open) to open |
not shown |
| Keyboard layout catalogue (Settings → Keybinds) | xkeyboard-config (/usr/share/X11/xkb/rules/evdev.xml), anod running |
no catalogue to pick from |
Bioma organisms (pieces bioma-*) |
qt6-5compat (Qt5Compat.GraphicalEffects); weather and photoperiod: curl and Open-Meteo (geocoding-api.open-meteo.com, api.open-meteo.com, no key); media band: cava and an MPRIS player; disks: df; system organisms: /proc, /sys, upowerd for the battery, pgrep/awk/sed/xargs for cytoplasm; recent files: ~/.local/share/recently-used.xbel; rings: stat, ext-idle-notify |
the organism shows why it's empty |
| Location (Settings → Services → Location: weather, night light's sunset schedule, the Bioma pieces' sun and moon) | automatic: geoclue (the GeoClue 2 service, Wi-Fi/GPS) and qt6-positioning (its geoclue2 plugin); fallback and city name: curl to ip-api.com (sends your IP address, city-level); manual: nothing |
weather falls back to its city setting or wttr.in's guess; the sunset schedule waits |
Weather warnings and rain soon (bar.weather.alerts) |
anod running (HTTP in Go, no extra binaries) and a known location; network access to nominatim.openstreetmap.org (country lookup, once per place) and the country's feed: api.weather.gov (US), api.met.no (Norway), api.brightsky.dev (Germany), feeds.meteoalarm.org (rest of Europe); libnotify (notify-send); rain soon: curl to wttr.in (as the weather) |
no warnings (other countries have no feed); no notifications |
Music recognition (musicRecognition.enable) |
songrec (uses Shazam's unofficial service), pipewire (pw-record), libnotify (notify-send ≥ 0.7.10 for the Copy/Search actions), wl-clipboard |
"Not recognised: songrec gave no answer" |
Device event pills (deviceEvents) |
BlueZ (Bluetooth), PipeWire (audio output), udev's udevadm (USB; systemd-udev or eudev) |
that kind of event isn't shown |
| Caps Lock / Num Lock OSD, lock screen Caps Lock warning | Hyprland: the bundled Caps_Lock/Num_Lock binds (non-consuming) and hyprctl (reads the main keyboard, so keyd and other virtual keyboards are fine); elsewhere: keyboard LEDs in /sys/class/leds (read only while locked; bind a key to qs ipc call lockKeys refresh for the OSD) |
no lock-key OSD; no warning |
Package updates (updates.enable, bar module updates) |
pacman-contrib (checkupdates); paru or yay for AUR counts; a terminal (Settings → Default apps) to run the update |
no count / AUR not counted |
Shell errors (Settings → About → Errors, ano doctor) |
anod running (reads Quickshell's log in $XDG_RUNTIME_DIR/quickshell/by-pid/) |
the card says it needs anod; ano doctor reads the log itself |
Atelier (Settings → Atelier, ano atelier) |
anod running (downloads, checksums and archives in Go, no extra binaries); catalogs need the network | the page says anod isn't running; catalogs show the cached index |
News piece (news) |
curl to news.google.com (RSS, no key; local news sends the place you set); source icons: Google's favicon service (www.google.com/s2/favicons, sends only the source's site; off with the widget's "Source icons" setting) |
the widget says it couldn't reach Google News; no icons |
| Pieces: lyrics, world clock, palette, screen time | lyrics: as the Lyrics service (lyrics.enable; curl to lrclib.net / NetEase, find for local .lrc); world clock: coreutils (date), sh and tzdata (/usr/share/zoneinfo); palette: wl-clipboard (wl-copy); screen time: anod running and screenTime.enable |
the piece says what's missing; the world clock marks an unknown zone; copying does nothing |
| Clock | the system clock; keep it synchronised (systemd-timesyncd: sudo timedatectl set-ntp true, or chrony) — ano doctor warns when it isn't |
the clock drifts |
EasyEffects quick toggle and presets (audio.easyEffects.enable) |
easyeffects ≥ 7 running (its CLI: -b, --bypass-toggle, -p, -l); the shell never starts it |
the pill stays hidden |
Sound effects and battery sounds (sounds.*) |
pipewire (pw-play); battery sounds: a sound theme (sound-theme-freedesktop) |
silence |
Startup applications (autostart.entries) |
anod running; a systemd user manager (systemd-run, systemctl), else setsid (util-linux) |
nothing starts at login |
Performance mode for listed apps (performance.apps) |
nothing (the compositor's window list) | — |
Performance mode's Hyprland levers (performance.hypr*) |
Hyprland with the Lua config (hyprctl getoption, hyprctl eval) |
not applied (nothing happens on niri) |
| Game mode indicator, performance mode during games | gamemode (gamemoded; games run with gamemoderun or libgamemode), dbus (dbus-monitor), systemd (busctl) |
performance mode only by hand or for fullscreen windows |
| Palette cursors and icons | librsvg (rsvg-convert), imagemagick (magick) |
the palette themes can't be built |
Lock screen (niri; lock.enable, lock.screen) |
pam with /etc/pam.d/login (the password check, faillock included); a compositor with ext-session-lock-v1; glib2 (gdbus) to lock on loginctl lock-session |
Super+L and qs ipc call lock lock still lock; loginctl lock-session (session menu, idle tools) doesn't |
KDE Connect (kdeConnect.enable, off by default; bar module "Phone") |
kdeconnect with kdeconnectd running (the shell doesn't start it; the bundled Hyprland/niri configs do), systemd (busctl), glib2 (gdbus), util-linux (setpriv); sending a file: zenity |
no pill and no phone actions; a hung kdeconnectd shows as not answering |
Fingerprint unlock (niri lock; lock.fingerprint.enable, off by default) |
fprintd (fprintd-list, pam_fprintd.so) and at least one enrolled print (fprintd-enroll); the shell's own modules/lock/pam/fprint service, no faillock |
password only |
Launcher plugins (search.userPlugins; bundled clipboard, websearch, files, kaomoji, unicode, keybinds, windows) |
nothing for the loader; clipboard needs cliphist; files needs fd; kaomoji, unicode and keybinds copy with wl-copy (wl-clipboard); keybinds needs anod |
that plugin shows nothing (keybinds says anod isn't running) |
Scratchpad & Pins (scratchpad.enable, off by default) |
wl-clipboard (copy), libnotify (notify-send: failed background commands), a terminal (Settings → Default apps) for terminal pins; ?? needs an AI provider (left sidebar) |
no copy / no failure notice / terminal pins don't open / ?? says no provider |
Text recognition (Super+Shift+X, screenshot ocr) |
tesseract and the data for each of screenshot.ocrLanguages (tesseract-data-eng by default); on Hyprland and other wlroots: grim + slurp; wl-clipboard |
a notification names what's missing |
Clock panel alarms and world clocks (middle-click the bar clock, qs ipc call clock toggle) |
libnotify (notify-send ≥ 0.7.10: the Snooze/Dismiss actions), pipewire (pw-play) and a sound theme with alarm-clock-elapsed (sound-theme-freedesktop) for clock.alarmSound; world clocks: coreutils (date, test) and tzdata (/usr/share/zoneinfo) |
no alarm notification / a silent alarm / "Unknown time zone" |
Frame jelly (appearance.connectedCorners.jelly) |
nothing (a spring in the frame shader) | — |
Screen-share picker (Hyprland; sharePicker.enable, Settings → Services → Screen sharing) |
xdg-desktop-portal-hyprland with custom_picker_binary in ~/.config/hypr/xdph.conf set to scripts/share-picker (the Settings button or ano share-pick install writes it, after a backup); ano (~/.local/bin or PATH); region: slurp; fallback: hyprland-share-picker (ships with xdph) |
the stock picker opens |
Actions (Settings → Actions, the ring on Super+Ctrl+X, actions IPC) |
per step: open file/URL xdg-utils (xdg-open); shell command sh; brightness as for brightness (brightnessctl, or ddcutil for external monitors); power profile power-profiles-daemon; wallpaper anod (else awww) |
that step fails, a notification names it, and the steps after it don't run |
| Umbriel session | umbriel ≥ 0.1 (its CLI: umbriel subscribe for workspaces, windows and layouts, umbriel msg for actions) and UMBRIEL_SOCKET, which umbriel exports; shell blur from the layer rules in external/umbriel/ano.toml |
the generic backend (ext-workspace, foreign-toplevel); no blur |
Dropdown terminal (Super+Shift+T, dropTerminal) |
a terminal that sets its window class: kitty, foot, alacritty, ghostty or wezterm (Settings → Default apps); on Umbriel the anodrop scratchpad from external/umbriel/ano.toml |
a notification says the terminal can't; on Umbriel without that file it doesn't hide |
Live pins (Super+Alt+P, livePins) |
window capture: Hyprland (hyprland-toplevel-export) | not offered on other compositors |
Tested on Quickshell 0.3.2 (Qt 6.11), Hyprland (Lua config) and polkit with pam_faillock.
Wallpaper → awww (apply) → matugen (Material You → colors.json) → MaterialThemeLoader
→ pywal (terminal colors + cava gradients)
→ gtk.css block (anod, GTK 3/4 + libadwaita; appearance.theme.gtk)
→ applycolor.sh (kitty/ghostty/foot/Qt)
Wallpapers are applied by anod: `ano wallpaper set IMAGE` (awww, matugen colours, then `background.hooks`).
Foundation: StyledText, MaterialSymbol, Circle, PointingHandInteraction, FadeLoader, Revealer, StyledImage, WavyLine, DragManager, RoundCorner
Controls: RippleButton, StyledSlider, StyledSwitch, StyledProgressBar, CircularProgress, CombinedCircularProgress, Graph, StyledScrollBar, StyledFlickable (fades its top/bottom edge where content is cut off; edgeFade: false opts out), Tooltips, StyledTextInput/Area
Composite: ToolbarButton, Toolbar, GroupButton, ButtonGroup, ConfigRow/Switch/Slider, ConfigTextInput (placeholder + validator + inline errors), ChoiceRow (single-select icon-row picker), RestartRequiredBadge (clickable reload-now pill), ContentSection, NoticeBox, KeyboardKey, CalendarView, NotificationItem, StyledBlurEffect, StyledDropShadow, ScrollEdgeFade (gradient edge fade for any Flickable/ListView, colour taken from the background behind it), StyledPopup, SettingsCard (with configKeys for command-palette resolution), SettingsPageHeader (per-page reset), SettingsCommandPalette (Ctrl+K dynamic-search overlay)
Animation: Anim, CAnim, AbstractChoreographable, FlyFadeEnterChoreographable, ChoreographerLayout
Morph: ShapeCanvas, MorphedPanel, TopLayerPanel, BarWidgetPopout, BarModulePopout (16 JS shape files)
Spectrum: LinearSpectrum, MirroredSpectrum
Set morphingPanel: true on any bar in bars[] to use polygon-based ShapeCanvas backgrounds that morph between states. The BarModulePopout wrapper auto-detects morph mode — 8 bar modules have rich morph-capable popouts.
Built from: @rebels (base), @hyprview (layouts), @inir (Niri/dock/alt-switcher/translator), @ilyamiro (FocusTime/display manager/Network Orbit/widget designs), @caelestia (animations/HUD), @noctalia-shell (spectrum/settings), @end-4 (AI chat/anti-flashbang/systray menus), @end-4 hefty-hype (polygon morphing system), wallpaperpicker (wallpaper card deck, spectrum ribbon, Wallhaven source)
Bioma (GPL-3.0: palette cursors and icon themes, the Bioma Gate lock screen, the sound effects in assets/sounds and their player, the files launcher plugin, the desktop "organisms" in pieces/bioma-* with their support code in pieces/_bioma, downloads, ideas throughout), novelmangareader (GPL-3.0: the reader), dhrruvsharma (GPL-3.0: the clock faces piece, the kaomoji list), iNiR theme presets (GPL-3.0: 37 colour themes).
GPL-3.0 (LICENSE), as the ported Bioma and novelmangareader code requires.
Source tree (click to expand)
ano/
├── shell.qml # Entry point — panel-family loader, IPC handlers
├── settings.qml # Standalone Settings window (FloatingWindow)
├── GlobalStates.qml # All panel/overlay open/close states
├── config.json # Bundled defaults (read-only at runtime)
│
├── modules/
│ ├── common/ # Singletons + reusable widgets
│ │ ├── Config.qml # JSON config R/W; user delta lives at ~/.config/anoshell/config.json
│ │ ├── Appearance.qml # MD3 colors, glass tokens, fonts, animation curves, previewTokens
│ │ ├── Directories.qml # XDG paths, theme paths, user-config path
│ │ ├── AnimationConfig.qml # Animation presets
│ │ ├── FamilyTransitionOverlay.qml
│ │ ├── functions/ # ColorUtils, DateUtils, FileUtils, Format (formatDuration), ObjectUtils, StringUtils
│ │ └── widgets/ # 50+ reusable widgets (see Widget Library)
│ │ ├── shapes/ # Polygon morph system (16 JS + 1 QML from hefty-hype)
│ │ └── spectrum/ # LinearSpectrum, MirroredSpectrum (cava)
│ │
│ ├── bar/ # Multi-bar system
│ │ ├── BarManager.qml # Creates N bars per monitor, respects morphingPanel
│ │ ├── BarWindow.qml # PanelWindow on any edge
│ │ ├── BarContent.qml # Spacing/padding/click/scroll actions
│ │ ├── BarGroup.qml # Rounded pill container
│ │ └── modules/ # 17 bar modules (see Bar Modules list)
│ │
│ ├── overview/ # AnoView with 11 layout algorithms
│ ├── taskView/ # Current-workspace window view
│ ├── altSwitcher/ # Alt-Tab switcher with thumbnails
│ ├── search/ # App launcher + calculator
│ ├── sidebarLeft/ # AI Chat | Notifications | Translator
│ ├── sidebarRight/ # Configurable widget stack (see Sidebar Right widgets)
│ ├── controlPanel/ # Floating notification-shade
│ ├── settings/ # 10-page settings system + SettingsKeyHandler + SettingsPageHeader + SettingsCommandPalette (Ctrl+K) + SettingsRegistry (dynamic search index)
│ ├── osd/ # 6-indicator on-screen display
│ ├── hud/ # Heads-up display
│ ├── session/ # Power menu: actions around the avatar, press twice to confirm
│ ├── dock/ # Pill / macOS application dock
│ ├── clipboard/ # cliphist browser
│ ├── mediaControls/ # Full media player with vinyl art + lyrics
│ ├── weather/ # Detailed weather panel
│ ├── notifications/ # Notification list component
│ ├── notificationPopup/ # Floating popup notifications
│ ├── cheatsheet/ # Searchable keybinds viewer
│ ├── wallpaperSelector/ # Wallpaper card deck (local / favourites / Wallhaven)
│ ├── lock/ # Niri lock screen + opt-in notifications/OSK/status row
│ ├── focusTime/ # App-usage tracker UI
│ ├── displayManager/ # Hyprland-only monitor config
│ ├── screenCorners/ # Hot corners
│ ├── recordingOsd/ # Live screen-recording overlay
│ ├── calendar/ # Standalone calendar with event dots
│ └── anoSpot/ # Dynamic-island pill + drag/drop stash + workspace hover-preview
│
├── services/ # 42 service singletons (see Services section)
│
├── assets/themes/ # 75 bundled static themes
├── layouts/ # 11 overview layout algorithms
│
├── scripts/
│ ├── colors/applycolor.sh # app colours (an anod wallpaper hook)
│ ├── hyprland/get_keybinds.py
│ ├── anoSpot/ # LocalSend send/discover scripts
│ └── focustime/{focus_daemon,get_stats}.py
│
├── plugins/ # C++ extension point placeholder
├── external/ # Bundled compositor configs (Hyprland, niri, sway, mango, labwc, Umbriel)
└── translations/ # Future content