Summary
Ship Modular Riffs as a downloadable desktop app — a normal installer (.exe / .dmg) on the GitHub Releases page that someone double-clicks, installs, and launches like any other application. No local server, no browser, no localhost, no permission-prompt dance.
Why it fits
The app is fantastic but the current on-ramp is technical: run serve.sh / serve.cmd (or Docker), open Chrome/Edge, understand why file:// won't work, approve Web MIDI. That's fine for tinkerers and the headless-server deploy, but it's a wall for a musician who just wants to plug in an interface and play. A native package makes Modular Riffs feel like the piece of gear it's dressed as.
This is additive — the existing static-serve and Docker paths stay exactly as they are for dev and always-on hosting. The installer is just a fourth way to run the same index.html + js/ + styles.css.
The Web MIDI constraint (drives the tech choice)
Web MIDI only runs in a Chromium-based secure context. That rules out any wrapper built on the macOS system WebView (WKWebView has no Web MIDI). So the packaging layer must bundle Chromium:
- Recommended: Electron. Bundles Chromium, so Web MIDI works identically on Windows and macOS (and Linux). The app already being a buildless static bundle means the "main process" is tiny — create a
BrowserWindow, load the local index.html, done. A packaged Electron page is a secure context, so MIDI access just works with no localhost server.
- Tauri is lighter but uses the system webview — WebView2 (Chromium) on Windows would work, but macOS WKWebView would not. So Tauri can't deliver cross-platform Web MIDI. Note it and move on unless we drop macOS.
Proposed scope
Packaging
- Add an
electron/ (or top-level) main process that opens a window pointed at the bundled app, sized to the panel.
- Use electron-builder to produce installers: Windows NSIS
.exe (and/or MSI), macOS .dmg (universal: Intel + Apple Silicon).
- Keep the web assets the single source of truth — the desktop build includes the same files the browser/Docker paths serve, so there's no fork.
Desktop niceties (small, high-value)
- App icon + name in the dock/taskbar; native window chrome.
- Remember window size/position.
- Optional: a native menu (or just keep the in-app controls).
- Optional later: auto-update via electron-builder's update feed, and code-signing/notarization so installers don't get OS-blocked (macOS Gatekeeper / Windows SmartScreen). Worth a follow-up issue — unsigned builds still install with a warning.
Release automation
- A GitHub Actions workflow (build matrix:
windows-latest, macos-latest) that runs electron-builder on tag push and attaches the .exe / .dmg to the Release, so "download from the release" is a real, repeatable artifact.
Docs
- README gets a short "Install the desktop app" section above the server instructions: download → install → open → Enable MIDI → pick interface → play.
Where
New packaging dir + electron-builder config; package.json (was buildless — this adds a dev-only dependency, the shipped app stays vanilla JS); .github/workflows/ (release build); README (install section). No changes to js/ app logic.
Done when
Open questions
- Code-signing now or later? (Affects the out-of-box install experience but not function — recommend ship unsigned first, sign in a follow-up.)
- Linux target too (
AppImage / .deb), or just Windows + macOS for v1?
- Bundle the internal synth's audio the same way (it's Web Audio, so it just works in Electron) — confirm no sample-rate / autoplay quirks in the packaged window.
Summary
Ship Modular Riffs as a downloadable desktop app — a normal installer (
.exe/.dmg) on the GitHub Releases page that someone double-clicks, installs, and launches like any other application. No local server, no browser, nolocalhost, no permission-prompt dance.Why it fits
The app is fantastic but the current on-ramp is technical: run
serve.sh/serve.cmd(or Docker), open Chrome/Edge, understand whyfile://won't work, approve Web MIDI. That's fine for tinkerers and the headless-server deploy, but it's a wall for a musician who just wants to plug in an interface and play. A native package makes Modular Riffs feel like the piece of gear it's dressed as.This is additive — the existing static-serve and Docker paths stay exactly as they are for dev and always-on hosting. The installer is just a fourth way to run the same
index.html+js/+styles.css.The Web MIDI constraint (drives the tech choice)
Web MIDI only runs in a Chromium-based secure context. That rules out any wrapper built on the macOS system WebView (WKWebView has no Web MIDI). So the packaging layer must bundle Chromium:
BrowserWindow, load the localindex.html, done. A packaged Electron page is a secure context, so MIDI access just works with nolocalhostserver.Proposed scope
Packaging
electron/(or top-level) main process that opens a window pointed at the bundled app, sized to the panel..exe(and/or MSI), macOS.dmg(universal: Intel + Apple Silicon).Desktop niceties (small, high-value)
Release automation
windows-latest,macos-latest) that runs electron-builder on tag push and attaches the.exe/.dmgto the Release, so "download from the release" is a real, repeatable artifact.Docs
Where
New packaging dir +
electron-builderconfig;package.json(was buildless — this adds a dev-only dependency, the shipped app stays vanilla JS);.github/workflows/(release build); README (install section). No changes tojs/app logic.Done when
npm run distproduces a Windows.exeand a macOS.dmg.serve.*/ Docker workflows are untouched and still documented.Open questions
AppImage/.deb), or just Windows + macOS for v1?