Browse Source

Enable community modules to define LED matrix and RGB matrix effects. (#25187)

Co-authored-by: Joel Challis <git@zvecr.com>
Pascal Getreuer 1 year ago
parent
commit
f4171412a6

+ 11 - 2
builddefs/build_keyboard.mk

@@ -274,10 +274,19 @@ $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h: $(KEYMAP_JSON) $(D
 	$(eval CMD=$(QMK_BIN) generate-community-modules-introspection-h -kb $(KEYBOARD) --quiet --output $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h $(KEYMAP_JSON))
 	@$(BUILD_CMD)
 
-SRC += $(INTERMEDIATE_OUTPUT)/src/community_modules.c
+$(INTERMEDIATE_OUTPUT)/src/led_matrix_community_modules.inc: $(KEYMAP_JSON) $(DD_CONFIG_FILES)
+	@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
+	$(eval CMD=$(QMK_BIN) generate-led-matrix-community-modules-inc -kb $(KEYBOARD) --quiet --output $(INTERMEDIATE_OUTPUT)/src/led_matrix_community_modules.inc $(KEYMAP_JSON))
+	@$(BUILD_CMD)
 
-generated-files: $(INTERMEDIATE_OUTPUT)/src/community_modules.h $(INTERMEDIATE_OUTPUT)/src/community_modules.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h
+$(INTERMEDIATE_OUTPUT)/src/rgb_matrix_community_modules.inc: $(KEYMAP_JSON) $(DD_CONFIG_FILES)
+	@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
+	$(eval CMD=$(QMK_BIN) generate-rgb-matrix-community-modules-inc -kb $(KEYBOARD) --quiet --output $(INTERMEDIATE_OUTPUT)/src/rgb_matrix_community_modules.inc $(KEYMAP_JSON))
+	@$(BUILD_CMD)
+
+SRC += $(INTERMEDIATE_OUTPUT)/src/community_modules.c
 
+generated-files: $(INTERMEDIATE_OUTPUT)/src/community_modules.h $(INTERMEDIATE_OUTPUT)/src/community_modules.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h $(INTERMEDIATE_OUTPUT)/src/led_matrix_community_modules.inc $(INTERMEDIATE_OUTPUT)/src/rgb_matrix_community_modules.inc
 
 include $(BUILDDEFS_PATH)/converters.mk
 

+ 3 - 0
data/constants/module_hooks/1.1.1.hjson

@@ -0,0 +1,3 @@
+{
+    // This version exists to signify addition of LED/RGB effect support.
+}

+ 8 - 0
docs/features/community_modules.md

@@ -123,6 +123,14 @@ The source file may provide functions which allow access to information specifie
 Introspection is a relatively advanced topic within QMK, and existing patterns should be followed. If you need help please [open an issue](https://github.com/qmk/qmk_firmware/issues/new) or [chat with us on Discord](https://discord.gg/qmk).
 :::
 
+### `led_matrix_module.inc`
+
+This file defines LED matrix effects in the same form as used with `led_matrix_kb.inc` and `led_matrix_user.inc` (see [Custom LED Matrix Effects](led_matrix#custom-led-matrix-effects)). Effect mode names are prepended with `LED_MATRIX_COMMUNITY_MODULE_`.
+
+### `rgb_matrix_module.inc`
+
+This file defines RGB matrix effects in the same form as used with `rgb_matrix_kb.inc` and `rgb_matrix_user.inc` (see [Custom RGB Matrix Effects](rgb_matrix#custom-rgb-matrix-effects)). Effect mode names are prepended with `RGB_MATRIX_COMMUNITY_MODULE_`.
+
 ### Compatible APIs
 
 Community Modules may provide specializations for the following APIs:

+ 12 - 0
keyboards/handwired/onekey/info.json

@@ -26,5 +26,17 @@
                 {"x": 0, "y": 0, "matrix": [0, 0]}
             ]
         }
+    },
+    "led_matrix": {
+        "driver": "snled27351",
+        "layout": [
+            {"matrix": [0, 0], "x": 0, "y": 0, "flags": 1}
+        ]
+    },
+    "rgb_matrix": {
+        "driver": "snled27351",
+        "layout": [
+            {"matrix": [0, 0], "x": 0, "y": 0, "flags": 1}
+        ]
     }
 }

+ 16 - 0
keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/config.h

@@ -0,0 +1,16 @@
+// Copyright 2025 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#define SNLED27351_I2C_ADDRESS_1 SNLED27351_I2C_ADDRESS_GND

+ 27 - 0
keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.c

@@ -0,0 +1,27 @@
+// Copyright 2025 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This keymap serves as a test for modules/qmk/flow_led_matrix_effect.
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {LAYOUT_ortho_1x1(LM_TOGG)};
+
+const snled27351_led_t PROGMEM g_snled27351_leds[LED_MATRIX_LED_COUNT] = {
+    {0, CB6_CA1},
+};
+
+void keyboard_post_init_user(void) {
+    led_matrix_mode_noeeprom(LED_MATRIX_COMMUNITY_MODULE_FLOW);
+}

+ 3 - 0
keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.json

@@ -0,0 +1,3 @@
+{
+    "modules": ["qmk/flow_led_matrix_effect"]
+}

+ 16 - 0
keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/config.h

@@ -0,0 +1,16 @@
+// Copyright 2025 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#define SNLED27351_I2C_ADDRESS_1 SNLED27351_I2C_ADDRESS_GND

+ 27 - 0
keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.c

@@ -0,0 +1,27 @@
+// Copyright 2025 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This keymap serves as a test for modules/qmk/flow_rgb_matrix_effect.
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {LAYOUT_ortho_1x1(RM_TOGG)};
+
+const snled27351_led_t PROGMEM g_snled27351_leds[LED_MATRIX_LED_COUNT] = {
+    {0, CB6_CA1},
+};
+
+void keyboard_post_init_user(void) {
+    rgb_matrix_mode_noeeprom(RGB_MATRIX_COMMUNITY_MODULE_FLOW);
+}

+ 3 - 0
keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.json

@@ -0,0 +1,3 @@
+{
+    "modules": ["qmk/flow_rgb_matrix_effect"]
+}

+ 39 - 36
lib/python/qmk/cli/generate/community_modules.py

@@ -278,33 +278,32 @@ def generate_community_modules_c(cli):
     dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True)
 
 
+def _generate_include_per_module(cli, include_file_name):
+    """Generates C code to include "<module_path>/include_file_name" for each module."""
+    if cli.args.output and cli.args.output.name == '-':
+        cli.args.output = None
+
+    lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE]
+
+    for module in get_modules(cli.args.keyboard, cli.args.filename):
+        full_path = f'{find_module_path(module)}/{include_file_name}'
+        lines.append('')
+        lines.append(f'#if __has_include("{full_path}")')
+        lines.append(f'#include "{full_path}"')
+        lines.append(f'#endif  // __has_include("{full_path}")')
+
+    dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True)
+
+
 @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
 @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
