4.6 KiB
Context
The desktop already uses Home Manager modules under modules/home-manager and keeps Hyprland keybinds in modules/home-manager/hyprland/default.nix. The new capability is a small user-session workflow, not a daemon: select a region with slurp, record it with the Wayland-native wf-recorder, encode the result with ffmpeg, and publish the finished file with wl-copy.
The same Hyprland bind must start and stop the workflow. The first invocation needs to remain alive while recording; a later invocation needs a stable way to find and signal that process. The implementation also needs to avoid leaving partial files in the screenshots directory when selection is cancelled or encoding fails.
Goals / Non-Goals
Goals:
- Encapsulate packages, script, option, output directory, and runtime state in
modules/home-manager/gif-recorder. - Use a single toggle command suitable for a Hyprland
bind. - Select a rectangular region interactively through
slurp. - Save optimized GIF output in
~/Pictures/Screenshotsand copy it asimage/gifwithwl-copy. - Keep host wiring minimal: import/enable in
hosts/jpporta-nixos/home.nix, bind in the existing Hyprland module.
Non-Goals:
- Full-screen or window recording modes.
- A recording history, notification UI, configurable encoder settings, or a separate stop bind.
- A new service or background daemon.
- Changes to the existing screenshot flow.
Decisions
D1. One shell script owns the toggle state
The module installs one gif-recorder executable and uses a runtime-directory state file containing the active script PID. If the state file names a live process, a new invocation sends it SIGINT; otherwise it runs slurp and starts a recording. This keeps the bind to one command and avoids adding a service or IPC layer.
Alternative: use separate start/stop scripts or a systemd user service. Rejected because they add commands and lifecycle machinery for one short-lived action.
D2. Use wf-recorder, slurp, ffmpeg, and wl-copy
These tools are small, composable Wayland utilities already suited to the requested flow. wf-recorder receives the geometry selected by slurp; ffmpeg handles palette generation and GIF encoding; wl-copy --type image/gif makes the resulting file available to Wayland clipboard consumers.
Alternative: OBS or a screenshot/GIF application. Rejected because a GUI recorder is heavier than the requested Hyprshot-like interaction.
D3. Encode through a temporary video file
Recording first to a temporary Matroska file keeps the output atomic: the final timestamped GIF is moved into ~/Pictures/Screenshots only after ffmpeg succeeds. The encoder uses a palette-generation filter and a bounded frame rate/width to avoid the worst GIF size and color-quality problems without introducing configuration options.
Alternative: record directly to GIF. Rejected because palette generation and interruption handling are worse, and wf-recorder is designed primarily for video output.
D4. Store state under XDG_RUNTIME_DIR
The state file belongs in ${XDG_RUNTIME_DIR:-/tmp} and is removed on normal completion or cancellation. It is session-local and avoids polluting the home directory with a lock file.
Risks / Trade-offs
- [GIFs are inherently large and limited to 256 colors] -> Cap output at a modest frame rate and width; keep the original temporary recording out of the screenshots directory.
- [A crashed process can leave a stale state file] -> Check whether the recorded PID is alive before treating the workflow as active, and remove stale state before starting.
- [Clipboard consumers differ in GIF support] -> Publish with the explicit
image/gifMIME type; the saved file remains the fallback when a consumer cannot paste animated images. - [The second bind may be pressed while region selection is active] -> Keep the controlling script PID in the state file before invoking
slurp, and handle interruption by cleaning up without creating output.
Migration Plan
- Apply the Home Manager configuration for
jpporta-nixos. - Press the new Hyprland bind and select a region; press it again to stop and wait for encoding.
- Verify the GIF in
~/Pictures/Screenshotsand paste it into a GIF-capable Wayland application. - Roll back by disabling/removing the module import and bind; no persistent data migration is required, and existing GIF files are left untouched.
Open Questions
- The exact key combination should follow the existing screenshot bind convention in the Hyprland module; implementation should reuse that convention rather than introduce a new modifier scheme.