LYNXware — Modular Wireless Input
lynx-v4 is a modular wireless split keyboard with two independent hand units and a USB receiver. Each lynxCAT combines finger and thumb keys with optional pointing hardware; lynxTOWER turns their input into keyboard and mouse reports for the computer. CAT stands for Compact Action Transmitter.
The project brings together three pillars: firmware, electronics and mechanical.
Firmware is bare-metal Rust (no_std) on ESP32-S3; PCB designs and Blender enclosure
sources live alongside it so the repository describes the complete device.
Physical layout
┌─────────┐
│ 💻 Host │
└──┬──────┘
│ USB
╭──────┴───────╮
│ 🗼 lynxTOWER │
╰──────┬───────╯
│
┌──────────────┴──────────────┐
│ 📡 ESP-NOW │
└──────────────┬──────────────┘
╱ ╲
╱ ╲
✋ lynxCAT (Left) lynxCAT (Right) 🤚
m0 🎡
r1 m1 i1 t21 t11 t11 t21 i1 m1 r1
p1 r2 m2 i2 i5 t22 t12 t12 t22 i5 i2 m2 r2 p1
p4 p2 r3 m3 i3 i6 t33 t23 t13 t13 t23 t33 i6 i3 m3 r3 p2 p4
p5 p3 r4 m4 i4 i7 t24 t14 t14 t24 i7 i4 m4 r4 p3 p5
t25 t15 t15 t25
╰── Finger (21) ─╯╰─ Thumb (11) ─╯ ╰─ Thumb (11) ─╯╰ Finger (20 + 🎡) ╯
The drawing shows physical controls, not their assigned characters. The right wheel also clicks: the layout has 64 key switches across both hands, including that click. Key bindings and layers are configurable through Vial.
Each hand has three hardware slots, and every module is made for both hands: finger and thumb modules exist as mirrored left and right builds, and a bottom module screws into the lid made for it in either hand (the tower turns each hand's sensor motion to suit). Each hand is configured on its own with any available module per slot; the drawing above is one configuration.
| Slot | Hardware |
|---|---|
| Finger | Finger keys, optionally with a scroll wheel |
| Thumb | Eleven keys and two RGB feedback LEDs; or four keys and a PS4 hall-effect stick, drawn but not built yet |
| Bottom | Optional mouse sensor or planned gyro module, beneath the hand and not shown above |
Fit the desired modules and build each cat's firmware for its configuration. The current pointing driver supports the PMW3389, battery-capable; a PMW3610 driver builds but has not yet run on hardware. The v3 ADNS-5050 mouse module is supported again for a hand without a battery: it runs from USB's 5 V. The joystick thumb's stick is read and sent, but the tower does not use it yet. The gyro module makes its hand an air mouse (set up per hand on the setup page); its driver has not yet run on a built module.
How it works
Cats capture; the tower interprets. Keeping keymaps and input processing in the receiver lets both hands share one configuration.
- Capture: each cat scans its key matrices and reads the fitted sensors. It reports physical key coordinates, motion and scroll deltas rather than assigning characters or interpreting layers.
- Wireless link: cats send input over ESP-NOW to their provisioned tower. USB provisioning establishes trust; each session derives a fresh encryption key. Key delivery uses acknowledgements and held-key snapshots for recovery.
- Processing and USB: the tower maps keys into RMK for bindings and layers, accumulates pointer input, and sends USB HID reports to the host. Vial provides the keymap configuration interface. Sensor inputs have a separate pipeline; gesture processing remains future work.
- Feedback: the tower sends layer, lock and configuration state back to the cats for their RGB LEDs. Optional battery monitoring adds charge indication and reports; cat power management controls scanning, LEDs and radio activity.
The stack uses esp-hal, esp-radio/esp-rtos, Embassy, RMK and postcard. The tower supports BPI-Leaf-S3 and LILYGO T-Dongle-S3 boards. The project is in active development; hardware qualification and outstanding fit issues are recorded in the relevant domain guides below.
Project structure
| Pillar | Sources and responsibilities |
|---|---|
| Firmware | firmware/cat/ captures input; firmware/tower/ processes it and owns USB. Their rules/ crates hold host-testable decisions. protocol/, provision/ and flash-record/ share wire and storage contracts. |
| Electronics | electronics/ contains KiCad boards, project libraries, the qualification baselines extracted from the frozen EasyEDA sources (kept privately) and the wiring contract. |
| Mechanical | mechanical/ contains the linked Blender part files and assembly scene (blender/), the printable STLs (stl/), docs, fit requirements and cross-domain associations. |
Supporting directories: tools/ contains CAD, electronics, assembly
and provisioning helpers; firmware/hardware-tests/ isolates
hardware bring-up; docs/ holds setup guidance, generated references
and project images. lx is the development entry point: firmware builds,
checks and flashing, and the electronics, mechanical and assembly tools.
./lx help lists its commands; DEV-CLI.md keeps its open decisions.
The authored Assembly, what a device is built from, gives controls a shared identity across firmware, PCBs and CAD. Its generated key table connects physical names to electrical and virtual coordinates. The generated pinout connects board headers to cat GPIOs. The build catalogue lists what a builder buys, which configurations are valid and the build steps. Edit their source files, then regenerate; do not maintain parallel tables by hand.
Getting started
Use the pinned development container and follow the setup, checks and flashing guide. New devices also need USB provisioning before they can communicate. For daily configuration and troubleshooting, see Vial settings and diagnostics.
To check the generated references from the repository root:
./lx assembly keys --check
./lx pcb pinout --check
Omit --check to regenerate. Build configurations (./lx check --list) and
dependency versions live in tools/lx/firmware.sh, the Cargo manifests and the lockfile.
License
Firmware and tools: GPL-3.0-or-later, with a permission for Espressif's radio libraries. Hardware: CERN-OHL-S-2.0. Documentation and images: CC-BY-SA-4.0. LICENSE gives the scope by path; LICENSES/ says what each covers, what comes from others, and what is deliberately left out, such as the PMW3389 sensor's firmware.