A tactile desktop audio deck. Turn an Arduino Nano + 3 knobs into a real mixer for your computer.
Download Β· Quick Start Β· Build Your Controller Β· Roadmap
Software volume sliders are fine until you have music, a call, and a stream running at once and need to ride three levels now. Ioruba gives those levels back their knobs.
Spin a physical dial, watch the bar move, hear the change β no alt-tabbing, no hunting through audio settings. It's the hands-on feel of a small hardware mixer, rebuilt on a modern stack:
- ποΈ Tactile by design β three real potentiometers map to three audio targets. Master, your apps, your mic β each on its own knob.
- π§ Real audio control on Linux β drive master volume, individual applications, microphone sources, and output sinks through
pactl. - π‘ Live telemetry you can trust β a connection state you can never misread, per-knob min/avg/max statistics, and a persistent watch log.
- π§© Yours to remix β editable JSON profiles, ready-made presets, and import/export for backup and sharing.
- πΈ Cheap to build β an Arduino Nano, three pots, and a handful of wires. The firmware and wiring guide are in this repo.
- π οΈ Built like a tool, not a toy β Tauri 2 + React 19 + TypeScript front end, a Rust audio backend, Arduino C++ firmware, and CI gating every layer.
Platform status at a glance Real, full audio control is production-ready on Linux via
pactl. Windows and macOS controlmaster/ default-output volume through Core Audio; application, source, and sink targets remain Linux-only.
Tactile dashboard β copper + teal instrument-panel direction, connection state always front and center.
- Why Ioruba?
- Table of contents
- β¨ Feature highlights
- π₯οΈ Platform support
- π How it works
- β‘ Install in one line
- π οΈ Build from source
- β First launch checklist
- ποΈ Default knob mapping
- π Where your data lives
- π§° npm scripts
- ποΈ Repository map
- π Documentation
- π€ Contributing & support
- π License
Hardware & protocol
- Three 10-bit knob readings streamed as compact serial frames like
512|768|1023. - Firmware handshake on connect:
HELLO board=...; fw=...; protocol=...; knobs=.... - Backward compatible with the legacy
P1:512packet format.
Audio control
- Linux target handling for master, application, source, and sink.
- Windows & macOS Core Audio backends for master (default output) volume.
- Demo mode to validate the UI without touching system audio.
Workflow & telemetry
- Live telemetry plus whole-session statistics (per-knob min / avg / max).
- Persistent, auto-trimmed watch log baked into the desktop app.
- First-run onboarding checklist covering controller, serial port, and audio backend.
Profiles
- Editable JSON profiles stored in your platform config directory.
- Ready-made presets for streaming, calls, and music.
- Profile import / export as JSON for backup and sharing.
Distribution & quality
- One-line cross-platform installer with OS/architecture detection and checksum verification.
- CI across desktop, shared, and Rust layers plus firmware compilation.
- Tagged release workflows producing desktop bundles (
deb,rpm,AppImage), firmware artifacts, and Arch packaging metadata (PKGBUILD+.SRCINFO).
| Platform | Status | Notes |
|---|---|---|
| Linux | β Supported | Main production path: serial workflow, pactl audio backend, demo mode, hardware validation. |
| macOS | Core Audio backend controls default output (master) volume; app/source/sink targets unsupported. |
|
| Windows | Core Audio backend controls default output (master) volume; app/source/sink targets unsupported. |
Note: Linux is still the only platform with full target coverage (
master, applications, sinks, sources). Windows and macOS currently support default-output volume only.
Knob turn β Arduino firmware β Serial β Shared protocol parser β Zustand store β Rust command β pactl
| Layer | Where | What it does |
|---|---|---|
| Firmware | firmware/arduino/ioruba-controller |
Reads three potentiometers, emits the handshake and 512|768|1023 frames over serial. |
| Shared logic | packages/shared |
Parses packets/handshake, runs knobβvalue math, owns domain types and validation. |
| Desktop UI | apps/desktop/src |
React + Zustand dashboard, serial runtime, telemetry charts, profile editor. |
| Rust backend | apps/desktop/src-tauri |
Tauri commands, state persistence, watch logging, and the pactl audio backend. |
Protocol and runtime-math changes live in packages/shared, never in the app β one source of truth for every layer.
Pre-built installers ship with every latest release. The installer auto-detects your OS and CPU architecture, downloads the matching asset, verifies it against SHA256SUMS.txt, and installs it.
Linux / macOS
curl -fsSL https://raw.githubusercontent.com/bernardopg/ioruba/main/scripts/install.sh | shOptions: --version v1.1.0 (pin a release), --type deb|rpm (Linux package instead of the default AppImage), --dir <path> (install location). On Linux the default is a rootless AppImage in ~/.local/bin; macOS installs the .app into /Applications.
Windows (PowerShell)
irm https://raw.githubusercontent.com/bernardopg/ioruba/main/scripts/install.ps1 | iexOptions: -Version v1.1.0, -Type msi|nsis (default msi).
π Always review a piped install script before running it. Source:
scripts/install.shΒ·scripts/install.ps1.
Distro-specific & manual installs
# Source build
yay -S ioruba-desktop
# Prebuilt AppImage
yay -S ioruba-desktop-bincurl -s https://api.github.com/repos/bernardopg/ioruba/releases/latest \
| jq -r '.assets[] | select(.name | test("\\.deb$")) | .browser_download_url' \
| xargs -n1 curl -LO
sudo apt install ./Ioruba_*_amd64.debcurl -s https://api.github.com/repos/bernardopg/ioruba/releases/latest \
| jq -r '.assets[] | select(.name | test("\\.rpm$")) | .browser_download_url' \
| xargs -n1 curl -LO
# If you use dnf (Fedora/RHEL):
sudo dnf install ./Ioruba-*.x86_64.rpm
# For zypper (openSUSE) or yum (older CentOS), substitute accordingly.curl -s https://api.github.com/repos/bernardopg/ioruba/releases/latest \
| jq -r '.assets[] | select(.name | test("\\.AppImage$")) | .browser_download_url' \
| xargs -n1 curl -LO
chmod +x Ioruba_*.AppImage
./Ioruba_*.AppImageDownload the Windows installer assets from the latest release page (.exe / .msi).
Download the macOS app bundle archive from the latest release page:
Ioruba_..._aarch64.app.tar.gzIoruba_..._x64.app.tar.gz
Reminder: On Windows and macOS, the app can control the default output (
master) volume only. Full audio target coverage (applications, sinks, sources) requires Linux.
Prerequisites
- Node.js
22(same major used in CI) +npm - Rust stable +
cargo arduino-clipactl(Linux only, for the full audio backend)- Git
Quick start
# 1. Clone & install
git clone https://github.com/bernardopg/ioruba.git
cd ioruba
npm install
# 2. Verify the stack (typecheck, tests, Rust checks, desktop build)
npm run verify
# 3. Compile firmware (optional β skip if the board is already flashed)
npm run firmware:compile
# 4. Launch the desktop app
npm run desktop:dev # Vite frontend only (fast UI iteration)
npm run desktop:watch # Full Tauri shell (serial, persistence, audio backend)Wire the controller with docs/guides/hardware-setup.md, flash the Nano with NANO_SETUP.md, and grab sample profiles from docs/guides/profile-examples.md.
When the app opens, confirm:
- The app detects serial ports (or uses your preferred port).
- The status card progresses through connection states (not stuck on "idle").
- The runtime receives the firmware handshake (
HELLO β¦) alongside knob frames. - The Watch tab shows frames like
512|768|1023. - Turning knobs moves the telemetry chart.
- The active profile saved to JSON survives restarts.
- Clicking Atualizar Γ‘udio refreshes the Linux audio inventory.
- Knobs control their configured targets (master volume, apps, microphone, etc.).
| Knob | Default label | Target |
|---|---|---|
| 1 | Master Volume | Default output / master volume |
| 2 | Applications | Spotify, Google Chrome, Firefox |
| 3 | Microphone | Default microphone input |
The desktop app persists two files in the platform-specific config directory:
ioruba-state.jsonβ active profile and runtime stateioruba-watch.logβ structured watch events (auto-trimmed to ~1 MiB)
| OS | Path |
|---|---|
| Linux | ~/.config/io.ioruba.desktop/ |
| macOS | ~/Library/Application Support/io.ioruba.desktop/ |
| Windows | %APPDATA%\io.ioruba.desktop\ |
| Script | Description |
|---|---|
npm run verify |
Full validation: typecheck, tests, Rust, desktop build. |
npm run desktop:dev |
Starts the Vite frontend (UI work). |
npm run desktop:watch |
Starts the full Tauri desktop shell (development). |
npm run desktop:icons |
Regenerates desktop/icon assets from app-icon.svg. |
npm run desktop:tauri:build |
Builds the Tauri app locally (no installers). |
npm run firmware:compile |
Compiles the Arduino Nano firmware. |
npm run rust:test |
Runs the Rust backend tests. |
npm run rust:audit |
Audits the Rust lockfile (includes local glib backport). |
| Path | Purpose |
|---|---|
apps/desktop |
Tauri 2 desktop app, React UI, Zustand state, telemetry dashboards. |
apps/desktop/src-tauri |
Rust commands (persistence, watch logging, Linux audio control). |
packages/shared |
Shared domain types, defaults, runtime math, protocol parsing. |
firmware/arduino/ioruba-controller |
Arduino firmware for Nano-compatible boards. |
docs/guides |
Practical setup guides (hardware, Nano, profiles, translations). |
docs/debug/support.md |
Support playbook for serial, audio, and profile-debug issues. |
TESTING.md |
Automated checks, smoke tests, release validation matrix. |
| Document | When you need⦠|
|---|---|
| QUICKSTART.md | Fastest path from zero to a running app (Linux). |
| NANO_SETUP.md | Flashing and validating the Arduino Nano. |
| docs/guides/hardware-setup.md | Wiring the physical controller (potentiometers, breadboard/enclosure). |
| docs/guides/profile-examples.md | Ready-to-paste JSON profile samples and Linux target-matching rules. |
| docs/guides/translation-guide.md | How translations work in the desktop app and validation steps. |
| docs/translations/pt-br/README.md | Portuguese translation index for docs and root manuals. |
| docs/debug/support.md | Troubleshooting serial, audio, and profile-related issues. |
| TESTING.md | Automated checks, smoke tests, and release validation. |
| TODO.md | Roadmap of upcoming features. |
Contributions to code, docs, and translations are welcome β start with CONTRIBUTING.md. Before opening a PR, run npm run verify; add npm run desktop:tauri:build for desktop-shell changes and compile the firmware when firmware files change.
If Ioruba is useful to you, consider supporting development:
See FUNDING.md for details.
MIT Β© Bernardo Gomes β see LICENSE.
