Omahub
← All plugins
G

Motion Wallpaper

by Gavin Nugent

Native looping video wallpaper for omarchy-shell. Renders a muted, looping video on the background layer above the static wallpaper, with a different clip per monitor if you want one, adjustable playback speed, optional rotation through your library on a per-monitor schedule, and auto-pause on fullscreen. Controlled from its bar widget, or from a terminal with the motion-wallpaper CLI.

Security review

Review recommended · 2 findings

Deterministic scan — not a security guarantee

Medium
Risk level
Medium
Analyzed commit
bacebac
Scanned
2 weeks ago
  • medium sudo wallpaper.sh:66

    Command runs with sudo, elevating the process beyond the plugin environment.

    sudo pacman -S --needed "${MISSING_PKGS[@]}"
  • Docs external_hosts README.md:37

    Downloads or connects to an external HTTP(S) host.

    git clone https://github.com/28allday/Motion-Wallpaper-Omarchy.git

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

Low
AI risk level
Low
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
bacebac
Reviewed
2 weeks ago

The plugin is a benign video-wallpaper service for Omarchy. The deterministic scan flagged the README's git clone URL (documentation only) and the installer's sudo pacman call (a standard, transparent dependency install). The QML code and CLI are straightforward, with no obfuscation, network calls at runtime, or destructive behavior.

  • The installer wallpaper.sh uses sudo to install missing packages (jq, python, hyprland, qt6-multimedia); this is a common, user-visible operation and not hidden or malicious.
  • The README contains a git clone command, but that is documentation for manual installation, not part of the plugin's executable code.
How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/28allday/Motion-Wallpaper-Omarchy --enable
Appearance #Hyprland #quickshell #media

Motion Wallpaper - Omarchy

Animated video wallpapers for Omarchy 4 (Arch Linux + Hyprland + Quickshell).

Two monitors, each running its own clip, with the control panel open

<sub>Two monitors, two different clips, panel open on the right. Clips from moewalls.com.</sub>

Drop some clips in ~/Videos, click the film icon in the bar, pick one. That's it.

  • A different clip on every monitor — or one everywhere, or video on some screens and your normal wallpaper on the rest
  • Native panel in the bar — play, pause, stop, pick a clip, all themed to match the rest of the shell
  • Pauses itself under fullscreen windows, so games and films don't pay for a wallpaper nobody can see
  • Cross-fades between clips — the desktop never flashes through mid-switch
  • Comes back after a reboot, with no autostart to set up
  • motion-wallpaper CLI for keybinds and scripting

There's no daemon, watcher, systemd unit or terminal UI — it is one omarchy-shell plugin doing the rendering, the controls and the state.

Omarchy 4+ only. It needs the Quickshell-based omarchy-shell; the installer checks for it and stops if it is missing.

Watch the demo

Quick Start

This repo is an Omarchy shell plugin, so Omarchy's own plugin command installs it:

omarchy plugin add https://github.com/28allday/Motion-Wallpaper-Omarchy.git --enable

That clones it into ~/.config/omarchy/plugins/, enables it, and asks which bar section to put the film icon in — left, center or right (right is pre-selected). Click the icon and pick a video: that is the whole install.

To also get the motion-wallpaper CLI (for keybinds and scripting), run the installer script as well:

git clone https://github.com/28allday/Motion-Wallpaper-Omarchy.git
cd Motion-Wallpaper-Omarchy
./wallpaper.sh

wallpaper.sh checks dependencies, installs the plugin if it isn't already there (asking where to put the bar icon, same as above), installs the CLI and icon, and restarts the shell. If you already have the plugin, it leaves it alone and just adds the CLI.

To update later:

omarchy plugin update nosignal.motion-wallpaper

Requirements

  • OS: Omarchy 4+ (Arch Linux) with omarchy-shell (Quickshell)
  • Compositor: Hyprland
  • Packages: qt6-multimedia (video decode), jq, python, hyprland — installed automatically if missing (no AUR helper needed)

What It Installs

