Skip to content
wochapPublic

About

Transparent real-time HUD for visualizing keyboard input on Hyprland.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

kb-hud

Recording_2026-08-14_07-07-11.mp4

kb-hud is a transparent desktop overlay for compatible ZMK keyboards. It renders the keyboard from a keymap-drawer SVG and updates it in real time from firmware telemetry received over Bluetooth LE.

The overlay shows pressed keys, active layers, transparent-key resolution, effective modifiers, and available keyboard status such as endpoint, battery, split connection, sequence gaps, and dropped notifications. Profiles select a keyboard, SVG, and visible status fields. The overlay fits its window (contain, centered), so size it with a compositor window rule. A mock telemetry panel supports UI development without keyboard hardware.

kb-hud is built with Tauri 2 and React 19. BLE support currently targets Linux with BlueZ.

Compatibility

The keyboard firmware must include zmk-key-telemetry and expose its encrypted read/notify GATT service. Follow that module's documentation for its ZMK, Zephyr, and firmware-build requirements. kb-hud does not depend directly on a particular ZMK or Zephyr release; its external contract is the module's telemetry protocol.

kb-hud requires the authoritative 48-byte telemetry state frame. It validates the complete frame, requires the initial characteristic read to be a snapshot, and does not guess or partially apply incompatible data. A notification needs an ATT MTU of at least 51: 48 bytes of value plus the 3-byte ATT notification header. The firmware must provide enough local L2CAP capacity and the BLE connection must negotiate that MTU.

Telemetry represents at most 64 zero-based physical key positions and 32 layers. Position numbers and layer order must match the supplied SVG. Split keyboards expose telemetry from the central half; the peripheral's key events reach it through normal ZMK split processing. Optional status is displayed only when its telemetry validity bit is set, so unavailable split, battery, endpoint, or HID-indicator data may be omitted safely.

Shifted tap-label previews use US keyboard symbol mappings. The battery badges label the central half L and the peripheral half R, so those labels assume a left-central split; this does not affect key-position rendering or telemetry transport.

The keyboard must already be paired with the host. The service UUID is not advertised, so kb-hud identifies compatible keyboards among paired devices. With deviceMac: "auto", kb-hud enumerates paired devices and uses BlueZ's cached service UUID metadata when available; when that cache is missing or inconclusive it briefly connects to paired candidates and inspects their GATT tables for the telemetry service and characteristic. A unique compatible keyboard is then selected automatically. If several compatible keyboards are paired, discovery reports the ambiguity and requires an explicit MAC instead. A sleeping or out-of-range keyboard cannot be probed, so identification may be delayed; connection failures are retried rather than treated as incompatibility. The settings window lists paired devices and stores the selected MAC in the active profile. Reconnection uses exponential backoff after sleep or loss of signal.

Keymap SVG

Provide an SVG generated by keymap-drawer with its structural classes preserved. kb-hud expects:

  • one g.layer-* group per layer, in firmware layer-index order;
  • the same physical positions on every layer;
  • keys represented by g.key.keypos-N with a direct rect.key child; and
  • tap and hold labels in text.tap and text.hold elements.

Transparent keys may use keymap-drawer's trans class or the ▽ tap label. Every keypos-N must use the same zero-based physical position number emitted by the firmware. Geometry is read from the SVG, so compatible split layouts are not restricted to a particular shape or key count within the telemetry limits.

Configuration

Open the settings window from the tray to configure profiles and exercise the mock telemetry controls. Each profile contains:

  • name
  • svgPath
  • deviceMac (an explicit Bluetooth MAC, or "auto" to discover a compatible zmk-key-telemetry keyboard among paired devices)
  • hud visibility flags
  • overlayAppearance (idle-key-background visibility plus label, idle background, key border, active key background, and top-bar pill background opacity values, each normalized 0–1)

Configuration is stored in ~/.config/com.wochap.kb-hud/profiles.json, the Tauri configuration directory. Changing the active profile updates the overlay immediately. Imported keymap SVGs are stored under ~/.config/com.wochap.kb-hud/keymaps/ using content-derived names.

The tray icon requires a StatusNotifier host, such as a desktop panel with SNI support. Its absence does not affect the overlay or settings windows.

Theming

kb-hud follows the GTK/system light or dark appearance and applies a Catppuccin palette to both the settings window and the overlay. All four flavors are bundled — Latte, Frappé, Macchiato, and Mocha — and Blue is the primary accent in every flavor. You assign which flavor to use for light mode and which for dark mode in the settings Appearance section; these assignments are global, not per profile, and apply immediately to every open window. First launch and legacy configuration default to Latte for light mode and Mocha for dark mode.

The system appearance is always authoritative; there is no manual light/dark override. If the platform does not report a known appearance, kb-hud uses the configured dark-mode palette. An unknown saved palette falls back to the default for the current appearance.

Per-profile overlay controls adjust legibility and transparency without restarting:

  • Show idle key backgrounds — hides idle key fills while preserving pressed-key and resolved-modifier feedback. Re-enabling restores the saved idle opacity.
  • Label opacity — tap and hold label visibility, including their contrasting outline.
  • Idle key background opacity
  • Key border opacity
  • Active key background opacity — applies to ordinary presses and resolved modifiers; press-decay animation multiplies this value.
  • Top-bar pill background opacity — affects pill fills only, not pill text, borders, or the connection-status dot.

Tap and hold labels use a theme-derived contrasting outline for legibility at small sizes and on rotated keys.

Appearance detection reads the GTK settings portal. On compositors or sessions without a settings portal, kb-hud falls back to the dark-mode palette; live light/dark switching requires a portal-providing environment.

Portable configuration

The settings window exports a single versioned JSON document containing the global palette assignments, the active profile, and every profile's name, HUD visibility, overlay appearance, and embedded keymap SVG. Bluetooth MAC addresses and original keymap filesystem paths are never included, so an export is safe to copy to another machine.

Importing is a validated, replace-all operation:

  1. Choose an export file. kb-hud parses and validates the whole document — format/version, bundled theme IDs, unique non-empty profile names, an existing active profile, finite/ranged numeric values, and every embedded keymap — and shows a replacement summary.
  2. Review the summary, which lists profile count, the restored active profile, palette assignments, per-profile keymap results, and the fact that every profile's device selection resets to "auto".
  3. Explicitly confirm replacement, or cancel to leave the current configuration unchanged.

On confirmation kb-hud re-reads and re-validates the file, stores embedded SVGs under app-managed content-derived paths, and replaces the configuration as one committed operation. A failure before the final commit leaves the previous configuration intact. After a successful import both windows reload and BLE reconnects using automatic discovery.

Build and development

Nix with flakes is required. The development shell provides Node.js, Rust, and the Tauri Linux dependencies.

nix develop
npm ci
npm run tauri dev

Run the checks with:

npm test
npm run build
cargo fmt --check --manifest-path src-tauri/Cargo.toml
cargo test --manifest-path src-tauri/Cargo.toml

Live BLE requires access to the host's Bluetooth controller and system BlueZ D-Bus. It does not work in a container without those host resources; use the mock telemetry panel for frontend work in that environment.

Packaging

The Nix flake builds the frontend from npm's offline dependency cache and the Tauri backend with buildRustPackage:

nix build        # result/bin/kb-hud
nix run

Frontend dependencies are pinned in package-lock.json. After changing package.json, update the lockfile, temporarily set the npmDeps hash in flake.nix to lib.fakeHash, and copy the hash reported by nix build back into the flake:

npm install
nix build

Hyprland

The overlay window has class kb-hud and title kb-hud overlay. Use Hyprland window rules to float, pin, position, and prevent focus for that window. kb-hud does not control compositor placement or visibility; a show/hide binding can move the window to and from a special workspace.

Replacing the placeholder icons

Replace src-tauri/icons/placeholders/app-icon.png, then regenerate the bundle icons with:

npm run tauri icon src-tauri/icons/placeholders/app-icon.png

The tray uses src-tauri/icons/placeholders/tray-icon.png directly. Keep it a small transparent PNG with a high-contrast monochrome glyph.

License

MIT

About

Transparent real-time HUD for visualizing keyboard input on Hyprland.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages