summary refs log tree commit diff
path: root/quantum
diff options
context:
space:
mode:
authorWilliam Chang <william@factual.com>2019-05-09 21:16:06 -0700
committerWilliam Chang <william@factual.com>2019-05-09 21:16:06 -0700
commit4b2d3288d013b1a71ea25402224c4a8225a099e9 (patch)
treeb7f5dded777a950e63c4dd967260744336bfaa6b /quantum
parent57a6ea11df685d84a1ea07953e88f224ce2b24f7 (diff)
parentbce391a663d2848bff8ffffca0e4bad771bd3890 (diff)
resolved conflicts
Diffstat (limited to 'quantum')
-rw-r--r--quantum/color.c9
-rw-r--r--quantum/keymap_extras/sendstring_uk.h4
-rw-r--r--quantum/led_tables.c48
-rw-r--r--quantum/mcu_selection.mk1
-rw-r--r--quantum/process_keycode/process_space_cadet.c151
-rw-r--r--quantum/process_keycode/process_space_cadet.h21
-rw-r--r--quantum/process_keycode/process_unicode.c6
-rw-r--r--quantum/process_keycode/process_unicode.h2
-rw-r--r--quantum/process_keycode/process_unicode_common.c38
-rw-r--r--quantum/process_keycode/process_unicode_common.h13
-rw-r--r--quantum/process_keycode/process_unicodemap.c36
-rw-r--r--quantum/process_keycode/process_unicodemap.h4
-rw-r--r--quantum/quantum.c392
-rw-r--r--quantum/quantum.h8
-rw-r--r--quantum/quantum_keycodes.h19
-rw-r--r--quantum/rgb_matrix.c165
-rw-r--r--quantum/rgb_matrix.h40
-rw-r--r--quantum/rgb_matrix_animations/alpha_mods_anim.h5
-rw-r--r--quantum/rgb_matrix_animations/breathing_anim.h1
-rw-r--r--quantum/rgb_matrix_animations/cycle_all_anim.h6
-rw-r--r--quantum/rgb_matrix_animations/cycle_left_right_anim.h6
-rw-r--r--quantum/rgb_matrix_animations/cycle_up_down_anim.h6
-rw-r--r--quantum/rgb_matrix_animations/digital_rain_anim.h33
-rw-r--r--quantum/rgb_matrix_animations/dual_beacon_anim.h6
-rw-r--r--quantum/rgb_matrix_animations/gradient_up_down_anim.h6
-rw-r--r--quantum/rgb_matrix_animations/jellybean_raindrops_anim.h9
-rw-r--r--quantum/rgb_matrix_animations/rainbow_beacon_anim.h6
-rw-r--r--quantum/rgb_matrix_animations/rainbow_moving_chevron_anim.h6
-rw-r--r--quantum/rgb_matrix_animations/rainbow_pinwheels_anim.h6
-rw-r--r--quantum/rgb_matrix_animations/raindrops_anim.h8
-rw-r--r--quantum/rgb_matrix_animations/solid_color_anim.h2
-rw-r--r--quantum/rgb_matrix_animations/solid_reactive_anim.h5
-rw-r--r--quantum/rgb_matrix_animations/solid_reactive_cross.h50
-rw-r--r--quantum/rgb_matrix_animations/solid_reactive_nexus.h48
-rw-r--r--quantum/rgb_matrix_animations/solid_reactive_simple_anim.h5
-rw-r--r--quantum/rgb_matrix_animations/solid_reactive_wide.h42
-rw-r--r--quantum/rgb_matrix_animations/solid_splash_anim.h8
-rw-r--r--quantum/rgb_matrix_animations/splash_anim.h8
-rw-r--r--quantum/rgb_matrix_animations/typing_heatmap_anim.h75
-rw-r--r--quantum/rgb_matrix_drivers.c4
-rw-r--r--quantum/rgb_matrix_types.h32
-rw-r--r--quantum/rgblight.c218
-rw-r--r--quantum/rgblight.h31
-rw-r--r--quantum/rgblight_breathe_table.h116
-rw-r--r--quantum/rgblight_list.h240
-rw-r--r--quantum/split_common/matrix.c2
-rw-r--r--quantum/split_common/transport.c5
-rw-r--r--quantum/stm32/proton_c.mk1
-rw-r--r--quantum/template/avr/config.h6
-rw-r--r--quantum/template/ps2avrgb/readme.md2
-rw-r--r--quantum/template/ps2avrgb/rules.mk4
-rw-r--r--quantum/template/ps2avrgb/usbconfig.h5
52 files changed, 1331 insertions, 639 deletions
diff --git a/quantum/color.c b/quantum/color.c
index c49877592e..466e6edacb 100644
--- a/quantum/color.c
+++ b/quantum/color.c
@@ -22,8 +22,8 @@
 RGB hsv_to_rgb( HSV hsv )
 {
 	RGB rgb;
-	uint8_t region, p, q, t;
-	uint16_t h, s, v, remainder;
+	uint8_t region, remainder, p, q, t;
+	uint16_t h, s, v;
 
 	if ( hsv.s == 0 )
 	{
@@ -37,8 +37,8 @@ RGB hsv_to_rgb( HSV hsv )
 	s = hsv.s;
 	v = hsv.v;
 
-	region = h / 43;
-	remainder = (h - (region * 43)) * 6;
+	region = h * 6 / 255;
+	remainder = (h * 2 - region * 85) * 3;
 
 	p = (v * (255 - s)) >> 8;
 	q = (v * (255 - ((s * remainder) >> 8))) >> 8;
@@ -46,6 +46,7 @@ RGB hsv_to_rgb( HSV hsv )
 
 	switch ( region )
 	{
+		case 6:
 		case 0:
 			rgb.r = v;
 			rgb.g = t;
diff --git a/quantum/keymap_extras/sendstring_uk.h b/quantum/keymap_extras/sendstring_uk.h
index 3c71f97640..2824e5d444 100644
--- a/quantum/keymap_extras/sendstring_uk.h
+++ b/quantum/keymap_extras/sendstring_uk.h
@@ -25,7 +25,7 @@ const bool ascii_to_shift_lut[0x80] PROGMEM = {
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
 
-    0, 1, 1, 1, 1, 1, 1, 0,
+    0, 1, 1, 0, 1, 1, 1, 0,
     1, 1, 1, 1, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 1, 0, 1, 0, 1, 1,
@@ -45,7 +45,7 @@ const uint8_t ascii_to_keycode_lut[0x80] PROGMEM = {
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, KC_ESC, 0, 0, 0, 0,
 
-    KC_SPC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
+    KC_SPC, KC_1, KC_2, KC_NUHS, KC_4, KC_5, KC_7, KC_QUOT,
     KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
     KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
     KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
diff --git a/quantum/led_tables.c b/quantum/led_tables.c
index b99f262097..0eeb5c44b6 100644
--- a/quantum/led_tables.c
+++ b/quantum/led_tables.c
@@ -19,38 +19,28 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #ifdef USE_CIE1931_CURVE
 // Lightness curve using the CIE 1931 lightness formula
 //Generated by the python script provided in http://jared.geek.nz/2013/feb/linear-led-pwm
-const uint8_t CIE1931_CURVE[] PROGMEM = {
-    0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
-    2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
-    3, 4, 4, 4, 4, 4, 4, 5, 5, 5,
-    5, 5, 6, 6, 6, 6, 6, 7, 7, 7,
-    7, 8, 8, 8, 8, 9, 9, 9, 10, 10,
-    10, 10, 11, 11, 11, 12, 12, 12, 13, 13,
-    13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
-    17, 18, 18, 19, 19, 20, 20, 21, 21, 22,
-    22, 23, 23, 24, 24, 25, 25, 26, 26, 27,
-    28, 28, 29, 29, 30, 31, 31, 32, 32, 33,
-    34, 34, 35, 36, 37, 37, 38, 39, 39, 40,
-    41, 42, 43, 43, 44, 45, 46, 47, 47, 48,
-    49, 50, 51, 52, 53, 54, 54, 55, 56, 57,
-    58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
-    68, 70, 71, 72, 73, 74, 75, 76, 77, 79,
-    80, 81, 82, 83, 85, 86, 87, 88, 90, 91,
-    92, 94, 95, 96, 98, 99, 100, 102, 103, 105,
-    106, 108, 109, 110, 112, 113, 115, 116, 118, 120,
-    121, 123, 124, 126, 128, 129, 131, 132, 134, 136,
-    138, 139, 141, 143, 145, 146, 148, 150, 152, 154,
-    155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
-    175, 177, 179, 181, 183, 185, 187, 189, 191, 193,
-    196, 198, 200, 202, 204, 207, 209, 211, 214, 216,
-    218, 220, 223, 225, 228, 230, 232, 235, 237, 240,
-    242, 245, 247, 250, 252, 255,
-    };
+const uint8_t CIE1931_CURVE[256] PROGMEM = {
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   1,
+  1,   1,   1,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3,
+  3,   3,   4,   4,   4,   4,   4,   5,   5,   5,   5,   5,   6,   6,   6,   6,
+  6,   7,   7,   7,   7,   8,   8,   8,   8,   9,   9,   9,  10,  10,  10,  11,
+ 11,  11,  12,  12,  12,  13,  13,  13,  14,  14,  14,  15,  15,  16,  16,  16,
+ 17,  17,  18,  18,  19,  19,  20,  20,  21,  21,  22,  22,  23,  23,  24,  24,
+ 25,  25,  26,  26,  27,  28,  28,  29,  29,  30,  31,  31,  32,  33,  33,  34,
+ 35,  35,  36,  37,  37,  38,  39,  40,  40,  41,  42,  43,  44,  44,  45,  46,
+ 47,  48,  49,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,
+ 62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  75,  76,  77,  78,
+ 79,  80,  82,  83,  84,  85,  87,  88,  89,  90,  92,  93,  94,  96,  97,  99,
+100, 101, 103, 104, 106, 107, 108, 110, 111, 113, 114, 116, 118, 119, 121, 122,
+124, 125, 127, 129, 130, 132, 134, 135, 137, 139, 141, 142, 144, 146, 148, 149,
+151, 153, 155, 157, 159, 161, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
+182, 185, 187, 189, 191, 193, 195, 197, 200, 202, 204, 206, 208, 211, 213, 215,
+218, 220, 222, 225, 227, 230, 232, 234, 237, 239, 242, 244, 247, 249, 252, 255
+};
 #endif
 
 #ifdef USE_LED_BREATHING_TABLE
-const uint8_t LED_BREATHING_TABLE[] PROGMEM = {
+const uint8_t LED_BREATHING_TABLE[256] PROGMEM = {
   0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9,
   10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35,
   37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76,
diff --git a/quantum/mcu_selection.mk b/quantum/mcu_selection.mk
index 209b578ea5..fa6dc8b53c 100644
--- a/quantum/mcu_selection.mk
+++ b/quantum/mcu_selection.mk
@@ -34,6 +34,7 @@ ifneq ($(findstring STM32F303, $(MCU)),)
 
   # Options to pass to dfu-util when flashing
   DFU_ARGS ?= -d 0483:df11 -a 0 -s 0x08000000:leave
+  DFU_SUFFIX_ARGS = -p DF11 -v 0483
 endif
 
 ifneq (,$(filter $(MCU),atmega32u4 at90usb1286))
diff --git a/quantum/process_keycode/process_space_cadet.c b/quantum/process_keycode/process_space_cadet.c
new file mode 100644
index 0000000000..ac39df8089
--- /dev/null
+++ b/quantum/process_keycode/process_space_cadet.c
@@ -0,0 +1,151 @@
+/* Copyright 2019 Jack Humbert
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "process_space_cadet.h"
+
+#ifndef TAPPING_TERM
+  #define TAPPING_TERM 200
+#endif
+
+// ********** OBSOLETE DEFINES, STOP USING! (pls?) **********
+// Shift / paren setup
+#ifndef LSPO_KEY
+  #define LSPO_KEY KC_9
+#endif
+#ifndef RSPC_KEY
+  #define RSPC_KEY KC_0
+#endif
+
+// Shift / Enter setup
+#ifndef SFTENT_KEY
+  #define SFTENT_KEY KC_ENT
+#endif
+
+#ifdef DISABLE_SPACE_CADET_MODIFIER
+  #ifndef LSPO_MOD
+    #define LSPO_MOD KC_TRNS
+  #endif
+  #ifndef RSPC_MOD
+    #define RSPC_MOD KC_TRNS
+  #endif
+#else
+  #ifndef LSPO_MOD
+    #define LSPO_MOD KC_LSFT
+  #endif
+  #ifndef RSPC_MOD
+    #define RSPC_MOD KC_RSFT
+  #endif
+#endif
+// **********************************************************
+
+// Shift / paren setup
+#ifndef LSPO_KEYS
+  #define LSPO_KEYS KC_LSFT, LSPO_MOD, LSPO_KEY
+#endif
+#ifndef RSPC_KEYS
+  #define RSPC_KEYS KC_RSFT, RSPC_MOD, RSPC_KEY
+#endif
+
+// Control / paren setup
+#ifndef LCPO_KEYS
+  #define LCPO_KEYS KC_LCTL, KC_LCTL, KC_9
+#endif
+#ifndef RCPC_KEYS
+  #define RCPC_KEYS KC_RCTL, KC_RCTL, KC_0
+#endif
+
+// Alt / paren setup
+#ifndef LAPO_KEYS
+  #define LAPO_KEYS KC_LALT, KC_LALT, KC_9
+#endif
+#ifndef RAPC_KEYS
+  #define RAPC_KEYS KC_RALT, KC_RALT, KC_0
+#endif
+
+// Shift / Enter setup
+#ifndef SFTENT_KEYS
+  #define SFTENT_KEYS KC_RSFT, KC_TRNS, SFTENT_KEY
+#endif
+
+static uint8_t sc_last = 0;
+static uint16_t sc_timer = 0;
+
+void perform_space_cadet(keyrecord_t *record, uint8_t holdMod, uint8_t tapMod, uint8_t keycode) {
+  if (record->event.pressed) {
+    sc_last = holdMod;
+    sc_timer = timer_read ();
+    if (IS_MOD(holdMod)) {
+      register_mods(MOD_BIT(holdMod));
+    }
+  }
+  else {
+    if (sc_last == holdMod && timer_elapsed(sc_timer) < TAPPING_TERM) {
+      if (holdMod != tapMod) {
+        if (IS_MOD(holdMod)) {
+          unregister_mods(MOD_BIT(holdMod));
+        }
+        if (IS_MOD(tapMod)) {
+          register_mods(MOD_BIT(tapMod));
+        }
+      }
+      tap_code(keycode);
+      if (IS_MOD(tapMod)) {
+        unregister_mods(MOD_BIT(tapMod));
+      }
+    } else {
+      if (IS_MOD(holdMod)) {
+        unregister_mods(MOD_BIT(holdMod));
+      }
+    }
+  }
+}
+
+bool process_space_cadet(uint16_t keycode, keyrecord_t *record) {
+  switch(keycode) {
+    case KC_LSPO: {
+      perform_space_cadet(record, LSPO_KEYS);
+      return false;
+    }
+    case KC_RSPC: {
+      perform_space_cadet(record, RSPC_KEYS);
+      return false;
+    }
+    case KC_LCPO: {
+      perform_space_cadet(record, LCPO_KEYS);
+      return false;
+    }
+    case KC_RCPC: {
+      perform_space_cadet(record, RCPC_KEYS);
+      return false;
+    }
+    case KC_LAPO: {
+      perform_space_cadet(record, LAPO_KEYS);
+      return false;
+    }
+    case KC_RAPC: {
+      perform_space_cadet(record, RAPC_KEYS);
+      return false;
+    }
+    case KC_SFTENT: {
+      perform_space_cadet(record, SFTENT_KEYS);
+      return false;
+    }
+    default: {
+      sc_last = 0;
+      break;
+    }
+  }
+  return true;
+}
diff --git a/quantum/process_keycode/process_space_cadet.h b/quantum/process_keycode/process_space_cadet.h
new file mode 100644
index 0000000000..c823143504
--- /dev/null
+++ b/quantum/process_keycode/process_space_cadet.h
@@ -0,0 +1,21 @@
+/* Copyright 2019 Jack Humbert
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#include "quantum.h"
+
+void perform_space_cadet(keyrecord_t *record, uint8_t holdMod, uint8_t tapMod, uint8_t keycode);
+bool process_space_cadet(uint16_t keycode, keyrecord_t *record);
diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c
index 19beb84520..2c914013ac 100644
--- a/quantum/process_keycode/process_unicode.c
+++ b/quantum/process_keycode/process_unicode.c
@@ -13,15 +13,15 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+
 #include "process_unicode.h"
 #include "action_util.h"
 #include "eeprom.h"
 
 bool process_unicode(uint16_t keycode, keyrecord_t *record) {
-  if (keycode > QK_UNICODE && record->event.pressed) {
-    uint16_t unicode = keycode & 0x7FFF;
+  if (keycode >= QK_UNICODE && keycode <= QK_UNICODE_MAX && record->event.pressed) {
     unicode_input_start();
-    register_hex(unicode);
+    register_hex(keycode & 0x7FFF);
     unicode_input_finish();
   }
   return true;
diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h
index 0913e99107..22765ad560 100644
--- a/quantum/process_keycode/process_unicode.h
+++ b/quantum/process_keycode/process_unicode.h
@@ -13,9 +13,9 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+
 #pragma once
 
-#include "quantum.h"
 #include "process_unicode_common.h"
 
 bool process_unicode(uint16_t keycode, keyrecord_t *record);
diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c
index d0a9cf2324..21ac2291db 100644
--- a/quantum/process_keycode/process_unicode_common.c
+++ b/quantum/process_keycode/process_unicode_common.c
@@ -20,6 +20,8 @@
 #include <string.h>
 
 unicode_config_t unicode_config;
+uint8_t          unicode_saved_mods;
+
 #if UNICODE_SELECTED_MODES != -1
 static uint8_t selected[] = { UNICODE_SELECTED_MODES };
 static uint8_t selected_count = sizeof selected / sizeof *selected;
@@ -75,30 +77,24 @@ void persist_unicode_input_mode(void) {
   eeprom_update_byte(EECONFIG_UNICODEMODE, unicode_config.input_mode);
 }
 
-static uint8_t saved_mods;
-
 __attribute__((weak))
 void unicode_input_start(void) {
-  saved_mods = get_mods(); // Save current mods
+  unicode_saved_mods = get_mods(); // Save current mods
   clear_mods(); // Unregister mods to start from a clean state
 
   switch (unicode_config.input_mode) {
   case UC_OSX:
-    register_code(UNICODE_OSX_KEY);
+    register_code(UNICODE_KEY_OSX);
     break;
   case UC_LNX:
-    register_code(KC_LCTL);
-    register_code(KC_LSFT);
-    tap_code(KC_U); // TODO: Replace with tap_code16(LCTL(LSFT(KC_U))); and test
-    unregister_code(KC_LSFT);
-    unregister_code(KC_LCTL);
+    tap_code16(UNICODE_KEY_LNX);
     break;
   case UC_WIN:
     register_code(KC_LALT);
     tap_code(KC_PPLS);
     break;
   case UC_WINC:
-    tap_code(UNICODE_WINC_KEY);
+    tap_code(UNICODE_KEY_WINC);
     tap_code(KC_U);
     break;
   }
@@ -110,7 +106,7 @@ __attribute__((weak))
 void unicode_input_finish(void) {
   switch (unicode_config.input_mode) {
   case UC_OSX:
-    unregister_code(UNICODE_OSX_KEY);
+    unregister_code(UNICODE_KEY_OSX);
     break;
   case UC_LNX:
     tap_code(KC_SPC);
@@ -123,7 +119,25 @@ void unicode_input_finish(void) {
     break;
   }
 
-  set_mods(saved_mods); // Reregister previously set mods
+  set_mods(unicode_saved_mods); // Reregister previously set mods
+}
+
+__attribute__((weak))
+void unicode_input_cancel(void) {
+  switch (unicode_config.input_mode) {
+  case UC_OSX:
+    unregister_code(UNICODE_KEY_OSX);
+    break;
+  case UC_LNX:
+  case UC_WINC:
+    tap_code(KC_ESC);
+    break;
+  case UC_WIN:
+    unregister_code(KC_LALT);
+    break;
+  }
+
+  set_mods(unicode_saved_mods); // Reregister previously set mods
 }
 
 __attribute__((weak))
diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h
index e608ab76be..7340800e56 100644
--- a/quantum/process_keycode/process_unicode_common.h
+++ b/quantum/process_keycode/process_unicode_common.h
@@ -23,11 +23,14 @@
 #endif
 
 // Keycodes used for starting Unicode input on different platforms
-#ifndef UNICODE_OSX_KEY
-  #define UNICODE_OSX_KEY  KC_LALT
+#ifndef UNICODE_KEY_OSX
+  #define UNICODE_KEY_OSX  KC_LALT
 #endif
-#ifndef UNICODE_WINC_KEY
-  #define UNICODE_WINC_KEY KC_RALT
+#ifndef UNICODE_KEY_LNX
+  #define UNICODE_KEY_LNX  LCTL(LSFT(KC_U))
+#endif
+#ifndef UNICODE_KEY_WINC
+  #define UNICODE_KEY_WINC KC_RALT
 #endif
 
 // Comma-delimited, ordered list of input modes selected for use (e.g. in cycle)
@@ -63,6 +66,7 @@ typedef union {
 } unicode_config_t;
 
 extern unicode_config_t unicode_config;
+extern uint8_t          unicode_saved_mods;
 
 void unicode_input_mode_init(void);
 uint8_t get_unicode_input_mode(void);
@@ -72,6 +76,7 @@ void persist_unicode_input_mode(void);
 
 void unicode_input_start(void);
 void unicode_input_finish(void);
+void unicode_input_cancel(void);
 
 void register_hex(uint16_t hex);
 void send_unicode_hex_string(const char *str);
diff --git a/quantum/process_keycode/process_unicodemap.c b/quantum/process_keycode/process_unicodemap.c
index 3274027613..b887879860 100644
--- a/quantum/process_keycode/process_unicodemap.c
+++ b/quantum/process_keycode/process_unicodemap.c
@@ -15,7 +15,6 @@
  */
 
 #include "process_unicodemap.h"
-#include "process_unicode_common.h"
 
 void register_hex32(uint32_t hex) {
   bool onzerostart = true;
@@ -38,28 +37,39 @@ void register_hex32(uint32_t hex) {
 }
 
 __attribute__((weak))
-void unicodemap_input_error() {}
+uint16_t unicodemap_index(uint16_t keycode) {
+  if (keycode >= QK_UNICODEMAP_PAIR) {
+    // Keycode is a pair: extract index based on Shift / Caps Lock state
+    uint16_t index = keycode - QK_UNICODEMAP_PAIR;
+
+    bool shift = unicode_saved_mods & MOD_MASK_SHIFT, caps = IS_HOST_LED_ON(USB_LED_CAPS_LOCK);
+    if (shift ^ caps) { index >>= 7; }
+
+    return index & 0x7F;
+  } else {
+    // Keycode is a regular index
+    return keycode - QK_UNICODEMAP;
+  }
+}
 
 bool process_unicodemap(uint16_t keycode, keyrecord_t *record) {
-  if ((keycode & QK_UNICODEMAP) == QK_UNICODEMAP && record->event.pressed) {
-    uint16_t index = keycode - QK_UNICODEMAP;
-    uint32_t code = pgm_read_dword(unicode_map + index);
+  if (keycode >= QK_UNICODEMAP && keycode <= QK_UNICODEMAP_PAIR_MAX && record->event.pressed) {
+    unicode_input_start();
+
+    uint32_t code = pgm_read_dword(unicode_map + unicodemap_index(keycode));
     uint8_t input_mode = get_unicode_input_mode();
 
-    if (code > 0xFFFF && code <= 0x10FFFF && input_mode == UC_OSX) {
-      // Convert to UTF-16 surrogate pair
+    if (code > 0x10FFFF || (code > 0xFFFF && input_mode == UC_WIN)) {
+      // Character is out of range supported by the platform
+      unicode_input_cancel();
+    } else if (code > 0xFFFF && input_mode == UC_OSX) {
+      // Convert to UTF-16 surrogate pair on Mac
       code -= 0x10000;
       uint32_t lo = code & 0x3FF, hi = (code & 0xFFC00) >> 10;
-
-      unicode_input_start();
       register_hex32(hi + 0xD800);
       register_hex32(lo + 0xDC00);
       unicode_input_finish();
-    } else if ((code > 0x10FFFF && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) {
-      // Character is out of range supported by the OS
-      unicodemap_input_error();
     } else {
-      unicode_input_start();
       register_hex32(code);
       unicode_input_finish();
     }
diff --git a/quantum/process_keycode/process_unicodemap.h b/quantum/process_keycode/process_unicodemap.h
index fe4f979155..51709c5dc8 100644
--- a/quantum/process_keycode/process_unicodemap.h
+++ b/quantum/process_keycode/process_unicodemap.h
@@ -16,10 +16,10 @@
 
 #pragma once
 
-#include "quantum.h"
 #include "process_unicode_common.h"
 
 extern const uint32_t PROGMEM unicode_map[];
 
-void unicodemap_input_error(void);
+void register_hex32(uint32_t hex);
+uint16_t unicodemap_index(uint16_t keycode);
 bool process_unicodemap(uint16_t keycode, keyrecord_t *record);
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 9aa498dadb..d4fa7f2efc 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -24,10 +24,6 @@
 #include "outputselect.h"
 #endif
 
-#ifndef TAPPING_TERM
-#define TAPPING_TERM 200
-#endif
-
 #ifndef BREATHING_PERIOD
 #define BREATHING_PERIOD 6
 #endif
@@ -196,30 +192,6 @@ void reset_keyboard(void) {
   bootloader_jump();
 }
 
-// Shift / paren setup
-
-#ifndef LSPO_KEY
-  #define LSPO_KEY KC_9
-#endif
-#ifndef RSPC_KEY
-  #define RSPC_KEY KC_0
-#endif
-
-#ifndef LSPO_MOD
-  #define LSPO_MOD KC_LSFT
-#endif
-#ifndef RSPC_MOD
-  #define RSPC_MOD KC_RSFT
-#endif
-
-// Shift / Enter setup
-#ifndef SFTENT_KEY
-  #define SFTENT_KEY KC_ENT
-#endif
-
-static bool shift_interrupted[2] = {0, 0};
-static uint16_t scs_timer[2] = {0, 0};
-
 /* true if the last press of GRAVE_ESC was shifted (i.e. GUI or SHIFT were pressed), false otherwise.
  * Used to ensure that the correct keycode is released if the key is released.
  */
@@ -275,12 +247,6 @@ bool process_record_quantum(keyrecord_t *record) {
     preprocess_tap_dance(keycode, record);
   #endif
 
-  #if defined(OLED_DRIVER_ENABLE) && !defined(OLED_DISABLE_TIMEOUT)
-    // Wake up oled if user is using those fabulous keys!
-    if (record->event.pressed)
-      oled_on();
-  #endif
-
   if (!(
   #if defined(KEY_LOCK_ENABLE)
     // Must run first to be able to mask key_up events.
@@ -329,6 +295,9 @@ bool process_record_quantum(keyrecord_t *record) {
   #ifdef TERMINAL_ENABLE
     process_terminal(keycode, record) &&
   #endif
+  #ifdef SPACE_CADET_ENABLE
+    process_space_cadet(keycode, record) &&
+  #endif
       true)) {
     return false;
   }
@@ -685,92 +654,6 @@ bool process_record_quantum(keyrecord_t *record) {
         return false;
       }
       break;
-    case KC_LSPO: {
-      if (record->event.pressed) {
-        shift_interrupted[0] = false;
-        scs_timer[0] = timer_read ();
-        register_mods(MOD_BIT(KC_LSFT));
-      }
-      else {
-        #ifdef DISABLE_SPACE_CADET_ROLLOVER
-          if (get_mods() & MOD_BIT(RSPC_MOD)) {
-            shift_interrupted[0] = true;
-            shift_interrupted[1] = true;
-          }
-        #endif
-        if (!shift_interrupted[0] && timer_elapsed(scs_timer[0]) < TAPPING_TERM) {
-          #ifdef DISABLE_SPACE_CADET_MODIFIER
-            unregister_mods(MOD_BIT(KC_LSFT));
-          #else
-            if( LSPO_MOD != KC_LSFT ){
-              unregister_mods(MOD_BIT(KC_LSFT));
-              register_mods(MOD_BIT(LSPO_MOD));
-            }
-          #endif
-          register_code(LSPO_KEY);
-          unregister_code(LSPO_KEY);
-          #ifndef DISABLE_SPACE_CADET_MODIFIER
-            if( LSPO_MOD != KC_LSFT ){
-              unregister_mods(MOD_BIT(LSPO_MOD));
-            }
-          #endif
-        }
-        unregister_mods(MOD_BIT(KC_LSFT));
-      }
-      return false;
-    }
-
-    case KC_RSPC: {
-      if (record->event.pressed) {
-        shift_interrupted[1] = false;
-        scs_timer[1] = timer_read ();
-        register_mods(MOD_BIT(KC_RSFT));
-      }
-      else {
-        #ifdef DISABLE_SPACE_CADET_ROLLOVER
-          if (get_mods() & MOD_BIT(LSPO_MOD)) {
-            shift_interrupted[0] = true;
-            shift_interrupted[1] = true;
-          }
-        #endif
-        if (!shift_interrupted[1] && timer_elapsed(scs_timer[1]) < TAPPING_TERM) {
-          #ifdef DISABLE_SPACE_CADET_MODIFIER
-            unregister_mods(MOD_BIT(KC_RSFT));
-          #else
-            if( RSPC_MOD != KC_RSFT ){
-              unregister_mods(MOD_BIT(KC_RSFT));
-              register_mods(MOD_BIT(RSPC_MOD));
-            }
-          #endif
-          register_code(RSPC_KEY);
-          unregister_code(RSPC_KEY);
-          #ifndef DISABLE_SPACE_CADET_MODIFIER
-            if ( RSPC_MOD != KC_RSFT ){
-              unregister_mods(MOD_BIT(RSPC_MOD));
-            }
-          #endif
-        }
-        unregister_mods(MOD_BIT(KC_RSFT));
-      }
-      return false;
-    }
-
-    case KC_SFTENT: {
-      if (record->event.pressed) {
-        shift_interrupted[1] = false;
-        scs_timer[1] = timer_read ();
-        register_mods(MOD_BIT(KC_RSFT));
-      }
-      else if (!shift_interrupted[1] && timer_elapsed(scs_timer[1]) < TAPPING_TERM) {
-        unregister_mods(MOD_BIT(KC_RSFT));
-        register_code(SFTENT_KEY);
-        unregister_code(SFTENT_KEY);
-      }
-      else {
-        unregister_mods(MOD_BIT(KC_RSFT));
-      }
-      return false;
-    }
 
     case GRAVE_ESC: {
       uint8_t shifted = get_mods() & ((MOD_BIT(KC_LSHIFT)|MOD_BIT(KC_RSHIFT)
@@ -825,12 +708,6 @@ bool process_record_quantum(keyrecord_t *record) {
       return false;
     }
 #endif
-
-    default: {
-      shift_interrupted[0] = true;
-      shift_interrupted[1] = true;
-      break;
-    }
   }
 
   return process_action_kb(record);
@@ -1093,9 +970,6 @@ void matrix_init_quantum() {
   #ifdef OUTPUT_AUTO_ENABLE
     set_output(OUTPUT_AUTO);
   #endif
-  #ifdef OLED_DRIVER_ENABLE
-    oled_init(OLED_ROTATION_0);
-  #endif
   matrix_init_kb();
 }
 
@@ -1132,36 +1006,40 @@ void matrix_scan_quantum() {
     haptic_task();
   #endif
 
-  #ifdef OLED_DRIVER_ENABLE
-    oled_task();
-  #endif
-
   matrix_scan_kb();
 }
-#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
+#if defined(BACKLIGHT_ENABLE) && (defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS))
 
-static const uint8_t backlight_pin = BACKLIGHT_PIN;
+// The logic is a bit complex, we support 3 setups:
+// 1. hardware PWM when backlight is wired to a PWM pin
+// depending on this pin, we use a different output compare unit
+// 2. software PWM with hardware timers, but the used timer depends
+// on the audio setup (audio wins other backlight)
+// 3. full software PWM
 
-// depending on the pin, we use a different output compare unit
 #if BACKLIGHT_PIN == B7
+#  define HARDWARE_PWM
 #  define TCCRxA TCCR1A
 #  define TCCRxB TCCR1B
 #  define COMxx1 COM1C1
 #  define OCRxx  OCR1C
 #  define ICRx   ICR1
 #elif BACKLIGHT_PIN == B6
+#  define HARDWARE_PWM
 #  define TCCRxA TCCR1A
 #  define TCCRxB TCCR1B
 #  define COMxx1 COM1B1
 #  define OCRxx  OCR1B
 #  define ICRx   ICR1
 #elif BACKLIGHT_PIN == B5
+#  define HARDWARE_PWM
 #  define TCCRxA TCCR1A
 #  define TCCRxB TCCR1B
 #  define COMxx1 COM1A1
 #  define OCRxx  OCR1A
 #  define ICRx   ICR1
 #elif BACKLIGHT_PIN == C6
+#  define HARDWARE_PWM
 #  define TCCRxA TCCR3A
 #  define TCCRxB TCCR3B
 #  define COMxx1 COM1A1
@@ -1175,28 +1053,115 @@ static const uint8_t backlight_pin = BACKLIGHT_PIN;
 #  define ICRx   ICR1
 #  define TIMSK1 TIMSK
 #else
-#  define NO_HARDWARE_PWM
+#  if !defined(BACKLIGHT_CUSTOM_DRIVER)
+#    if !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO)
+     // timer 1 is not used by audio , backlight can use it
+#pragma message "Using hardware timer 1 with software PWM"
+#      define HARDWARE_PWM
+#      define BACKLIGHT_PWM_TIMER
+#      define TCCRxA TCCR1A
+#      define TCCRxB TCCR1B
+#      define OCRxx  OCR1A
+#      define OCRxAH OCR1AH
+#      define OCRxAL OCR1AL
+#      define TIMERx_COMPA_vect TIMER1_COMPA_vect
+#      define TIMERx_OVF_vect TIMER1_OVF_vect
+#      define OCIExA OCIE1A
+#      define TOIEx  TOIE1
+#      define ICRx   ICR1
+#      ifndef TIMSK
+#        define TIMSK TIMSK1
+#      endif
+#    elif !defined(C6_AUDIO) && !defined(C5_AUDIO) && !defined(C4_AUDIO)
+#pragma message "Using hardware timer 3 with software PWM"
+// timer 3 is not used by audio, backlight can use it
+#      define HARDWARE_PWM
+#      define BACKLIGHT_PWM_TIMER
+#      define TCCRxA TCCR3A
+#      define TCCRxB TCCR3B
+#      define OCRxx OCR3A
+#      define OCRxAH OCR3AH
+#      define OCRxAL OCR3AL
+#      define TIMERx_COMPA_vect TIMER3_COMPA_vect
+#      define TIMERx_OVF_vect TIMER3_OVF_vect
+#      define OCIExA OCIE3A
+#      define TOIEx  TOIE3
+#      define ICRx   ICR1
+#      ifndef TIMSK
+#        define TIMSK TIMSK3
+#      endif
+#    else
+#pragma message "Audio in use - using pure software PWM"
+#define NO_HARDWARE_PWM
+#    endif
+#  else
+#pragma message "Custom driver defined - using pure software PWM"
+#define NO_HARDWARE_PWM
+#  endif
 #endif
 
 #ifndef BACKLIGHT_ON_STATE
 #define BACKLIGHT_ON_STATE 0
 #endif
 
-#ifdef NO_HARDWARE_PWM // pwm through software
+void backlight_on(uint8_t backlight_pin) {
+#if BACKLIGHT_ON_STATE == 0
+  writePinLow(backlight_pin);
+#else
+  writePinHigh(backlight_pin);
+#endif
+}
 
-__attribute__ ((weak))
+void backlight_off(uint8_t backlight_pin) {
+#if BACKLIGHT_ON_STATE == 0
+  writePinHigh(backlight_pin);
+#else
+  writePinLow(backlight_pin);
+#endif
+}
+
+
+#if defined(NO_HARDWARE_PWM) || defined(BACKLIGHT_PWM_TIMER)  // pwm through software
+
+// we support multiple backlight pins
+#ifndef BACKLIGHT_LED_COUNT
+#define BACKLIGHT_LED_COUNT 1
+#endif
+
+#if BACKLIGHT_LED_COUNT == 1
+#define BACKLIGHT_PIN_INIT { BACKLIGHT_PIN }
+#else
+#define BACKLIGHT_PIN_INIT BACKLIGHT_PINS
+#endif
+
+#define FOR_EACH_LED(x)                             \
+  for (uint8_t i = 0; i < BACKLIGHT_LED_COUNT; i++) \
+  {                                                 \
+    uint8_t backlight_pin = backlight_pins[i];      \
+    { \
+      x                         \
+    }                                             \
+  }
+
+static const uint8_t backlight_pins[BACKLIGHT_LED_COUNT] = BACKLIGHT_PIN_INIT;
+
+#else // full hardware PWM
+
+// we support only one backlight pin
+static const uint8_t backlight_pin = BACKLIGHT_PIN;
+#define FOR_EACH_LED(x) x
+
+#endif
+
+#ifdef NO_HARDWARE_PWM
+__attribute__((weak))
 void backlight_init_ports(void)
 {
   // Setup backlight pin as output and output to on state.
-  // DDRx |= n
-  _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
-  #if BACKLIGHT_ON_STATE == 0
-    // PORTx &= ~n
-    _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
-  #else
-    // PORTx |= n
-    _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
-  #endif
+  FOR_EACH_LED(
+    setPinOutput(backlight_pin);
+    backlight_on(backlight_pin);
+  )
 }
 
 __attribute__ ((weak))
@@ -1207,21 +1172,14 @@ uint8_t backlight_tick = 0;
 #ifndef BACKLIGHT_CUSTOM_DRIVER
 void backlight_task(void) {
   if ((0xFFFF >> ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) {
-    #if BACKLIGHT_ON_STATE == 0
-      // PORTx &= ~n
-      _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
-    #else
-      // PORTx |= n
-      _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
-    #endif
-  } else {
-    #if BACKLIGHT_ON_STATE == 0
-      // PORTx |= n
-      _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
-    #else
-      // PORTx &= ~n
-      _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
-    #endif
+    FOR_EACH_LED(
+      backlight_on(backlight_pin);
+    )
+  }
+  else {
+    FOR_EACH_LED(
+      backlight_off(backlight_pin);
+    )
   }
   backlight_tick = (backlight_tick + 1) % 16;
 }
@@ -1233,7 +1191,52 @@ void backlight_task(void) {
   #endif
 #endif
 
-#else // pwm through timer
+#else // hardware pwm through timer
+
+#ifdef BACKLIGHT_PWM_TIMER
+
+// The idea of software PWM assisted by hardware timers is the following
+// we use the hardware timer in fast PWM mode like for hardware PWM, but
+// instead of letting the Output Match Comparator control the led pin
+// (which is not possible since the backlight is not wired to PWM pins on the
+// CPU), we do the LED on/off by oursleves.
+// The timer is setup to count up to 0xFFFF, and we set the Output Compare
+// register to the current 16bits backlight level (after CIE correction).
+// This means the CPU will trigger a compare match interrupt when the counter
+// reaches the backlight level, where we turn off the LEDs,
+// but also an overflow interrupt when the counter rolls back to 0,
+// in which we're going to turn on the LEDs.
+// The LED will then be on for OCRxx/0xFFFF time, adjusted every 244Hz.
+
+// Triggered when the counter reaches the OCRx value
+ISR(TIMERx_COMPA_vect) {
+  FOR_EACH_LED(
+    backlight_off(backlight_pin);
+  )
+}
+
+// Triggered when the counter reaches the TOP value
+// this one triggers at F_CPU/65536 =~ 244 Hz
+ISR(TIMERx_OVF_vect) {
+#ifdef BACKLIGHT_BREATHING
+  breathing_task();
+#endif
+  // for very small values of OCRxx (or backlight level)
+  // we can't guarantee this whole code won't execute
+  // at the same time as the compare match interrupt
+  // which means that we might turn on the leds while
+  // trying to turn them off, leading to flickering
+  // artifacts (especially while breathing, because breathing_task
+  // takes many computation cycles).
+  // so better not turn them on while the counter TOP is very low.
+  if (OCRxx > 256) {
+    FOR_EACH_LED(
+      backlight_on(backlight_pin);
+    )
+  }
+}
+
+#endif
 
 #define TIMER_TOP 0xFFFFU
 
@@ -1265,11 +1268,28 @@ void backlight_set(uint8_t level) {
     level = BACKLIGHT_LEVELS;
 
   if (level == 0) {
+    #ifdef BACKLIGHT_PWM_TIMER
+      if (OCRxx) {
+        TIMSK &= ~(_BV(OCIExA));
+        TIMSK &= ~(_BV(TOIEx));
+        FOR_EACH_LED(
+          backlight_off(backlight_pin);
+        )
+      }
+    #else
     // Turn off PWM control on backlight pin
     TCCRxA &= ~(_BV(COMxx1));
+    #endif
   } else {
+    #ifdef BACKLIGHT_PWM_TIMER
+      if (!OCRxx) {
+        TIMSK |= _BV(OCIExA);
+        TIMSK |= _BV(TOIEx);
+      }
+    #else
     // Turn on PWM control of backlight pin
     TCCRxA |= _BV(COMxx1);
+    #endif
   }
   // Set the brightness
   set_pwm(cie_lightness(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS));
@@ -1289,12 +1309,25 @@ static uint8_t breathing_period = BREATHING_PERIOD;
 static uint8_t breathing_halt = BREATHING_NO_HALT;
 static uint16_t breathing_counter = 0;
 
+#ifdef BACKLIGHT_PWM_TIMER
+static bool breathing = false;
+
+bool is_breathing(void) {
+  return breathing;
+}
+
+#define breathing_interrupt_enable() do { breathing = true; } while (0)
+#define breathing_interrupt_disable() do { breathing = false; } while (0)
+#else
+
 bool is_breathing(void) {
     return !!(TIMSK1 & _BV(TOIE1));
 }
 
 #define breathing_interrupt_enable() do {TIMSK1 |= _BV(TOIE1);} while (0)
 #define breathing_interrupt_disable() do {TIMSK1 &= ~_BV(TOIE1);} while (0)
+#endif
+
 #define breathing_min() do {breathing_counter = 0;} while (0)
 #define breathing_max() do {breathing_counter = breathing_period * 244 / 2;} while (0)
 
@@ -1368,10 +1401,14 @@ static inline uint16_t scale_backlight(uint16_t v) {
   return v / BACKLIGHT_LEVELS * get_backlight_level();
 }
 
+#ifdef BACKLIGHT_PWM_TIMER
+void breathing_task(void)
+#else
 /* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run
  * about 244 times per second.
  */
 ISR(TIMER1_OVF_vect)
+#endif
 {
   uint16_t interval = (uint16_t) breathing_period * 244 / BREATHING_STEPS;
   // resetting after one period to prevent ugly reset at overflow.
@@ -1393,19 +1430,21 @@ __attribute__ ((weak))
 void backlight_init_ports(void)
 {
   // Setup backlight pin as output and output to on state.
-  // DDRx |= n
-  _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
-  #if BACKLIGHT_ON_STATE == 0
-    // PORTx &= ~n
-    _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
-  #else
-    // PORTx |= n
-    _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
-  #endif
+  FOR_EACH_LED(
+    setPinOutput(backlight_pin);
+    backlight_on(backlight_pin);
+  )
+
   // I could write a wall of text here to explain... but TL;DW
   // Go read the ATmega32u4 datasheet.
   // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
 
+#ifdef BACKLIGHT_PWM_TIMER
+  // TimerX setup, Fast PWM mode count to TOP set in ICRx
+  TCCRxA = _BV(WGM11); // = 0b00000010;
+  // clock select clk/1
+  TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
+#else // hardware PWM
   // Pin PB7 = OCR1C (Timer 1, Channel C)
   // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
   // (i.e. start high, go low when counter matches.)
@@ -1417,8 +1456,9 @@ void backlight_init_ports(void)
   "In fast PWM mode, the compare units allow generation of PWM waveforms on the OCnx pins. Setting the COMnx1:0 bits to two will produce a non-inverted PWM [..]."
   "In fast PWM mode the counter is incremented until the counter value matches either one of the fixed values 0x00FF, 0x01FF, or 0x03FF (WGMn3:0 = 5, 6, or 7), the value in ICRn (WGMn3:0 = 14), or the value in OCRnA (WGMn3:0 = 15)."
   */
-  TCCRxA = _BV(COMxx1) | _BV(WGM11); // = 0b00001010;
+  TCCRxA = _BV(COMxx1) | _BV(WGM11);            // = 0b00001010;
   TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
+#endif
   // Use full 16-bit resolution. Counter counts to ICR1 before reset to 0.
   ICRx = TIMER_TOP;
 
@@ -1428,9 +1468,9 @@ void backlight_init_ports(void)
   #endif
 }
 
-#endif // NO_HARDWARE_PWM
+#endif // hardware backlight
 
-#else // backlight
+#else // no backlight
 
 __attribute__ ((weak))
 void backlight_init_ports(void) {}
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 987516dedb..208268df65 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -131,6 +131,10 @@ extern uint32_t default_layer_state;
     #include "process_terminal_nop.h"
 #endif
 
+#ifdef SPACE_CADET_ENABLE
+  #include "process_space_cadet.h"
+#endif
+
 #ifdef HD44780_ENABLE
     #include "hd44780.h"
 #endif
@@ -260,8 +264,12 @@ void tap_code16(uint16_t code);
 #ifdef BACKLIGHT_ENABLE
 void backlight_init_ports(void);
 void backlight_task(void);
+void backlight_task_internal(void);
+void backlight_on(uint8_t backlight_pin);
+void backlight_off(uint8_t backlight_pin);
 
 #ifdef BACKLIGHT_BREATHING
+void breathing_task(void);
 void breathing_enable(void);
 void breathing_pulse(void);
 void breathing_disable(void);
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index fe2e3510d6..779c355efc 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -87,7 +87,9 @@ enum quantum_keycodes {
 #endif
 #ifdef UNICODEMAP_ENABLE
     QK_UNICODEMAP         = 0x8000,
-    QK_UNICODEMAP_MAX     = 0x83FF,
+    QK_UNICODEMAP_MAX     = 0xBFFF,
+    QK_UNICODEMAP_PAIR    = 0xC000,
+    QK_UNICODEMAP_PAIR_MAX = 0xFFFF,
 #endif
 
     // Loose keycodes - to be used directly
@@ -475,6 +477,18 @@ enum quantum_keycodes {
     HPT_DWLI,
     HPT_DWLD,
 
+    // Left control, open paren
+    KC_LCPO,
+
+    // Right control, close paren
+    KC_RCPC,
+
+    // Left control, open paren
+    KC_LAPO,
+
+    // Right control, close paren
+    KC_RAPC,
+
     // always leave at the end
     SAFE_RANGE
 };
@@ -700,7 +714,8 @@ enum quantum_keycodes {
 #endif
 #ifdef UNICODEMAP_ENABLE
   // Allows Unicode input up to 0x10FFFF, requires unicode_map
-  #define X(i) (QK_UNICODEMAP | (i))
+  #define X(i)     (QK_UNICODEMAP | (i))
+  #define XP(i, j) (QK_UNICODEMAP_PAIR | ((i) & 0x7F) | (((j) & 0x7F) << 7)) // 127 max i and j
 #endif
 
 #define UC_MOD  UNICODE_MODE_FORWARD
diff --git a/quantum/rgb_matrix.c b/quantum/rgb_matrix.c
index a1193d4c07..92a94df80f 100644
--- a/quantum/rgb_matrix.c
+++ b/quantum/rgb_matrix.c
@@ -38,13 +38,30 @@
 #include "rgb_matrix_animations/rainbow_pinwheels_anim.h"
 #include "rgb_matrix_animations/rainbow_moving_chevron_anim.h"
 #include "rgb_matrix_animations/jellybean_raindrops_anim.h"
+#include "rgb_matrix_animations/typing_heatmap_anim.h"
 #include "rgb_matrix_animations/digital_rain_anim.h"
 #include "rgb_matrix_animations/solid_reactive_simple_anim.h"
 #include "rgb_matrix_animations/solid_reactive_anim.h"
+#include "rgb_matrix_animations/solid_reactive_wide.h"
+#include "rgb_matrix_animations/solid_reactive_cross.h"
+#include "rgb_matrix_animations/solid_reactive_nexus.h"
 #include "rgb_matrix_animations/splash_anim.h"
 #include "rgb_matrix_animations/solid_splash_anim.h"
 #include "rgb_matrix_animations/breathing_anim.h"
 
+#if defined(RGB_MATRIX_CUSTOM_KB) || defined(RGB_MATRIX_CUSTOM_USER)
+  #define RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+    #define RGB_MATRIX_EFFECT(name, ...)
+    #ifdef RGB_MATRIX_CUSTOM_KB
+      #include "rgb_matrix_kb.inc"
+    #endif
+    #ifdef RGB_MATRIX_CUSTOM_USER
+      #include "rgb_matrix_user.inc"
+    #endif
+    #undef RGB_MATRIX_EFFECT
+  #undef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+#endif
+
 #ifndef RGB_DISABLE_AFTER_TIMEOUT
   #define RGB_DISABLE_AFTER_TIMEOUT 0
 #endif
@@ -78,13 +95,27 @@
   #define RGB_MATRIX_SPD_STEP 16
 #endif
 
+#if !defined(RGB_MATRIX_STARTUP_MODE)
+  #ifndef DISABLE_RGB_MATRIX_CYCLE_ALL
+    #define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_LEFT_RIGHT
+  #else
+    // fallback to solid colors if RGB_MATRIX_CYCLE_LEFT_RIGHT is disabled in userspace
+    #define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_SOLID_COLOR
+  #endif
+#endif
+
 bool g_suspend_state = false;
 
+extern led_config_t g_led_config;
 rgb_config_t rgb_matrix_config;
 
 rgb_counters_t g_rgb_counters;
 static uint32_t rgb_counters_buffer;
 
+#ifdef RGB_MATRIX_FRAMEBUFFER_EFFECTS
+uint8_t rgb_frame_buffer[MATRIX_ROWS][MATRIX_COLS] = {{0}};
+#endif
+
 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
   last_hit_t g_last_hit_tracker;
   static last_hit_t last_hit_buffer;
@@ -101,12 +132,7 @@ void eeconfig_update_rgb_matrix(uint32_t val) {
 void eeconfig_update_rgb_matrix_default(void) {
   dprintf("eeconfig_update_rgb_matrix_default\n");
   rgb_matrix_config.enable = 1;
-#ifndef DISABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
-  rgb_matrix_config.mode = RGB_MATRIX_CYCLE_LEFT_RIGHT;
-#else
-  // fallback to solid colors if RGB_MATRIX_CYCLE_LEFT_RIGHT is disabled in userspace
-  rgb_matrix_config.mode = RGB_MATRIX_SOLID_COLOR;
-#endif
+  rgb_matrix_config.mode = RGB_MATRIX_STARTUP_MODE;
   rgb_matrix_config.hue = 0;
   rgb_matrix_config.sat = UINT8_MAX;
   rgb_matrix_config.val = RGB_MATRIX_MAXIMUM_BRIGHTNESS;
@@ -124,15 +150,17 @@ void eeconfig_debug_rgb_matrix(void) {
   dprintf("rgb_matrix_config.speed = %d\n", rgb_matrix_config.speed);
 }
 
+__attribute__ ((weak))
+uint8_t rgb_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) {
+  return 0;
+}
+
 uint8_t rgb_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i) {
-  // TODO: This is kinda expensive, fix this soonish
-  uint8_t led_count = 0;
-  for (uint8_t i = 0; i < DRIVER_LED_TOTAL && led_count < LED_HITS_TO_REMEMBER; i++) {
-    matrix_co_t matrix_co = g_rgb_leds[i].matrix_co;
-    if (row == matrix_co.row && column == matrix_co.col) {
-      led_i[led_count] = i;
-      led_count++;
-    }
+  uint8_t led_count = rgb_matrix_map_row_column_to_led_kb(row, column, led_i);
+  uint8_t led_index = g_led_config.matrix_co[row][column];
+  if (led_index != NO_LED) {
+    led_i[led_count] = led_index;
+    led_count++;
   }
   return led_count;
 }
@@ -142,28 +170,11 @@ void rgb_matrix_update_pwm_buffers(void) {
 }
 
 void rgb_matrix_set_color( int index, uint8_t red, uint8_t green, uint8_t blue ) {
-#ifdef RGB_MATRIX_EXTRA_TOG
-  const bool is_key = g_rgb_leds[index].matrix_co.raw != 0xff;
-  if (
-    (rgb_matrix_config.enable == RGB_ZONE_KEYS && !is_key) ||
-    (rgb_matrix_config.enable == RGB_ZONE_UNDER && is_key)
-  ) {
-    rgb_matrix_driver.set_color(index, 0, 0, 0);
-    return;
-  }
-#endif
-
   rgb_matrix_driver.set_color(index, red, green, blue);
 }
 
 void rgb_matrix_set_color_all( uint8_t red, uint8_t green, uint8_t blue ) {
-#ifdef RGB_MATRIX_EXTRA_TOG
-  for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
-      rgb_matrix_set_color(i, red, green, blue);
-  }
-#else
   rgb_matrix_driver.set_color_all(red, green, blue);
-#endif
 }
 
 bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
@@ -193,13 +204,20 @@ bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
 
   for(uint8_t i = 0; i < led_count; i++) {
     uint8_t index = last_hit_buffer.count;
-    last_hit_buffer.x[index] = g_rgb_leds[led[i]].point.x;
-    last_hit_buffer.y[index] = g_rgb_leds[led[i]].point.y;
+    last_hit_buffer.x[index] = g_led_config.point[led[i]].x;
+    last_hit_buffer.y[index] = g_led_config.point[led[i]].y;
     last_hit_buffer.index[index] = led[i];
     last_hit_buffer.tick[index] = 0;
     last_hit_buffer.count++;
   }
 #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
+
+#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_TYPING_HEATMAP)
+  if (rgb_matrix_config.mode == RGB_MATRIX_TYPING_HEATMAP) {
+    process_rgb_matrix_typing_heatmap(record);
+  }
+#endif // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_TYPING_HEATMAP)
+
   return true;
 }
 
@@ -242,7 +260,7 @@ static bool rgb_matrix_none(effect_params_t* params) {
 
 static uint8_t rgb_last_enable = UINT8_MAX;
 static uint8_t rgb_last_effect = UINT8_MAX;
-static effect_params_t rgb_effect_params = { 0, 0 };
+static effect_params_t rgb_effect_params = { 0, 0xFF };
 static rgb_task_states rgb_task_state = SYNCING;
 
 static void rgb_task_timers(void) {
@@ -364,11 +382,20 @@ static void rgb_task_render(uint8_t effect) {
       rendering = rgb_matrix_jellybean_raindrops(&rgb_effect_params);   // Max 1ms Avg 0ms
       break;
 #endif // DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
+
+#ifdef RGB_MATRIX_FRAMEBUFFER_EFFECTS
+#ifndef DISABLE_RGB_MATRIX_TYPING_HEATMAP
+    case RGB_MATRIX_TYPING_HEATMAP:
+      rendering = rgb_matrix_typing_heatmap(&rgb_effect_params);        // Max 4ms Avg 3ms
+      break;
+#endif // DISABLE_RGB_MATRIX_TYPING_HEATMAP
 #ifndef DISABLE_RGB_MATRIX_DIGITAL_RAIN
     case RGB_MATRIX_DIGITAL_RAIN:
       rendering = rgb_matrix_digital_rain(&rgb_effect_params);         // Max 9ms Avg 8ms | this is expensive, fix it
       break;
 #endif // DISABLE_RGB_MATRIX_DIGITAL_RAIN
+#endif // RGB_MATRIX_FRAMEBUFFER_EFFECTS
+
 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
 #ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
     case RGB_MATRIX_SOLID_REACTIVE_SIMPLE:
@@ -380,6 +407,36 @@ static void rgb_task_render(uint8_t effect) {
       rendering = rgb_matrix_solid_reactive(&rgb_effect_params);       // Max 4ms Avg 3ms
       break;
 #endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
+    case RGB_MATRIX_SOLID_REACTIVE_WIDE:
+      rendering = rgb_matrix_solid_reactive_wide(&rgb_effect_params);       // Max ?? ms Avg ?? ms
+      break;
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
+    case RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE:
+      rendering = rgb_matrix_solid_reactive_multiwide(&rgb_effect_params);       // Max ?? ms Avg ?? ms
+      break;
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
+    case RGB_MATRIX_SOLID_REACTIVE_CROSS:
+      rendering = rgb_matrix_solid_reactive_cross(&rgb_effect_params);       // Max ?? ms Avg ?? ms
+      break;
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
+    case RGB_MATRIX_SOLID_REACTIVE_MULTICROSS:
+      rendering = rgb_matrix_solid_reactive_multicross(&rgb_effect_params);       // Max ?? ms Avg ?? ms
+      break;
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
+    case RGB_MATRIX_SOLID_REACTIVE_NEXUS:
+      rendering = rgb_matrix_solid_reactive_nexus(&rgb_effect_params);       // Max ?? ms Avg ?? ms
+      break;
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
+    case RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS:
+      rendering = rgb_matrix_solid_reactive_multinexus(&rgb_effect_params);       // Max ?? ms Avg ?? ms
+      break;
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
 #ifndef DISABLE_RGB_MATRIX_SPLASH
     case RGB_MATRIX_SPLASH:
       rendering = rgb_matrix_splash(&rgb_effect_params);               // Max 5ms Avg 3ms
@@ -402,6 +459,20 @@ static void rgb_task_render(uint8_t effect) {
 #endif // DISABLE_RGB_MATRIX_SOLID_MULTISPLASH
 #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
 
+#if defined(RGB_MATRIX_CUSTOM_KB) || defined(RGB_MATRIX_CUSTOM_USER)
+  #define RGB_MATRIX_EFFECT(name, ...) \
+    case RGB_MATRIX_CUSTOM_##name: \
+      rendering = name(&rgb_effect_params); \
+      break;
+  #ifdef RGB_MATRIX_CUSTOM_KB
+    #include "rgb_matrix_kb.inc"
+  #endif
+  #ifdef RGB_MATRIX_CUSTOM_USER
+    #include "rgb_matrix_user.inc"
+  #endif
+  #undef RGB_MATRIX_EFFECT
+#endif
+
     // Factory default magic value
     case UINT8_MAX: {
         rgb_matrix_test();
@@ -511,29 +582,31 @@ void rgb_matrix_set_suspend_state(bool state) {
 }
 
 void rgb_matrix_toggle(void) {
-  rgb_matrix_config.enable++;
-  if (!rgb_matrix_config.enable) {
-    rgb_task_state = STARTING;
-  }
+  rgb_matrix_config.enable ^= 1;
+  rgb_task_state = STARTING;
   eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
 }
 
 void rgb_matrix_enable(void) {
-	rgb_matrix_config.enable = 1;
+  rgb_matrix_enable_noeeprom();
   eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
 }
 
 void rgb_matrix_enable_noeeprom(void) {
-	rgb_matrix_config.enable = 1;
+  if (!rgb_matrix_config.enable)
+    rgb_task_state = STARTING;
+  rgb_matrix_config.enable = 1;
 }
 
 void rgb_matrix_disable(void) {
-	rgb_matrix_config.enable = 0;
+  rgb_matrix_disable_noeeprom();
   eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
 }
 
 void rgb_matrix_disable_noeeprom(void) {
-	rgb_matrix_config.enable = 0;
+  if (rgb_matrix_config.enable)
+    rgb_task_state = STARTING;
+  rgb_matrix_config.enable = 0;
 }
 
 void rgb_matrix_step(void) {
@@ -594,6 +667,14 @@ void rgb_matrix_decrease_speed(void) {
   eeconfig_update_rgb_matrix(rgb_matrix_config.raw);//EECONFIG needs to be increased to support this
 }
 
+led_flags_t rgb_matrix_get_flags(void) {
+  return rgb_effect_params.flags;
+}
+
+void rgb_matrix_set_flags(led_flags_t flags) {
+  rgb_effect_params.flags = flags;
+}
+
 void rgb_matrix_mode(uint8_t mode) {
   rgb_matrix_config.mode = mode;
   rgb_task_state = STARTING;
diff --git a/quantum/rgb_matrix.h b/quantum/rgb_matrix.h
index 0a11f26920..add0715d9f 100644
--- a/quantum/rgb_matrix.h
+++ b/quantum/rgb_matrix.h
@@ -24,6 +24,7 @@
 #include "rgb_matrix_types.h"
 #include "color.h"
 #include "quantum.h"
+#include "rgblight_list.h"
 
 #ifdef IS31FL3731
   #include "is31fl3731.h"
@@ -53,7 +54,7 @@
   uint8_t max = DRIVER_LED_TOTAL;
 #endif
 
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+#define RGB_MATRIX_TEST_LED_FLAGS() if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) continue
 
 typedef struct
 {
@@ -100,9 +101,14 @@ enum rgb_matrix_effects {
 #ifndef DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
   RGB_MATRIX_JELLYBEAN_RAINDROPS,
 #endif // DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
+#ifdef RGB_MATRIX_FRAMEBUFFER_EFFECTS
+#ifndef DISABLE_RGB_MATRIX_TYPING_HEATMAP
+  RGB_MATRIX_TYPING_HEATMAP,
+#endif // DISABLE_RGB_MATRIX_TYPING_HEATMAP
 #ifndef DISABLE_RGB_MATRIX_DIGITAL_RAIN
   RGB_MATRIX_DIGITAL_RAIN,
 #endif // DISABLE_RGB_MATRIX_DIGITAL_RAIN
+#endif // RGB_MATRIX_FRAMEBUFFER_EFFECTS
 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
 #ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
   RGB_MATRIX_SOLID_REACTIVE_SIMPLE,
@@ -110,6 +116,24 @@ enum rgb_matrix_effects {
 #ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE
   RGB_MATRIX_SOLID_REACTIVE,
 #endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
+  RGB_MATRIX_SOLID_REACTIVE_WIDE,
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
+  RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE,
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
+  RGB_MATRIX_SOLID_REACTIVE_CROSS,
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
+  RGB_MATRIX_SOLID_REACTIVE_MULTICROSS,
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
+  RGB_MATRIX_SOLID_REACTIVE_NEXUS,
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
+#ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
+  RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS,
+#endif // DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
 #ifndef DISABLE_RGB_MATRIX_SPLASH
   RGB_MATRIX_SPLASH,
 #endif // DISABLE_RGB_MATRIX_SPLASH
@@ -123,6 +147,18 @@ enum rgb_matrix_effects {
   RGB_MATRIX_SOLID_MULTISPLASH,
 #endif // DISABLE_RGB_MATRIX_SOLID_MULTISPLASH
 #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
+
+#if defined(RGB_MATRIX_CUSTOM_KB) || defined(RGB_MATRIX_CUSTOM_USER)
+  #define RGB_MATRIX_EFFECT(name, ...) RGB_MATRIX_CUSTOM_##name,
+  #ifdef RGB_MATRIX_CUSTOM_KB
+    #include "rgb_matrix_kb.inc"
+  #endif
+  #ifdef RGB_MATRIX_CUSTOM_USER
+    #include "rgb_matrix_user.inc"
+  #endif
+  #undef RGB_MATRIX_EFFECT
+#endif
+
   RGB_MATRIX_EFFECT_MAX
 };
 
@@ -178,6 +214,8 @@ void rgb_matrix_increase_val(void);
 void rgb_matrix_decrease_val(void);
 void rgb_matrix_increase_speed(void);
 void rgb_matrix_decrease_speed(void);
+led_flags_t rgb_matrix_get_flags(void);
+void rgb_matrix_set_flags(led_flags_t flags);
 void rgb_matrix_mode(uint8_t mode);
 void rgb_matrix_mode_noeeprom(uint8_t mode);
 uint8_t rgb_matrix_get_mode(void);
diff --git a/quantum/rgb_matrix_animations/alpha_mods_anim.h b/quantum/rgb_matrix_animations/alpha_mods_anim.h
index cc1914d7f4..d7f6f4655b 100644
--- a/quantum/rgb_matrix_animations/alpha_mods_anim.h
+++ b/quantum/rgb_matrix_animations/alpha_mods_anim.h
@@ -1,7 +1,7 @@
 #pragma once
 #ifndef DISABLE_RGB_MATRIX_ALPHAS_MODS
 
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 // alphas = color1, mods = color2
@@ -14,7 +14,8 @@ bool rgb_matrix_alphas_mods(effect_params_t* params) {
   RGB rgb2 = hsv_to_rgb(hsv);
 
   for (uint8_t i = led_min; i < led_max; i++) {
-    if (g_rgb_leds[i].modifier) {
+    RGB_MATRIX_TEST_LED_FLAGS();
+    if (HAS_FLAGS(g_led_config.flags[i], LED_FLAG_MODIFIER)) {
       rgb_matrix_set_color(i, rgb2.r, rgb2.g, rgb2.b);
     } else {
       rgb_matrix_set_color(i, rgb1.r, rgb1.g, rgb1.b);
diff --git a/quantum/rgb_matrix_animations/breathing_anim.h b/quantum/rgb_matrix_animations/breathing_anim.h
index 4a9a1dcdb2..54d60f927d 100644
--- a/quantum/rgb_matrix_animations/breathing_anim.h
+++ b/quantum/rgb_matrix_animations/breathing_anim.h
@@ -12,6 +12,7 @@ bool rgb_matrix_breathing(effect_params_t* params) {
   HSV hsv = { rgb_matrix_config.hue, rgb_matrix_config.sat, val };
   RGB rgb = hsv_to_rgb(hsv);
   for (uint8_t i = led_min; i < led_max; i++) {
+    RGB_MATRIX_TEST_LED_FLAGS();
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
   return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgb_matrix_animations/cycle_all_anim.h b/quantum/rgb_matrix_animations/cycle_all_anim.h
index 5c18cfa0c9..e93798f900 100644
--- a/quantum/rgb_matrix_animations/cycle_all_anim.h
+++ b/quantum/rgb_matrix_animations/cycle_all_anim.h
@@ -2,16 +2,16 @@
 #ifndef DISABLE_RGB_MATRIX_CYCLE_ALL
 
 extern rgb_counters_t g_rgb_counters;
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 bool rgb_matrix_cycle_all(effect_params_t* params) {
   RGB_MATRIX_USE_LIMITS(led_min, led_max);
 
   HSV hsv = { 0, rgb_matrix_config.sat, rgb_matrix_config.val };
-  uint8_t time = scale16by8(g_rgb_counters.tick, rgb_matrix_config.speed / 4);
+  hsv.h = scale16by8(g_rgb_counters.tick, rgb_matrix_config.speed / 4);
   for (uint8_t i = led_min; i < led_max; i++) {
-    hsv.h = time;
+    RGB_MATRIX_TEST_LED_FLAGS();
     RGB rgb = hsv_to_rgb(hsv);
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
diff --git a/quantum/rgb_matrix_animations/cycle_left_right_anim.h b/quantum/rgb_matrix_animations/cycle_left_right_anim.h
index f519aeb476..4b09d5826b 100644
--- a/quantum/rgb_matrix_animations/cycle_left_right_anim.h
+++ b/quantum/rgb_matrix_animations/cycle_left_right_anim.h
@@ -2,7 +2,7 @@
 #ifndef DISABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
 
 extern rgb_counters_t g_rgb_counters;
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 bool rgb_matrix_cycle_left_right(effect_params_t* params) {
@@ -11,8 +11,8 @@ bool rgb_matrix_cycle_left_right(effect_params_t* params) {
   HSV hsv = { 0, rgb_matrix_config.sat, rgb_matrix_config.val };
   uint8_t time = scale16by8(g_rgb_counters.tick, rgb_matrix_config.speed / 4);
   for (uint8_t i = led_min; i < led_max; i++) {
-    point_t point = g_rgb_leds[i].point;
-    hsv.h = point.x - time;
+    RGB_MATRIX_TEST_LED_FLAGS();
+    hsv.h = g_led_config.point[i].x - time;
     RGB rgb = hsv_to_rgb(hsv);
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
diff --git a/quantum/rgb_matrix_animations/cycle_up_down_anim.h b/quantum/rgb_matrix_animations/cycle_up_down_anim.h
index 8b91d890de..403214bb73 100644
--- a/quantum/rgb_matrix_animations/cycle_up_down_anim.h
+++ b/quantum/rgb_matrix_animations/cycle_up_down_anim.h
@@ -2,7 +2,7 @@
 #ifndef DISABLE_RGB_MATRIX_CYCLE_UP_DOWN
 
 extern rgb_counters_t g_rgb_counters;
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 bool rgb_matrix_cycle_up_down(effect_params_t* params) {
@@ -11,8 +11,8 @@ bool rgb_matrix_cycle_up_down(effect_params_t* params) {
   HSV hsv = { 0, rgb_matrix_config.sat, rgb_matrix_config.val };
   uint8_t time = scale16by8(g_rgb_counters.tick, rgb_matrix_config.speed / 4);
   for (uint8_t i = led_min; i < led_max; i++) {
-    point_t point = g_rgb_leds[i].point;
-    hsv.h = point.y - time;
+    RGB_MATRIX_TEST_LED_FLAGS();
+    hsv.h = g_led_config.point[i].y - time;
     RGB rgb = hsv_to_rgb(hsv);
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
diff --git a/quantum/rgb_matrix_animations/digital_rain_anim.h b/quantum/rgb_matrix_animations/digital_rain_anim.h
index 4ba3c1c87d..6ccba392aa 100644
--- a/quantum/rgb_matrix_animations/digital_rain_anim.h
+++ b/quantum/rgb_matrix_animations/digital_rain_anim.h
@@ -1,11 +1,13 @@
 #pragma once
-#ifndef DISABLE_RGB_MATRIX_DIGITAL_RAIN
+#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_DIGITAL_RAIN)
 
 #ifndef RGB_DIGITAL_RAIN_DROPS
     // lower the number for denser effect/wider keyboard
     #define RGB_DIGITAL_RAIN_DROPS 24
 #endif
 
+extern uint8_t rgb_frame_buffer[MATRIX_ROWS][MATRIX_COLS];
+
 bool rgb_matrix_digital_rain(effect_params_t* params) {
   // algorithm ported from https://github.com/tremby/Kaleidoscope-LEDEffect-DigitalRain
   const uint8_t drop_ticks           = 28;
@@ -13,24 +15,24 @@ bool rgb_matrix_digital_rain(effect_params_t* params) {
   const uint8_t max_brightness_boost = 0xc0;
   const uint8_t max_intensity        = 0xff;
 
-  static uint8_t map[MATRIX_COLS][MATRIX_ROWS] = {{0}};
   static uint8_t drop = 0;
 
   if (params->init) {
     rgb_matrix_set_color_all(0, 0, 0);
-    memset(map, 0, sizeof map);
+    memset(rgb_frame_buffer, 0, sizeof rgb_frame_buffer);
     drop = 0;
   }
+
   for (uint8_t col = 0; col < MATRIX_COLS; col++) {
     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
       if (row == 0 && drop == 0 && rand() < RAND_MAX / RGB_DIGITAL_RAIN_DROPS) {
         // top row, pixels have just fallen and we're
         // making a new rain drop in this column
-        map[col][row] = max_intensity;
+        rgb_frame_buffer[col][row] = max_intensity;
       }
-      else if (map[col][row] > 0 && map[col][row] < max_intensity) {
+      else if (rgb_frame_buffer[col][row] > 0 && rgb_frame_buffer[col][row] < max_intensity) {
         // neither fully bright nor dark, decay it
-        map[col][row]--;
+        rgb_frame_buffer[col][row]--;
       }
       // set the pixel colour
       uint8_t led[LED_HITS_TO_REMEMBER];
@@ -38,32 +40,33 @@ bool rgb_matrix_digital_rain(effect_params_t* params) {
 
       // TODO: multiple leds are supported mapped to the same row/column
       if (led_count > 0) {
-        if (map[col][row] > pure_green_intensity) {
-          const uint8_t boost = (uint8_t) ((uint16_t) max_brightness_boost * (map[col][row] - pure_green_intensity) / (max_intensity - pure_green_intensity));
+        if (rgb_frame_buffer[col][row] > pure_green_intensity) {
+          const uint8_t boost = (uint8_t) ((uint16_t) max_brightness_boost * (rgb_frame_buffer[col][row] - pure_green_intensity) / (max_intensity - pure_green_intensity));
           rgb_matrix_set_color(led[0], boost, max_intensity, boost);
         }
         else {
-          const uint8_t green = (uint8_t) ((uint16_t) max_intensity * map[col][row] / pure_green_intensity);
+          const uint8_t green = (uint8_t) ((uint16_t) max_intensity * rgb_frame_buffer[col][row] / pure_green_intensity);
           rgb_matrix_set_color(led[0], 0, green, 0);
         }
       }
     }
   }
+
   if (++drop > drop_ticks) {
     // reset drop timer
     drop = 0;
     for (uint8_t row = MATRIX_ROWS - 1; row > 0; row--) {
       for (uint8_t col = 0; col < MATRIX_COLS; col++) {
         // if ths is on the bottom row and bright allow decay
-        if (row == MATRIX_ROWS - 1 && map[col][row] == max_intensity) {
-          map[col][row]--;
+        if (row == MATRIX_ROWS - 1 && rgb_frame_buffer[col][row] == max_intensity) {
+          rgb_frame_buffer[col][row]--;
         }
         // check if the pixel above is bright
-        if (map[col][row - 1] == max_intensity) {
+        if (rgb_frame_buffer[col][row - 1] == max_intensity) {
           // allow old bright pixel to decay
-          map[col][row - 1]--;
+          rgb_frame_buffer[col][row - 1]--;
           // make this pixel bright
-          map[col][row] = max_intensity;
+          rgb_frame_buffer[col][row] = max_intensity;
         }
       }
     }
@@ -71,4 +74,4 @@ bool rgb_matrix_digital_rain(effect_params_t* params) {
   return false;
 }
 
-#endif // DISABLE_RGB_MATRIX_DIGITAL_RAIN
+#endif // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_DIGITAL_RAIN)
diff --git a/quantum/rgb_matrix_animations/dual_beacon_anim.h b/quantum/rgb_matrix_animations/dual_beacon_anim.h
index dda3157809..dcb594029e 100644
--- a/quantum/rgb_matrix_animations/dual_beacon_anim.h
+++ b/quantum/rgb_matrix_animations/dual_beacon_anim.h
@@ -2,7 +2,7 @@
 #ifndef DISABLE_RGB_MATRIX_DUAL_BEACON
 
 extern rgb_counters_t g_rgb_counters;
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 bool rgb_matrix_dual_beacon(effect_params_t* params) {
@@ -13,8 +13,8 @@ bool rgb_matrix_dual_beacon(effect_params_t* params) {
   int8_t cos_value = cos8(time) - 128;
   int8_t sin_value = sin8(time) - 128;
   for (uint8_t i = led_min; i < led_max; i++) {
-    point_t point = g_rgb_leds[i].point;
-    hsv.h = ((point.y - 32) * cos_value + (point.x - 112) * sin_value) / 128 + rgb_matrix_config.hue;
+    RGB_MATRIX_TEST_LED_FLAGS();
+    hsv.h = ((g_led_config.point[i].y - 32) * cos_value + (g_led_config.point[i].x - 112) * sin_value) / 128 + rgb_matrix_config.hue;
     RGB rgb = hsv_to_rgb(hsv);
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
diff --git a/quantum/rgb_matrix_animations/gradient_up_down_anim.h b/quantum/rgb_matrix_animations/gradient_up_down_anim.h
index 11498e22f5..7a6ed14219 100644
--- a/quantum/rgb_matrix_animations/gradient_up_down_anim.h
+++ b/quantum/rgb_matrix_animations/gradient_up_down_anim.h
@@ -1,7 +1,7 @@
 #pragma once
 #ifndef DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
 
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 bool rgb_matrix_gradient_up_down(effect_params_t* params) {
@@ -10,10 +10,10 @@ bool rgb_matrix_gradient_up_down(effect_params_t* params) {
   HSV hsv = { 0, rgb_matrix_config.sat, rgb_matrix_config.val };
   uint8_t scale = scale8(64, rgb_matrix_config.speed);
   for (uint8_t i = led_min; i < led_max; i++) {
-    point_t point = g_rgb_leds[i].point;
+    RGB_MATRIX_TEST_LED_FLAGS();
     // The y range will be 0..64, map this to 0..4
     // Relies on hue being 8-bit and wrapping
-    hsv.h = rgb_matrix_config.hue + scale * (point.y >> 4);
+    hsv.h = rgb_matrix_config.hue + scale * (g_led_config.point[i].y >> 4);
     RGB rgb = hsv_to_rgb(hsv);
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
diff --git a/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h b/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h
index 01ff5c2306..5ea971435e 100644
--- a/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h
+++ b/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h
@@ -2,10 +2,11 @@
 #ifndef DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
 
 extern rgb_counters_t g_rgb_counters;
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
-static void jellybean_raindrops_set_color(int i) {
+static void jellybean_raindrops_set_color(int i, effect_params_t* params) {
+  if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) return;
   HSV hsv = { rand() & 0xFF , rand() & 0xFF, rgb_matrix_config.val };
   RGB rgb = hsv_to_rgb(hsv);
   rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
@@ -15,14 +16,14 @@ bool rgb_matrix_jellybean_raindrops(effect_params_t* params) {
   if (!params->init) {
     // Change one LED every tick, make sure speed is not 0
     if (scale16by8(g_rgb_counters.tick, qadd8(rgb_matrix_config.speed, 16)) % 5 == 0) {
-      jellybean_raindrops_set_color(rand() % DRIVER_LED_TOTAL);
+      jellybean_raindrops_set_color(rand() % DRIVER_LED_TOTAL, params);
     }
     return false;
   }
 
   RGB_MATRIX_USE_LIMITS(led_min, led_max);
   for (int i = led_min; i < led_max; i++) {
-    jellybean_raindrops_set_color(i);
+    jellybean_raindrops_set_color(i, params);
   }
   return led_max < DRIVER_LED_TOTAL;
 }
diff --git a/quantum/rgb_matrix_animations/rainbow_beacon_anim.h b/quantum/rgb_matrix_animations/rainbow_beacon_anim.h
index 3c15e64ab6..d462880731 100644
--- a/quantum/rgb_matrix_animations/rainbow_beacon_anim.h
+++ b/quantum/rgb_matrix_animations/rainbow_beacon_anim.h
@@ -2,7 +2,7 @@
 #ifndef DISABLE_RGB_MATRIX_RAINBOW_BEACON
 
 extern rgb_counters_t g_rgb_counters;
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 bool rgb_matrix_rainbow_beacon(effect_params_t* params) {
@@ -13,8 +13,8 @@ bool rgb_matrix_rainbow_beacon(effect_params_t* params) {
   int16_t cos_value = 2 * (cos8(time) - 128);
   int16_t sin_value = 2 * (sin8(time) - 128);
   for (uint8_t i = led_min; i < led_max; i++) {
-    point_t point = g_rgb_leds[i].point;
-    hsv.h = ((point.y - 32) * cos_value + (point.x - 112) * sin_value) / 128 + rgb_matrix_config.hue;
+    RGB_MATRIX_TEST_LED_FLAGS();
+    hsv.h = ((g_led_config.point[i].y - 32) * cos_value + (g_led_config.point[i].x - 112) * sin_value) / 128 + rgb_matrix_config.hue;
     RGB rgb = hsv_to_rgb(hsv);
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
diff --git a/quantum/rgb_matrix_animations/rainbow_moving_chevron_anim.h b/quantum/rgb_matrix_animations/rainbow_moving_chevron_anim.h
index 0d11d52802..3b7d9689f8 100644
--- a/quantum/rgb_matrix_animations/rainbow_moving_chevron_anim.h
+++ b/quantum/rgb_matrix_animations/rainbow_moving_chevron_anim.h
@@ -2,7 +2,7 @@
 #ifndef DISABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
 
 extern rgb_counters_t g_rgb_counters;
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 bool rgb_matrix_rainbow_moving_chevron(effect_params_t* params) {
@@ -11,8 +11,8 @@ bool rgb_matrix_rainbow_moving_chevron(effect_params_t* params) {
   HSV hsv = { 0, rgb_matrix_config.sat, rgb_matrix_config.val };
   uint8_t time = scale16by8(g_rgb_counters.tick, rgb_matrix_config.speed / 4);
   for (uint8_t i = led_min; i < led_max; i++) {
-    point_t point = g_rgb_leds[i].point;
-    hsv.h = abs8(point.y - 32) + (point.x - time) + rgb_matrix_config.hue;
+    RGB_MATRIX_TEST_LED_FLAGS();
+    hsv.h = abs8(g_led_config.point[i].y - 32) + (g_led_config.point[i].x - time) + rgb_matrix_config.hue;
     RGB rgb = hsv_to_rgb(hsv);
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
diff --git a/quantum/rgb_matrix_animations/rainbow_pinwheels_anim.h b/quantum/rgb_matrix_animations/rainbow_pinwheels_anim.h
index d7cd42cbe8..e92f351765 100644
--- a/quantum/rgb_matrix_animations/rainbow_pinwheels_anim.h
+++ b/quantum/rgb_matrix_animations/rainbow_pinwheels_anim.h
@@ -2,7 +2,7 @@
 #ifndef DISABLE_RGB_MATRIX_RAINBOW_PINWHEELS
 
 extern rgb_counters_t g_rgb_counters;
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 bool rgb_matrix_rainbow_pinwheels(effect_params_t* params) {
@@ -13,8 +13,8 @@ bool rgb_matrix_rainbow_pinwheels(effect_params_t* params) {
   int16_t cos_value = 3 * (cos8(time) - 128);
   int16_t sin_value = 3 * (sin8(time) - 128);
   for (uint8_t i = led_min; i < led_max; i++) {
-    point_t point = g_rgb_leds[i].point;
-    hsv.h = ((point.y - 32) * cos_value + (56 - abs8(point.x - 112)) * sin_value) / 128 + rgb_matrix_config.hue;
+    RGB_MATRIX_TEST_LED_FLAGS();
+    hsv.h = ((g_led_config.point[i].y - 32) * cos_value + (56 - abs8(g_led_config.point[i].x - 112)) * sin_value) / 128 + rgb_matrix_config.hue;
     RGB rgb = hsv_to_rgb(hsv);
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
diff --git a/quantum/rgb_matrix_animations/raindrops_anim.h b/quantum/rgb_matrix_animations/raindrops_anim.h
index fc721375b0..4ce1d65e57 100644
--- a/quantum/rgb_matrix_animations/raindrops_anim.h
+++ b/quantum/rgb_matrix_animations/raindrops_anim.h
@@ -3,9 +3,11 @@
 #include "rgb_matrix_types.h"
 
 extern rgb_counters_t g_rgb_counters;
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
-static void raindrops_set_color(int i) {
+static void raindrops_set_color(int i, effect_params_t* params) {
+  if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) return;
   HSV hsv = { 0 , rgb_matrix_config.sat, rgb_matrix_config.val };
 
   // Take the shortest path between hues
@@ -25,14 +27,14 @@ bool rgb_matrix_raindrops(effect_params_t* params) {
   if (!params->init) {
     // Change one LED every tick, make sure speed is not 0
     if (scale16by8(g_rgb_counters.tick, qadd8(rgb_matrix_config.speed, 16)) % 10 == 0) {
-      raindrops_set_color(rand() % DRIVER_LED_TOTAL);
+      raindrops_set_color(rand() % DRIVER_LED_TOTAL, params);
     }
     return false;
   }
 
   RGB_MATRIX_USE_LIMITS(led_min, led_max);
   for (int i = led_min; i < led_max; i++) {
-    raindrops_set_color(i);
+    raindrops_set_color(i, params);
   }
   return led_max < DRIVER_LED_TOTAL;
 }
diff --git a/quantum/rgb_matrix_animations/solid_color_anim.h b/quantum/rgb_matrix_animations/solid_color_anim.h
index 24a197beb3..ba2cea15e3 100644
--- a/quantum/rgb_matrix_animations/solid_color_anim.h
+++ b/quantum/rgb_matrix_animations/solid_color_anim.h
@@ -1,5 +1,6 @@
 #pragma once
 
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 
 bool rgb_matrix_solid_color(effect_params_t* params) {
@@ -8,6 +9,7 @@ bool rgb_matrix_solid_color(effect_params_t* params) {
   HSV hsv = { rgb_matrix_config.hue, rgb_matrix_config.sat, rgb_matrix_config.val };
   RGB rgb = hsv_to_rgb(hsv);
   for (uint8_t i = led_min; i < led_max; i++) {
+    RGB_MATRIX_TEST_LED_FLAGS();
     rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
   }
   return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgb_matrix_animations/solid_reactive_anim.h b/quantum/rgb_matrix_animations/solid_reactive_anim.h
index 220e542331..c3dba8a5af 100644
--- a/quantum/rgb_matrix_animations/solid_reactive_anim.h
+++ b/quantum/rgb_matrix_animations/solid_reactive_anim.h
@@ -2,6 +2,7 @@
 #if defined(RGB_MATRIX_KEYREACTIVE_ENABLED)
 #ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE
 
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 extern last_hit_t g_last_hit_tracker;
 
@@ -13,8 +14,10 @@ bool rgb_matrix_solid_reactive(effect_params_t* params) {
   uint16_t max_tick = 65535 / rgb_matrix_config.speed;
   // Relies on hue being 8-bit and wrapping
   for (uint8_t i = led_min; i < led_max; i++) {
+    RGB_MATRIX_TEST_LED_FLAGS();
     uint16_t tick = max_tick;
-    for(uint8_t j = 0; j < g_last_hit_tracker.count; j++) {
+    // Reverse search to find most recent key hit
+    for (int8_t j = g_last_hit_tracker.count - 1; j >= 0; j--) {
       if (g_last_hit_tracker.index[j] == i && g_last_hit_tracker.tick[j] < tick) {
         tick = g_last_hit_tracker.tick[j];
         break;
diff --git a/quantum/rgb_matrix_animations/solid_reactive_cross.h b/quantum/rgb_matrix_animations/solid_reactive_cross.h
new file mode 100644
index 0000000000..8858f71e60
--- /dev/null
+++ b/quantum/rgb_matrix_animations/solid_reactive_cross.h
@@ -0,0 +1,50 @@
+#pragma once
+#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
+#if !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS) || !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS)
+
+extern led_config_t g_led_config;
+extern rgb_config_t rgb_matrix_config;
+extern last_hit_t g_last_hit_tracker;
+
+static bool rgb_matrix_solid_reactive_multicross_range(uint8_t start, effect_params_t* params) {
+  RGB_MATRIX_USE_LIMITS(led_min, led_max);
+
+  HSV hsv = { rgb_matrix_config.hue, rgb_matrix_config.sat, 0 };
+  uint8_t count = g_last_hit_tracker.count;
+  for (uint8_t i = led_min; i < led_max; i++) {
+    hsv.v = 0;
+    for (uint8_t j = start; j < count; j++) {
+      RGB_MATRIX_TEST_LED_FLAGS();
+      int16_t dx = g_led_config.point[i].x - g_last_hit_tracker.x[j];
+      int16_t dy = g_led_config.point[i].y - g_last_hit_tracker.y[j];
+      uint8_t dist = sqrt16(dx * dx + dy * dy);
+      int16_t dist2 = 16;
+      uint8_t dist3;
+      uint16_t effect = scale16by8(g_last_hit_tracker.tick[j], rgb_matrix_config.speed) + dist;
+      dx = dx < 0 ? dx * -1 : dx;
+      dy = dy < 0 ? dy * -1 : dy;
+      dx = dx * dist2 > 255 ? 255 : dx * dist2;
+      dy = dy * dist2 > 255 ? 255 : dy * dist2;
+      dist3 = dx > dy ? dy : dx;
+      effect += dist3;
+      if (effect > 255)
+        effect = 255;
+      hsv.v = qadd8(hsv.v, 255 - effect);
+    }
+    hsv.v = scale8(hsv.v, rgb_matrix_config.val);
+    RGB rgb = hsv_to_rgb(hsv);
+    rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
+  }
+  return led_max < DRIVER_LED_TOTAL;
+}
+
+bool rgb_matrix_solid_reactive_multicross(effect_params_t* params) {
+  return rgb_matrix_solid_reactive_multicross_range(0, params);
+}
+
+bool rgb_matrix_solid_reactive_cross(effect_params_t* params) {
+  return rgb_matrix_solid_reactive_multicross_range(qsub8(g_last_hit_tracker.count, 1), params);
+}
+
+#endif // !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS) || !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS)
+#endif // RGB_MATRIX_KEYREACTIVE_ENABLED
diff --git a/quantum/rgb_matrix_animations/solid_reactive_nexus.h b/quantum/rgb_matrix_animations/solid_reactive_nexus.h
new file mode 100644
index 0000000000..c0e3c24507
--- /dev/null
+++ b/quantum/rgb_matrix_animations/solid_reactive_nexus.h
@@ -0,0 +1,48 @@
+#pragma once
+#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
+#if !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS) || !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS)
+
+extern led_config_t g_led_config;
+extern rgb_config_t rgb_matrix_config;
+extern last_hit_t g_last_hit_tracker;
+
+static bool rgb_matrix_solid_reactive_multinexus_range(uint8_t start, effect_params_t* params) {
+  RGB_MATRIX_USE_LIMITS(led_min, led_max);
+
+  HSV hsv = { rgb_matrix_config.hue, rgb_matrix_config.sat, 0 };
+  uint8_t count = g_last_hit_tracker.count;
+  for (uint8_t i = led_min; i < led_max; i++) {
+    hsv.v = 0;
+    for (uint8_t j = start; j < count; j++) {
+      RGB_MATRIX_TEST_LED_FLAGS();
+      int16_t dx = g_led_config.point[i].x - g_last_hit_tracker.x[j];
+      int16_t dy = g_led_config.point[i].y - g_last_hit_tracker.y[j];
+      uint8_t dist = sqrt16(dx * dx + dy * dy);
+      int16_t dist2 = 8;
+      uint16_t effect = scale16by8(g_last_hit_tracker.tick[j], rgb_matrix_config.speed) - dist;
+      if (effect > 255)
+        effect = 255;
+      if (dist > 72)
+        effect = 255;
+      if ((dx > dist2 || dx < -dist2) && (dy > dist2 || dy < -dist2))
+        effect = 255;
+      hsv.v = qadd8(hsv.v, 255 - effect);
+      hsv.h = rgb_matrix_config.hue + dy / 4;
+    }
+    hsv.v = scale8(hsv.v, rgb_matrix_config.val);
+    RGB rgb = hsv_to_rgb(hsv);
+    rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
+  }
+  return led_max < DRIVER_LED_TOTAL;
+}
+
+bool rgb_matrix_solid_reactive_multinexus(effect_params_t* params) {
+  return rgb_matrix_solid_reactive_multinexus_range(0, params);
+}
+
+bool rgb_matrix_solid_reactive_nexus(effect_params_t* params) {
+  return rgb_matrix_solid_reactive_multinexus_range(qsub8(g_last_hit_tracker.count, 1), params);
+}
+
+#endif // !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS) || !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS)
+#endif // RGB_MATRIX_KEYREACTIVE_ENABLED
diff --git a/quantum/rgb_matrix_animations/solid_reactive_simple_anim.h b/quantum/rgb_matrix_animations/solid_reactive_simple_anim.h
index e84cd69392..abc7e36a89 100644
--- a/quantum/rgb_matrix_animations/solid_reactive_simple_anim.h
+++ b/quantum/rgb_matrix_animations/solid_reactive_simple_anim.h
@@ -2,6 +2,7 @@
 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
 #ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
 
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 extern last_hit_t g_last_hit_tracker;
 
@@ -12,8 +13,10 @@ bool rgb_matrix_solid_reactive_simple(effect_params_t* params) {
   // Max tick based on speed scale ensures results from scale16by8 with rgb_matrix_config.speed are no greater than 255
   uint16_t max_tick = 65535 / rgb_matrix_config.speed;
   for (uint8_t i = led_min; i < led_max; i++) {
+    RGB_MATRIX_TEST_LED_FLAGS();
     uint16_t tick = max_tick;
-    for(uint8_t j = 0; j < g_last_hit_tracker.count; j++) {
+    // Reverse search to find most recent key hit
+    for (int8_t j = g_last_hit_tracker.count - 1; j >= 0; j--) {
       if (g_last_hit_tracker.index[j] == i && g_last_hit_tracker.tick[j] < tick) {
         tick = g_last_hit_tracker.tick[j];
         break;
diff --git a/quantum/rgb_matrix_animations/solid_reactive_wide.h b/quantum/rgb_matrix_animations/solid_reactive_wide.h
new file mode 100644
index 0000000000..3d1d38e806
--- /dev/null
+++ b/quantum/rgb_matrix_animations/solid_reactive_wide.h
@@ -0,0 +1,42 @@
+#pragma once
+#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
+#if !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE) || !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE)
+
+extern led_config_t g_led_config;
+extern rgb_config_t rgb_matrix_config;
+extern last_hit_t g_last_hit_tracker;
+
+static bool rgb_matrix_solid_reactive_multiwide_range(uint8_t start, effect_params_t* params) {
+  RGB_MATRIX_USE_LIMITS(led_min, led_max);
+
+  HSV hsv = { rgb_matrix_config.hue, rgb_matrix_config.sat, 0 };
+  uint8_t count = g_last_hit_tracker.count;
+  for (uint8_t i = led_min; i < led_max; i++) {
+    hsv.v = 0;
+    for (uint8_t j = start; j < count; j++) {
+      RGB_MATRIX_TEST_LED_FLAGS();
+      int16_t dx = g_led_config.point[i].x - g_last_hit_tracker.x[j];
+      int16_t dy = g_led_config.point[i].y - g_last_hit_tracker.y[j];
+      uint8_t dist = sqrt16(dx * dx + dy * dy);
+      uint16_t effect = scale16by8(g_last_hit_tracker.tick[j], rgb_matrix_config.speed) + dist * 5;
+      if (effect > 255)
+        effect = 255;
+      hsv.v = qadd8(hsv.v, 255 - effect);
+    }
+    hsv.v = scale8(hsv.v, rgb_matrix_config.val);
+    RGB rgb = hsv_to_rgb(hsv);
+    rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
+  }
+  return led_max < DRIVER_LED_TOTAL;
+}
+
+bool rgb_matrix_solid_reactive_multiwide(effect_params_t* params) {
+  return rgb_matrix_solid_reactive_multiwide_range(0, params);
+}
+
+bool rgb_matrix_solid_reactive_wide(effect_params_t* params) {
+  return rgb_matrix_solid_reactive_multiwide_range(qsub8(g_last_hit_tracker.count, 1), params);
+}
+
+#endif // !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE) || !defined(DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE)
+#endif // RGB_MATRIX_KEYREACTIVE_ENABLED
diff --git a/quantum/rgb_matrix_animations/solid_splash_anim.h b/quantum/rgb_matrix_animations/solid_splash_anim.h
index 82ac055b88..4e5565d0d3 100644
--- a/quantum/rgb_matrix_animations/solid_splash_anim.h
+++ b/quantum/rgb_matrix_animations/solid_splash_anim.h
@@ -2,7 +2,7 @@
 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
 #if !defined(DISABLE_RGB_MATRIX_SOLID_SPLASH) || !defined(DISABLE_RGB_MATRIX_SOLID_MULTISPLASH)
 
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 extern last_hit_t g_last_hit_tracker;
 
@@ -12,11 +12,11 @@ static bool rgb_matrix_solid_multisplash_range(uint8_t start, effect_params_t* p
   HSV hsv = { rgb_matrix_config.hue, rgb_matrix_config.sat, 0 };
   uint8_t count = g_last_hit_tracker.count;
   for (uint8_t i = led_min; i < led_max; i++) {
+    RGB_MATRIX_TEST_LED_FLAGS();
     hsv.v = 0;
-    point_t point = g_rgb_leds[i].point;
     for (uint8_t j = start; j < count; j++) {
-      int16_t dx = point.x - g_last_hit_tracker.x[j];
-      int16_t dy = point.y - g_last_hit_tracker.y[j];
+      int16_t dx = g_led_config.point[i].x - g_last_hit_tracker.x[j];
+      int16_t dy = g_led_config.point[i].y - g_last_hit_tracker.y[j];
       uint8_t dist = sqrt16(dx * dx + dy * dy);
       uint16_t effect = scale16by8(g_last_hit_tracker.tick[j], rgb_matrix_config.speed) - dist;
       if (effect > 255)
diff --git a/quantum/rgb_matrix_animations/splash_anim.h b/quantum/rgb_matrix_animations/splash_anim.h
index 829d30eef5..fbe7761117 100644
--- a/quantum/rgb_matrix_animations/splash_anim.h
+++ b/quantum/rgb_matrix_animations/splash_anim.h
@@ -2,7 +2,7 @@
 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
 #if !defined(DISABLE_RGB_MATRIX_SPLASH) || !defined(DISABLE_RGB_MATRIX_MULTISPLASH)
 
-extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
+extern led_config_t g_led_config;
 extern rgb_config_t rgb_matrix_config;
 extern last_hit_t g_last_hit_tracker;
 
@@ -12,12 +12,12 @@ static bool rgb_matrix_multisplash_range(uint8_t start, effect_params_t* params)
   HSV hsv = { 0, rgb_matrix_config.sat, 0 };
   uint8_t count = g_last_hit_tracker.count;
   for (uint8_t i = led_min; i < led_max; i++) {
+    RGB_MATRIX_TEST_LED_FLAGS();
     hsv.h = rgb_matrix_config.hue;
     hsv.v = 0;
-    point_t point = g_rgb_leds[i].point;
     for (uint8_t j = start; j < count; j++) {
-      int16_t dx = point.x - g_last_hit_tracker.x[j];
-      int16_t dy = point.y - g_last_hit_tracker.y[j];
+      int16_t dx = g_led_config.point[i].x - g_last_hit_tracker.x[j];
+      int16_t dy = g_led_config.point[i].y - g_last_hit_tracker.y[j];
       uint8_t dist = sqrt16(dx * dx + dy * dy);
       uint16_t effect = scale16by8(g_last_hit_tracker.tick[j], rgb_matrix_config.speed) - dist;
       if (effect > 255)
diff --git a/quantum/rgb_matrix_animations/typing_heatmap_anim.h b/quantum/rgb_matrix_animations/typing_heatmap_anim.h
new file mode 100644
index 0000000000..aade53fccc
--- /dev/null
+++ b/quantum/rgb_matrix_animations/typing_heatmap_anim.h
@@ -0,0 +1,75 @@
+#pragma once
+#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_TYPING_HEATMAP)
+
+extern rgb_config_t rgb_matrix_config;
+extern uint8_t rgb_frame_buffer[MATRIX_ROWS][MATRIX_COLS];
+
+void process_rgb_matrix_typing_heatmap(keyrecord_t *record) {
+    uint8_t row = record->event.key.row;
+    uint8_t col = record->event.key.col;
+    uint8_t m_row = row - 1;
+    uint8_t p_row = row + 1;
+    uint8_t m_col = col - 1;
+    uint8_t p_col = col + 1;
+
+    if (m_col < col)
+      rgb_frame_buffer[row][m_col] = qadd8(rgb_frame_buffer[row][m_col], 16);
+    rgb_frame_buffer[row][col] = qadd8(rgb_frame_buffer[row][col], 32);
+    if (p_col < MATRIX_COLS)
+      rgb_frame_buffer[row][p_col] = qadd8(rgb_frame_buffer[row][p_col], 16);
+
+    if (p_row < MATRIX_ROWS) {
+      if (m_col < col)
+        rgb_frame_buffer[p_row][m_col] = qadd8(rgb_frame_buffer[p_row][m_col], 13);
+      rgb_frame_buffer[p_row][col] = qadd8(rgb_frame_buffer[p_row][col], 16);
+      if (p_col < MATRIX_COLS)
+        rgb_frame_buffer[p_row][p_col] = qadd8(rgb_frame_buffer[p_row][p_col], 13);
+    }
+
+    if (m_row < row) {
+      if (m_col < col)
+        rgb_frame_buffer[m_row][m_col] = qadd8(rgb_frame_buffer[m_row][m_col], 13);
+      rgb_frame_buffer[m_row][col] = qadd8(rgb_frame_buffer[m_row][col], 16);
+      if (p_col < MATRIX_COLS)
+        rgb_frame_buffer[m_row][p_col] = qadd8(rgb_frame_buffer[m_row][p_col], 13);
+    }
+}
+
+bool rgb_matrix_typing_heatmap(effect_params_t* params) {
+  // Modified version of RGB_MATRIX_USE_LIMITS to work off of matrix row / col size
+  uint8_t led_min = RGB_MATRIX_LED_PROCESS_LIMIT * params->iter;
+  uint8_t led_max = led_min + RGB_MATRIX_LED_PROCESS_LIMIT;
+  if (led_max > sizeof(rgb_frame_buffer))
+    led_max = sizeof(rgb_frame_buffer);
+
+  if (params->init) {
+    rgb_matrix_set_color_all(0, 0, 0);
+    memset(rgb_frame_buffer, 0, sizeof rgb_frame_buffer);
+  }
+
+  // Render heatmap & decrease
+  for (int i = led_min; i < led_max; i++) {
+    uint8_t row = i % MATRIX_ROWS;
+    uint8_t col = i / MATRIX_ROWS;
+    uint8_t val = rgb_frame_buffer[row][col];
+
+    // set the pixel colour
+    uint8_t led[LED_HITS_TO_REMEMBER];
+    uint8_t led_count = rgb_matrix_map_row_column_to_led(row, col, led);
+    for (uint8_t j = 0; j < led_count; ++j)
+    {
+      if (!HAS_ANY_FLAGS(g_led_config.flags[led[j]], params->flags))
+        continue;
+
+      HSV hsv = { 170 - qsub8(val, 85), rgb_matrix_config.sat, scale8((qadd8(170, val) - 170) * 3, rgb_matrix_config.val) };
+      RGB rgb = hsv_to_rgb(hsv);
+      rgb_matrix_set_color(led[j], rgb.r, rgb.g, rgb.b);
+    }
+
+    rgb_frame_buffer[row][col] = qsub8(val, 1);
+  }
+
+  return led_max < sizeof(rgb_frame_buffer);
+}
+
+#endif // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_TYPING_HEATMAP)
diff --git a/quantum/rgb_matrix_drivers.c b/quantum/rgb_matrix_drivers.c
index 3814dd61fc..1d64dc9093 100644
--- a/quantum/rgb_matrix_drivers.c
+++ b/quantum/rgb_matrix_drivers.c
@@ -99,12 +99,12 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
 
 #elif defined(WS2812)
 
-extern LED_TYPE led[RGBLED_NUM];
+extern LED_TYPE led[DRIVER_LED_TOTAL];
 
   static void flush( void )
   {
     // Assumes use of RGB_DI_PIN
-    ws2812_setleds(led, RGBLED_NUM);
+    ws2812_setleds(led, DRIVER_LED_TOTAL);
   }
 
   static void init( void )
diff --git a/quantum/rgb_matrix_types.h b/quantum/rgb_matrix_types.h
index 908e96da56..f890edd94f 100644
--- a/quantum/rgb_matrix_types.h
+++ b/quantum/rgb_matrix_types.h
@@ -59,26 +59,22 @@ typedef struct PACKED {
 	uint8_t y;
 } point_t;
 
-typedef union {
-  uint8_t raw;
-  struct {
-    uint8_t row:4; // 16 max
-    uint8_t col:4; // 16 max
-  };
-} matrix_co_t;
+#define HAS_FLAGS(bits, flags) ((bits & flags) == flags)
+#define HAS_ANY_FLAGS(bits, flags) ((bits & flags) != 0x00)
+
+#define LED_FLAG_ALL 0xFF
+#define LED_FLAG_NONE 0x00
+#define LED_FLAG_MODIFIER 0x01
+#define LED_FLAG_UNDERGLOW 0x02
+#define LED_FLAG_KEYLIGHT 0x04
+
+#define NO_LED 255
 
 typedef struct PACKED {
-	matrix_co_t matrix_co;
-	point_t point;
-	uint8_t modifier:1;
-} rgb_led;
-
-typedef enum {
-  RGB_ZONE_OFF = 0,
-  RGB_ZONE_ALL,
-  RGB_ZONE_KEYS,
-  RGB_ZONE_UNDER,
-} rgb_zone_t;
+  uint8_t matrix_co[MATRIX_ROWS][MATRIX_COLS];
+  point_t point[DRIVER_LED_TOTAL];
+  uint8_t flags[DRIVER_LED_TOTAL];
+} led_config_t;
 
 typedef union {
   uint32_t raw;
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index 5ec11bc077..77772e2925 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -28,8 +28,10 @@
 #include "progmem.h"
 #include "timer.h"
 #include "rgblight.h"
+#include "color.h"
 #include "debug.h"
 #include "led_tables.h"
+#include "lib/lib8tion/lib8tion.h"
 #ifdef VELOCIKEY_ENABLE
   #include "velocikey.h"
 #endif
@@ -38,11 +40,13 @@
   /* for split keyboard */
   #define RGBLIGHT_SPLIT_SET_CHANGE_MODE         rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_MODE
   #define RGBLIGHT_SPLIT_SET_CHANGE_HSVS         rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_HSVS
+  #define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS     rgblight_status.change_flags |= (RGBLIGHT_STATUS_CHANGE_MODE|RGBLIGHT_STATUS_CHANGE_HSVS)
   #define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_TIMER
   #define RGBLIGHT_SPLIT_ANIMATION_TICK          rgblight_status.change_flags |= RGBLIGHT_STATUS_ANIMATION_TICK
 #else
   #define RGBLIGHT_SPLIT_SET_CHANGE_MODE
   #define RGBLIGHT_SPLIT_SET_CHANGE_HSVS
+  #define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS
   #define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE
   #define RGBLIGHT_SPLIT_ANIMATION_TICK
 #endif
@@ -72,16 +76,13 @@ static inline int is_static_effect(uint8_t mode) {
     return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL;
 }
 
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
 #ifdef RGBLIGHT_LED_MAP
 const uint8_t led_map[] PROGMEM = RGBLIGHT_LED_MAP;
 #endif
 
 #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
 __attribute__ ((weak))
-const uint16_t RGBLED_GRADIENT_RANGES[] PROGMEM = {360, 240, 180, 120, 90};
+const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64};
 #endif
 
 rgblight_config_t rgblight_config;
@@ -107,59 +108,10 @@ void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds) {
 }
 
 
-void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
-  uint8_t r = 0, g = 0, b = 0, base, color;
-
-  if (val > RGBLIGHT_LIMIT_VAL) {
-      val=RGBLIGHT_LIMIT_VAL; // limit the val
-  }
-
-  if (sat == 0) { // Acromatic color (gray). Hue doesn't mind.
-    r = val;
-    g = val;
-    b = val;
-  } else {
-    base = ((255 - sat) * val) >> 8;
-    color = (val - base) * (hue % 60) / 60;
-
-    switch (hue / 60) {
-      case 0:
-        r = val;
-        g = base + color;
-        b = base;
-        break;
-      case 1:
-        r = val - color;
-        g = val;
-        b = base;
-        break;
-      case 2:
-        r = base;
-        g = val;
-        b = base + color;
-        break;
-      case 3:
-        r = base;
-        g = val - color;
-        b = val;
-        break;
-      case 4:
-        r = base + color;
-        g = base;
-        b = val;
-        break;
-      case 5:
-        r = val;
-        g = base;
-        b = val - color;
-        break;
-    }
-  }
-  r = pgm_read_byte(&CIE1931_CURVE[r]);
-  g = pgm_read_byte(&CIE1931_CURVE[g]);
-  b = pgm_read_byte(&CIE1931_CURVE[b]);
-
-  setrgb(r, g, b, led1);
+void sethsv(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
+  HSV hsv = { hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val };
+  RGB rgb = hsv_to_rgb(hsv);
+  setrgb(rgb.r, rgb.g, rgb.b, led1);
 }
 
 void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
@@ -178,24 +130,9 @@ void rgblight_check_config(void) {
     rgblight_config.mode = RGBLIGHT_MODES;
   }
 
-  if (rgblight_config.hue < 0) {
-    rgblight_config.hue = 0;
-  } else if (rgblight_config.hue > 360) {
-    rgblight_config.hue %= 360;
-  }
-
-  if (rgblight_config.sat < 0) {
-    rgblight_config.sat = 0;
-  } else if (rgblight_config.sat > 255) {
-    rgblight_config.sat = 255;
-  }
-
-  if (rgblight_config.val < 0) {
-    rgblight_config.val = 0;
-  } else if (rgblight_config.val > RGBLIGHT_LIMIT_VAL) {
+  if (rgblight_config.val > RGBLIGHT_LIMIT_VAL) {
     rgblight_config.val = RGBLIGHT_LIMIT_VAL;
   }
-
 }
 
 uint32_t eeconfig_read_rgblight(void) {
@@ -218,9 +155,10 @@ void eeconfig_update_rgblight_default(void) {
   rgblight_config.enable = 1;
   rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
   rgblight_config.hue = 0;
-  rgblight_config.sat = 255;
+  rgblight_config.sat = UINT8_MAX;
   rgblight_config.val = RGBLIGHT_LIMIT_VAL;
   rgblight_config.speed = 0;
+  RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
   eeconfig_update_rgblight(rgblight_config.raw);
 }
 
@@ -249,7 +187,7 @@ void rgblight_init(void) {
     eeconfig_update_rgblight_default();
   }
   rgblight_config.raw = eeconfig_read_rgblight();
-  RGBLIGHT_SPLIT_SET_CHANGE_HSVS;
+  RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
   if (!rgblight_config.mode) {
     dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n");
     eeconfig_update_rgblight_default();
@@ -276,6 +214,7 @@ uint32_t rgblight_read_dword(void) {
 }
 
 void rgblight_update_dword(uint32_t dword) {
+  RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
   rgblight_config.raw = dword;
   if (rgblight_config.enable)
     rgblight_mode_noeeprom(rgblight_config.mode);
@@ -438,23 +377,8 @@ void rgblight_disable_noeeprom(void) {
   rgblight_set();
 }
 
-
-// Deals with the messy details of incrementing an integer
-static uint8_t increment( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
-    int16_t new_value = value;
-    new_value += step;
-    return MIN( MAX( new_value, min ), max );
-}
-
-static uint8_t decrement( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
-    int16_t new_value = value;
-    new_value -= step;
-    return MIN( MAX( new_value, min ), max );
-}
-
 void rgblight_increase_hue_helper(bool write_to_eeprom) {
-  uint16_t hue;
-  hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360;
+  uint8_t hue = rgblight_config.hue + RGBLIGHT_HUE_STEP;
   rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
 }
 void rgblight_increase_hue_noeeprom(void) {
@@ -464,12 +388,7 @@ void rgblight_increase_hue(void) {
   rgblight_increase_hue_helper(true);
 }
 void rgblight_decrease_hue_helper(bool write_to_eeprom) {
-  uint16_t hue;
-  if (rgblight_config.hue-RGBLIGHT_HUE_STEP < 0) {
-    hue = (rgblight_config.hue + 360 - RGBLIGHT_HUE_STEP) % 360;
-  } else {
-    hue = (rgblight_config.hue - RGBLIGHT_HUE_STEP) % 360;
-  }
+  uint8_t hue = rgblight_config.hue - RGBLIGHT_HUE_STEP;
   rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
 }
 void rgblight_decrease_hue_noeeprom(void) {
@@ -479,12 +398,7 @@ void rgblight_decrease_hue(void) {
   rgblight_decrease_hue_helper(true);
 }
 void rgblight_increase_sat_helper(bool write_to_eeprom) {
-  uint8_t sat;
-  if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) {
-    sat = 255;
-  } else {
-    sat = rgblight_config.sat + RGBLIGHT_SAT_STEP;
-  }
+  uint8_t sat = qadd8(rgblight_config.sat, RGBLIGHT_SAT_STEP);
   rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
 }
 void rgblight_increase_sat_noeeprom(void) {
@@ -494,12 +408,7 @@ void rgblight_increase_sat(void) {
   rgblight_increase_sat_helper(true);
 }
 void rgblight_decrease_sat_helper(bool write_to_eeprom) {
-  uint8_t sat;
-  if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) {
-    sat = 0;
-  } else {
-    sat = rgblight_config.sat - RGBLIGHT_SAT_STEP;
-  }
+  uint8_t sat = qsub8(rgblight_config.sat, RGBLIGHT_SAT_STEP);
   rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
 }
 void rgblight_decrease_sat_noeeprom(void) {
@@ -509,12 +418,7 @@ void rgblight_decrease_sat(void) {
   rgblight_decrease_sat_helper(true);
 }
 void rgblight_increase_val_helper(bool write_to_eeprom) {
-  uint8_t val;
-  if (rgblight_config.val + RGBLIGHT_VAL_STEP > RGBLIGHT_LIMIT_VAL) {
-    val = RGBLIGHT_LIMIT_VAL;
-  } else {
-    val = rgblight_config.val + RGBLIGHT_VAL_STEP;
-  }
+  uint8_t val = qadd8(rgblight_config.val, RGBLIGHT_VAL_STEP);
   rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
 }
 void rgblight_increase_val_noeeprom(void) {
@@ -524,12 +428,7 @@ void rgblight_increase_val(void) {
   rgblight_increase_val_helper(true);
 }
 void rgblight_decrease_val_helper(bool write_to_eeprom) {
-  uint8_t val;
-  if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) {
-    val = 0;
-  } else {
-    val = rgblight_config.val - RGBLIGHT_VAL_STEP;
-  }
+  uint8_t val = qsub8(rgblight_config.val, RGBLIGHT_VAL_STEP);
   rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
 }
 void rgblight_decrease_val_noeeprom(void) {
@@ -539,18 +438,20 @@ void rgblight_decrease_val(void) {
   rgblight_decrease_val_helper(true);
 }
 void rgblight_increase_speed(void) {
-    rgblight_config.speed = increment( rgblight_config.speed, 1, 0, 3 );
+    if (rgblight_config.speed < 3)
+        rgblight_config.speed++;
     //RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED?
     eeconfig_update_rgblight(rgblight_config.raw);//EECONFIG needs to be increased to support this
 }
 
 void rgblight_decrease_speed(void) {
-    rgblight_config.speed = decrement( rgblight_config.speed, 1, 0, 3 );
+    if (rgblight_config.speed > 0)
+        rgblight_config.speed--;
     //RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED??
     eeconfig_update_rgblight(rgblight_config.raw);//EECONFIG needs to be increased to support this
 }
 
-void rgblight_sethsv_noeeprom_old(uint16_t hue, uint8_t sat, uint8_t val) {
+void rgblight_sethsv_noeeprom_old(uint8_t hue, uint8_t sat, uint8_t val) {
   if (rgblight_config.enable) {
     LED_TYPE tmp_led;
     sethsv(hue, sat, val, &tmp_led);
@@ -559,7 +460,7 @@ void rgblight_sethsv_noeeprom_old(uint16_t hue, uint8_t sat, uint8_t val) {
   }
 }
 
-void rgblight_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) {
+void rgblight_sethsv_eeprom_helper(uint8_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) {
   if (rgblight_config.enable) {
     rgblight_status.base_mode = mode_base_table[rgblight_config.mode];
     if (rgblight_config.mode == RGBLIGHT_MODE_STATIC_LIGHT) {
@@ -592,13 +493,22 @@ void rgblight_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, bool
 #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
       else if (rgblight_status.base_mode == RGBLIGHT_MODE_STATIC_GRADIENT) {
         // static gradient
-        uint16_t _hue;
         uint8_t delta = rgblight_config.mode - rgblight_status.base_mode;
-        int8_t direction = (delta % 2) ? -1 : 1;
-        uint16_t range = pgm_read_word(&RGBLED_GRADIENT_RANGES[delta / 2]);
+        bool direction = (delta % 2) == 0;
+#ifdef __AVR__
+        // probably due to how pgm_read_word is defined for ARM, but the ARM compiler really hates this line
+        uint8_t range = pgm_read_word(&RGBLED_GRADIENT_RANGES[delta / 2]);
+#else
+        uint8_t range = RGBLED_GRADIENT_RANGES[delta / 2];
+#endif
         for (uint8_t i = 0; i < RGBLED_NUM; i++) {
-          _hue = (range / RGBLED_NUM * i * direction + hue + 360) % 360;
-          dprintf("rgblight rainbow set hsv: %u,%u,%d,%u\n", i, _hue, direction, range);
+          uint8_t _hue = ((uint16_t)i * (uint16_t)range) / RGBLED_NUM;
+          if (direction) {
+            _hue = hue + _hue;
+          } else {
+            _hue = hue - _hue;
+          }
+          dprintf("rgblight rainbow set hsv: %d,%d,%d,%u\n", i, _hue, direction, range);
           sethsv(_hue, sat, val, (LED_TYPE *)&led[i]);
         }
         rgblight_set();
@@ -624,15 +534,15 @@ void rgblight_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, bool
   }
 }
 
-void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
+void rgblight_sethsv(uint8_t hue, uint8_t sat, uint8_t val) {
   rgblight_sethsv_eeprom_helper(hue, sat, val, true);
 }
 
-void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
+void rgblight_sethsv_noeeprom(uint8_t hue, uint8_t sat, uint8_t val) {
   rgblight_sethsv_eeprom_helper(hue, sat, val, false);
 }
 
-uint16_t rgblight_get_hue(void) {
+uint8_t rgblight_get_hue(void) {
   return rgblight_config.hue;
 }
 
@@ -664,7 +574,7 @@ void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) {
   rgblight_set();
 }
 
-void rgblight_sethsv_at(uint16_t hue, uint8_t sat, uint8_t val, uint8_t index) {
+void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index) {
   if (!rgblight_config.enable) { return; }
 
   LED_TYPE tmp_led;
@@ -697,7 +607,7 @@ void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8
   wait_ms(1);
 }
 
-void rgblight_sethsv_range(uint16_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end) {
+void rgblight_sethsv_range(uint8_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end) {
   if (!rgblight_config.enable) { return; }
 
   LED_TYPE tmp_led;
@@ -713,11 +623,11 @@ void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b) {
   rgblight_setrgb_range(r, g, b, (uint8_t) RGBLED_NUM/2, (uint8_t) RGBLED_NUM);
 }
 
-void rgblight_sethsv_master(uint16_t hue, uint8_t sat, uint8_t val) {
+void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val) {
   rgblight_sethsv_range(hue, sat, val, 0, (uint8_t) RGBLED_NUM/2);
 }
 
-void rgblight_sethsv_slave(uint16_t hue, uint8_t sat, uint8_t val) {
+void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) {
   rgblight_sethsv_range(hue, sat, val, (uint8_t) RGBLED_NUM/2, (uint8_t) RGBLED_NUM);
 }
 
@@ -969,6 +879,14 @@ void rgblight_task(void) {
 
 // Effects
 #ifdef RGBLIGHT_EFFECT_BREATHING
+
+#ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
+  #ifndef RGBLIGHT_BREATHE_TABLE_SIZE
+    #define RGBLIGHT_BREATHE_TABLE_SIZE 256 // 256 or 128 or 64
+  #endif
+  #include <rgblight_breathe_table.h>
+#endif
+
 __attribute__ ((weak))
 const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
 
@@ -976,9 +894,13 @@ void rgblight_effect_breathing(animation_status_t *anim) {
   float val;
 
   // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
+#ifdef RGBLIGHT_EFFECT_BREATHE_TABLE
+  val = pgm_read_byte(&rgblight_effect_breathe_table[anim->pos / table_scale]);
+#else
   val = (exp(sin((anim->pos/255.0)*M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER/M_E)*(RGBLIGHT_EFFECT_BREATHE_MAX/(M_E-1/M_E));
+#endif
   rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
-  anim->pos = (anim->pos + 1) % 256;
+  anim->pos = (anim->pos + 1);
 }
 #endif
 
@@ -988,36 +910,32 @@ const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30};
 
 void rgblight_effect_rainbow_mood(animation_status_t *anim) {
   rgblight_sethsv_noeeprom_old(anim->current_hue, rgblight_config.sat, rgblight_config.val);
-  anim->current_hue = (anim->current_hue + 1) % 360;
+  anim->current_hue++;
 }
 #endif
 
 #ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
 #ifndef RGBLIGHT_RAINBOW_SWIRL_RANGE
-  #define RGBLIGHT_RAINBOW_SWIRL_RANGE 360
+  #define RGBLIGHT_RAINBOW_SWIRL_RANGE 255
 #endif
 
 __attribute__ ((weak))
 const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20};
 
 void rgblight_effect_rainbow_swirl(animation_status_t *anim) {
-  uint16_t hue;
+  uint8_t hue;
   uint8_t i;
 
   for (i = 0; i < RGBLED_NUM; i++) {
-    hue = (RGBLIGHT_RAINBOW_SWIRL_RANGE / RGBLED_NUM * i + anim->current_hue) % 360;
+    hue = (RGBLIGHT_RAINBOW_SWIRL_RANGE / RGBLED_NUM * i + anim->current_hue);
     sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
   }
   rgblight_set();
 
   if (anim->delta % 2) {
-    anim->current_hue = (anim->current_hue + 1) % 360;
+    anim->current_hue++;
   } else {
-    if (anim->current_hue - 1 < 0) {
-      anim->current_hue = 359;
-    } else {
-      anim->current_hue = anim->current_hue - 1;
-    }
+    anim->current_hue--;
   }
 }
 #endif
@@ -1142,12 +1060,12 @@ void rgblight_effect_knight(animation_status_t *anim) {
 
 #ifdef RGBLIGHT_EFFECT_CHRISTMAS
 void rgblight_effect_christmas(animation_status_t *anim) {
-  uint16_t hue;
+  uint8_t hue;
   uint8_t i;
 
   anim->current_offset = (anim->current_offset + 1) % 2;
   for (i = 0; i < RGBLED_NUM; i++) {
-    hue = 0 + ((i/RGBLIGHT_EFFECT_CHRISTMAS_STEP + anim->current_offset) % 2) * 120;
+    hue = 0 + ((i/RGBLIGHT_EFFECT_CHRISTMAS_STEP + anim->current_offset) % 2) * 85;
     sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
   }
   rgblight_set();
diff --git a/quantum/rgblight.h b/quantum/rgblight.h
index 748d009dcf..35d7942ca6 100644
--- a/quantum/rgblight.h
+++ b/quantum/rgblight.h
@@ -80,9 +80,7 @@ enum RGBLIGHT_EFFECT_MODE {
 
 #define RGBLIGHT_MODES (RGBLIGHT_MODE_last-1)
 
-#ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
-#define RGBLIGHT_EFFECT_BREATHE_CENTER 1.85  // 1-2.7
-#endif
+// sample: #define RGBLIGHT_EFFECT_BREATHE_CENTER   1.85
 
 #ifndef RGBLIGHT_EFFECT_BREATHE_MAX
 #define RGBLIGHT_EFFECT_BREATHE_MAX 255   // 0-255
@@ -113,7 +111,7 @@ enum RGBLIGHT_EFFECT_MODE {
 #endif
 
 #ifndef RGBLIGHT_HUE_STEP
-#define RGBLIGHT_HUE_STEP 10
+#define RGBLIGHT_HUE_STEP 8
 #endif
 #ifndef RGBLIGHT_SAT_STEP
 #define RGBLIGHT_SAT_STEP 17
@@ -151,12 +149,13 @@ extern const uint8_t RGBLED_KNIGHT_INTERVALS[3] PROGMEM;
 extern const uint16_t RGBLED_RGBTEST_INTERVALS[1] PROGMEM;
 extern bool is_rgblight_initialized;
 
+// Should stay in sycn with rgb matrix config as we reuse eeprom storage for both (for now)
 typedef union {
   uint32_t raw;
   struct {
     bool     enable  :1;
-    uint8_t  mode    :6;
-    uint16_t hue     :9;
+    uint8_t  mode    :7;
+    uint8_t  hue     :8;
     uint8_t  sat     :8;
     uint8_t  val     :8;
     uint8_t  speed   :8;//EECONFIG needs to be increased to support this
@@ -211,19 +210,19 @@ void rgblight_increase_val(void);
 void rgblight_decrease_val(void);
 void rgblight_increase_speed(void);
 void rgblight_decrease_speed(void);
-void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val);
-uint16_t rgblight_get_hue(void);
+void rgblight_sethsv(uint8_t hue, uint8_t sat, uint8_t val);
+uint8_t rgblight_get_hue(void);
 uint8_t rgblight_get_sat(void);
 uint8_t rgblight_get_val(void);
 void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b);
 void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index);
-void rgblight_sethsv_at(uint16_t hue, uint8_t sat, uint8_t val, uint8_t index);
+void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index);
 void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8_t end);
-void rgblight_sethsv_range(uint16_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end);
+void rgblight_sethsv_range(uint8_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end);
 void rgblight_setrgb_master(uint8_t r, uint8_t g, uint8_t b);
 void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b);
-void rgblight_sethsv_master(uint16_t hue, uint8_t sat, uint8_t val);
-void rgblight_sethsv_slave(uint16_t hue, uint8_t sat, uint8_t val);
+void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val);
+void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val);
 void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds);
 
 uint32_t eeconfig_read_rgblight(void);
@@ -234,10 +233,10 @@ void eeconfig_debug_rgblight(void);
 void rgb_matrix_increase(void);
 void rgb_matrix_decrease(void);
 
-void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1);
+void sethsv(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1);
 void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1);
 
-void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val);
+void rgblight_sethsv_noeeprom(uint8_t hue, uint8_t sat, uint8_t val);
 void rgblight_mode_noeeprom(uint8_t mode);
 void rgblight_toggle_noeeprom(void);
 void rgblight_enable_noeeprom(void);
@@ -251,7 +250,7 @@ void rgblight_decrease_sat_noeeprom(void);
 void rgblight_increase_val_noeeprom(void);
 void rgblight_decrease_val_noeeprom(void);
 
-void rgblight_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom);
+void rgblight_sethsv_eeprom_helper(uint8_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom);
 void rgblight_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom);
 
 
@@ -274,7 +273,7 @@ typedef struct _animation_status_t {
     union {
         uint16_t pos16;
         uint8_t  pos;
-        int16_t  current_hue;
+        int8_t   current_hue;
         uint16_t current_offset;
     };
 } animation_status_t;
diff --git a/quantum/rgblight_breathe_table.h b/quantum/rgblight_breathe_table.h
new file mode 100644
index 0000000000..7ab8cc9479
--- /dev/null
+++ b/quantum/rgblight_breathe_table.h
@@ -0,0 +1,116 @@
+#ifndef RGBLIGHT_EFFECT_BREATHE_TABLE
+#define RGBLIGHT_EFFECT_BREATHE_TABLE
+
+const uint8_t rgblight_effect_breathe_table[] PROGMEM = {
+  /* #define RGBLIGHT_EFFECT_BREATHE_CENTER   1.85 */
+  /* #define RGBLIGHT_EFFECT_BREATHE_MAX      255 */
+
+ #if RGBLIGHT_BREATHE_TABLE_SIZE == 256
+  0x22,  0x23,  0x25,  0x26,  0x28,  0x29,  0x2a,  0x2c,
+  0x2d,  0x2f,  0x30,  0x32,  0x33,  0x35,  0x36,  0x38,
+  0x3a,  0x3b,  0x3d,  0x3e,  0x40,  0x42,  0x43,  0x45,
+  0x47,  0x49,  0x4a,  0x4c,  0x4e,  0x50,  0x51,  0x53,
+  0x55,  0x57,  0x59,  0x5a,  0x5c,  0x5e,  0x60,  0x62,
+  0x64,  0x66,  0x68,  0x69,  0x6b,  0x6d,  0x6f,  0x71,
+  0x73,  0x75,  0x77,  0x79,  0x7b,  0x7d,  0x7f,  0x81,
+  0x83,  0x85,  0x87,  0x89,  0x8a,  0x8c,  0x8e,  0x90,
+  0x92,  0x94,  0x96,  0x98,  0x9a,  0x9c,  0x9e,  0x9f,
+  0xa1,  0xa3,  0xa5,  0xa7,  0xa8,  0xaa,  0xac,  0xae,
+  0xaf,  0xb1,  0xb3,  0xb4,  0xb6,  0xb8,  0xb9,  0xbb,
+  0xbc,  0xbe,  0xbf,  0xc1,  0xc2,  0xc3,  0xc5,  0xc6,
+  0xc7,  0xc9,  0xca,  0xcb,  0xcc,  0xcd,  0xce,  0xd0,
+  0xd1,  0xd2,  0xd2,  0xd3,  0xd4,  0xd5,  0xd6,  0xd7,
+  0xd7,  0xd8,  0xd9,  0xd9,  0xda,  0xda,  0xdb,  0xdb,
+  0xdb,  0xdc,  0xdc,  0xdc,  0xdc,  0xdc,  0xdd,  0xdd,
+  0xdd,  0xdd,  0xdc,  0xdc,  0xdc,  0xdc,  0xdc,  0xdb,
+  0xdb,  0xdb,  0xda,  0xda,  0xd9,  0xd9,  0xd8,  0xd7,
+  0xd7,  0xd6,  0xd5,  0xd4,  0xd3,  0xd2,  0xd2,  0xd1,
+  0xd0,  0xce,  0xcd,  0xcc,  0xcb,  0xca,  0xc9,  0xc7,
+  0xc6,  0xc5,  0xc3,  0xc2,  0xc1,  0xbf,  0xbe,  0xbc,
+  0xbb,  0xb9,  0xb8,  0xb6,  0xb4,  0xb3,  0xb1,  0xaf,
+  0xae,  0xac,  0xaa,  0xa8,  0xa7,  0xa5,  0xa3,  0xa1,
+  0x9f,  0x9e,  0x9c,  0x9a,  0x98,  0x96,  0x94,  0x92,
+  0x90,  0x8e,  0x8c,  0x8a,  0x89,  0x87,  0x85,  0x83,
+  0x81,  0x7f,  0x7d,  0x7b,  0x79,  0x77,  0x75,  0x73,
+  0x71,  0x6f,  0x6d,  0x6b,  0x69,  0x68,  0x66,  0x64,
+  0x62,  0x60,  0x5e,  0x5c,  0x5a,  0x59,  0x57,  0x55,
+  0x53,  0x51,  0x50,  0x4e,  0x4c,  0x4a,  0x49,  0x47,
+  0x45,  0x43,  0x42,  0x40,  0x3e,  0x3d,  0x3b,  0x3a,
+  0x38,  0x36,  0x35,  0x33,  0x32,  0x30,  0x2f,  0x2d,
+  0x2c,  0x2a,  0x29,  0x28,  0x26,  0x25,  0x23,  0x22
+ #endif /* 256 bytes table */
+
+ #if RGBLIGHT_BREATHE_TABLE_SIZE == 128
+  0x22,  0x25,  0x28,  0x2a,
+  0x2d,  0x30,  0x33,  0x36,
+  0x3a,  0x3d,  0x40,  0x43,
+  0x47,  0x4a,  0x4e,  0x51,
+  0x55,  0x59,  0x5c,  0x60,
+  0x64,  0x68,  0x6b,  0x6f,
+  0x73,  0x77,  0x7b,  0x7f,
+  0x83,  0x87,  0x8a,  0x8e,
+  0x92,  0x96,  0x9a,  0x9e,
+  0xa1,  0xa5,  0xa8,  0xac,
+  0xaf,  0xb3,  0xb6,  0xb9,
+  0xbc,  0xbf,  0xc2,  0xc5,
+  0xc7,  0xca,  0xcc,  0xce,
+  0xd1,  0xd2,  0xd4,  0xd6,
+  0xd7,  0xd9,  0xda,  0xdb,
+  0xdb,  0xdc,  0xdc,  0xdd,
+  0xdd,  0xdc,  0xdc,  0xdc,
+  0xdb,  0xda,  0xd9,  0xd8,
+  0xd7,  0xd5,  0xd3,  0xd2,
+  0xd0,  0xcd,  0xcb,  0xc9,
+  0xc6,  0xc3,  0xc1,  0xbe,
+  0xbb,  0xb8,  0xb4,  0xb1,
+  0xae,  0xaa,  0xa7,  0xa3,
+  0x9f,  0x9c,  0x98,  0x94,
+  0x90,  0x8c,  0x89,  0x85,
+  0x81,  0x7d,  0x79,  0x75,
+  0x71,  0x6d,  0x69,  0x66,
+  0x62,  0x5e,  0x5a,  0x57,
+  0x53,  0x50,  0x4c,  0x49,
+  0x45,  0x42,  0x3e,  0x3b,
+  0x38,  0x35,  0x32,  0x2f,
+  0x2c,  0x29,  0x26,  0x23
+ #endif /* 128 bytes table */
+
+ #if RGBLIGHT_BREATHE_TABLE_SIZE == 64
+  0x22,  0x28,
+  0x2d,  0x33,
+  0x3a,  0x40,
+  0x47,  0x4e,
+  0x55,  0x5c,
+  0x64,  0x6b,
+  0x73,  0x7b,
+  0x83,  0x8a,
+  0x92,  0x9a,
+  0xa1,  0xa8,
+  0xaf,  0xb6,
+  0xbc,  0xc2,
+  0xc7,  0xcc,
+  0xd1,  0xd4,
+  0xd7,  0xda,
+  0xdb,  0xdc,
+  0xdd,  0xdc,
+  0xdb,  0xd9,
+  0xd7,  0xd3,
+  0xd0,  0xcb,
+  0xc6,  0xc1,
+  0xbb,  0xb4,
+  0xae,  0xa7,
+  0x9f,  0x98,
+  0x90,  0x89,
+  0x81,  0x79,
+  0x71,  0x69,
+  0x62,  0x5a,
+  0x53,  0x4c,
+  0x45,  0x3e,
+  0x38,  0x32,
+  0x2c,  0x26
+ #endif /* 64 bytes table */
+};
+
+static const int table_scale = 256/sizeof(rgblight_effect_breathe_table);
+
+#endif /* RGBLIGHT_EFFECT_BREATHE_TABLE */
diff --git a/quantum/rgblight_list.h b/quantum/rgblight_list.h
index 407fd8e9d3..702e33e765 100644
--- a/quantum/rgblight_list.h
+++ b/quantum/rgblight_list.h
@@ -13,111 +13,163 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-#ifndef RGBLIGHT_LIST_H
-#define RGBLIGHT_LIST_H
+#pragma once
+
+/*              RGB COLORS             */
+#define RGB_WHITE        0xFF, 0xFF, 0xFF
+#define RGB_RED          0xFF, 0x00, 0x00
+#define RGB_CORAL        0xFF, 0x7C, 0x4D
+#define RGB_ORANGE       0xFF, 0x80, 0x00
+#define RGB_GOLDENROD    0xD9, 0xA5, 0x21
+#define RGB_GOLD         0xFF, 0xD9, 0x00
+#define RGB_YELLOW       0xFF, 0xFF, 0x00
+#define RGB_CHARTREUSE   0x80, 0xFF, 0x00
+#define RGB_GREEN        0x00, 0xFF, 0x00
+#define RGB_SPRINGGREEN  0x00, 0xFF, 0x80
+#define RGB_TURQUOISE    0x47, 0x6E, 0x6A
+#define RGB_TEAL         0x00, 0x80, 0x80
+#define RGB_CYAN         0x00, 0xFF, 0xFF
+#define RGB_AZURE        0x99, 0xf5, 0xFF
+#define RGB_BLUE         0x00, 0x00, 0xFF
+#define RGB_PURPLE       0x7A, 0x00, 0xFF
+#define RGB_MAGENTA      0xFF, 0x00, 0xFF
+#define RGB_PINK         0xFF, 0x80, 0xBF
+
+/*            HSV COLORS            */
+#define HSV_WHITE          0,   0, 255
+#define HSV_RED            0, 255, 255
+#define HSV_CORAL         11, 176, 255
+#define HSV_ORANGE        28, 255, 255
+#define HSV_GOLDENROD     30, 218, 218
+#define HSV_GOLD          36, 255, 255
+#define HSV_YELLOW        43, 255, 255
+#define HSV_CHARTREUSE    64, 255, 255
+#define HSV_GREEN         85, 255, 255
+#define HSV_SPRINGGREEN  106, 255, 255
+#define HSV_TURQUOISE    123,  90, 112
+#define HSV_TEAL         128, 255, 128
+#define HSV_CYAN         128, 255, 255
+#define HSV_AZURE        132, 102, 255
+#define HSV_BLUE         170, 255, 255
+#define HSV_PURPLE       191, 255, 255
+#define HSV_MAGENTA      213, 255, 255
+#define HSV_PINK         234, 128, 255
+
+
+/*
+########################################################################################
+##                                                                                    ##
+##                                                                                    ##
+##                                                                                    ##
+##  The functions below have been deprecated and may be removed in a future release.  ##
+##                                                                                    ##
+##                Please use the values above with the RGB functions.                 ##
+##                                                                                    ##
+##                                                                                    ##
+##                                                                                    ##
+########################################################################################
+*/
 
 /*                            SET RGB List                            */
-#define rgblight_setrgb_white()       rgblight_setrgb (0xFF, 0xFF, 0xFF)
-#define rgblight_setrgb_red()         rgblight_setrgb (0xFF, 0x00, 0x00)
-#define rgblight_setrgb_coral()       rgblight_setrgb (0xFF, 0x7C, 0x4D)
-#define rgblight_setrgb_orange()      rgblight_setrgb (0xFF, 0x80, 0x00)
-#define rgblight_setrgb_goldenrod()   rgblight_setrgb (0xD9, 0xA5, 0x21)
-#define rgblight_setrgb_gold()        rgblight_setrgb (0xFF, 0xD9, 0x00)
-#define rgblight_setrgb_yellow()      rgblight_setrgb (0xFF, 0xFF, 0x00)
-#define rgblight_setrgb_chartreuse()  rgblight_setrgb (0x80, 0xFF, 0x00)
-#define rgblight_setrgb_green()       rgblight_setrgb (0x00, 0xFF, 0x00)
-#define rgblight_setrgb_springgreen() rgblight_setrgb (0x00, 0xFF, 0x80)
-#define rgblight_setrgb_turquoise()   rgblight_setrgb (0x47, 0x6E, 0x6A)
-#define rgblight_setrgb_teal()        rgblight_setrgb (0x00, 0x80, 0x80)
-#define rgblight_setrgb_cyan()        rgblight_setrgb (0x00, 0xFF, 0xFF)
-#define rgblight_setrgb_azure()       rgblight_setrgb (0x99, 0xf5, 0xFF)
-#define rgblight_setrgb_blue()        rgblight_setrgb (0x00, 0x00, 0xFF)
-#define rgblight_setrgb_purple()      rgblight_setrgb (0x7A, 0x00, 0xFF)
-#define rgblight_setrgb_magenta()     rgblight_setrgb (0xFF, 0x00, 0xFF)
-#define rgblight_setrgb_pink()        rgblight_setrgb (0xFF, 0x80, 0xBF)
+#define rgblight_setrgb_white()       rgblight_setrgb (RGB_WHITE)
+#define rgblight_setrgb_red()         rgblight_setrgb (RGB_RED)
+#define rgblight_setrgb_coral()       rgblight_setrgb (RGB_CORAL)
+#define rgblight_setrgb_orange()      rgblight_setrgb (RGB_ORANGE)
+#define rgblight_setrgb_goldenrod()   rgblight_setrgb (RGB_GOLDENROD)
+#define rgblight_setrgb_gold()        rgblight_setrgb (RGB_GOLD)
+#define rgblight_setrgb_yellow()      rgblight_setrgb (RGB_YELLOW)
+#define rgblight_setrgb_chartreuse()  rgblight_setrgb (RGB_CHARTREUSE)
+#define rgblight_setrgb_green()       rgblight_setrgb (RGB_GREEN)
+#define rgblight_setrgb_springgreen() rgblight_setrgb (RGB_SPRINGGREEN)
+#define rgblight_setrgb_turquoise()   rgblight_setrgb (RGB_TURQUOISE)
+#define rgblight_setrgb_teal()        rgblight_setrgb (RGB_TEAL)
+#define rgblight_setrgb_cyan()        rgblight_setrgb (RGB_CYAN)
+#define rgblight_setrgb_azure()       rgblight_setrgb (RGB_AZURE)
+#define rgblight_setrgb_blue()        rgblight_setrgb (RGB_BLUE)
+#define rgblight_setrgb_purple()      rgblight_setrgb (RGB_PURPLE)
+#define rgblight_setrgb_magenta()     rgblight_setrgb (RGB_MAGENTA)
+#define rgblight_setrgb_pink()        rgblight_setrgb (RGB_PINK)
 
 /*                            SET RGB List                            */
-#define rgblight_setrgb_white_at(at)       rgblight_setrgb_at (0xFF, 0xFF, 0xFF, at)
-#define rgblight_setrgb_red_at(at)         rgblight_setrgb_at (0xFF, 0x00, 0x00, at)
-#define rgblight_setrgb_coral_at(at)       rgblight_setrgb_at (0xFF, 0x7C, 0x4D, at)
-#define rgblight_setrgb_orange_at(at)      rgblight_setrgb_at (0xFF, 0x80, 0x00, at)
-#define rgblight_setrgb_goldenrod_at(at)   rgblight_setrgb_at (0xD9, 0xA5, 0x21, at)
-#define rgblight_setrgb_gold_at(at)        rgblight_setrgb_at (0xFF, 0xD9, 0x00, at)
-#define rgblight_setrgb_yellow_at(at)      rgblight_setrgb_at (0xFF, 0xFF, 0x00, at)
-#define rgblight_setrgb_chartreuse_at(at)  rgblight_setrgb_at (0x80, 0xFF, 0x00, at)
-#define rgblight_setrgb_green_at(at)       rgblight_setrgb_at (0x00, 0xFF, 0x00, at)
-#define rgblight_setrgb_springgreen_at(at) rgblight_setrgb_at (0x00, 0xFF, 0x80, at)
-#define rgblight_setrgb_turquoise_at(at)   rgblight_setrgb_at (0x47, 0x6E, 0x6A, at)
-#define rgblight_setrgb_teal_at(at)        rgblight_setrgb_at (0x00, 0x80, 0x80, at)
-#define rgblight_setrgb_cyan_at(at)        rgblight_setrgb_at (0x00, 0xFF, 0xFF, at)
-#define rgblight_setrgb_azure_at(at)       rgblight_setrgb_at (0x99, 0xf5, 0xFF, at)
-#define rgblight_setrgb_blue_at(at)        rgblight_setrgb_at (0x00, 0x00, 0xFF, at)
-#define rgblight_setrgb_purple_at(at)      rgblight_setrgb_at (0x7A, 0x00, 0xFF, at)
-#define rgblight_setrgb_magenta_at(at)     rgblight_setrgb_at (0xFF, 0x00, 0xFF, at)
-#define rgblight_setrgb_pink_at(at)        rgblight_setrgb_at (0xFF, 0x80, 0xBF, at)
+#define rgblight_setrgb_white_at(at)       rgblight_setrgb_at (RGB_WHITE, at)
+#define rgblight_setrgb_red_at(at)         rgblight_setrgb_at (RGB_RED, at)
+#define rgblight_setrgb_coral_at(at)       rgblight_setrgb_at (RGB_CORAL, at)
+#define rgblight_setrgb_orange_at(at)      rgblight_setrgb_at (RGB_ORANGE at)
+#define rgblight_setrgb_goldenrod_at(at)   rgblight_setrgb_at (RGB_GOLDENROD, at)
+#define rgblight_setrgb_gold_at(at)        rgblight_setrgb_at (RGB_GOLD, at)
+#define rgblight_setrgb_yellow_at(at)      rgblight_setrgb_at (RGB_YELLOW, at)
+#define rgblight_setrgb_chartreuse_at(at)  rgblight_setrgb_at (RGB_CHARTREUSE, at)
+#define rgblight_setrgb_green_at(at)       rgblight_setrgb_at (RGB_GREEN, at)
+#define rgblight_setrgb_springgreen_at(at) rgblight_setrgb_at (RGB_SPRINGGREEN, at)
+#define rgblight_setrgb_turquoise_at(at)   rgblight_setrgb_at (RGB_TURQUOISE, at)
+#define rgblight_setrgb_teal_at(at)        rgblight_setrgb_at (RGB_TEAL, at)
+#define rgblight_setrgb_cyan_at(at)        rgblight_setrgb_at (RGB_CYAN, at)
+#define rgblight_setrgb_azure_at(at)       rgblight_setrgb_at (RGB_AZURE, at)
+#define rgblight_setrgb_blue_at(at)        rgblight_setrgb_at (RGB_BLUE, at)
+#define rgblight_setrgb_purple_at(at)      rgblight_setrgb_at (RGB_PURPLE, at)
+#define rgblight_setrgb_magenta_at(at)     rgblight_setrgb_at (RGB_MAGENTA, at)
+#define rgblight_setrgb_pink_at(at)        rgblight_setrgb_at (RGB_PINK, at)
 
 /*                            SET HSV List                            */
-#define rgblight_sethsv_white()       rgblight_sethsv (  0,   0, 255)
-#define rgblight_sethsv_red()         rgblight_sethsv (  0, 255, 255)
-#define rgblight_sethsv_coral()       rgblight_sethsv ( 16, 176, 255)
-#define rgblight_sethsv_orange()      rgblight_sethsv ( 39, 255, 255)
-#define rgblight_sethsv_goldenrod()   rgblight_sethsv ( 43, 218, 218)
-#define rgblight_sethsv_gold()        rgblight_sethsv ( 51, 255, 255)
-#define rgblight_sethsv_yellow()      rgblight_sethsv ( 60, 255, 255)
-#define rgblight_sethsv_chartreuse()  rgblight_sethsv ( 90, 255, 255)
-#define rgblight_sethsv_green()       rgblight_sethsv (120, 255, 255)
-#define rgblight_sethsv_springgreen() rgblight_sethsv (150, 255, 255)
-#define rgblight_sethsv_turquoise()   rgblight_sethsv (174,  90, 112)
-#define rgblight_sethsv_teal()        rgblight_sethsv (180, 255, 128)
-#define rgblight_sethsv_cyan()        rgblight_sethsv (180, 255, 255)
-#define rgblight_sethsv_azure()       rgblight_sethsv (186, 102, 255)
-#define rgblight_sethsv_blue()        rgblight_sethsv (240, 255, 255)
-#define rgblight_sethsv_purple()      rgblight_sethsv (270, 255, 255)
-#define rgblight_sethsv_magenta()     rgblight_sethsv (300, 255, 255)
-#define rgblight_sethsv_pink()        rgblight_sethsv (330, 128, 255)
+#define rgblight_sethsv_white()       rgblight_sethsv (HSV_WHITE)
+#define rgblight_sethsv_red()         rgblight_sethsv (HSV_RED)
+#define rgblight_sethsv_coral()       rgblight_sethsv (HSV_CORAL)
+#define rgblight_sethsv_orange()      rgblight_sethsv (HSV_ORANGE)
+#define rgblight_sethsv_goldenrod()   rgblight_sethsv (HSV_GOLDENROD)
+#define rgblight_sethsv_gold()        rgblight_sethsv (HSV_GOLD)
+#define rgblight_sethsv_yellow()      rgblight_sethsv (HSV_YELLOW)
+#define rgblight_sethsv_chartreuse()  rgblight_sethsv (HSV_CHARTREUSE)
+#define rgblight_sethsv_green()       rgblight_sethsv (HSV_GREEN)
+#define rgblight_sethsv_springgreen() rgblight_sethsv (HSV_SPRINGGREEN)
+#define rgblight_sethsv_turquoise()   rgblight_sethsv (HSV_TURQUOISE)
+#define rgblight_sethsv_teal()        rgblight_sethsv (HSV_TEAL)
+#define rgblight_sethsv_cyan()        rgblight_sethsv (HSV_CYAN)
+#define rgblight_sethsv_azure()       rgblight_sethsv (HSV_AZURE)
+#define rgblight_sethsv_blue()        rgblight_sethsv (HSV_BLUE)
+#define rgblight_sethsv_purple()      rgblight_sethsv (HSV_PURPLE)
+#define rgblight_sethsv_magenta()     rgblight_sethsv (HSV_MAGENTA)
+#define rgblight_sethsv_pink()        rgblight_sethsv (HSV_PINK)
 
 /*                            SET HSV List                            */
 /*   If you're doing layer indication, this is best, as it won't      */
 /*   write to the eeprom, since it's limited (very high value).       */
 /*   If you want to use modes with this (since you can), then you     */
 /*   want to use rgblight_mode_noeeprom(x) instead.                   */
-#define rgblight_sethsv_noeeprom_white()       rgblight_sethsv_noeeprom (  0,   0, 255)
-#define rgblight_sethsv_noeeprom_red()         rgblight_sethsv_noeeprom (  0, 255, 255)
-#define rgblight_sethsv_noeeprom_coral()       rgblight_sethsv_noeeprom ( 16, 176, 255)
-#define rgblight_sethsv_noeeprom_orange()      rgblight_sethsv_noeeprom ( 39, 255, 255)
-#define rgblight_sethsv_noeeprom_goldenrod()   rgblight_sethsv_noeeprom ( 43, 218, 218)
-#define rgblight_sethsv_noeeprom_gold()        rgblight_sethsv_noeeprom ( 51, 255, 255)
-#define rgblight_sethsv_noeeprom_yellow()      rgblight_sethsv_noeeprom ( 60, 255, 255)
-#define rgblight_sethsv_noeeprom_chartreuse()  rgblight_sethsv_noeeprom ( 90, 255, 255)
-#define rgblight_sethsv_noeeprom_green()       rgblight_sethsv_noeeprom (120, 255, 255)
-#define rgblight_sethsv_noeeprom_springgreen() rgblight_sethsv_noeeprom (150, 255, 255)
-#define rgblight_sethsv_noeeprom_turquoise()   rgblight_sethsv_noeeprom (174,  90, 112)
-#define rgblight_sethsv_noeeprom_teal()        rgblight_sethsv_noeeprom (180, 255, 128)
-#define rgblight_sethsv_noeeprom_cyan()        rgblight_sethsv_noeeprom (180, 255, 255)
-#define rgblight_sethsv_noeeprom_azure()       rgblight_sethsv_noeeprom (186, 102, 255)
-#define rgblight_sethsv_noeeprom_blue()        rgblight_sethsv_noeeprom (240, 255, 255)
-#define rgblight_sethsv_noeeprom_purple()      rgblight_sethsv_noeeprom (270, 255, 255)
-#define rgblight_sethsv_noeeprom_magenta()     rgblight_sethsv_noeeprom (300, 255, 255)
-#define rgblight_sethsv_noeeprom_pink()        rgblight_sethsv_noeeprom (330, 128, 255)
+#define rgblight_sethsv_noeeprom_white()       rgblight_sethsv_noeeprom (HSV_WHITE)
+#define rgblight_sethsv_noeeprom_red()         rgblight_sethsv_noeeprom (HSV_RED)
+#define rgblight_sethsv_noeeprom_coral()       rgblight_sethsv_noeeprom (HSV_CORAL)
+#define rgblight_sethsv_noeeprom_orange()      rgblight_sethsv_noeeprom (HSV_ORANGE)
+#define rgblight_sethsv_noeeprom_goldenrod()   rgblight_sethsv_noeeprom (HSV_GOLDENROD)
+#define rgblight_sethsv_noeeprom_gold()        rgblight_sethsv_noeeprom (HSV_GOLD)
+#define rgblight_sethsv_noeeprom_yellow()      rgblight_sethsv_noeeprom (HSV_YELLOW)
+#define rgblight_sethsv_noeeprom_chartreuse()  rgblight_sethsv_noeeprom (HSV_CHARTREUSE)
+#define rgblight_sethsv_noeeprom_green()       rgblight_sethsv_noeeprom (HSV_GREEN)
+#define rgblight_sethsv_noeeprom_springgreen() rgblight_sethsv_noeeprom (HSV_SPRINGGREEN)
+#define rgblight_sethsv_noeeprom_turquoise()   rgblight_sethsv_noeeprom (HSV_TURQUOISE)
+#define rgblight_sethsv_noeeprom_teal()        rgblight_sethsv_noeeprom (HSV_TEAL)
+#define rgblight_sethsv_noeeprom_cyan()        rgblight_sethsv_noeeprom (HSV_CYAN)
+#define rgblight_sethsv_noeeprom_azure()       rgblight_sethsv_noeeprom (HSV_AZURE)
+#define rgblight_sethsv_noeeprom_blue()        rgblight_sethsv_noeeprom (HSV_BLUE)
+#define rgblight_sethsv_noeeprom_purple()      rgblight_sethsv_noeeprom (HSV_PURPLE)
+#define rgblight_sethsv_noeeprom_magenta()     rgblight_sethsv_noeeprom (HSV_MAGENTA)
+#define rgblight_sethsv_noeeprom_pink()        rgblight_sethsv_noeeprom (HSV_PINK)
 
 /*                            SET HSV List                            */
-#define rgblight_sethsv_white_at(at)       rgblight_sethsv_at (  0,   0, 255, at)
-#define rgblight_sethsv_red_at(at)         rgblight_sethsv_at (  0, 255, 255, at)
-#define rgblight_sethsv_coral_at(at)       rgblight_sethsv_at ( 16, 176, 255, at)
-#define rgblight_sethsv_orange_at(at)      rgblight_sethsv_at ( 39, 255, 255, at)
-#define rgblight_sethsv_goldenrod_at(at)   rgblight_sethsv_at ( 43, 218, 218, at)
-#define rgblight_sethsv_gold_at(at)        rgblight_sethsv_at ( 51, 255, 255, at)
-#define rgblight_sethsv_yellow_at(at)      rgblight_sethsv_at ( 60, 255, 255, at)
-#define rgblight_sethsv_chartreuse_at(at)  rgblight_sethsv_at ( 90, 255, 255, at)
-#define rgblight_sethsv_green_at(at)       rgblight_sethsv_at (120, 255, 255, at)
-#define rgblight_sethsv_springgreen_at(at) rgblight_sethsv_at (150, 255, 255, at)
-#define rgblight_sethsv_turquoise_at(at)   rgblight_sethsv_at (174,  90, 112, at)
-#define rgblight_sethsv_teal_at(at)        rgblight_sethsv_at (180, 255, 128, at)
-#define rgblight_sethsv_cyan_at(at)        rgblight_sethsv_at (180, 255, 255, at)
-#define rgblight_sethsv_azure_at(at)       rgblight_sethsv_at (186, 102, 255, at)
-#define rgblight_sethsv_blue_at(at)        rgblight_sethsv_at (240, 255, 255, at)
-#define rgblight_sethsv_purple_at(at)      rgblight_sethsv_at (270, 255, 255, at)
-#define rgblight_sethsv_magenta_at(at)     rgblight_sethsv_at (300, 255, 255, at)
-#define rgblight_sethsv_pink_at(at)        rgblight_sethsv_at (330, 128, 255, at)
-
-#endif
+#define rgblight_sethsv_white_at(at)       rgblight_sethsv_at (HSV_WHITE, at)
+#define rgblight_sethsv_red_at(at)         rgblight_sethsv_at (HSV_RED, at)
+#define rgblight_sethsv_coral_at(at)       rgblight_sethsv_at (HSV_CORAL, at)
+#define rgblight_sethsv_orange_at(at)      rgblight_sethsv_at (HSV_ORANGE, at)
+#define rgblight_sethsv_goldenrod_at(at)   rgblight_sethsv_at (HSV_GOLDENROD, at)
+#define rgblight_sethsv_gold_at(at)        rgblight_sethsv_at (HSV_GOLD, at)
+#define rgblight_sethsv_yellow_at(at)      rgblight_sethsv_at (HSV_YELLOW, at)
+#define rgblight_sethsv_chartreuse_at(at)  rgblight_sethsv_at (HSV_CHARTREUSE, at)
+#define rgblight_sethsv_green_at(at)       rgblight_sethsv_at (HSV_GREEN, at)
+#define rgblight_sethsv_springgreen_at(at) rgblight_sethsv_at (HSV_SPRINGGREEN, at)
+#define rgblight_sethsv_turquoise_at(at)   rgblight_sethsv_at (HSV_TURQUOISE, at)
+#define rgblight_sethsv_teal_at(at)        rgblight_sethsv_at (HSV_TEAL, at)
+#define rgblight_sethsv_cyan_at(at)        rgblight_sethsv_at (HSV_CYAN, at)
+#define rgblight_sethsv_azure_at(at)       rgblight_sethsv_at (HSV_AZURE, at)
+#define rgblight_sethsv_blue_at(at)        rgblight_sethsv_at (HSV_BLUE, at)
+#define rgblight_sethsv_purple_at(at)      rgblight_sethsv_at (HSV_PURPLE, at)
+#define rgblight_sethsv_magenta_at(at)     rgblight_sethsv_at (HSV_MAGENTA, at)
+#define rgblight_sethsv_pink_at(at)        rgblight_sethsv_at (HSV_PINK, at)
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c
index eb110bd23a..3c3daf3d3b 100644
--- a/quantum/split_common/matrix.c
+++ b/quantum/split_common/matrix.c
@@ -299,7 +299,7 @@ uint8_t _matrix_scan(void) {
 
   debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed);
 
-  return 1;
+  return (uint8_t)changed;
 }
 
 uint8_t matrix_scan(void) {
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c
index 7ea1a9cec9..a3539576f5 100644
--- a/quantum/split_common/transport.c
+++ b/quantum/split_common/transport.c
@@ -13,7 +13,6 @@
 
 #ifdef BACKLIGHT_ENABLE
 #  include "backlight.h"
-extern backlight_config_t backlight_config;
 #endif
 
 #ifdef ENCODER_ENABLE
@@ -55,7 +54,7 @@ bool transport_master(matrix_row_t matrix[]) {
 
   // write backlight info
 #  ifdef BACKLIGHT_ENABLE
-  uint8_t level = get_backlight_level();
+  uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0;
   if (level != i2c_buffer->backlight_level) {
     if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_BACKLIGHT_START, (void *)&level, sizeof(level), TIMEOUT) >= 0) {
       i2c_buffer->backlight_level = level;
@@ -223,7 +222,7 @@ bool transport_master(matrix_row_t matrix[]) {
 
 #  ifdef BACKLIGHT_ENABLE
   // Write backlight level for slave to read
-  serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0;
+  serial_m2s_buffer.backlight_level = is_backlight_enabled() ? get_backlight_level() : 0;
 #  endif
 
 #  ifdef ENCODER_ENABLE
diff --git a/quantum/stm32/proton_c.mk b/quantum/stm32/proton_c.mk
index a0fa013736..a65e283d3f 100644
--- a/quantum/stm32/proton_c.mk
+++ b/quantum/stm32/proton_c.mk
@@ -42,3 +42,4 @@ OPT_DEFS =
 
 # Options to pass to dfu-util when flashing
 DFU_ARGS = -d 0483:df11 -a 0 -s 0x08000000:leave
+DFU_SUFFIX_ARGS = -p df11 -v 0483
diff --git a/quantum/template/avr/config.h b/quantum/template/avr/config.h
index a9bb754821..48d7afb149 100644
--- a/quantum/template/avr/config.h
+++ b/quantum/template/avr/config.h
@@ -77,6 +77,12 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 //   #define RGBLIGHT_EFFECT_STATIC_GRADIENT
 //   #define RGBLIGHT_EFFECT_RGB_TEST
 //   #define RGBLIGHT_EFFECT_ALTERNATING
+// /*== customize breathing effect ==*/
+//   /*==== (DEFAULT) use fixed table instead of exp() and sin() ====*/
+//   #define RGBLIGHT_BREATHE_TABLE_SIZE 256      // 256(default) or 128 or 64
+//   /*==== use exp() and sin() ====*/
+//   #define RGBLIGHT_EFFECT_BREATHE_CENTER 1.85  // 1 to 2.7
+//   #define RGBLIGHT_EFFECT_BREATHE_MAX    255   // 0 to 255
 // #endif
 
 /* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
diff --git a/quantum/template/ps2avrgb/readme.md b/quantum/template/ps2avrgb/readme.md
index ef24deb8f7..1449b278cd 100644
--- a/quantum/template/ps2avrgb/readme.md
+++ b/quantum/template/ps2avrgb/readme.md
@@ -16,6 +16,8 @@ Flashing
 
 ps2avr(GB) boards use an atmega32a microcontroller and a different bootloader. It is not flashable using the regular QMK methods. 
 
+**Reset Key:** Hold down the key located at `K00`, commonly programmed as `Esc` while plugging in the keyboard.
+
 Windows: 
 1. Download [HIDBootFlash](http://vusb.wikidot.com/project:hidbootflash).
 2. Place your keyboard into reset. 
diff --git a/quantum/template/ps2avrgb/rules.mk b/quantum/template/ps2avrgb/rules.mk
index 191a138446..bd0eed0527 100644
--- a/quantum/template/ps2avrgb/rules.mk
+++ b/quantum/template/ps2avrgb/rules.mk
@@ -31,13 +31,13 @@ F_CPU = 12000000
 BOOTLOADER = bootloadHID
 
 # build options
-BOOTMAGIC_ENABLE = full
+BOOTMAGIC_ENABLE = no
 MOUSEKEY_ENABLE = no
 EXTRAKEY_ENABLE = yes
 CONSOLE_ENABLE = yes
 COMMAND_ENABLE = yes
 BACKLIGHT_ENABLE = no
-RGBLIGHT_ENABLE = no
+RGBLIGHT_ENABLE = yes
 RGBLIGHT_CUSTOM_DRIVER = yes
 
 OPT_DEFS = -DDEBUG_LEVEL=0
diff --git a/quantum/template/ps2avrgb/usbconfig.h b/quantum/template/ps2avrgb/usbconfig.h
index d2d848fcdc..54a7d20f14 100644
--- a/quantum/template/ps2avrgb/usbconfig.h
+++ b/quantum/template/ps2avrgb/usbconfig.h
@@ -8,8 +8,7 @@
  * This Revision: $Id: usbconfig-prototype.h 785 2010-05-30 17:57:07Z cs $
  */
 
-#ifndef __usbconfig_h_included__
-#define __usbconfig_h_included__
+#pragma once
 
 #include "config.h"
 
@@ -392,5 +391,3 @@ section at the end of this file).
 /* #define USB_INTR_PENDING        EIFR */
 #define USB_INTR_PENDING_BIT    INTF1
 #define USB_INTR_VECTOR         INT1_vect
-
-#endif /* __usbconfig_h_included__ */