Modern Electron-based desktop control center featuring smart profiles, automation, live widgets, and contextual app-aware controls.
EchoDeck is a next-generation Stream Deck alternative built with Electron, React, and Node.js.
It combines:
- dynamic profiles
- automation
- app-aware switching
- live widgets
- macros
- desktop integrations
- real-time controls
- soundboard routing
- native tray integration
into a customizable desktop command center.
Buttons that do something you cannot undo — restart, shutdown, ending a stream — can be set to require a deliberate press instead of a tap.
Turn on Confirm before running in the button editor. On the phone, a tap then does nothing: the button has to be held for about three quarters of a second, with a ring filling around the tile edge where your thumb does not cover it. Letting go early cancels and leaves nothing armed, so there is never a primed button waiting to fire on a later tap. Guarded buttons show a small 🔒 badge on both the phone and the desktop layout.
This is an accident guard in the interface, not a security control — the host still runs any well-formed press it receives.
Phones pair by scanning a QR code from Add Phone in the top bar.
The code in the QR is short-lived and is replaced every time EchoDeck starts, so an old screenshot stops working. On a successful pair the host issues that phone its own credential, which is stored and survives restarts — pair once and the phone reconnects on its own from then on.
Paired Devices in the top bar lists every phone that has paired, offline ones included, with when it last connected:
- Disconnect ends the current session; the phone reconnects on its own
- Revoke removes the pairing entirely — that phone must scan a new QR code
The API and WebSocket both refuse unpaired devices, and requests from the machine EchoDeck is running on are always trusted.
Automatically switch profiles depending on the active application on your PC.
Each page can have one rule. A rule is a list of conditions that describe when that page should activate. EchoDeck watches your currently focused window and evaluates all rules continuously.
A condition checks one thing about the focused window:
| Type | What it checks |
|---|---|
| Process | The .exe name (e.g. Code.exe, chrome.exe) |
| Window title | The text in the title bar |
| Executable path | The full file path on disk |
Each condition uses an operator to match against a value you type:
equals · contains · starts_with · ends_with · regex · not_equals · not_contains · exists
When a rule has multiple conditions:
- AND — all conditions must match for the page to activate
- OR — any one condition matching is enough
Most setups only need a single condition, so this only matters if you add a second one.
If two pages have rules that both match your current app, priority decides which one wins — lower number = higher priority. A rule with priority 10 beats one with 100. If all your pages target different apps, leave everything at 100.
The checkbox next to a rule lets you temporarily disable it without deleting it.
You want your Streaming page when OBS is focused, and your Coding page when VS Code is open.
- Streaming page rule: Process equals
obs64.exe, priority100- Coding page rule: Process equals
Code.exe, priority100Clicking into OBS flips the deck to Streaming. Clicking into VS Code flips it to Coding. Anything else — it stays on whatever page it was last on.
process
window_title
executable_path
equals
contains
starts_with
ends_with
regex
not_equals
not_contains
exists
{
"logic": "AND",
"priority": 10,
"conditions": [
{
"type": "process",
"operator": "equals",
"value": "Code.exe"
}
]
}Live WebSocket-powered dashboard with:
- instant profile switching
- button updates
- system monitoring (CPU, RAM, clock)
- volume control
- device state sync
Create unlimited profiles/pages:
- Main · Coding · Sounds · Streaming · Gaming
- Productivity · AI Tools · Custom workflows
Trigger:
- keyboard shortcuts
- applications & URLs
- shell commands
- media & volume controls (hold a volume button to ramp; step size is configurable)
- audio device switching
- soundboard (phone-only, PC-only, or both)
- multi-action sequences and two-stack switches
Each button can play a sound file with three routing modes:
| Mode | Where it plays |
|---|---|
| 📱 Phone only | Out of the phone |
| 🖥️ PC only | Out of the PC, on the device you choose |
| 📱+🖥️ Both | Both at once |
Routing is a property of the button, so remember to hit Save Changes — an "Unsaved changes" banner appears whenever the panel has edits pending.
Audio Settings in the top bar lists your real playback devices. Pick any one; no Voicemeeter, no virtual audio software required for ordinary playback.
To get soundboard audio into Discord, OBS or any other app that captures a microphone, you need a virtual audio device — Windows has no way to feed audio into a mic input on its own, and Stream Deck has the same requirement.
- Install a virtual cable (VB-CABLE is free)
- Set PC output device to
CABLE Input - Set Discord's input device to
CABLE Output
A virtual cable is not a speaker, so routing sounds into one means you stop hearing them. Set Also play on (monitor) to your headset and each sound plays to both at once — the cable for the call, your headphones for you.
- CPU usage
- RAM usage
- Clock
- Volume control
- Media playback
- Live Browser (YouTube previews, Twitch chat, Home Assistant, security cameras)
- OBS stats
- AI widgets
- Homelab monitoring
- System tray — runs silently in the background; single-click to toggle the window
- Startup launch — opt-in from the tray menu; when enabled, opens hidden to tray on boot
- Active window detection — powers auto profile switching
- Native notifications — startup confirmation, tray hints
- Process monitoring — real-time running app list for rule capture
Add screenshot here
Add screenshot here
- React · Vite · Electron · WebSockets
- Node.js · Express · SQLite
- Electron Tray · Native Window Detection · Process Monitoring · Login Item Registration
echodeck/
├── .github/
│ └── workflows/
│ └── android-release.yml ← CI: builds APK + EXE on every tag push
│
├── client/ ← React frontend + Capacitor Android app
│ ├── src/
│ │ ├── App.jsx
│ │ ├── desktop/
│ │ │ └── DesktopApp.jsx
│ │ ├── ConfigUI.jsx
│ │ ├── constants.js
│ │ └── index.css
│ ├── android/ ← Capacitor Android project (generated)
│ └── package.json
│
├── host/ ← Electron main process + Express backend
│ ├── scripts/
│ │ └── fetch-tools.mjs ← downloads bundled binaries at build time
│ ├── src/
│ │ ├── server.js
│ │ ├── actions.js
│ │ ├── db.js
│ │ ├── network.js
│ │ ├── activeWindow.js
│ │ └── ruleEngine.js
│ ├── assets/
│ │ └── icon.png / icon.ico
│ ├── main.js
│ ├── preload.js
│ ├── macro-deck.db
│ └── package.json
│
├── build-android.ps1 ← Local Android build script (Windows)
└── README.md
- Node.js v22 or later
- Android Studio (only needed for local Android builds)
- Windows OS (the desktop app is Windows-only for now)
# Client
cd client && npm install
# Host
cd host && npm install# 1. Start the frontend (Vite dev server)
cd client && npm run dev
# 2. Start the backend
cd host && node src/server.js
# 3. Start Electron (separate terminal)
cd host && npm start# Build the React/Vite web bundle
cd client && npm run build
# Build the Windows installer (also runs the client build via predist)
cd host && npm run distnpm run dist first runs npm run fetch:tools, which downloads ffplay into
host/assets/tools/. That binary is ~112 MB, so it is fetched at build time
rather than committed, and skipped on later builds once present. It is only
used to play soundboard audio when the desktop app is not running — for example
under npm run dev, which starts the server without Electron.
EchoDeck uses GitHub Actions to automatically build and publish releases. Every time a version tag is pushed, the CI pipeline builds both the Windows installer and the Android APK in parallel, then attaches them to a GitHub Release.
git tag v1.2.0 && git push origin v1.2.0
↓
GitHub Actions triggers two parallel jobs:
┌─────────────────────────┐ ┌──────────────────────────┐
│ Build Android APK │ │ Build Windows EXE │
│ ubuntu-latest │ │ windows-latest │
│ │ │ │
│ npm run build │ │ npm run build (client) │
│ cap sync android │ │ npm run dist (host) │
│ gradlew assembleDebug │ │ electron-builder │
└────────────┬────────────┘ └─────────────┬────────────┘
└──────────┬──────────────────┘
↓
GitHub Release: v1.2.0
├── EchoDeck-Setup.exe
└── echodeck-v1.2.0.apk
Make sure everything is committed and pushed, then:
git tag v1.2.0
git push origin v1.2.0That's it. Check the Actions tab on GitHub to watch the build, then Releases for the output.
v1.0.0 → first stable build
v1.0.1 → bug fix
v1.1.0 → new feature
v2.0.0 → major update
If you want to build the APK locally without pushing a tag:
# From the repo root
.\build-android.ps1 # outputs echodeck-local.apk
.\build-android.ps1 v1.2.0 # outputs echodeck-v1.2.0.apk- The workflow uses
GITHUB_TOKENwhich is automatically available — no secrets needed - The APK is debug-signed, which is fine for sideloading
- Windows SmartScreen will warn on the EXE since it has no code signing certificate — click More info → Run anyway. This is expected for unsigned open-source apps
- If you fork and want your own releases, no changes are needed — the workflow uses
github.ref_nameso it picks up your own tags automatically
- Real-time WebSocket dashboard
- Dynamic pages / profiles
- Auto profile switching with rule engine
- SQLite persistence
- Electron tray integration (single-click toggle, startup launch, hidden-on-boot)
- Volume controls & audio device switching
- Soundboard with 3-way routing (phone / PC / both)
- Soundboard output device selection, no Voicemeeter required
- Monitor output — hear a sound while it also goes to a virtual cable
- Hold-to-confirm guard for destructive buttons
- Persistent device pairing with per-device revocation
- Active window detection & running app picker
- Delayed app capture (3-second countdown)
- Full Electron desktop UI (Elgato-style layout)
- Drag-to-reorder buttons
- Button toggle states
- Icon & sound file uploads
- QR code phone pairing
- Config UI (mobile-friendly)
- Audio settings panel
- Windows startup registration (opt-in from the tray)
- Android companion app
- Automated GitHub releases (APK + EXE via CI)
- Plugin architecture
- Widget system expansion
- Advanced profile editor
- Live Browser button (page previews inside a key)
- Browser-aware profiles (switch by URL/tab)
- Twitch / YouTube integration
- OBS integration
- AI-powered controls & suggestions
- iOS companion app
- Plugin marketplace
- Multi-device syncing
EchoDeck is not just a Stream Deck clone.
The goal is to build a smart desktop command center — a contextual workflow automation platform that knows what you're doing and surfaces the right controls at the right time.
Combining ideas from Stream Deck, Raycast, OBS, Home Assistant, BetterTouchTool, and desktop automation tools into one unified experience.
Embed a live web view inside a deck key — updated snapshots or live iframes of:
- YouTube stream preview
- Twitch chat
- Home Assistant dashboard
- Security camera feeds
- Discord activity
youtube.com → Media profile
github.com → Coding profile
figma.com → Design profile
- AI-generated workflows
- Voice commands
- Smart suggestions
- Contextual actions
Discord · Spotify · Twitch · YouTube · OBS · Home Assistant · MQTT
MIT License
Built by Hoss.