Skip to content
AnoRebelPublic

About

A QuickShell desktop shell for Hyprland and Niri.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

AnoShell

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/

What's in it

  • 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/.

Quick Start

# 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.qml

To start it with your session, use the bundled compositor configs (external/: Hyprland, niri, sway, mango, labwc, Umbriel); see docs/installation.md.

Services

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.

Compositor & windows

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.

Audio, brightness, input

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.

Network, devices, system

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.

Theme & appearance

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.

Media

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.

Time, weather, notifications, calendar, AI

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.

AnoSpot

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.

Configuration

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.

How config persistence works

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.height doesn't wipe bar.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.

Settings pages

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).

Bar System

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…).

Panel Families

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).

Sidebar Right widgets

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).

Theme system

Two color sources, switched via appearance.theme.source:

  • materialYou (default) — MaterialThemeLoader derives Material 3 palette from the active wallpaper via matugen.
  • static — StaticThemeLoader reads assets/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).

AnoSpot (dynamic-island overlay)

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).

Click bindings

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.

Drag and drop

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 —

Shelf

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:

  1. Config.options.anoSpot.stashDir if non-empty (explicit override)
  2. $XDG_RUNTIME_DIR/anoSpot (preferred — per-user, ephemeral, auto-cleaned at logout)
  3. /tmp/anoSpot-<UID> (fallback if XDG_RUNTIME_DIR is unset)

The directory is created on first use. Originals are never moved; AnoSpot stages copies and acts on those copies.

Custom drop actions

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 — Splits command on 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 — Runs command via bash -c; pipes, redirects, and globs work. Each placeholder becomes a variable ({path} → ${ANO_PATH}, also ANO_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.

Event border animation

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 existing config.json still uses the old activSpot key, it is migrated automatically on first start (values copied to anoSpot, old key removed; one-shot, idempotent).

Overview (AnoView)

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.

AI Chat

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

Optional services

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).

Module Enable/Disable

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.

Keeping settings wired (developers)

  • Every key lives in the schema (modules/common/Config.qml), the bundled defaults (config.json) and is read by runtime code outside modules/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[] are null to 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 index

IPC Commands

qs -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)

Keybinds (Hyprland)

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.

QuickShell UI Toggles

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

Pyprland

Key Action
Super+Shift+T Dropdown terminal
Super+M Toggle minimized workspace
Super+Shift+- Minimize/restore window
Ctrl+Super+L Fetch lost windows

Screenshots & Capture

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)

Window Management

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

Session

Key Action
Super+L Lock screen
Super+Shift+L Suspend
Super+Alt+F1 VM mode (disable keybinds)

External Packages

Required

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.

Recommended

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)

Optional

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/)

AnoSpot dependency map

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.

System integration dependency map

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.

Color Pipeline

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`).

Widget Library (50+ components)

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

Morphing Panel System (from hefty-hype)

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.

Credits

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).

Licence

GPL-3.0 (LICENSE), as the ported Bioma and novelmangareader code requires.

Architecture

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

About

A QuickShell desktop shell for Hyprland and Niri.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages