everything-imu is a native bridge that turns Nintendo, Sony, and other game controllers
into full-body trackers for SlimeVR-Server. Plug a controller into your PC,
strap it on, and it shows up in SlimeVR as a regular tracker — no extra hardware,
no firmware flashing.
It also incorporates Haptics via the device's rumble, for information on how to set this up on your Avatar, go HERE
The bridge reads the controller's built-in IMU at its native sample rate, runs a sensor fusion filter (VQF or Madgwick) in Rust, and forwards the resulting quaternion to SlimeVR-Server over UDP using the official protocol.
Status: 1.0.4. The core fusion + protocol pipeline is stable and hardware-validated across the supported controllers. If you hit a snag, please file an issue with reproduction steps and the logs from the Logs tab.
- 10 controller families supported across USB · BT Classic · BLE · TCP.
- VQF / Madgwick / BasicVQF fusion, switchable per-device.
- Magnetometer calibration wizard for Joy-Con 2 and PS Move ZCM1 (sphere fit + coverage meter).
- Reset Yaw / Reset Full / Reset Mounting from the UI, system tray, global hotkey, or on-device gesture.
- VRChat OSC → rumble bridge with per-rule gain, threshold, pulse mode, and a per-device haptic calibration wizard (floor / gain mapping).
- UDP-forwarded haptic targets — register
host:portendpoints as virtual rumble devices for remote setups. - Linux udev installer — one-click hidraw access for Joy-Con / DualSense / PSMove without sudo.
- Auto-update at startup (GitHub Releases), with optional crash reporting via Sentry. Both opt-in, both off by default.
- Live diagnostics — per-tracker rate panels, bridge latency, raw IMU charts on the Debug page, circular battery rings, signal meter.
SlimeVR-Server already supports full-body tracking with dedicated SlimeVR hardware. This project plugs the bring-your-own-IMU gap: most homes have controllers with high-quality IMUs sitting in a drawer, and they make great secondary trackers (waist, knees, feet) when you're trying SlimeVR for the first time and don't want to commit to buying nodes yet.
We deliberately do not reimplement SlimeVR-Server features (skeletal model, SteamVR driver, calibration UI, etc.). everything-imu is the bridge layer only.
| Device | Transport | Native rate | Mag | Status |
|---|---|---|---|---|
| Joy-Con (L/R) | USB · BT Classic | 200 Hz | ✗ | hardware-validated |
| Switch Pro Controller | USB · BT Classic | 200 Hz | ✗ | hardware-validated |
| Joy-Con 2 / Pro 2 / NSO GC2 | BLE only | 62 Hz | ✓ | hardware-validated |
| DualSense (PS5) | USB · BT | 250 Hz | ✗ | hardware-validated |
| DualSense Edge | USB · BT | 250 Hz | ✗ | needs hardware |
| DualShock 4 (PS4) | USB | 250 Hz | ✗ | hardware-validated |
| PS Move ZCM1 | USB · BT | 175 Hz | ✓ | hardware-validated |
| PS Move ZCM2 | USB · BT | 175 Hz | ✗ | hardware-validated |
| Wii Remote | TCP forwarder (127.0.0.1:9909) |
100 Hz | ✗ | hardware-validated |
| HOPX / Triki | BLE | 52 Hz | ✗ | hardware-validated |
Deep-dive on each: DEVICES.md.
mobile/ ships a native Android phone tracker + Wear OS companion that
streams the phone IMU straight to SlimeVR-Server using the same UDP
protocol the desktop bridge speaks — no PC controller required.
- 4-tab UI (Home · Calibrate · Haptics · Settings) sharing the desktop sumi-ink theme, with a washi light palette and a follow-system mode.
- Configurable send rate, magnetometer toggle, and shake-to-recenter — all live-applied without restart.
- Notification quick actions: Recenter and Stop.
- Battery level reported to SlimeVR-Server (packet 12) every 30 s.
- Auto-reconnect on Wi-Fi changes via
ConnectivityManager.NetworkCallback. - Figure-8 magnetometer wizard + automatic gyro-bias estimation.
- VRChat OSC → device vibration bridge on UDP
9001. - Foreground service with wake + Wi-Fi locks; OEM battery-optimization helper (Xiaomi / Huawei / Samsung / dontkillmyapp guides).
- EN / ES localisation, persisted in DataStore.
- Native VQF fusion via JNI (
crates/jni-android), with a pure-Kotlin Madgwick fallback when the.sois unavailable. - Wear OS standalone setup — the watch no longer needs the phone to know
the server address. A paired watch auto-syncs
host:portfrom the phone over the Wearable Data Layer; any watch (including AOSP / de-Googled builds with no Play Services) can enter the IP directly with an on-watch wheel picker — rotary crown or swipe, no keyboard, no companion app required.
Install: grab everything-imu-phone-<tag>.apk (and optionally
everything-imu-wear-<tag>.apk) from the latest release.
The release APKs are signed; if you are upgrading from an earlier unsigned
build, uninstall it first — Android blocks an in-place upgrade when the signing
key changes. Build locally from mobile/ with ./gradlew :app-mobile:assembleDebug.
Grab the latest installer from the Releases page:
- Windows:
everything-imu_<version>_x64-setup.exe - Linux (Debian/Ubuntu):
everything-imu_<version>_amd64.deb - Linux (any):
everything-imu_<version>_amd64.AppImage
Or build from source — see Building from source below.
You MUST have VRCFury on your Unity Project.
You MUST NOT Upload the avatar as a test, as it prevents the initialization of OSC protocols, please create a duplicate avatar and test it from there.
-
Import the IMUHaptics.unitypackage into your Unity Project
-
Drag and drop the prefab found under
Assets/MooshPaw/IMU Hapticsinto your Avatar
- Move the GameObjects to match your avatar proportions
- (Optional) Disable Haptic points you won't use, this frees your PC from loading unnecessary parameters, even though the performance impact is minimal
- Upload avatar and test
Duplicate any of the existing tracking points and position it where you want them. Then, change the Avatar Parameter to Haptics/{YourDesiredName} and REPLACE the parent bone under Armature Link
- You may also move the GameObject to the bone you want it parented to in the Hierarchy
- You should avoid putting the bone on the Contact Receiver Component as the Gizmo won't Sync
To create one from scratch, take in mind the following:
You MUST Change the Parameter address. It's recommended to leave the Haptic/ nomenclature for organization
You Should leave Local Only enabled, as there's no need to Sync this parameter since your Haptics run locally. This allows the avatar to get a better rating and avoids VRChat's maximum contacts
Armature Link automatically parents your haptic point to a Humanoid bone. You must change this bone to the one you want parented to, or move the GameObject within a bone from the Hierarchy.
Avoid putting the bone on the Contact Receiver Component as the Gizmo won't Sync
The gizmo represents the center of the Contact Receiver, as well as where your IRL Tracker should be. If your tracker is going to be at your stomach, your Haptic point should also be there
- Go to the Haptics section
- Enable the Bridge
- Ensure the OSC Port is
9001(VRChat's default output) - Test your devices
- Add the mappings you need
- Change the Parameter Name to
/avatar/parameters/Haptics/{YourHapticPoint}. It MUST BE THE SAME NAME as the one from the VRChat contact receiver component. If you misspell it, you won't get any haptic - Select the device that will rumble when your haptic point is triggered
- Adjust settings accordingly
Proximity (variable)
Variable float strength from 0 to 1, will rumble more when the VRC contact receiver is touched at the center, and less when is touched at the edges.
Pulse (fixed)
Activates the Rumble Once for a certain amount of time (Pulse (ms)) before turning it off. Useful to pair with a VRC contact receiver set to On Enter
Select available OSC addresses
To avoid typing the address manually, you may add them via the Discovered OSC Addresses section.
- Install SlimeVR-Server and leave it running. The default UDP port is
6969. - Run everything-imu. The status bar at the bottom will read
Liveonce a handshake with the server completes. - Plug or pair a supported controller. It appears in the Devices tab; a tracker for it shows up automatically in SlimeVR-Server.
- Mount the controller to your body (waist, knee, ankle, etc.) and assign it in SlimeVR-Server's Body Proportions flow.
- Reset orientation:
R(yaw) /Shift+R(full) from the global hotkeys, or click Reset Yaw / Reset Full / Reset Mounting on the device card. On controllers without a magnetometer (Joy-Con 1, DualSense, DualShock 4, Wii Remote) yaw drifts on body rotation — re-yaw facing forward, or use Reset Mounting right after strapping the tracker. Some devices accept on-device gestures — see DEVICES.md.
| Shortcut | Action |
|---|---|
Ctrl+K |
Command palette |
Ctrl+F |
Global search |
Ctrl+Enter |
Cinema mode (immersive overlay) |
Ctrl+Shift+B |
Kill-switch the bridge (pause emission) |
R / Shift+R |
Broadcast yaw / full reset |
Mounting reset is per-device — click Reset Mounting on the device card or the tracker detail page.
- Rust stable (1.79+ recommended)
- Node.js 22+ and pnpm 10
- Windows: WebView2 (preinstalled on Windows 11)
- Linux:
libwebkit2gtk-4.1-dev,libgtk-3-dev,libsoup-3.0-dev,librsvg2-dev,libayatana-appindicator3-dev,libxdo-dev,libssl-dev,libudev-dev,patchelf
git clone https://github.com/matiaspalmac/everything-imu.git
cd everything-imu
pnpm install # JS deps
pnpm tauri dev # dev: live-reload UI + Rust backend
pnpm tauri build # release bundle (MSI on Windows, AppImage on Linux)
# Backend-only iteration:
cargo test --workspace # unit + integration tests
cargo run -p headless-cli # headless bridge for debuggingThe everything-imu-app binary is the full Tauri shell; headless-cli is a
no-UI driver useful for tracing protocol-level issues.
| File | Purpose |
|---|---|
| ARCHITECTURE.md | Crate graph + responsibilities |
| DEVICES.md | Per-device IMU, transport, calibration |
| PROTOCOL.md | SlimeVR UDP wire format notes |
| CONTRIBUTING.md | Dev workflow, style, PR rules |
| SECURITY.md | Reporting vulnerabilities |
| CODE_OF_CONDUCT.md | Community ground rules |
- Core: Rust,
tokio,hidapi,btleplug,nalgebra - Math & fusion: VQF (Laidig 2023), Madgwick, BasicVQF
- Haptics:
roscOSC listener, per-device rumble drivers - Persistence: SQLite via
rusqlite - Desktop shell: Tauri 2 + tauri-specta (typed IPC)
- Frontend: React 19, TypeScript, Vite, TailwindCSS 4, Zustand 5, react-three-fiber
MIT. Contributions are accepted under the same license.