-@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate community_modules.c for.')
+@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate community_modules_introspection.h for.')
 @cli.argument('filename', nargs='?', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file')
 @cli.subcommand('Creates a community_modules_introspection.h from a keymap.json file.')
 def generate_community_modules_introspection_h(cli):
     """Creates a community_modules_introspection.h from a keymap.json file
     """
-    if cli.args.output and cli.args.output.name == '-':
-        cli.args.output = None
-
-    lines = [
-        GPL2_HEADER_C_LIKE,
-        GENERATED_HEADER_C_LIKE,
-        '',
-    ]
-
-    modules = get_modules(cli.args.keyboard, cli.args.filename)
-    if len(modules) > 0:
-        for module in modules:
-            module_path = find_module_path(module)
-            lines.append(f'#if __has_include("{module_path}/introspection.h")')
-            lines.append(f'#include "{module_path}/introspection.h"')
-            lines.append(f'#endif  // __has_include("{module_path}/introspection.h")')
-            lines.append('')
-
-    dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True)
+    _generate_include_per_module(cli, 'introspection.h')
 
 
 @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
@@ -315,22 +314,26 @@ def generate_community_modules_introspection_h(cli):
 def generate_community_modules_introspection_c(cli):
     """Creates a community_modules_introspection.c from a keymap.json file
     """
-    if cli.args.output and cli.args.output.name == '-':
-        cli.args.output = None
+    _generate_include_per_module(cli, 'introspection.c')
 
-    lines = [
-        GPL2_HEADER_C_LIKE,
-        GENERATED_HEADER_C_LIKE,
-        '',
-    ]
 
-    modules = get_modules(cli.args.keyboard, cli.args.filename)
-    if len(modules) > 0:
-        for module in modules:
-            module_path = find_module_path(module)
-            lines.append(f'#if __has_include("{module_path}/introspection.c")')
-            lines.append(f'#include "{module_path}/introspection.c"')
-            lines.append(f'#endif  // __has_include("{module_path}/introspection.c")')
-            lines.append('')
+@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
+@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
+@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate led_matrix_community_modules.inc for.')
+@cli.argument('filename', nargs='?', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file')
+@cli.subcommand('Creates an led_matrix_community_modules.inc from a keymap.json file.')
+def generate_led_matrix_community_modules_inc(cli):
+    """Creates an led_matrix_community_modules.inc from a keymap.json file
+    """
+    _generate_include_per_module(cli, 'led_matrix_module.inc')
 
-    dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True)
+
+@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
+@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
+@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate rgb_matrix_community_modules.inc for.')
+@cli.argument('filename', nargs='?', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file')
+@cli.subcommand('Creates an rgb_matrix_community_modules.inc from a keymap.json file.')
+def generate_rgb_matrix_community_modules_inc(cli):
+    """Creates an rgb_matrix_community_modules.inc from a keymap.json file
+    """
+    _generate_include_per_module(cli, 'rgb_matrix_module.inc')

+ 58 - 0
modules/qmk/flow_led_matrix_effect/led_matrix_module.inc

@@ -0,0 +1,58 @@
+// Copyright 2024-2025 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+LED_MATRIX_EFFECT(FLOW)
+
+#ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS
+
+// "Flow" animated effect. Draws moving wave patterns mimicking the appearance
+// of flowing liquid. For interesting variety of patterns, space coordinates are
+// slowly rotated and a function of several sine waves is evaluated.
+static bool FLOW(effect_params_t* params) {
+    LED_MATRIX_USE_LIMITS(led_min, led_max);
+
+    static uint16_t wrap_correction = 0;
+    static uint8_t  last_high_byte  = 0;
+    const uint8_t   time_scale      = 1 + led_matrix_eeconfig.speed / 8;
+    const uint8_t   high_byte       = (uint8_t)(g_led_timer >> 16);
+    if (last_high_byte != high_byte) {
+        last_high_byte = high_byte;
+        wrap_correction += ((uint16_t)time_scale) << 8;
+    }
+    const uint16_t time = scale16by8(g_led_timer, time_scale) + wrap_correction;
+
+    // Compute rotation coefficients with 7 fractional bits.
+    const int8_t  rot_c = cos8(time / 4) - 128;
+    const int8_t  rot_s = sin8(time / 4) - 128;
+    const uint8_t omega = 32 + sin8(time) / 4;
+
+    for (uint8_t i = led_min; i < led_max; ++i) {
+        LED_MATRIX_TEST_LED_FLAGS();
+        const uint8_t x = g_led_config.point[i].x;
+        const uint8_t y = g_led_config.point[i].y;
+
+        // Rotate (x, y) by the 2x2 rotation matrix described by rot_c, rot_s.
+        const uint8_t x1 = (uint8_t)((((int16_t)rot_c) * ((int16_t)x)) / 128) - (uint8_t)((((int16_t)rot_s) * ((int16_t)y)) / 128);
+        const uint8_t y1 = (uint8_t)((((int16_t)rot_s) * ((int16_t)x)) / 128) + (uint8_t)((((int16_t)rot_c) * ((int16_t)y)) / 128);
+
+        uint8_t value = scale8(sin8(x1 - 2 * time), omega) + y1 + time / 4;
+        value         = (value <= 127) ? value : (255 - value);
+
+        led_matrix_set_value(i, scale8(led_matrix_eeconfig.val, value));
+    }
+
+    return led_matrix_check_finished_leds(led_max);
+}
+
+#endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS

+ 8 - 0
modules/qmk/flow_led_matrix_effect/qmk_module.json

@@ -0,0 +1,8 @@
+{
+    "module_name": "Flow LED matrix effect",
+    "maintainer": "QMK Maintainers",
+    "license": "Apache-2.0",
+    "features": {
+        "led_matrix": true
+    }
+}

+ 8 - 0
modules/qmk/flow_rgb_matrix_effect/qmk_module.json

@@ -0,0 +1,8 @@
+{
+    "module_name": "Flow RGB matrix effect",
+    "maintainer": "QMK Maintainers",
+    "license": "Apache-2.0",
+    "features": {
+        "rgb_matrix": true
+    }
+}

+ 64 - 0
modules/qmk/flow_rgb_matrix_effect/rgb_matrix_module.inc

@@ -0,0 +1,64 @@
+// Copyright 2024-2025 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+RGB_MATRIX_EFFECT(FLOW)
+
+#ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+
+// "Flow" animated effect. Draws moving wave patterns mimicking the appearance
+// of flowing liquid. For interesting variety of patterns, space coordinates are
+// slowly rotated and a function of several sine waves is evaluated.
+static bool FLOW(effect_params_t* params) {
+    RGB_MATRIX_USE_LIMITS(led_min, led_max);
+
+    static uint16_t wrap_correction = 0;
+    static uint8_t  last_high_byte  = 0;
+    const uint8_t   time_scale      = 1 + rgb_matrix_config.speed / 8;
+    const uint8_t   high_byte       = (uint8_t)(g_rgb_timer >> 16);
+    if (last_high_byte != high_byte) {
+        last_high_byte = high_byte;
+        wrap_correction += ((uint16_t)time_scale) << 8;
+    }
+    const uint16_t time = scale16by8(g_rgb_timer, time_scale) + wrap_correction;
+
+    // Compute rotation coefficients with 7 fractional bits.
+    const int8_t  rot_c = cos8(time / 4) - 128;
+    const int8_t  rot_s = sin8(time / 4) - 128;
+    const uint8_t omega = 32 + sin8(time) / 4;
+
+    for (uint8_t i = led_min; i < led_max; ++i) {
+        RGB_MATRIX_TEST_LED_FLAGS();
+        const uint8_t x = g_led_config.point[i].x;
+        const uint8_t y = g_led_config.point[i].y;
+
+        // Rotate (x, y) by the 2x2 rotation matrix described by rot_c, rot_s.
+        const uint8_t x1 = (uint8_t)((((int16_t)rot_c) * ((int16_t)x)) / 128) - (uint8_t)((((int16_t)rot_s) * ((int16_t)y)) / 128);
+        const uint8_t y1 = (uint8_t)((((int16_t)rot_s) * ((int16_t)x)) / 128) + (uint8_t)((((int16_t)rot_c) * ((int16_t)y)) / 128);
+
+        uint8_t value = scale8(sin8(x1 - 2 * time), omega) + y1 + time / 4;
+        value         = (value <= 127) ? value : (255 - value);
+
+        hsv_t hsv = rgb_matrix_config.hsv;
+        hsv.h -= value / 4;
+        hsv.s     = scale8(hsv.s, (value < 74) ? 255 : (549 - 4 * value));
+        hsv.v     = scale8(hsv.v, (value < 95) ? (64 + 2 * value) : 255);
+
+        rgb_t rgb = rgb_matrix_hsv_to_rgb(hsv);
+        rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
+    }
+
+    return rgb_matrix_check_finished_leds(led_max);
+}
+
+#endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS

+ 12 - 0
quantum/led_matrix/led_matrix.c

@@ -45,6 +45,9 @@ const led_point_t k_led_matrix_center = LED_MATRIX_CENTER;
 #define LED_MATRIX_CUSTOM_EFFECT_IMPLS
 
 #include "led_matrix_effects.inc"
+#ifdef COMMUNITY_MODULES_ENABLE
+#    include "led_matrix_community_modules.inc"
+#endif
 #ifdef LED_MATRIX_CUSTOM_KB
 #    include "led_matrix_kb.inc"
 #endif
@@ -282,6 +285,15 @@ static void led_task_render(uint8_t effect) {
 #include "led_matrix_effects.inc"
 #undef LED_MATRIX_EFFECT
 
+#ifdef COMMUNITY_MODULES_ENABLE
+#    define LED_MATRIX_EFFECT(name, ...)          \
+        case LED_MATRIX_COMMUNITY_MODULE_##name:  \
+            rendering = name(&led_effect_params); \
+            break;
+#    include "led_matrix_community_modules.inc"
+#    undef LED_MATRIX_EFFECT
+#endif
+
 #if defined(LED_MATRIX_CUSTOM_KB) || defined(LED_MATRIX_CUSTOM_USER)
 #    define LED_MATRIX_EFFECT(name, ...)          \
         case LED_MATRIX_CUSTOM_##name:            \

+ 6 - 0
quantum/led_matrix/led_matrix.h

@@ -98,6 +98,12 @@ enum led_matrix_effects {
 #include "led_matrix_effects.inc"
 #undef LED_MATRIX_EFFECT
 
+#ifdef COMMUNITY_MODULES_ENABLE
+#    define LED_MATRIX_EFFECT(name, ...) LED_MATRIX_COMMUNITY_MODULE_##name,
+#    include "led_matrix_community_modules.inc"
+#    undef LED_MATRIX_EFFECT
+#endif
+
 #if defined(LED_MATRIX_CUSTOM_KB) || defined(LED_MATRIX_CUSTOM_USER)
 #    define LED_MATRIX_EFFECT(name, ...) LED_MATRIX_CUSTOM_##name,
 #    ifdef LED_MATRIX_CUSTOM_KB

+ 12 - 0
quantum/rgb_matrix/rgb_matrix.c

@@ -47,6 +47,9 @@ __attribute__((weak)) rgb_t rgb_matrix_hsv_to_rgb(hsv_t hsv) {
 #define RGB_MATRIX_CUSTOM_EFFECT_IMPLS
 
 #include "rgb_matrix_effects.inc"
+#ifdef COMMUNITY_MODULES_ENABLE
+#    include "rgb_matrix_community_modules.inc"
+#endif
 #ifdef RGB_MATRIX_CUSTOM_KB
 #    include "rgb_matrix_kb.inc"
 #endif
@@ -310,6 +313,15 @@ static void rgb_task_render(uint8_t effect) {
 #include "rgb_matrix_effects.inc"
 #undef RGB_MATRIX_EFFECT
 
+#ifdef COMMUNITY_MODULES_ENABLE
+#    define RGB_MATRIX_EFFECT(name, ...)          \
+        case RGB_MATRIX_COMMUNITY_MODULE_##name:  \
+            rendering = name(&rgb_effect_params); \
+            break;
+#    include "rgb_matrix_community_modules.inc"
+#    undef RGB_MATRIX_EFFECT
+#endif
+
 #if defined(RGB_MATRIX_CUSTOM_KB) || defined(RGB_MATRIX_CUSTOM_USER)
 #    define RGB_MATRIX_EFFECT(name, ...)          \
         case RGB_MATRIX_CUSTOM_##name:            \

+ 6 - 0
quantum/rgb_matrix/rgb_matrix.h

@@ -123,6 +123,12 @@ enum rgb_matrix_effects {
 #include "rgb_matrix_effects.inc"
 #undef RGB_MATRIX_EFFECT
 
+#ifdef COMMUNITY_MODULES_ENABLE
+#    define RGB_MATRIX_EFFECT(name, ...) RGB_MATRIX_COMMUNITY_MODULE_##name,
+#    include "rgb_matrix_community_modules.inc"
+#    undef RGB_MATRIX_EFFECT
+#endif
+
 #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