Backlog for the widget layer this fork adds on top of illogical-impulse. Two streams feed it: improving the modules that already exist, and a set of features mined from end-4's open issue tracker (431 open issues, agent-triaged) that the shell doesn't cover yet. Net-new ideas that duplicate existing capability were dropped (see bottom).
Conventions for any work here follow the "done" checklist in CONTRIBUTING.md: an
enable flag in Config.qml, gating on Config.ready && enable, a Settings → Custom entry, and
any shelled-out tool recorded in setup/dependencies.txt (and the NixOS home.packages). Build in
a worktree, parse-gate with qs -p, deploy by ff-merge.
Status legend: [ ] queued, [~] in progress, [x] shipped, [-] dropped.
Each entry cites its upstream issue (e4#NNNN = end-4/dots-hyprland).
A general-purpose GLSL screen shader applied via decoration:screen_shader. Built on the existing
anti-flashbang infrastructure rather than the hyprctl eval path: HyprlandConfig.setMany writes
the override to the Lua config (so it persists across reloads/reboots) and HyprlandConfigOption
reads state back reactively. No hyprshade binary, no hyprctl keyword.
- Service:
services/ScreenShader.qml(apply/clear/toggle +screenShaderIpcHandler), gated onlight.shader.enable; clears the shader when the feature is switched off. - Shaders:
services/screenShader/{bluelight,grayscale}.glsl(GLES3, anti-flashbang header format). Empty config path falls back to bluelight. - Config:
light.shader.{enable, path}. Toggle registered in all 3 panel styles (android delegate + wrapper, classic instantiation, waffle action center). Settings entry on the Custom page. - Deps: none (hyprctl present). Verified end-to-end on Hyprland 0.55.4: toggle sets/clears
decoration:screen_shader,getoptionreflects it, persistent override stays clean. - Note: rapid back-to-back programmatic toggles race the async
getoptionread (shared with anti-flashbang); harmless for human clicks. A shader picker (cycle ashaderDir) is a future add. ⚠ General rule for this system: any runtime Hyprland option change must usehyprctl eval 'hl.config({...})'orHyprlandConfig.set*, NOThyprctl keyword(disabled under the Lua parser). Audit done 2026-06-30: nohyprctl keywordusage in the tree.
Recent source/target language pairs remembered and pinned to the top; a swap button + hotkey.
- Where: extend
services/ScreenTranslator.qml(persist recent pairs) +modules/ii/screenTranslator/ScreenTranslatorPanel.qml(recent-pairs row + swap affordance). - How: pure QML state. Persist a JSON array of
[src,dst]to~/.local/state/quickshell/(thenews_read.jsonFileView pattern); swap = exchange two properties. No new deps. - Config:
screenTranslator.recentPairs(auto-managed). In-panel swap hotkey, no global keybind.
Typing a path-ish query (prefix /, ~, or f:) surfaces file results next to apps/math.
- Where: extend
services/LauncherSearch.qml(orAppSearch.qml) +modules/ii/overview/ SearchBar.qml/SearchWidget.qml/SearchItem.qml. - How: on a path prefix,
Processrunsfd --max-results 20 <query> ~(fd present); render results in the same list with a file-type icon; open viaxdg-open. Debounce input. - Config:
overview.fileSearch.{enable, root, maxResults}. Dep:fd(present).
A draggable seek bar on the media control, and surface only the active/most-recent player when several are running.
- Where:
services/MprisController.qml(position polling + seek dispatch, active-player pick) +modules/ii/mediaControls/MediaControls.qml/PlayerControl.qml. - How: read
Position/Length(MPRIS orplayerctl position/metadata mpris:length); seek viaSetPosition/playerctl position <s>; poll ~1s only while playing + visible. Rank players by playback status + last-active. Dep:playerctl(present). - Config:
mediaControls.{showSeekBar, singlePlayer}.
Compact now-playing + play/pause/skip on the lock surface.
- Where:
modules/ii/lock/LockSurface.qml, add a small media widget bound toMprisController. - How: reuse the existing MPRIS service; controls call play/pause/next. Security: show only
title/artist/art and transport, no notifications, no seek to arbitrary content; gate behind
lock.showMedia. Render below the auth field, never stealing focus from it. - Config:
lock.showMedia(default true).
A Spotify-style overlay: large art, controls, and time-synced lyrics.
- Where: new
modules/ii/nowPlaying/NowPlaying.qml(FloatingWindow or layer overlay) registered inIllogicalImpulseFamily, +services/Lyrics.qml. - How: data from
MprisController; lyrics via anXMLHttpRequestto lrclib.net (/api/get?artist=&track=&duration=), matched toPositionfor the active line. Keybind to open. - Config:
nowPlaying.{enable, lyrics}. No binary dep (HTTP API). Keybind e.g.Super+Alt+N.
Switch headphone ⇄ speaker (ports on one sink) from the volume popup.
- Where: extend
modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml/AudioDeviceSelectorButton.qml+services/Audio.qml. - How: enumerate ports
pactl -f json list sinks(ports[].name/availability); switchpactl set-sink-port <sink> <port>. Distinguish port-vs-sink cleanly. Dep:pactl(present). - Config: none needed beyond the existing audio panel.
Transient Material-You popup with device name + battery % on connect.
- Where: new
services/BluetoothBattery.qml+ a reuse of the OSD popup (modules/ii/onScreenDisplay/). - How: watch
org.bluezvia Quickshell DBus (Battery1.Percentage, device Connected signal); 3-5s auto-dismiss popup. No binary dep (native DBus). - Config:
bluetoothBattery.enable.
Flip the colour scheme at sunrise/sunset (or fixed times).
- Where: new
services/AutoTheme.qml(Timer) calling the existing dark/light switch (services/Wallpapers.qml+scripts/colors/applycolor.sh, same pathDarkModeToggleuses). - How: compute sunrise/sunset from
Weather.qmlcoords (or config lat/long), else fixedlightAt/darkAt; a Timer checks every few minutes and switches once per boundary. No new dep. - Config:
autoTheme.{enable, mode: sun|fixed, lightAt, darkAt}.
Special-workspace (scratchpad) indicator in the bar, and per-monitor workspace filtering.
- Where:
modules/ii/bar/workspace widget. - How: Hyprland IPC.
activespecialevent drives the badge; filter the workspaceRepeaterbymonitor === thisScreenusinghyprctl monitors -j. No new dep. - Config:
bar.workspaces.{showSpecial, perMonitor}.
Auto-cycle wallpapers from a folder; run a user script after each change.
- Where: extend
services/Wallpapers.qml. - How: Timer cycles a configured folder at an interval, calling the existing wallpaper-set path;
after the color-generation step,
Processrunswallpaper.{hookScript}(for OpenRGB / terminal sync). No new dep. - Config:
wallpaper.{rotateFolder, rotateMinutes, hookScript}.
Hold-to-record, transcribe, inject into the focused field.
- Where: new
services/VoiceInput.qml+ a recording OSD indicator. - How: keybind starts capture;
Processpipes mic (PipeWire) towhisper.cpp(orvosk); result typed viawtype/ydotool(present). Recording indicator while active. - Config:
voiceInput.{enable, model}. Dep:whisper-cpp(add). Keybind e.g.Super+Alt+V.
Detect a captive portal and open the login page.
- Where: extend
services/VpnStatus.qml(already does connectivity/trust) or newservices/CaptivePortal.qml; a notification action. - How: probe
http://nmcheck.gnome.org/(or NMCONNECTIVITY=portal); on portal, notify +xdg-openthe redirect URL. Ties into the existing trusted/untrusted-network logic. - Config:
captivePortal.enable. No new dep.
Summon the AI assistant as a dismiss-on-blur floating window (not the sidebar).
- Where: new
modules/ii/aiOverlay/AiOverlay.qml(FloatingWindow, the reconLauncher pattern) + reuseservices/Ai.qml. - How: keybind toggles a centered floating window over the current workspace;
GlobalFocusGrabor onVisibleChanged dismiss; reuses the AI backend + the local-LLM text-action plumbing. - Config:
aiOverlay.enable. Keybind e.g.Super+Alt+C.
- Eye-care break overlay
[ ]: tiered breaks / 20-20-20 countdown;Timer+ layer-shell window, suppressed duringgameMode/fullscreen, reusingidleInhibitor. Easy. (stretchly, blink-eye) - giteaActivity → PR/issue quick actions
[ ]: key-bound diff/comment/checkout/open overgh/tea. Improves the existing read-only card. (gh-dash)
Add to setup/dependencies.txt + NixOS home.packages when the owning feature is built:
hyprshade(#1),whisper-cpp(#12). Already present:fd,playerctl,pactl,ydotool,wtype,sensors. HTTP-only (no binary): lrclib lyrics (#6).
- Command palette → overview is already a search-launcher (+ serviceLauncher/reconLauncher/homelabGlance).
- Clipboard history →
cliphistruns; pickers at Super+V and Super+Alt+V +cliphistService. - Bar popups + inline graphs →
SensorSparklinealready renders inline graphs. - Recon MCP backend →
reconLauncheralready covers it. - Secrets surfacing → overlaps gnome-keyring / browser PW managers / CLI pass+sops (built then reverted
6ce0731). - Pomodoro bar widget (e4#3272) → already have a
pomodoromodule. - Large rewrites skipped: Niri support (e4#1745), "windoes" flavor (e4#2342), modular bar / hefty-hype (e4#3072), GPU/resource monitoring (e4#1472, end-4 is waiting on a Quickshell stats API).
- end-4 issue tracker: https://github.com/end-4/dots-hyprland/issues
- gh-dash: https://github.com/dlvhdr/gh-dash · Stretchly: https://github.com/hovancik/stretchly · Blink Eye: https://github.com/nomandhoni-cs/blink-eye · lrclib: https://lrclib.net