Path Purpose
~/.config/omarchy/plugins/nosignal.motion-wallpaper/ the plugin (service + bar widget + panel)
~/.local/bin/motion-wallpaper CLI control (keybinds / scripting)

In your shell.json, enabling adds a single bar-widget entry in the section you chose. Out of the box the plugin starts with no video selected, so your normal static wallpaper is what you see until you pick a clip.

Setting defaults in shell.json

Optional. Add an entry for this plugin id under plugins[] to choose what it starts with:

{ "id": "nosignal.motion-wallpaper", "videoPath": "~/Videos/clip.mp4",
  "enabled": true, "output": "all", "pauseOnFullscreen": true }

To start each monitor on its own clip, add screenVideos, keyed by connector name (hyprctl monitors lists them). An empty string keeps that screen on the static wallpaper, and any monitor you don't list falls back to videoPath:

{ "id": "nosignal.motion-wallpaper",
  "videoPath": "~/Videos/clip.mp4",
  "screenVideos": { "DP-1": "~/Videos/rain.mp4", "DP-2": "" },
  "enabled": true, "pauseOnFullscreen": true }

Usage

The bar widget + panel

<img src="docs/panel.png" alt="The Motion Wallpaper panel" width="330" align="right">

Click the film icon in the bar to open the control panel. From there you can:

  • Play / Pause / Stop the video
  • Pick a clip from a list of the videos in ~/Videos — clips cross-fade into each other, so the desktop never flashes through mid-switch
  • Choose the screen — the SCREEN dropdown (only shown when you have more than one monitor) aims everything below it: leave it on All screens to set every monitor at once, or pick a monitor to change just that one. Each option is labelled with the clip that screen is playing, so the dropdown doubles as the per-monitor readout.
  • Toggle auto-pause when a fullscreen window covers the wallpaper

The bar icon reflects state at a glance: accent when playing, amber when paused, dim when stopped.

From the terminal

motion-wallpaper                 # print current state, per monitor (default)
motion-wallpaper screens         # what each monitor is showing
motion-wallpaper play ~/Videos/clip.mp4          # every monitor
motion-wallpaper play ~/Videos/rain.mp4 DP-1     # just that monitor
motion-wallpaper off DP-2        # blank one screen; the others keep playing
motion-wallpaper clear DP-1      # drop its own clip; follow the default again
motion-wallpaper stop            # stop everywhere; static wallpaper shows through
motion-wallpaper toggle          # flip on/off
motion-wallpaper pause           # pause / resume
motion-wallpaper resume
motion-wallpaper autopause off   # or: on
motion-wallpaper speed 0.5       # playback speed, 0.25-2 (e.g. 1, 0.66)
motion-wallpaper stop DP-2       # blank one monitor; the other keeps playing
motion-wallpaper play DP-2       # and start it again
motion-wallpaper speed 0.5 DP-1  # speed for just that monitor
motion-wallpaper follow DP-1     # drop its own settings, follow the default

With a keybind

Omarchy 4 keeps user keybinds in ~/.config/hypr/bindings.lua. Avoid SUPER+W — that's Close window in Omarchy:

-- flip the wallpaper on and off
o.bind("SUPER + ALT + W", "Motion wallpaper", "motion-wallpaper toggle")

-- or open the panel itself
o.bind("SUPER + ALT + V", "Motion wallpaper panel",
       "omarchy-shell shell toggle nosignal.motion-wallpaper")

Video library folder

Drop clips in ~/Videos and they appear in the panel's list (a ~/Videos/Wallpapers subfolder is picked up too). To play a file from anywhere else, use motion-wallpaper play <path>.

Multiple monitors

Every monitor is set independently, so you can run a different clip on each screen, the same clip on all of them, or video on some and the static wallpaper on the rest. It all applies live, with no shell restart.

From the panel: pick a monitor in the SCREEN dropdown, then click a clip — only that screen changes. With a monitor picked, the video list grows an Off — static wallpaper row that blanks that one screen while the others keep playing. Switch back to All screens and clicking a clip sets every monitor at once (dropping the per-screen choices).

