Skip to content

✨Bring your Stream Deck to life with stunning animated wallpapers — generated from any GIF and installed with a single click. Private by design, runs locally on your Elgato device.

License

Notifications You must be signed in to change notification settings

SaschaWebDev/stream-deck-gif-splitter

Repository files navigation

Stream Deck GIF Splitter

Split any animated GIF into perfectly sized tiles for your Elgato Stream Deck — including Stream Deck MK.2, Stream Deck XL, Stream Deck Mini, Stream Deck +, and Stream Deck Neo. Create seamless animated backgrounds and wallpapers that span your entire device, with gap-aware cutoff mode, custom crop, loop trimming, and one-click .streamDeckProfile export. Runs 100% in your browser — no uploads, no servers, no account needed.

✨ Turn any animated GIF into a seamless Stream Deck background — entirely in your browser. ✨

MIT License Website Vitest React 19 TypeScript Vite FFmpeg.wasm

Stream Deck GIF Splitter — animated background wallpaper tool for Elgato Stream Deck

🚀 - Try it live - · 🐛 Report Bug · 💡 Request Feature

🔥 Key Features

  • 🖱️ Drag & drop — Upload any GIF and see an instant cropped preview
  • 🔍 GIPHY search — Browse trending GIFs or search GIPHY directly from the app — no need to leave the page
  • 🎚️ 5 device presets — Stream Deck MK.2, XL, Mini, +, and Neo
  • ✂️ Cutoff mode — Accounts for the physical gap between buttons so animations appear seamless
  • 🎯 Custom crop position — Drag the crop region to choose exactly which part of the GIF to keep, instead of always center-cropping
  • 🔁 Custom loop trim — Trim the animation loop length with a timeline scrubber to keep only the portion you want
  • 📐 Custom grid size — Use a smaller sub-area of your device (e.g. 6×3 on an 8×4 XL) and position it anywhere on the button layout
  • 🎨 High-quality encoding — Two-pass palette generation with Floyd-Steinberg dithering
  • 📦 ZIP download — Get all tiles in a numbered, ready-to-assign archive
  • 🗂️ .streamDeckProfile export — One-click installable profile with all tiles pre-assigned
  • 📡 Fully offline — FFmpeg is cached after first load; works without internet on repeat visits
  • 🔒 Privacy-first — Your files never leave your browser

🎮 Supported Devices

Device Grid Tile Size Button Gap
Stream Deck MK.2 5 × 3 72 × 72 px 16 px
Stream Deck XL 8 × 4 144 × 144 px 40 px
Stream Deck Mini 3 × 2 72 × 72 px 16 px
Stream Deck + 4 × 2 72 × 72 px 16 px
Stream Deck Neo 4 × 2 72 × 72 px 16 px

🚀 Getting Started

Prerequisites

  • Node.js 18+ (LTS recommended)
  • npm, yarn, or pnpm

📥 Installation

git clone https://github.com/SaschaWebDev/animated-stream-deck-background-gif-converter.git
cd animated-stream-deck-background-gif-converter
npm install

💻 Development

npm run dev

Open http://localhost:5173 in your browser.

🧪 Testing

npm test              # run all tests once
npm run test:watch    # run tests in watch mode
npm run test:coverage # run tests with coverage report

📦 Build

npm run build
npm run preview   # preview the production build locally

🛠️ Tech Stack

Layer Technology
⚛️ Framework React 19 with React Compiler
🟦 Language TypeScript 5.9
⚡ Bundler Vite 7
🎬 Video Processing FFmpeg.wasm 0.12
🗜️ Archive Generation JSZip
🔍 GIF Search GIPHY API
🧹 Linting ESLint 9 with TypeScript & React plugins

⚙️ How It Works

  1. 📤 Upload — Drop a GIF, click to browse, or search GIPHY for the perfect animation
  2. ⚙️ Configure — Select your device model. Optionally enable Custom Grid to target a smaller sub-area (e.g. 6×3 on an XL) and use the arrow controls to position it on the device
  3. ✂️ Crop — The GIF is automatically cropped and scaled to match the target grid area (including optional gap compensation). Enable Custom Crop to drag the crop region and choose which area to keep
  4. 🔁 Trim — Enable Custom Loop to shorten the animation loop. A filmstrip timeline shows snapshot frames at evenly-spaced intervals; drag the left/right handles to select the portion you want. Trimmed-out regions are shown with a striped overlay
  5. 🔪 Split — FFmpeg slices the cropped GIF into individual tile animations using two-pass encoding for optimal quality
  6. 💾 Export — Download as a ZIP of numbered tiles or as a ready-to-install .streamDeckProfile. With Custom Grid, the profile places tiles at the correct offset positions and the mockup shows the full device with unused slots blacked out

📁 Project Structure

src/
├── main.tsx                          # Entry point
├── App.tsx                           # Root application component
├── index.css                         # Global styles & CSS variables
├── App.css                           # App-level styles
├── components/
│   ├── CropPreview.tsx               # Cropped GIF preview with split controls & custom crop editor
│   ├── DeviceConfig.tsx              # Device preset, cutoff mode & custom crop selector
│   ├── FileDropZone.tsx              # Drag-and-drop file upload area
│   ├── GifSourceTabs.tsx             # Upload / GIPHY toggle switcher
│   ├── GiphyPicker.tsx              # GIPHY search, grid & GIF selection
│   ├── HeroSection.tsx               # Landing hero banner
│   ├── ResultsPanel.tsx              # Tile grid results & download buttons
│   └── UserManual.tsx                # Inline usage instructions
├── constants/
│   └── presets.ts                    # Device preset configurations
├── hooks/
│   ├── useAutoScroll.ts              # Auto-scroll to results
│   ├── useDeviceConfig.ts            # Device preset state management
│   ├── useDownload.ts                # ZIP & profile download logic
│   ├── useFileUpload.ts              # File input & drag-and-drop handling
│   ├── useGifProcessor.ts            # Crop & split orchestration
│   ├── useGifSync.ts                 # Synchronized GIF playback
│   └── useGiphySearch.ts             # GIPHY search state & debouncing
├── services/
│   ├── ffmpeg.ts                     # FFmpeg.wasm hook (crop, split, progress)
│   ├── giphy.ts                      # GIPHY API service & GIF-to-File fetcher
│   └── streamDeckProfile.ts          # .streamDeckProfile ZIP generator
├── types/
│   └── index.ts                      # Shared TypeScript interfaces
└── utils/
    ├── crop.ts                       # Crop filter, trim args & coordinate calculations
    ├── device.ts                     # Device dimension calculations
    ├── filename.ts                   # Download filename generation
    ├── format.ts                     # File size formatting
    ├── gifDuration.ts                # GIF duration parser with outlier detection
    └── progress.ts                   # Progress label formatting

🤝 Contributing

Contributions are welcome! Feel free to open an issue or submit a pull request.

  1. 🍴 Fork the repository
  2. 🌿 Create your feature branch (git checkout -b feature/amazing-feature)
  3. 💾 Commit your changes (git commit -m 'Add amazing feature')
  4. 📤 Push to the branch (git push origin feature/amazing-feature)
  5. 🎉 Open a Pull Request

📄 License

Distributed under the MIT License. See LICENSE for details.


Made with ❤️ by Sascha Majewsky