To support an offline-ready desktop client alongside our web application, we need to integrate Tauri into the project root and abstract our hardware communications.
Because browser support for WebHID is fragmented (e.g., completely blocked in Safari and Firefox, and restricted in macOS webviews), we cannot rely solely on raw frontend navigator.hid calls. Setting up a dedicated Hardware Abstraction Layer (HAL) now will prevent contributors from hardcoding WebHID structures directly into UI components, ensuring long-term maintainability before PRs become congested.
Proposed Architecture
We will initialize Tauri in the repository root (npx tauri init), creating a src-tauri native wrapper next to our existing Vite setup. The frontend will communicate through a unified bridge layer:
openmouse/
├── src/ # Existing Vite + TS frontend
│ ├── hardware/ # <--- New Hardware Abstraction Layer (HAL)
│ │ ├── bridge.ts # Detects environment & routes packets
│ │ ├── webHID.ts # Web-specific handler (navigator.hid)
│ │ └── native.ts # Desktop-specific handler (invoke("tauri_command"))
├── src-tauri/ # <--- Tauri's Rust backend
│ └── src/main.rs # Low-level native HID handling (via hidapi crate)
Implementation Plan
- Setup Tauri Wrapper: Add
@tauri-apps/cli and run npx tauri init at the project root to map our build settings (../dist, http://localhost:5173).
- Build the Environment Bridge: Create
src/hardware/bridge.ts to detect the context runtime (checking for window.__TAURI_INTERNALS__). It will route hardware instructions to WebHID or Tauri IPC command pipelines dynamically.
- Rust HID Backend: Set up the Rust ecosystem with the
hidapi crate to execute native USB packet writing for desktop targets.
- Vite Configurations: Update
vite.config.ts to ignore **/src-tauri/** to keep the background compilation cycles from entering hot-reload loops.
Additional Context
Doing this now establishes guardrails for incoming open-source contributions. Any developer adding a new mouse profile down the road only needs to script the data packets inside our unified /hardware directory to seamlessly support both targets out of the box.
To support an offline-ready desktop client alongside our web application, we need to integrate Tauri into the project root and abstract our hardware communications.
Because browser support for WebHID is fragmented (e.g., completely blocked in Safari and Firefox, and restricted in macOS webviews), we cannot rely solely on raw frontend
navigator.hidcalls. Setting up a dedicated Hardware Abstraction Layer (HAL) now will prevent contributors from hardcoding WebHID structures directly into UI components, ensuring long-term maintainability before PRs become congested.Proposed Architecture
We will initialize Tauri in the repository root (
npx tauri init), creating asrc-taurinative wrapper next to our existing Vite setup. The frontend will communicate through a unified bridge layer:Implementation Plan
@tauri-apps/cliand runnpx tauri initat the project root to map our build settings (../dist,http://localhost:5173).src/hardware/bridge.tsto detect the context runtime (checking forwindow.__TAURI_INTERNALS__). It will route hardware instructions to WebHID or Tauri IPC command pipelines dynamically.hidapicrate to execute native USB packet writing for desktop targets.vite.config.tsto ignore**/src-tauri/**to keep the background compilation cycles from entering hot-reload loops.Additional Context
Doing this now establishes guardrails for incoming open-source contributions. Any developer adding a new mouse profile down the road only needs to script the data packets inside our unified
/hardwaredirectory to seamlessly support both targets out of the box.