razer-linux-desktop/PROMPT.md
2026-05-17 21:34:06 +02:00

7.7 KiB

Goal: migrate the existing razerqdhid app into razer-linux-desktop as a native Linux desktop application using Tauri 2 for the shell and Leptos for the UI.

Context:

  • Source app: ./razerqdhid
  • Target app: ./razer-linux-desktop
  • Current target state: the target is still the default Tauri + Leptos template (src/app.rs, src-tauri/src/lib.rs).
  • Current source stack: Vue 3 + Vite + WebHID + Pyodide/Python.
  • Source device/protocol logic lives mainly under razerqdhid/public/py/.
  • This project is Linux-only. The app configures supported Razer mice, currently centered on Basilisk V3 / V3 Pro behavior already implemented in the source project.

Local test hardware (dev machine):

  • Connected device: Razer Basilisk V3 Pro (USB)
    • lsusb: 1532:00ab (Razer USA, Ltd)
    • USB sysfs node: /sys/bus/usb/devices/5-2.2.1
    • Exposed HID raw nodes (same VID/PID): /dev/hidraw3, /dev/hidraw5, /dev/hidraw6
      • ID_USB_INTERFACE_NUM: 00 -> /dev/hidraw3 (mouse interface)
      • ID_USB_INTERFACE_NUM: 01 -> /dev/hidraw5
      • ID_USB_INTERFACE_NUM: 02 -> /dev/hidraw6
    • Device serial string currently reports as 000000000000 (do not rely on it for unique identification).

What exists in the source app:

  • A connect flow in razerqdhid/src/components/ConnectDevice.vue
  • A main device screen in razerqdhid/src/components/DeviceMain.vue
  • Configuration sections for:
    • basic settings
    • button mapping
    • LED
    • profiles
    • macros
    • sensor settings
    • device info
  • The source app currently relies on browser APIs and Pyodide. The desktop app should replace that with native Tauri/Rust integration.

What I want:

  • Port the app into ./razer-linux-desktop.
  • Keep the migrated app grounded in the existing source behavior and feature structure instead of inventing a new product.
  • Replace WebHID/Pyodide with a native backend that talks to the device on Linux.
  • Reuse or carefully reimplement the existing protocol logic from the Python code in Rust where appropriate.
  • Keep the app runnable after each meaningful step. Do not leave the target in a half-broken state.

Execution requirements:

  1. Inspect the source app and identify the real feature surface before changing architecture.
  2. Inspect the Python protocol/device code under razerqdhid/public/py/ and use it as the behavioral reference.
  3. Build the migration incrementally, starting with a working vertical slice instead of attempting every feature at once.
  4. Preserve the current single-app workflow:
    • connect to device
    • show main configuration UI
    • expose the existing sections progressively
  5. Prefer Rust/Tauri-native device access over embedding Python in the final architecture unless there is a concrete blocker.
  6. Keep the UI practical and desktop-oriented. Do not ship the default template UI.
  7. Do not perform unrelated refactors in the source project unless required for the migration.

Suggested migration order:

  1. Replace the default Tauri + Leptos starter UI with a real app shell.
  2. Implement backend device discovery/connection for supported Razer devices on Linux.
  3. Port the connect screen and basic device info flow.
  4. Port the basic settings/profile selection path end to end.
  5. Port the remaining sections in descending order of user value: LED, button mapping, profiles, macros, sensor, info/debug tooling.
  6. Remove template/demo code once replaced.

Definition of done:

  • ./razer-linux-desktop is the active app, not a starter template.
  • The app can launch locally as a Tauri desktop app.
  • At least one real end-to-end device workflow is implemented natively in the target app.
  • The migration status is clear: completed pieces, remaining gaps, and next highest-value steps.
  • Any missing source features are called out explicitly instead of being silently dropped.