Once your screens are set individually, the panel opens aimed at the monitor it is on rather than at All screens — so a stray click changes one screen instead of flattening the lot. The screen it is aimed at is named in the pill next to the title.

The same thing from the terminal:

motion-wallpaper play ~/Videos/rain.mp4 DP-1
motion-wallpaper play ~/Videos/city.mp4 HDMI-A-1
motion-wallpaper off DP-2
motion-wallpaper screens          # check what landed where

Connector names come from hyprctl monitors. A monitor keeps its clip while it is unplugged, so it comes back to the right one; a monitor you have never set follows the default videoPath (and the legacy motion-wallpaper screen <name|all> targeting, which only applies to monitors with no clip of their own).

Playback speed

A SPEED slider in the panel sets how fast the clip plays, anywhere from 0.25x to 2x. It is free rather than stepped — 0.66 and 0.99 are as reachable as 1 — with tick marks at the round speeds as anchors. Dragging previews live; letting go saves. The speed applies to every monitor.

motion-wallpaper speed 0.5

One profile per screen

Everything below the SCREEN dropdown follows it: the clip list, rotation, the speed slider, and Play/Stop/Pause. On All screens you are editing the shared default; on a named screen you are editing that screen alone.

A screen with no settings of its own follows the shared default, so nothing changes until you give it some. Using any control while a screen is selected gives it its own; a line in the ROTATION section always says which of the two you are editing. To hand a screen back to the shared default, use the CLI:

motion-wallpaper follow DP-1              # rotation and playback
motion-wallpaper follow DP-1 rotation     # or just one half

So one monitor can be stopped, slowed down, or rotating on its own schedule while the other carries on:

motion-wallpaper stop DP-2          # DP-1 keeps playing
motion-wallpaper speed 0.5 DP-1     # only that monitor slows down
motion-wallpaper pause DP-2         # freeze one screen
motion-wallpaper play DP-2          # start it again
motion-wallpaper follow DP-1        # back to the shared default

The global Stop still governs every screen that has no profile of its own, so the plugin behaves exactly as before for anyone not using this.

Rotation

Off by default. Left alone, the plugin behaves exactly as it always has: one clip per monitor until you change it. Turn rotation on and it cycles your library instead.

In the panel's ROTATION section:

Setting Options
Mode Off · Rotate all videos · Rotate chosen videos
Order Shuffle · In order
Change every 1, 2, 5, 10, 15, 30 minutes, or 1 hour
Videos in rotation which clips to cycle, in chosen mode

Each monitor can rotate differently. The rotation controls follow the SCREEN dropdown, the same as the video list: on All screens you are editing the shared default, and on a named screen you are editing that screen alone. A screen with no settings of its own follows the shared default; changing anything while it is selected gives it its own, and a Follow default button hands it back.

So one monitor can shuffle every five minutes while the other sits on a single clip:

motion-wallpaper rotate all shuffle 5 DP-1   # DP-1 shuffles the whole library
motion-wallpaper rotate off "" "" DP-2       # DP-2 stays on its clip
motion-wallpaper next DP-1                   # skip ahead now
motion-wallpaper follow DP-1                 # back to the shared default

For chosen mode, pick the clips first:

motion-wallpaper playlist DP-1 ~/Videos/a.mp4 ~/Videos/b.mp4
motion-wallpaper rotate selected order 10 DP-1

Each monitor keeps its own position in the list, so two screens sharing a playlist rarely show the same clip at the same time. Rotation drives monitors that have a clip of their own too — that clip is just what is showing there now — and turning rotation off restores it untouched. A monitor blanked with off stays blank: that is how you keep one screen out of the rotation entirely.

Rotation pauses with the video, so a fullscreen window does not churn wallpapers behind it.

Persistence

A playing wallpaper resumes automatically after a reboot — the plugin persists its state to ~/.local/state/motion-wallpaper/state.json and the shell loads it on login. There's no separate autostart step: stop means it stays off next boot, play means it comes back.

