Skip to content

feat(screencast-gif): add hotkey-driven region screencast → GIF plugin#766

Draft
mewmewmemw wants to merge 3 commits into
noctalia-dev:mainfrom
mewmewmemw:feat/screencast-gif
Draft

feat(screencast-gif): add hotkey-driven region screencast → GIF plugin#766
mewmewmemw wants to merge 3 commits into
noctalia-dev:mainfrom
mewmewmemw:feat/screencast-gif

Conversation

@mewmewmemw
Copy link
Copy Markdown

Summary

Adds screencast-gif — a toggle-style screen recorder for wlroots
compositors that selects a region with slurp, records it with
wf-recorder, converts the result to an animated GIF with gifski, and
copies the GIF straight to the Wayland clipboard. The bar widget turns red
while recording is active.

preview

Features

  • Hotkey toggle — first press picks a region with slurp and starts
    the recorder, second press stops it, runs the GIF conversion, and copies
    the result to the clipboard
  • Bar widget indicator — circle pill, turns Color.mError red while
    recording is active, click to start/stop
  • Clipboard deliverywl-copy --type image/gif, ready to paste into
    Telegram / Discord / Element / etc.
  • Auto-stop watchdog — configurable MAX_SECS safety net so a
    forgotten recording can't fill the disk
  • Configurable via plugin settings: output directory, frame rate,
    auto-stop seconds

Requirements

  • Noctalia Shell ≥ 4.6.6
  • wf-recorder, gifski, slurp, ffmpeg, wl-clipboard
    (util-linux for flock, libnotify for notify-send)
sudo pacman -S --needed wf-recorder gifski slurp ffmpeg wl-clipboard libnotify

IPC

qs ipc call plugin:screencast-gif toggle

New tags proposed

The manifest uses two tags that don't yet appear in
registry.json / README.md: Recording and GIF. Both are
maximally descriptive for discoverability and there's no good existing
tag that captures "screen recording" or "animated GIF output". Happy to
drop or rename either if the maintainers prefer.

Test plan

  • Plugin loads, bar widget shows neutral pill, turns red on recording
  • Hotkey via qs ipc call plugin:screencast-gif toggle starts/stops
  • Bar widget click starts/stops (same code path as IPC)
  • GIF lands in clipboard as image/gif (verified with wl-paste --list-types)
  • GIF saved to OUTDIR (default ~/Screenshots/screencast_*.gif)
  • Auto-stop watchdog fires after MAX_SECS and produces a GIF
  • Stop-then-restart works: a new recording can be started while the
    previous conversion is still running
  • Settings persist across restarts (FPS / OUTDIR / MAX_SECS)
  • preview.png is 960×540 (16:9)
  • All required files present (manifest.json, README.md, preview.png)
  • BarWidget has all 6 required properties (pluginApi, screen,
    widgetId, section, sectionWidgetIndex, sectionWidgetsCount)
  • repository field points at noctalia-dev/noctalia-plugins
  • No registry.json change in the PR
  • Source repo also runs a 15-case bats-core suite + shellcheck CI
    (https://github.com/mewmewmemw/noctalia-screencast-gif)

@github-actions

This comment was marked as duplicate.

@github-actions

This comment was marked as resolved.

@mewmewmemw
Copy link
Copy Markdown
Author

The two auto-quality comments above were generated against the first two commits, which had hardcoded English strings in Settings.qml and BarWidget.qml. The third commit (d3ac414c) moves them all into screencast-gif/i18n/en.json and switches to pluginApi?.tr(...), matching the hello-world and kubectl-ctx patterns. Latest code-quality and manifest-check runs are green.

EN is the only locale shipped for now — happy to follow up with translations or accept community PRs for them.

@mewmewmemw mewmewmemw force-pushed the feat/screencast-gif branch from a7057ab to d3ac414 Compare April 26, 2026 13:02
Copy link
Copy Markdown
Collaborator

@spiros132 spiros132 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor feedback about the PR! :)

Comment thread screencast-gif/Main.qml
property var pluginApi: null
property bool recordingActive: false

readonly property string scriptPath: pluginApi?.pluginDir ? pluginApi.pluginDir + "/screencast-gif.sh" : ""
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use the following shorter syntax pluginApi?.pluginDir + "/screencast-gif.sh" ?? "" instead.

Comment thread screencast-gif/Main.qml
Process {
id: checker
running: false
command: ["sh", "-c", "[ -f /tmp/screencast-gif.pid ] && kill -0 \"$(awk '{print $1}' /tmp/screencast-gif.pid 2>/dev/null)\" 2>/dev/null && printf 1 || printf 0"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to have this script have its own script file? For better debugging and organization.

"description": "Hotkey-driven region screencast that produces an animated GIF and copies it to the clipboard. Bar pill turns red while recording. Backed by wf-recorder + gifski.",
"tags": [
"Bar",
"Recording",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tag doesn't exist

"Recording",
"Hyprland",
"Sway",
"GIF",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tag doesn't exist either.

Comment thread screencast-gif/README.md
| [`slurp`](https://github.com/emersion/slurp) | region selection | `slurp` |
| `ffmpeg` | extract frames from the captured mp4 | `ffmpeg` |
| `wl-clipboard` | clipboard plumbing (`wl-copy`) | `wl-clipboard` |
| `flock` (util-linux) | invocation locking | `util-linux` |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this requirement needed? I'm a bit confused.

@spiros132 spiros132 marked this pull request as draft May 1, 2026 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants