QMK RGB Tool
Control the RGB lighting on QMK-compatible keyboards. Supports Impact 80 and Rainy 75 out of the box, and any other keyboard running QMK with the RGB Matrix subsystem and VIA support.
Cross-platform CLI for Linux, macOS, and Windows. Designed for automation, scripting, and agent consumption.
|
|
пре 1 недеља | |
|---|---|---|
| .claude | пре 1 недеља | |
| .opencode | пре 2 недеља | |
| cmd | пре 1 недеља | |
| graphify-out | пре 1 недеља | |
| internal | пре 1 недеља | |
| profiles | пре 1 недеља | |
| .gitignore | пре 1 недеља | |
| AGENTS.md | пре 1 недеља | |
| CLAUDE.md | пре 2 недеља | |
| LICENSE | пре 2 недеља | |
| PLAN.md | пре 2 недеља | |
| README.md | пре 1 недеља | |
| go.mod | пре 1 недеља | |
| go.sum | пре 2 недеља | |
| keyboards.json | пре 1 недеља |
Control the RGB lighting on QMK-compatible keyboards. Supports Impact 80 and Rainy 75 out of the box, and any other keyboard running QMK with the RGB Matrix subsystem and VIA support.
Cross-platform CLI for Linux, macOS, and Windows. Designed for automation, scripting, and agent consumption.
On Linux, libudev-dev is required before building:
sudo apt install -y libudev-dev
Build locally:
git clone <repo-url>
cd qmk-rgb
go build -o qmk-rgb-tool ./cmd/qmk-rgb-tool/
And, to run it from anywhere, install globally (run from the repo root, installs to $GOPATH/bin/):
go install ./cmd/qmk-rgb-tool/
# Discover connected keyboards
./qmk-rgb-tool keyboard info
# RGB commands target Logo, Backlight, and Side by default
./qmk-rgb-tool effect breathing
./qmk-rgb-tool effect rainbow_moving_chevron
./qmk-rgb-tool effect rainbow_moving_chevron --zone backlight
./qmk-rgb-tool brightness 160
./qmk-rgb-tool speed 2
./qmk-rgb-tool color 00ff00
# Raw mode IDs are zone-specific; ID 17 is Backlight-only
./qmk-rgb-tool mode 17 --zone backlight
./qmk-rgb-tool enable
./qmk-rgb-tool disable
./qmk-rgb-tool info
# Select exactly one zone
./qmk-rgb-tool brightness 160 --zone side
# Save and load RGB profiles
./qmk-rgb-tool save paul
./qmk-rgb-tool load paul
./qmk-rgb-tool list
./qmk-rgb-tool delete paul
# Select a keyboard by the number shown in `keyboard info`
./qmk-rgb-tool --device 1 enable
--zone accepts logo, backlight, or side and may be given on any
subcommand. It is not remembered between runs: repeat it on every invocation.
Without --zone, commands target Logo, Backlight, and Side in that order.
With --zone, commands target exactly the selected zone. An unsupported
name for an explicit zone fails before the device is opened; a default
command skips unsupported zones and prints a warning on stderr.
All output is machine-parseable JSON when applicable.
keyboard info numbers every connected QMK keyboard starting at 1, and
--device takes that number:
./qmk-rgb-tool keyboard info
./qmk-rgb-tool --device 2 brightness 160
Without --device, commands run only when exactly one keyboard is connected.
With two or more, they fail and list the numbers you can choose from, so a
command never hits an unintended keyboard.
Numbers are assigned in a stable order (vendor ID, product ID, path), but they
are only guaranteed for the current session. Keyboards are identified by their
HID path, which the operating system reassigns on reboot, and most keyboards
report no serial number. Re-run keyboard info after reconnecting a keyboard
rather than storing the number.
The keyboard's firmware transforms these values per channel, so the accepted
range is 0–255 but the value the keyboard ends up holding is often different.
brightness and speed read every zone back and report what it actually
applied:
$ qmk-rgb-tool brightness 200
Brightness logo 160 backlight 255 side 160 (requested 200)
$ qmk-rgb-tool brightness 160 --zone logo
Brightness set to 160
$ qmk-rgb-tool speed 60
Speed logo 4 backlight 60 side 4 (requested 60)
$ qmk-rgb-tool speed 60 --zone backlight
Speed set to 60
Observed on the Impact 80:
| Zone | Channel | Brightness | Speed |
|---|---|---|---|
logo |
0x02 |
clamps at 160 | any value above 0 becomes 4 |
backlight |
0x03 |
scales up, saturating at 255 | applied as given |
side |
0x04 |
clamps at 160 | any value above 0 becomes 4 |
The command exits 0 either way: a value the firmware cannot represent is not a failure, but the summary line always states the value that was actually applied.
profiles/off, breathe, rainbow, solid, static resolve to correct effect IDs per zonecolor and speed for key-press illuminationkeyboard info, info, list, and effect --listkeyboard info numbers each keyboard; --device <n> targets one| Zone | CLI name | VIA channel | Effect IDs |
|---|---|---|---|
| Logo | logo |
2 | 0–6 |
| Backlight | backlight |
3 | 0–45 |
| Side | side |
4 | 0–6 |
Logo and Side share this complete effect family:
| ID | Name |
|---|---|
| 0 | none |
| 1 | wave |
| 2 | fixed_wave |
| 3 | spectrum |
| 4 | breathing |
| 5 | light |
| 6 | shutdown |
Backlight uses the complete Impact 80 catalog:
| ID | Name | ID | Name |
|---|---|---|---|
| 0 | none |
23 | flower_blooming |
| 1 | solid_color |
24 | raindrops |
| 2 | alphas_mods |
25 | jellybean_raindrops |
| 3 | gradient_up_down |
26 | hue_breathing |
| 4 | gradient_left_right |
27 | hue_pendulum |
| 5 | breathing |
28 | hue_wave |
| 6 | band_sat |
29 | pixel_flow |
| 7 | band_val |
30 | digital_rain |
| 8 | band_pinwheel_sat |
31 | solid_reactive |
| 9 | band_pinwheel_val |
32 | solid_reactive_wide |
| 10 | band_spiral_sat |
33 | solid_reactive_multiwide |
| 11 | band_spiral_val |
34 | solid_reactive_cross |
| 12 | cycle_all |
35 | solid_reactive_multicross |
| 13 | cycle_left_right |
36 | solid_reactive_nexus |
| 14 | cycle_up_down |
37 | solid_reactive_multinexus |
| 15 | cycle_out_in |
38 | splash |
| 16 | cycle_out_in_dual |
39 | multisplash |
| 17 | rainbow_moving_chevron |
40 | solid_splash |
| 18 | cycle_pinwheel |
41 | solid_multisplash |
| 19 | cycle_spiral |
42 | starlight |
| 20 | dual_beacon |
43 | starlight_dual_hue |
| 21 | rainbow_beacon |
44 | starlight_dual_sat |
| 22 | rainbow_pinwheels |
45 | riverflow |
Effects fall into categories that behave differently:
solid_color, none) display a steady output. The color is set by color and is constant.solid_reactive*) light up on key press. They honor the color set by color — the pressed key's LEDs flash in the configured color. Use speed to adjust how long the illumination lasts.breathing, hue_breathing) slowly fade in and out. They do not honor color directly; hue_breathing cycles through the full hue range.band_*, cycle_*, rainbow_*, starlight*, raindrops, jellybean_raindrops, flower_blooming, pixel_flow, riverflow) animate independently. Most ignore color and use their own color palettes. hue_breathing, hue_pendulum, and hue_wave cycle through hues.splash, multisplash, solid_splash, solid_multisplash) react to key presses like reactive effects but with a splash pattern. solid_splash and solid_multisplash honor color.gradient_up_down, gradient_left_right) create a color gradient across the keyboard. They do not honor color.alphas_mods) colors modifier keys differently from alphanumeric keys. The colors are built-in and cannot be changed.To set a permanent color, use solid_color and then color <hex>.
Effect names are resolved independently for each target zone. Compatibility
aliases are off → none, breathe → breathing, rainbow → spectrum
for Logo/Side and rainbow_moving_chevron for Backlight, rainbow_wave →
wave for Logo/Side, and solid → light for Logo/Side and solid_color
for Backlight. The legacy static alias remains accepted as a compatibility
alias for solid.
The effect catalog is consistent with the QMK RGB Matrix firmware. The
keyboard implements the VIA protocol (version 3) and its 46 backlight effect
names match the QMK RGB Matrix effect catalog exactly — verified through live
testing. The animations are defined in
QMK rgb_matrix/animations/,
where each effect has its own header file (e.g.
digital_rain_anim.h, solid_reactive_anim.h, riverflow_anim.h).
ID 39 is multisplash; ID 41 is the distinct solid_multisplash name.
info reports a zones array with each zone's channel, enabled state,
effect name and ID, brightness, speed, and color. The top-level enabled,
mode, brightness, and speed fields summarize the first selected zone.
If one zone cannot be queried, its record contains an error, other records
are retained, and the process exits non-zero after printing the JSON.
The tool uses hidapi for cross-platform HID access. Most platforms need no configuration, but Linux requires extra setup.
To build, libudev-dev is required:
sudo apt install -y libudev-dev
To run without sudo, grant your user group access to hidraw devices. By default, hidraw devices are owned by root (600).
Choose one of the methods below.
Grant your user group access to all HIDRAW devices:
sudo chown root:adm /dev/hidraw*
sudo chmod 660 /dev/hidraw*
This works for the current session only. Permissions reset after reboot.
Create a persistent rule for the Impact 80:
echo 'SUBSYSTEM=="hidraw", ATTRS{idVendor}=="36b0", ATTRS{idProduct}=="309f", MODE="0660", GROUP="adm"' \
| sudo tee /etc/udev/rules.d/99-qmk-rgb-tool.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
sudo udevadm reload
This makes the Impact 80 accessible to members of the adm group on every boot.
No setup required. macOS applications access HID devices directly through IOKit.
No setup required. Windows applications access HID devices directly through the Windows HID API.
After Linux setup, run the tool as your regular user (no sudo needed).
Any keyboard running QMK with the RGB Matrix subsystem and VIA support is detected automatically via the QMK Raw HID signature (Usage Page 0xFF60, Usage 0x61). No manual configuration required.
keyboards.json is optional. When present it only supplies friendly names:
keyboard info reports "known": true for models listed there and
"known": false for every other QMK keyboard. Both are fully controllable —
known describes the name lookup, not compatibility. Deleting or corrupting
the file costs you names only.
Two models are listed in keyboards.json:
| Keyboard | VID | PID |
|---|---|---|
| Wobkey Rainy 75 | 0x6666 | 0x0001 |
| Wobkey Impact 80 | 0x36B0 | 0x309F |
| Command | Description |
|---|---|
qmk-rgb-tool keyboard info |
Discover connected QMK keyboards |
qmk-rgb-tool enable |
Enable selected lighting zones |
qmk-rgb-tool disable |
Disable selected lighting zones |
qmk-rgb-tool info |
Show per-zone RGB state (JSON) |
qmk-rgb-tool effect <name> |
Set a zone-aware effect by name |
qmk-rgb-tool brightness <val> |
Set brightness (0–255) on selected zones, verified by read-back |
qmk-rgb-tool speed <val> |
Set effect speed (0–255) on selected zones, verified by read-back |
qmk-rgb-tool color <hex> |
Set color (e.g. ff0000) on selected zones |
qmk-rgb-tool mode <index> |
Set a raw zone-specific effect ID |
qmk-rgb-tool --zone <zone> ... |
Target logo, backlight, or side |
qmk-rgb-tool --device <n> ... |
Target keyboard by number (see keyboard info) |
qmk-rgb-tool save [name] |
Save current RGB state to profiles/<name>.json |
qmk-rgb-tool load [name] |
Load and apply a profile from profiles/ |
qmk-rgb-tool list |
List saved profiles |
qmk-rgb-tool delete [name] |
Delete a saved profile |
enable, disable, info and list take no arguments and reject a stray
token. effect, load, save and delete accept an optional name.
brightness, speed, color and mode require exactly one argument.
Profiles store RGB state (effect, brightness, speed, color) per zone as JSON
files in the profiles/ directory. They are the only way to persist RGB
settings across reboots. The keyboard's VIA protocol does not expose a
standard command to save RGB state to internal EEPROM, so profiles rely on
files instead.
cmd/qmk-rgb-tool/ # Cobra-based CLI
internal/device/ # HID discovery + keyboards.json loader
internal/hid/ # Cross-platform HID access (hidapi)
internal/rgb/ # Effects, colors, state
internal/via/ # VIA protocol implementation
Communicates via the QMK Raw HID interface (Usage Page 0xFF60, Usage 0x61) with 32-byte feature reports.
0x07 — Custom set value0x08 — Custom get value0x02 logo, 0x03 backlight, 0x04 side lighting0x01, effect 0x02, speed 0x03, color 0x04