{"id":50065685,"url":"https://github.com/jfreed-dev/niri-screensaver","last_synced_at":"2026-05-31T07:30:48.980Z","repository":{"id":356539762,"uuid":"1232988988","full_name":"jfreed-dev/niri-screensaver","owner":"jfreed-dev","description":"Terminal-based screensaver for Niri (TerminalTextEffects + Noctalia plugin)","archived":false,"fork":false,"pushed_at":"2026-05-16T13:41:47.000Z","size":1167,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-16T15:08:58.454Z","etag":null,"topics":["ascii-art","niri","noctalia","quickshell","screensaver","terminal","terminaltexteffects","wayland"],"latest_commit_sha":null,"homepage":"https://github.com/jfreed-dev/niri-screensaver","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jfreed-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-08T13:26:10.000Z","updated_at":"2026-05-16T13:41:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jfreed-dev/niri-screensaver","commit_stats":null,"previous_names":["jfreed-dev/niri-screensaver"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jfreed-dev/niri-screensaver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfreed-dev%2Fniri-screensaver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfreed-dev%2Fniri-screensaver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfreed-dev%2Fniri-screensaver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfreed-dev%2Fniri-screensaver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jfreed-dev","download_url":"https://codeload.github.com/jfreed-dev/niri-screensaver/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfreed-dev%2Fniri-screensaver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33723548,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ascii-art","niri","noctalia","quickshell","screensaver","terminal","terminaltexteffects","wayland"],"created_at":"2026-05-21T23:00:37.213Z","updated_at":"2026-05-31T07:30:48.974Z","avatar_url":"https://github.com/jfreed-dev.png","language":"Shell","funding_links":[],"categories":["Tools"],"sub_categories":["System Integration and Automation"],"readme":"# niri-screensaver\n\n[![License: GPL v3](https://img.shields.io/badge/license-GPL--3.0-blue.svg)](LICENSE)\n[![Latest release](https://img.shields.io/github/v/release/jfreed-dev/niri-screensaver)](https://github.com/jfreed-dev/niri-screensaver/releases)\n[![AUR version](https://img.shields.io/aur/version/niri-screensaver?label=AUR)](https://aur.archlinux.org/packages/niri-screensaver)\n[![CI](https://github.com/jfreed-dev/niri-screensaver/actions/workflows/ci.yml/badge.svg)](https://github.com/jfreed-dev/niri-screensaver/actions/workflows/ci.yml)\n\nA terminal-based screensaver for [Niri](https://github.com/YaLTeR/niri), driven by\n[TerminalTextEffects](https://github.com/ChrisBuilds/terminaltexteffects) and\ndesigned to integrate with the [Noctalia](https://github.com/noctalia-dev/noctalia-shell)\ndesktop shell.\n\n![Screensaver demo](docs/screensaver.gif)\n\n\u003e 8-second loop on CachyOS — the niri brand mark rendered with one of\n\u003e TTE's particle/rain effects on the cyan-to-magenta gradient.\n\nForked from [cosmic-order](https://github.com/jfreed-dev/cosmic-order)'s screensaver\ncomponent, with the COSMIC-specific glue (cosmic-randr, cosmic-greeter, the\nfocus-follows-cursor / autotile dance) stripped out and replaced with niri-native\nequivalents. Idle, lock, and DPMS are deferred to Noctalia rather than reimplemented\nin swayidle.\n\n## Layout\n\n```text\nbin/\n  niri-screensaver         Inner driver — runs TTE in the current terminal.\n  niri-screensaver-launch  Spawns one fullscreen Alacritty per output, runs the driver inside.\n  niri-screensaver-ctl     Thin shim: launch | kill | toggle | status | test | preview | effects.\nshare/\n  alacritty-screensaver.toml  Minimal Alacritty config (black bg, no padding, hidden cursor).\n  logos/                       ASCII art logos (Framework cog, CachyOS shield, combos). See `Logos` below.\ndocs/\n  niri-window-rule.kdl         Snippet for ~/.config/niri/config.kdl.\n  noctalia-customCommand.json  Snippet for ~/.config/noctalia/settings.json idle.customCommands.\nnoctalia-plugin/                Native Noctalia plugin (manifest + QML).\ninstall.sh                     User-local install (defaults to ~/.local).\n```\n\n## Requirements\n\n| Package | Required | Purpose |\n|---------|----------|---------|\n| `niri` | yes | The compositor; window-rule + `niri msg action spawn` |\n| `alacritty` | yes | Host terminal for the fullscreen screensaver surface |\n| `terminaltexteffects` (`tte`) | yes | Renders the actual effects |\n| `jq` | optional | Used by the launcher to enumerate outputs |\n| `figlet` | optional | Renders the between-effects clock and now-playing overlay |\n| `playerctl` | optional | Source for the now-playing track display |\n| `notify-send` (`libnotify`) | optional | Toggle / status notifications |\n\nInstall the dependencies for your distro:\n\n```bash\n# Arch / CachyOS\nparu -S python-terminaltexteffects alacritty niri jq figlet libnotify playerctl\n\n# Fedora / RHEL\nsudo dnf install alacritty niri jq figlet libnotify playerctl\npipx install terminaltexteffects\n\n# Debian / Ubuntu\nsudo apt install alacritty jq figlet libnotify-bin playerctl\npipx install terminaltexteffects\n# (niri may need a manual install on older releases)\n```\n\nThe Noctalia plugin additionally requires Noctalia ≥ 4.7.0 (uses the plugin\nAPI's `tr()` translation helper and Tabler icon names).\n\n## Install\n\n### Arch / CachyOS (AUR)\n\n```bash\nyay -S niri-screensaver         # stable, tracks tagged releases\n# or\nyay -S niri-screensaver-git     # tracks main HEAD\n```\n\nSubstitute `paru` / `pikaur` / your AUR helper of choice. Either package\ninstalls the bash CLI to `/usr/bin`, shared assets to\n`/usr/share/niri-screensaver/`, the `.desktop` entry and hicolor icon\nto the standard XDG paths, and prints a post-install message with the\nremaining wire-up steps (niri window-rule, Noctalia plugin symlink).\n\nThe two packages `provides`/`conflicts` each other — install one or the\nother, not both.\n\n### Other distros / from source\n\n```bash\n./install.sh                             # installs into ~/.local\nINSTALL_PREFIX=/usr/local ./install.sh   # system-wide\n```\n\nThis deploys the three `bin/` scripts and the `share/` assets (Alacritty\nconfig + logos + `.desktop` entry + hicolor icon). It does **not**\ninstall the niri window-rule or the Noctalia plugin — those are separate\nsteps below.\n\n### Verify\n\n```bash\nniri-screensaver-ctl status\nniri-screensaver-ctl test     # render one effect inline (no fullscreen)\n```\n\n## Wire it into Niri\n\nAppend the contents of `docs/niri-window-rule.kdl` to your `~/.config/niri/config.kdl`.\nThe rule matches `app-id=\"niri-screensaver\"` and applies `open-fullscreen true`,\nwhich is how the launcher achieves fullscreen without an Alacritty CLI flag.\n\n## Wire it into Noctalia\n\nThree options, from least to most friction.\n\nThe plugin adds a Settings tab, a bar widget, and auto-registers the\nscreensaver in Noctalia's `IdleService` when enabled.\n\n![Plugin bar widget with screensaver running](noctalia-plugin/preview.png)\n\n\u003e Niri logo mid-gradient with the Noctalia bar visible at the top — the\n\u003e plugin's bar widget (custom monitor-with-image icon, far left of the\n\u003e tray cluster) launches the screensaver on click.\n\n### Option A — Copy the AUR-shipped plugin (Arch / CachyOS, recommended)\n\nIf you installed via the AUR package above, the plugin source is already\non disk at `/usr/share/niri-screensaver/noctalia-plugin/`. Copy it into\nNoctalia's per-user plugin dir:\n\n```bash\nmkdir -p ~/.config/noctalia/plugins\ncp -r /usr/share/niri-screensaver/noctalia-plugin \\\n      ~/.config/noctalia/plugins/niri-screensaver\n```\n\nThen enable it in **Noctalia → Settings → Plugins**.\n\n\u003e **Why `cp -r` and not `ln -sfn`** — Noctalia writes plugin settings\n\u003e back into the plugin dir on every toggle in the Settings tab. The\n\u003e AUR-shipped tree under `/usr/share/` is root-owned, so a symlinked\n\u003e plugin loads fine but silently fails to persist any user-changed\n\u003e settings (defaults always come back on Noctalia restart). The cost\n\u003e of using `cp -r` is that plugin updates from `pacman -Syu` don't\n\u003e auto-flow — re-run the `cp -r` after each upgrade if you want the\n\u003e latest plugin code.\n\n### Option B — Install from the Noctalia plugin registry (any distro)\n\n\u003e **Pending registry acceptance.** Until\n\u003e [noctalia-plugins#852](https://github.com/noctalia-dev/noctalia-plugins/pull/852)\n\u003e merges, `niri-screensaver` won't appear in the registry browser yet — use\n\u003e Option A (AUR) or Option C below in the meantime.\n\nOpen **Noctalia → Settings → Plugins**, find `niri-screensaver` in the\nregistry browser, install. The plugin lands in\n`~/.config/noctalia/plugins/`.\n\nNote: the registry ships only the plugin's QML files. The bash CLI\n(`niri-screensaver-launch` and friends) is a separate install — use the\nAUR package on Arch / CachyOS, or `./install.sh` from this repo on other\ndistros. If the CLI is missing, the plugin's Settings tab shows a\n\"install niri-screensaver first\" banner.\n\n### Option C — Manual JSON edit (no plugin)\n\nIf you don't want the Noctalia plugin (no Settings UI, no bar widget),\njust wire the idle trigger directly: copy the relevant fields from\n`docs/noctalia-customCommand.json` into `~/.config/noctalia/settings.json`\nunder the `idle` object. After saving, restart Noctalia (`pkill qs` then\nre-launch `qs -c noctalia-shell`) to pick up the new idle hook.\n\n## Usage\n\n```bash\nniri-screensaver-ctl launch    # trigger now\nniri-screensaver-ctl kill      # stop\nniri-screensaver-ctl status    # report state\nniri-screensaver-ctl toggle    # disable / re-enable the launcher\nniri-screensaver-ctl test           # run a single random effect inline (no fullscreen)\nniri-screensaver-ctl preview rain   # preview a specific named effect inline\nniri-screensaver-ctl effects        # list all TTE effects\n```\n\n## Configuration\n\n`~/.config/niri-screensaver/config` is sourced as shell. Keys:\n\n| Key | Default | Notes |\n|-----|---------|-------|\n| `BATTERY_MIN_PERCENT` | `0` | Read by the launcher: skip auto-launch when on battery below this %. `0` disables; plugged in or no battery never skips; `launch force` overrides |\n| `FRAME_RATE` | `60` | TTE frame rate |\n| `INCLUDE_EFFECTS` | _empty_ | Comma-separated effect names; takes precedence over excludes |\n| `EXCLUDE_EFFECTS` | `dev_worm` | Comma-separated effects to skip |\n| `FADE_IN_EFFECT` | _empty_ | One-shot effect on launch (e.g. `expand`, `slide`) |\n| `FADE_OUT_EFFECT` | _empty_ | One-shot effect on dismiss (e.g. `burn`, `crumble`) |\n| `SHOW_CLOCK` | `false` | Render time between effects |\n| `CLOCK_DURATION` | `3` | Seconds to display the clock |\n| `CLOCK_FORMAT` | `%H:%M` | strftime format string |\n| `CLOCK_FONT` | _empty_ | figlet font name (shared with the now-playing overlay) |\n| `SHOW_NOW_PLAYING` | `false` | Render the playerctl track title between effects (no-op if `playerctl` is missing or nothing is playing) |\n| `NOW_PLAYING_DURATION` | `3` | Seconds to display the now-playing overlay |\n| `CURSOR_HIDE` | `true` | Hide the *text* cursor (`tput civis`) |\n| `DISMISS_ON_KEY` | `true` | Any key dismisses; ESC and mouse always dismiss |\n| `RANDOM_LOGO` | `false` | When `true`, pick a random `*.txt` from `LOGO_DIR` before each effect cycle |\n| `LOGO_DIR` | _empty_ | Directory the random picker scans. Defaults to the installed `share/logos/` |\n\nOn launch, the launcher parks the mouse pointer in the bottom-right corner via\n`wlrctl` (preferred) or `ydotool` if either is installed. For a full hide,\ncombine with niri's `cursor { hide-after-inactive-ms 500 }` so the parked\npointer disappears after the idle window. With neither tool installed, the\nlauncher logs a one-time hint and falls back to niri-only auto-hide.\n\n## Logos\n\n`share/logos/` ships ready-to-use ASCII art. Point `LOGO_FILE` at one of them\nin `~/.config/niri-screensaver/config` (or via the Noctalia plugin's Settings\npanel) — or symlink your favorite to the active path:\n\n```bash\nln -sf ~/.local/share/niri-screensaver/logos/framework-name-with-icon-medium.txt \\\n       ~/.config/niri-screensaver/logo.txt\n```\n\n### CachyOS\n\n| File | Contents |\n|------|----------|\n| `cachyos-icon.txt` | CachyOS shield |\n| `cachyos-name.txt` | `CACHYOS` ANSI Shadow wordmark |\n| `cachyos-name-with-icon.txt` | Shield + wordmark |\n\n### Framework\n\n| File | Contents |\n|------|----------|\n| `framework-icon.txt` | 8-lobed Framework cog (40×18) |\n| `framework-icon-medium.txt` | Same cog (30×14) |\n| `framework-icon-small.txt` | Same cog (24×10) |\n| `framework-name.txt` | `FRAMEWORK` ANSI Shadow wordmark |\n| `framework-name-with-icon.txt` | Cog (40×18) + wordmark |\n| `framework-name-with-icon-medium.txt` | Cog (30×14) + wordmark |\n| `framework-name-with-icon-small.txt` | Cog (24×10) + wordmark |\n| `framework-name-with-cachyos-icon.txt` | CachyOS shield + `FRAMEWORK` wordmark — for CachyOS-on-Framework setups |\n\n### Hyprland\n\n| File | Contents |\n|------|----------|\n| `hyprland-icon.txt` | Hyprland teardrop |\n| `hyprland-name.txt` | `HYPRLAND` ANSI Shadow wordmark |\n| `hyprland-name-with-icon.txt` | Teardrop + wordmark |\n\n### niri\n\n| File | Contents |\n|------|----------|\n| `niri-icon.txt` | Stylized \"i\" / arguably owl-shaped niri brand mark |\n| `niri-name.txt` | `NIRI` ANSI Shadow wordmark |\n| `niri-name-with-icon.txt` | Icon + wordmark |\n| `niri-tiles.txt` | Five scrolling-tile columns — niri's signature layout |\n| `niri-name-with-tiles.txt` | Tiles + wordmark |\n\nPer-file attribution, licensing, and trademark notes are in\n[share/logos/LICENSES.md](share/logos/LICENSES.md).\n\n### Creating your own\n\nDrop any UTF-8 text file into `~/.local/share/niri-screensaver/logos/`\n(or `share/logos/` in the repo) and point `LOGO_FILE` at it — or pick\nit from the Noctalia plugin's logo dropdown (which auto-refreshes when\nfiles appear in that directory). The plugin's Logo directory field also\nhas a Browse button if you want to point it at a different folder of\n`.txt` files.\n\n**Size.** Logos render as-is, no rescaling, so plan for the narrowest\nterminal you'll run on. The shipped logos stay within ~40–60 columns\nwide; go much wider and lines will wrap on smaller monitors. Height is\nforgiving — `niri-name-with-icon.txt` is 49 lines and renders fine at\n1080p. Useful reference points:\n\n| Logo file | Width × height |\n|---|---|\n| `framework-icon-small.txt` | 24 × 13 |\n| `framework-icon.txt` | 40 × 21 |\n| `niri-name-with-icon.txt` | 40 × 49 |\n| `cachyos-name.txt` | 60 × 9 |\n\n**Layout.** TTE centers the entire block (the full bounding box of your\nfile) horizontally and vertically on the output. A few consequences:\n\n- **Trailing whitespace counts.** Lines padded with extra spaces on the\n  right widen the bounding box and shift the visual center off-axis.\n  Strip trailing whitespace before saving — most editors have a setting\n  for it (`:set list` in vim, \"Trim trailing whitespace on save\" in\n  VS Code).\n- **Blank lines at top/bottom add vertical padding.** Useful if you\n  want breathing room around an icon-only logo. They're treated as part\n  of the bounding box.\n- **Combining icon + wordmark** (the `*-name-with-icon.txt` pattern):\n  stack them in one file with one or two blank lines between. They'll\n  render as one block.\n\n**Characters.** Block elements (`█ ▓ ▒ ░`) and box-drawing\n(`╔═╗ ║ ╚═╝`) render most cleanly across monospace fonts. Per-glyph\nANSI Shadow wordmarks (the style used by every `*-name.txt`) are the\neasiest way to get a polished result.\n\n**Tools.**\n\n- Wordmarks from text: `figlet -f \"ANSI Shadow\" YOURTEXT`. If the font\n  isn't installed, grab it from\n  [xero/figlet-fonts](https://github.com/xero/figlet-fonts) or use the\n  web generator below.\n- Image → ASCII: `jp2a --width=40 --chars=\" ░▒▓█\" logo.png` or\n  `chafa --symbols=block --size=40x logo.png`. Both emit pure UTF-8\n  without ANSI color codes (TTE won't preserve mid-effect colors).\n- Web generator: [patorjk.com/software/taag/](https://patorjk.com/software/taag/)\n  has a font picker and a \"Copy\" button — paste the output into a\n  `.txt` and trim any trailing blank lines.\n\n**Preview.** Render a single effect inline (no fullscreen) with your\nin-progress file:\n\n```bash\nLOGO_FILE=~/Downloads/mylogo.txt niri-screensaver-ctl test\nLOGO_FILE=~/Downloads/mylogo.txt niri-screensaver-ctl test beams\n```\n\nIterate on the file, re-run `test`, drop it into the logos directory\nwhen you're happy with it.\n\n## Trademarks\n\nniri-screensaver is **not affiliated with or endorsed by** Framework\nComputer Inc., the CachyOS project, the Hyprland project, or the niri\nproject. Brand marks rendered in `share/logos/` belong to their\nrespective owners and are referenced for the convenience of users who\nown / run those products. The Hyprland-derived ASCII carries the\nupstream BSD-3-Clause attribution; Framework and CachyOS marks are\nprovided for nominative use only. See\n[share/logos/LICENSES.md](share/logos/LICENSES.md) for per-file detail.\n\nIf you are a brand owner and would like a logo removed or the\nattribution adjusted, please open an issue.\n\n## What was dropped from cosmic-order\n\n- The 1500-line `screensaver-ctl.sh` (swayidle config generator, systemd unit\n  installer, lock command setup) — Noctalia owns idle/lock/DPMS now.\n- The `disable_compositor_interference` block (focus_follows_cursor / autotile\n  poking) — niri doesn't have the focus-stealing problem.\n- The `ydotool` Super+F injection to toggle fullscreen — replaced by niri\n  window-rule with `open-fullscreen true`.\n- Ghostty-specific config generation; replaced with a single Alacritty TOML.\n- cosmic-randr monitor enumeration; replaced with `niri msg --json outputs`.\n- `cosmic-greeter --lock`; Noctalia's native lock is invoked via `loginctl\n  lock-session` or directly through Noctalia's IdleService.\n- Power-aware effect profiles (UPower D-Bus). Add back via the Noctalia plugin\n  if you want them.\n\n## License\n\nGPL-3.0-only (carried over from cosmic-order).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfreed-dev%2Fniri-screensaver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjfreed-dev%2Fniri-screensaver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfreed-dev%2Fniri-screensaver/lists"}