LED effects engine for embedded systems, written in C. Provides a tick-based rendering loop with smooth brightness transitions, color blending, and a library of built-in effects. Platform-agnostic โ works on any target through a minimal HAL (hardware abstraction layer).
- Tick-driven architecture with configurable FPS
- Smooth brightness fading and effect crossfade
- HSV/RGB/Kelvin color utilities, gradients, color correction
- Configurable LED count, color order, and pixel skip at runtime
- 15 built-in effects: static, rainbow, breathing, aurora, candlelight, comet, tide, ocean, ember, silk, heartbeat, and more
Add as a PlatformIO dependency:
[env]
lib_deps = mishamyrt/LightComposer@^2.0.0Implement the HAL for your LED driver:
#include <light_composer.h>
static void set_pixel(uint16_t i, rgb_t c) { /* write to your LED driver */ }
static rgb_t get_pixel(uint16_t i) { /* read back if needed */ }
static void show(void) { /* flush data to the strip */ }
static const lc_hal_t hal = { set_pixel, get_pixel, show };Initialize and run:
#define LED_COUNT 60
static rgb_t pixels[LED_COUNT];
void setup(void) {
lc_config_t cfg = {
.hal = &hal,
.pixel_buf = pixels,
.max_leds_count = LED_COUNT,
.leds_count = LED_COUNT,
.color_correction = LC_RGB(255, 255, 255),
.color_order = LC_ORDER_GRB,
.fps = 60,
};
lc_init(&cfg);
lc_set_brightness(200);
lc_set_power(true);
lc_set_color(LC_RGB(255, 80, 0));
lc_set_effect(&lc_fx_static);
}
void loop(void) {
lc_tick();
}Switch effects at any time โ the engine will crossfade automatically:
lc_set_effect(&lc_fx_breathing);Define a new effect by implementing render, activate, and color_update callbacks:
typedef struct { /* per-effect state */ } my_ctx_t;
static bool my_render(lc_state_t *s, void *raw) {
my_ctx_t *c = (my_ctx_t *)raw;
lc_fill(s, s->target_color);
return true; // true = pixels changed, flush needed
}
static void my_activate(lc_state_t *s, void *raw) { /* init state */ }
static void my_color_update(lc_state_t *s, void *raw) { /* handle color change */ }
LC_EFFECT_DEFINE(my, LC_EFFECT_FLAG_NONE, my_ctx_t);
// then use it:
lc_set_effect(&lc_fx_my);MIT