Play animated GIFs on your Stream Deck / OpenDeck keys — with an optional command fired on key press.
The Stream Deck SDK's setImage doesn't support animated formats. GifDeck works around this the same way Elgato's own animated plugins do: it decodes the GIF into individual frames once, then cycles them onto the key with setImage on a timer driven by each frame's real delay. The result is smooth animation on any device OpenDeck supports — including non-Elgato hardware like the Mirabox N3.
- Animated GIF playback on any keypad key
- Per-frame timing taken from the GIF itself (not a fixed framerate)
- Adjustable speed multiplier (0.25×–4×)
- Optional shell command on key press — turns any animated key into a launcher
- Works on Linux via OpenDeck
- OpenDeck (Linux/macOS/Windows) or Elgato Stream Deck software 6.0+
- Node.js 20+ and the Elgato CLI (for building from source)
git clone https://github.com/GitFlowLink/gifdeck.git
cd gifdeck
npm install
npm run buildThen link the plugin into OpenDeck's plugin directory and restart OpenDeck (see the OpenDeck plugin docs for the exact path on your system), or package a distributable with the Elgato CLI:
npx streamdeck pack dev.gitflowlink.gifdeck.sdPlugin- Drag the GIF Player action onto a key.
- In the Property Inspector, click Browse… to pick a
.giffile via your system file dialog (useskdialogon KDE, falls back tozenityon GTK), or paste an absolute path directly into the field. - (Optional) Enter a command to run when the key is pressed.
- (Optional) Adjust playback speed.
The key animates immediately. Pick a different GIF at any time and it swaps right away.
- The native file picker needs
kdialog(KDE) orzenity(GNOME/GTK) installed. Most desktops ship one of them; if neither is present, paste the path manually. - Paths support
~expansion (e.g.~/Pictures/cat.gif).
GIF file ──▶ gifuct-js (decode + de-dispose frames)
──▶ composite each frame onto a persistent RGBA canvas
──▶ scale to 144×144, encode PNG (pngjs)
──▶ data-URL frames cached in memory
──▶ setImage() on a timer using each frame's delay
State is tracked per key context, so multiple animated keys run independently. Timers are cleared
on onWillDisappear to avoid leaks when switching profiles or pages.
TypeScript · Elgato Stream Deck SDK v1 · gifuct-js · pngjs · Rollup
MIT © 2026 Vladimir (GitFlowLink)