Faithful Port Checklist (source parity targets):

  • App workflow parity:
    • Connect screen: scan/select device, connect, error handling, optional "no hardware" mode for UI-only exploration.
    • Main screen: profile selector + tabs matching the Vue app: Basic, Button, LED, Profile, Macro, Sensor, Info, plus log/debug tooling.
  • Backend protocol parity (map to Python razerqdhid/public/py/qdrazer/device.py + qdrazer/protocol.py):
    • Device info:
      • manufacturer/product strings (USB indexed strings)
      • serial number (0x0082)
      • firmware version (0x0081)
      • device mode get/set (0x0084 / 0x0004) as required for sensor calibration flows
    • Basic settings (already partially ported):
      • scroll mode get/set (0x0294 / 0x0214)
      • scroll acceleration get/set (0x0296 / 0x0216)
      • smart reel get/set (0x0297 / 0x0217)
      • polling delay get/set (0x008e / 0x000e)
      • current DPI X/Y get/set (0x0485 / 0x0405)
      • DPI stages get/set (0x0486 / 0x0406) and active stage selection
    • Profile management:
      • available profile count/list (0x0580 / 0x0581)
      • create/delete profile (0x0502 / 0x0503)
      • profile info read/write chunking (0x0588 / 0x0508) for YAML import/export parity (source exports/imports Basic/Button/LED configs)
      • flash usage/readiness helpers (0x068e, 0x0086) as needed for safe writes
    • LED:
      • per-region effect get/set (0x0f82 / 0x0f02) including mode/speed/colors
      • per-region brightness get/set (0x0f84 / 0x0f04)
      • optional static LED write path (0x0f03) if needed for full parity
    • Button mapping + Hypershift:
      • button function get/set (0x028c / 0x020c)
      • full ButtonFunction encoding/decoding parity with qdrazer.protocol.ButtonFunction
        • categories used by UI: disabled, mouse, keyboard, macro, dpi_switch, profile_switch, system, consumer, hypershift_toggle, scroll_mode_toggle, plus "custom/raw"
      • support both Hypershift OFF and ON mappings
    • Macros:
      • macro list/count (get_macro_list/get_macro_count paths in Python) and any required query commands
      • macro info chunked get/set (0x068c / 0x060c)
      • macro size get/set (0x0688 / 0x0608)
      • macro function chunked get/set (0x0689 / 0x0609)
      • delete macro (0x0603)
      • flash reset tooling (0x060a + poll 0x068a) for the source "reset flash" workflow
      • YAML import/export for macro functions (source uses YAML to represent macro op lists)
    • Sensor / lift-off calibration:
      • sensor lift config get/set (0x0b8b / 0x0b0b)
      • lift config blobs get/set (0x0b85 / 0x0b05, 0x0b8c / 0x0b0c, 0x0b8d / 0x0b0d)
      • sensor state + calibration toggles (0x0b83 / 0x0b03, 0x0b09)
      • device mode transitions needed by the calibration workflow (DeviceMode.DRIVER/NORMAL)
    • Logs/debug:
      • source-equivalent log console: show sent/received report frames, status, and raw bytes
      • safe exclusive-access messaging when device replies with "different command" (indicates competing software)
  • UI parity notes from Vue components:
    • Basic: includes DPI stages editing (count 1..5), active stage, and a "Y = X" helper.
    • LED: regions wheel/logo/strip; effects off/static/spectrum/wave variants; per-region speed + brightness; apply-to-all.
    • Button: per-button assignments + per-button Hypershift assignments; category editor; custom/raw inspector.
    • Profile: create/delete; YAML export/import for selected profile configs (basic/button/led only in source).
    • Macro: list macros; load/edit/save/delete; YAML export/import all.
    • Sensor: lift config modes; calibration start/stop; parameter calculator + set params.

While working:

  • Make concrete code changes, not just a plan.
  • Explain architecture decisions briefly when they matter.
  • Validate builds/tests when possible.
  • If the full migration is too large for one pass, complete the highest-value vertical slice and leave the repo in a clean, runnable state with clear next steps.