Lumino: opinionated RGB Matrix light control
Pascal Getreuer, 2025-04-16
Overview
QMK’s RGB Matrix
Lighting is flexible, with finely tunable brightness using the
RM_VALU
and RM_VALD
keys … But it’s too much!
These tuning knobs are unwieldy. Functionally, I want some backlighting
to help find the keys at a dim or strong level depending on my
environment. Aesthetically, I want lighting that looks good without
being distracting.
Lumino implements a minimal, opinionated control scheme for RGB matrix lighting:
Pressing the LUMINO key cycles the lighting brightness between 3 states: off, 40%, and 100%. The set brightness is saved persistently to EEPROM.
Lighting turns off when idle. The normal timeout is 2 minutes of inactivity. However, if the keyboard had few key strokes since it last awoke, it turns off after 5 seconds.
Brightness changes are smoothly animated to minimize distraction.
When
QK_BOOT
is pressed, lighting is set to red color.
This scheme is born from my personal use, but perhaps this appeals to you too. Brightness levels and other above details are configurable.
Add Lumino to your keyboard
Install my community
modules. Then enable module getreuer/lumino
in your keymap.json
file. Or if keymap.json
does not exist, create it with the following content:
{
"modules": ["getreuer/lumino"]
}
Then use the “LUMINO
” keycode somewhere in your
layout.
Optionally, Lumino may be used in combination with PaletteFx for custom palette-based lighting effects:
{
"modules": ["getreuer/lumino", "getreuer/palettefx"]
}
Customization
Brightness levels
Lumino cycles the brightness level between off,
LUMINO_LOW_BRIGHTNESS
, and
LUMINO_HIGH_BRIGHTNESS
. The latter two are values between
0.0
(off) and 1.0
(max).
LUMINO_HIGH_BRIGHTNESS
is the brighter level. (Default:1.0
.)LUMINO_LOW_BRIGHTNESS
is the dimmer level. (Default: 40% ofLUMINO_HIGH_BRIGHTNESS
.)
To customize, define them in your config.h
. Example:
#define LUMINO_HIGH_BRIGHTNESS 0.8
#define LUMINO_LOW_BRIGHTNESS 0.1
It is expected that LUMINO_LOW_BRIGHTNESS
is less than
LUMINO_HIGH_BRIGHTNESS
for 3-state cycling. If not, the
LUMINO key toggles between off and
LUMINO_LOW_BRIGHTNESS
.
By default, the brightness level set with the LUMINO key
is saved persistently to EEPROM. To tell Lumino to never write to
EEPROM, define LUMINO_NO_EEPROM
:
#define LUMINO_NO_EEPROM
Time related
Times are configured in units of milliseconds.
LUMINO_LONG_TIMEOUT
is the idle timeout in milliseconds after which the lighting turns off. If set to zero, the lighting never turns off. (Default:120000
ms or 2 minutes.)LUMINO_SOON_TIMEOUT
is the fast idle timeout, used when few keystrokes were received since the last time the keyboard woke up. If this timeout is zero or exceeds the long timeout, the long timeout always applies. (Default:5000
ms or 5 seconds.)LUMINO_TRANSITION
is the animated transition time for smoothly changing brightness levels. It must be no more than2000
ms. (Default:500
ms.)
Define them in config.h
to customize. For longer times,
you may find it convenient to express them as
(1000 *
<seconds>)
or
(1000 * 60 *
<minutes>)
for
tuning in units of seconds or minutes rather than milliseconds.
Example:
#define LUMINO_LONG_TIMEOUT 1000 * 60 * 5 // = 5 minutes.
#define LUMINO_SOON_TIMEOUT 1000 * 12 // = 12 seconds.
#define LUMINO_TRANSITION 750 // = 750 ms.
Another example, where lighting never turns off:
#define LUMINO_LONG_TIMEOUT 0 // Never time out.
#define LUMINO_SOON_TIMEOUT 0 // Never time out.
#define LUMINO_TRANSITION 500 // = 500 ms.
Boot color
⚠ Experimental
I don’t know whether boot color works with all keyboards. It relies on the lighting PWM driver continuing to run while in DFU mode, which seems iffy. I’ve tested that it works on the ZSA Moonlander and Voyager keyboards.
When the QK_BOOT
button is pressed for bootloader mode,
the lighting is set to RGB color LUMINO_BOOT_COLOR
. The
default color is RGB_RED
. Another RGB color such as one in this list
may be specified as:
#define LUMINO_BOOT_COLOR RGB_WHITE
Or use RGB_OFF
to turn lighting off when going to
bootloader mode:
#define LUMINO_BOOT_COLOR RGB_OFF
Functions
These functions may be used to interact with Lumino programmatically:
void lumino_cycle_3_state(void);
uint8_t lumino_get_value(void);
void lumino_set_value(uint8_t new_value);
void lumino_sleep_soon(void);
Function lumino_cycle_3_state()
cycles the brightness
between 0, LUMINO_LOW_BRIGHTNESS
, and
LUMINO_HIGH_BRIGHTNESS
. Call this function to invoke the
same effect as the LUMINO key within a macro, tap dance,
etc.
The lumino_get_value()
function returns the current
Lumino brightness level as a uint8_t
value between
0
and RGB_MATRIX_MAXIMUM_BRIGHTNESS
. The
corresponding function lumino_set_value(value)
sets the
value.
// Set brightness to 100%.
(RGB_MATRIX_MAXIMUM_BRIGHTNESS); lumino_set_value
Function lumino_sleep_soon()
tells Lumino to go to sleep
after LUMINO_SOON_TIMEOUT
, provided that few keystrokes
occur in that time. This is useful to hint that the keyboard will likely
go idle soon after using a certain key, say when a lock screen keycode
has been pressed:
bool process_record_user(uint16_t keycode, keyrecord_t* record) {
switch (keycode) {
case G(KC_L):
// Hint Lumino to sleep soon after lock screen GUI+L key is used.
();
lumino_sleep_soonreturn true; // Continue default handling.
}
return true;
}
With the above, if G(KC_L)
is pressed and followed by at
most 5 key taps, the keyboard is considered idle and lighting will go to
sleep after the “soon” timeout. If, however, G(KC_L)
is
followed by more than 5 keys, then the keyboard is not idle and the
“long” timeout applies as usual.
Implementation notes
Lumino is implemented through calling the RGB Matrix functions. To avoid unnecessary EEPROM writes, the “
_noeeprom
” variants are used as much as possible.Brightness level changes are animated. A housekeeping task updates the RGB Matrix brightness once every 16 ms (≈ 60 fps). To transition smoothly, the animated brightness is computed with lib8tion’s
ease8InOutCubic()
.