The relay runs inside the Tauri Rust process — not in Node.js or the browser.
127.0.0.1:8787 (IPv4) and [::1]:8787 (IPv6) via tokio + tokio-tungstenite{"type":"hello","role":"index"} or "canvas"HUFFSYPH → Syphon, HUFFSPOUT → Spout, all other → canvas clients| Crate | Version | Purpose |
|---|---|---|
| tauri | 1.x | App shell, two-window management, Tauri IPC |
| tokio | 1.x | Async runtime (relay + OSC listener) |
| tokio-tungstenite | 0.21 | WebSocket server |
| midir | 0.9 | Native MIDI input (USB + virtual) |
| rosc | 0.10 | OSC UDP packet decoder |
| once_cell | 1.x | Lazy static initialisation for global client map |
| serde / serde_json | 1.x | JSON IPC serialisation |
| objc / objc-foundation | 0.2 / 0.1 | macOS Syphon ObjC FFI (macOS only) |
| cmake | 0.1 | Spout bridge CMake build (Windows only) |
The frontend intentionally has no build step and no bundler. Everything is plain ES6 loaded via script tags. This keeps the dev cycle fast — edit a file, reload the WebView, see the change immediately.
index.html is large (~2300 lines) because the entire controls UI, all MIDI/OSC/Syphon/Spout logic, and the p5 draw loop all live in one file. This is intentional — a single file is trivially auditable and has no dependency graph to maintain.
effects.js is the one separate module because its functions are called from both canvas.js and index.html. The only shared interface between the two is the frameRing array and gBuf p5 Graphics object.