How It Works

  • Rendering — the plugin creates one PanelWindow per targeted monitor on the Wayland background layer (namespace omarchy-motion-background), using QtMultimedia MediaPlayer + VideoOutput (looped, muted, PreserveAspectCrop). Each surface resolves its own clip, which is what lets monitors differ. It loads after the first-party static-wallpaper surface, so it stacks above it. When a monitor has no video set or its file is missing, no surface is created there at all — so the static wallpaper shows through (never a black or frozen frame).
  • Auto-pause on fullscreen — the plugin listens to Hyprland's event stream (Quickshell.Hyprland) and, on any fullscreen-affecting event, reads per-monitor ground truth from hyprctl to pause the video on exactly the monitor whose visible workspace has a fullscreen window. Toggle it from the panel (or motion-wallpaper autopause on|off).
  • Theme changes — nothing to do: switch themes freely, the first-party static wallpaper updates underneath. The video keeps playing until you stop it.
  • Controls — the bar widget and panel talk to the plugin's service instance in-process. The motion-wallpaper CLI is a thin client over the same shell IPC target (play / playAll / playOn / clearScreen / stop / toggle / pause / resume / status / screens / setOutput / setPauseOnFullscreen), reachable directly as omarchy-shell motion-wallpaper <fn>. State (per-screen clips, default video, enabled, auto-pause) persists to ~/.local/state/motion-wallpaper/state.json.

Supported Video Formats

Anything QtMultimedia's FFmpeg backend can decode — .mp4, .mkv, .webm, .mov, .avi. H.264/H.265 MP4 is the safest bet for smooth looping.

Finding Video Wallpapers

  • MoeWalls — large library of looping anime/aesthetic clips
  • Any short, seamlessly-looping video works well; keep it at your display resolution to avoid needless GPU scaling.

Performance

Video wallpaper decodes continuously on the GPU, so it uses more power than a static image. The fullscreen auto-pause keeps games and full-screen video from paying that cost. For laptops on battery, consider motion-wallpaper stop or a shorter/lower-bitrate clip.

QtMultimedia picks a hardware decode backend automatically when one initialises. The plugin probes this at startup (ffmpeg hwaccels, the GPU vendor from the DRM render nodes, a VAAPI init test, plus a CUDA init test on NVIDIA) and surfaces it via motion-wallpaper hwaccel and motion-wallpaper status (plus a panel hint when software fallback is active while playing). If it reports software fallback, the hint names the usual fix for your vendor (intel-media-driver on Intel, libva-mesa-driver on AMD, the proprietary driver / nvidia-utils on NVIDIA); QT_FFMPEG_DECODING_HW_DEVICE_TYPES overrides the backend priority when set. The probe result is cached in state.json and refreshed when older than a day (or on the next motion-wallpaper hwaccel call), so repeat shell starts don't respawn the check.

Troubleshooting

  • No bar icon / "plugin isn't loaded" — make sure it is enabled (omarchy plugin enable nosignal.motion-wallpaper), then restart the shell with omarchy-restart-shell. Confirm the IPC target answers with omarchy-shell motion-wallpaper status.
  • No video appears — check motion-wallpaper status: videoFileExists: false means the saved path is gone; pick a new file. Watch for QML errors in the shell's journal.
  • Edited the plugin QML — plugin code changes need a full omarchy-restart-shell; ipc call shell rescanPlugins only discovers newly-added plugins, it doesn't reload edited code. Don't use omarchy-refresh-shell — it resets shell.json.
  • Logs — ~/.cache/motion-wallpaper.log (CLI) and the shell's own stderr/journal (plugin).

Uninstalling

motion-wallpaper stop
omarchy plugin remove nosignal.motion-wallpaper

# The extras the plugin command doesn't own:
rm -f  ~/.local/bin/motion-wallpaper
rm -rf ~/.local/state/motion-wallpaper

Credits

Built for Omarchy by DHH and the Omarchy community. Video playback via Qt Multimedia; shell integration via Quickshell.

License

MIT