This commit is contained in:
2026-07-30 16:04:29 -03:00
parent cf5ef1eda4
commit 9b763743bd
9 changed files with 337 additions and 21 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-30
@@ -0,0 +1,64 @@
## 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/Screenshots` and copy it as `image/gif` with `wl-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/gif` MIME 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
1. Apply the Home Manager configuration for `jpporta-nixos`.
2. Press the new Hyprland bind and select a region; press it again to stop and wait for encoding.
3. Verify the GIF in `~/Pictures/Screenshots` and paste it into a GIF-capable Wayland application.
4. 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.
@@ -0,0 +1,31 @@
## Why
The Hyprland desktop has a screenshot flow but no equally convenient way to capture a short animated region of the screen. A Wayland-native GIF recorder should let the user select a region, press the same bind to stop, and receive the finished GIF in `~/Pictures/Screenshots` and on the clipboard.
## What Changes
- Add a new Home Manager module, `modules/home-manager/gif-recorder`, with a single enable option.
- Provide a Wayland-native recording script using `wf-recorder` and `slurp` to select and record a screen region.
- Toggle recording with one Hyprland bind: the first press starts region selection/recording and the next press stops it.
- Convert the recording to an optimized GIF after stopping.
- Save completed GIFs under `~/Pictures/Screenshots` with timestamped filenames.
- Copy the completed GIF to the Wayland clipboard for immediate pasting.
- Enable the module from `hosts/jpporta-nixos/home.nix` and add only the required bind in the existing Hyprland Home Manager module.
## Capabilities
### New Capabilities
- `gif-recorder`: Select, toggle-record, save, and clipboard-copy short Wayland screen-region GIFs.
### Modified Capabilities
- None.
## Impact
- New Home Manager module and user-facing recording script.
- Existing `modules/home-manager/hyprland/default.nix` gains the toggle bind.
- `hosts/jpporta-nixos/home.nix` imports and enables the module.
- Adds the runtime packages `wf-recorder`, `slurp`, `ffmpeg`, and a Wayland clipboard utility through the module.
- Creates `~/Pictures/Screenshots` when a recording is completed; existing screenshot behavior remains unchanged.
@@ -0,0 +1,49 @@
## ADDED Requirements
### Requirement: Region recording is toggled by one command
The GIF recorder SHALL use one executable that starts an interactive region recording when idle and stops the active recording when invoked again.
#### Scenario: Start a recording
- **WHEN** the recorder is invoked while no recording is active
- **THEN** it lets the user select a rectangular Wayland region and starts recording that region
#### Scenario: Stop a recording
- **WHEN** the recorder is invoked while a recording is active
- **THEN** it stops the active recording and begins finalization without starting a second recording
#### Scenario: Cancel region selection
- **WHEN** the user cancels region selection before recording starts
- **THEN** the recorder exits without creating a GIF and clears its runtime state
### Requirement: Completed recordings are saved as GIF screenshots
The recorder SHALL save each successfully finalized recording as a timestamped `.gif` file below `~/Pictures/Screenshots`.
#### Scenario: Successful finalization
- **WHEN** an active recording is stopped and encoding succeeds
- **THEN** the recorder creates the screenshots directory if needed and stores one completed GIF there
#### Scenario: Failed finalization
- **WHEN** recording or GIF encoding fails
- **THEN** the recorder does not publish a partial GIF as a completed screenshot and removes temporary recording data
### Requirement: Completed recordings are copied to the Wayland clipboard
After successful GIF encoding, the recorder SHALL copy the resulting file to the Wayland clipboard using the `image/gif` MIME type.
#### Scenario: Clipboard copy succeeds
- **WHEN** a GIF is successfully written
- **THEN** the recorder publishes that GIF to the clipboard as `image/gif`
#### Scenario: Clipboard copy is unavailable
- **WHEN** a GIF is successfully written but clipboard publication fails
- **THEN** the recorder preserves the GIF in `~/Pictures/Screenshots` and exits without deleting it
### Requirement: Home Manager integration is opt-in
The feature SHALL be exposed as a Home Manager module with an enable option, and enabling it SHALL install all required runtime tools and the recorder executable.
#### Scenario: Module enabled
- **WHEN** `custom.gif-recorder.enable` is true
- **THEN** the user environment contains the recorder command and its Wayland recording, selection, encoding, and clipboard dependencies
#### Scenario: Module disabled
- **WHEN** `custom.gif-recorder.enable` is false
- **THEN** the module adds no GIF recorder command, packages, or Hyprland bind
@@ -0,0 +1,18 @@
## 1. Add the Home Manager module
- [x] 1.1 Create `modules/home-manager/gif-recorder/default.nix` with `custom.gif-recorder.enable` and an enabled-only configuration.
- [x] 1.2 Install `wf-recorder`, `slurp`, `ffmpeg`, and `wl-clipboard` through the module and expose one `gif-recorder` script in the user's session path.
- [x] 1.3 Implement the toggle state under `XDG_RUNTIME_DIR`: start region selection/recording when idle, signal the active process on the second invocation, clean up on cancellation/interruption, and reject stale state.
- [x] 1.4 Finalize successful recordings with palette-based `ffmpeg` GIF encoding, timestamp the output below `~/Pictures/Screenshots`, and copy it with `wl-copy --type image/gif` while preserving the saved file if clipboard copy fails.
## 2. Wire the feature into the existing host
- [x] 2.1 Import `../../modules/home-manager/gif-recorder` and set `custom.gif-recorder.enable = true` in `hosts/jpporta-nixos/home.nix`.
- [x] 2.2 Add `SUPER + SHIFT + 5` to the existing `Screenshots` section of `modules/home-manager/hyprland/default.nix`, invoking `gif-recorder` so the same bind starts and stops the capture.
## 3. Verify the workflow
- [x] 3.1 Evaluate/build the `jpporta-nixos` Home Manager activation package and confirm the module and script parse successfully.
- [x] 3.2 Confirm the bind invokes the installed command and that the runtime dependency paths are available in the script.
- [ ] 3.3 In a live Hyprland session, select a region, stop with the same bind, and verify a timestamped GIF appears in `~/Pictures/Screenshots` and can be pasted from the Wayland clipboard.
- [ ] 3.4 Verify canceling `slurp`, stopping early, and an encoding failure leave no partial GIF and no stale runtime state.
+55
View File
@@ -0,0 +1,55 @@
# GIF Recorder
## Purpose
This capability provides an opt-in Wayland workflow for recording a selected screen region as a GIF, saving it as a screenshot, and copying it to the clipboard.
## Requirements
### Requirement: Region recording is toggled by one command
The GIF recorder SHALL use one executable that starts an interactive region recording when idle and stops the active recording when invoked again.
#### Scenario: Start a recording
- **WHEN** the recorder is invoked while no recording is active
- **THEN** it lets the user select a rectangular Wayland region and starts recording that region
#### Scenario: Stop a recording
- **WHEN** the recorder is invoked while a recording is active
- **THEN** it stops the active recording and begins finalization without starting a second recording
#### Scenario: Cancel region selection
- **WHEN** the user cancels region selection before recording starts
- **THEN** the recorder exits without creating a GIF and clears its runtime state
### Requirement: Completed recordings are saved as GIF screenshots
The recorder SHALL save each successfully finalized recording as a timestamped `.gif` file below `~/Pictures/Screenshots`.
#### Scenario: Successful finalization
- **WHEN** an active recording is stopped and encoding succeeds
- **THEN** the recorder creates the screenshots directory if needed and stores one completed GIF there
#### Scenario: Failed finalization
- **WHEN** recording or GIF encoding fails
- **THEN** the recorder does not publish a partial GIF as a completed screenshot and removes temporary recording data
### Requirement: Completed recordings are copied to the Wayland clipboard
After successful GIF encoding, the recorder SHALL copy the resulting file to the Wayland clipboard using the `image/gif` MIME type.
#### Scenario: Clipboard copy succeeds
- **WHEN** a GIF is successfully written
- **THEN** the recorder publishes that GIF to the clipboard as `image/gif`
#### Scenario: Clipboard copy is unavailable
- **WHEN** a GIF is successfully written but clipboard publication fails
- **THEN** the recorder preserves the GIF in `~/Pictures/Screenshots` and exits without deleting it
### Requirement: Home Manager integration is opt-in
The feature SHALL be exposed as a Home Manager module with an enable option, and enabling it SHALL install all required runtime tools and the recorder executable.
#### Scenario: Module enabled
- **WHEN** `custom.gif-recorder.enable` is true
- **THEN** the user environment contains the recorder command and its Wayland recording, selection, encoding, and clipboard dependencies
#### Scenario: Module disabled
- **WHEN** `custom.gif-recorder.enable` is false
- **THEN** the module adds no GIF recorder command, packages, or Hyprland bind