From e7c5dcade9cd294c1fa442ee965984415778b0f7 Mon Sep 17 00:00:00 2001 From: Joachim Dick <62520542+JoaDick@users.noreply.github.com> Date: Thu, 16 Oct 2025 21:17:38 +0200 Subject: [PATCH 1/2] New Effect: Color Clouds ColorClouds: Random start points for clouds and color ColorClouds: new config option 'More red' --- wled00/FX.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ wled00/FX.h | 3 ++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 685df03879..b00d37e447 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -5031,6 +5031,79 @@ uint16_t mode_aurora(void) { static const char _data_FX_MODE_AURORA[] PROGMEM = "Aurora@!,!;1,2,3;!;;sx=24,pal=50"; + +/** Softly floating colorful clouds. + * This is a very smooth effect that moves colorful clouds randomly around the LED strip. + * It was initially intended for rather unobtrusive ambient lights (with very slow speed settings). + * Nevertheless, it appears completely different and quite vibrant when the sliders are moved near + * to their limits. No matter in which direction or in which combination... + * Ported to WLED from https://github.com/JoaDick/EyeCandy/blob/master/ColorClouds.h + */ +uint16_t mode_ColorClouds() +{ + // Set random start points for clouds and color. + if(SEGENV.call == 0) { + SEGENV.aux0 = hw_random16(); + SEGENV.aux1 = hw_random16(); + } + const uint32_t volX0 = SEGENV.aux0; + const uint32_t hueX0 = SEGENV.aux1; + const uint8_t hueOffset0 = volX0 + hueX0; + + // Higher values make the clouds move faster. + const uint32_t volSpeed = 1 + SEGMENT.speed; + + // Higher values make the color change faster. + const uint32_t hueSpeed = 1 + SEGMENT.intensity; + + // Higher values make more clouds (but smaller ones). + const uint32_t volSqueeze = 8 + SEGMENT.custom1; + + // Higher values make the clouds more colorful. + const uint32_t hueSqueeze = SEGMENT.custom2; + + // Higher values make larger gaps between the clouds. + const long volCutoff = 2000 + SEGMENT.custom3 * 1250; + + // Put more emphasis on the red'ish colors when true. + const bool moreRed = SEGMENT.check3; + + const uint32_t now = strip.now; + const uint32_t volT = now * volSpeed / 8; + const uint32_t hueT = now * hueSpeed / 8; + const uint8_t hueOffset = beat88(64) >> 8; + + for (int i = 0; i < SEGLEN; i++) { + const uint32_t volX = i * volSqueeze * 64; + long vol = inoise16(volX0 + volX, volT); + vol = map(vol, volCutoff, 46000, 0, 255); + vol = constrain(vol, 0, 255); + + const uint32_t hueX = i * hueSqueeze * 8; + uint8_t hue = inoise16(hueX0 + hueX, hueT) >> 7; + hue += hueOffset0; + hue += hueOffset; + if (moreRed) + { + hue = cos8(128 + hue / 2); + } + + CRGB pixel = CHSV(hue, 255, vol); + // Suppress extremely dark pixels to avoid flickering of plain r/g/b. + // Unfortunately this doesn't work anymore when gamma correction for color is enabled. + // So, when using this effect standalone, also try it without color gamma correction. + if (int(pixel.r) + pixel.g + pixel.b <= 2) { + pixel = CRGB::Black; + } + + SEGMENT.setPixelColor(i, pixel); + } + + return FRAMETIME; +} +static const char _data_FX_MODE_COLORCLOUDS[] PROGMEM = "Color Clouds@Cloud speed,Color speed,Clouds,Colors,Distance,,,More red;;;;sx=24,ix=32,c1=48,c2=64,c3=12"; + + // WLED-SR effects ///////////////////////// @@ -11039,6 +11112,7 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_COLOR_SWEEP_RANDOM, &mode_color_sweep_random, _data_FX_MODE_COLOR_SWEEP_RANDOM); addEffect(FX_MODE_RUNNING_COLOR, &mode_running_color, _data_FX_MODE_RUNNING_COLOR); addEffect(FX_MODE_AURORA, &mode_aurora, _data_FX_MODE_AURORA); + addEffect(FX_MODE_COLORCLOUDS, &mode_ColorClouds, _data_FX_MODE_COLORCLOUDS); addEffect(FX_MODE_RUNNING_RANDOM, &mode_running_random, _data_FX_MODE_RUNNING_RANDOM); addEffect(FX_MODE_LARSON_SCANNER, &mode_larson_scanner, _data_FX_MODE_LARSON_SCANNER); addEffect(FX_MODE_RAIN, &mode_rain, _data_FX_MODE_RAIN); diff --git a/wled00/FX.h b/wled00/FX.h index bcbab69a59..0da18412e0 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -379,7 +379,8 @@ extern byte realtimeMode; // used in getMappedPixelIndex() #define FX_MODE_PS1DSONICBOOM 215 #define FX_MODE_PS1DSPRINGY 216 #define FX_MODE_PARTICLEGALAXY 217 -#define MODE_COUNT 218 +#define FX_MODE_COLORCLOUDS 218 +#define MODE_COUNT 219 #define BLEND_STYLE_FADE 0x00 // universal From 2e78c5a3bac9c9d00c0b95905d5a223cf35ab027 Mon Sep 17 00:00:00 2001 From: Joachim Dick <62520542+JoaDick@users.noreply.github.com> Date: Sun, 4 Jan 2026 20:24:26 +0100 Subject: [PATCH 2/2] ColorClouds: Incorporated review comments - Support for color palettes - Use perlin16() instead of inoise16() - Use cos8_t() instead of cos8() --- wled00/FX.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b00d37e447..d64edf9717 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -5050,6 +5050,9 @@ uint16_t mode_ColorClouds() const uint32_t hueX0 = SEGENV.aux1; const uint8_t hueOffset0 = volX0 + hueX0; + // Put more emphasis on the red'ish colors when true (or begin & end of palette). + const bool moreRed = SEGMENT.check3; + // Higher values make the clouds move faster. const uint32_t volSpeed = 1 + SEGMENT.speed; @@ -5063,10 +5066,9 @@ uint16_t mode_ColorClouds() const uint32_t hueSqueeze = SEGMENT.custom2; // Higher values make larger gaps between the clouds. - const long volCutoff = 2000 + SEGMENT.custom3 * 1250; - - // Put more emphasis on the red'ish colors when true. - const bool moreRed = SEGMENT.check3; + const long volCutoff = 12500 + SEGMENT.custom3 * 900; + const long volSaturate = 52000; + // Note: When adjusting these calculations, ensure that volCutoff is always smaller than volSaturate. const uint32_t now = strip.now; const uint32_t volT = now * volSpeed / 8; @@ -5075,25 +5077,27 @@ uint16_t mode_ColorClouds() for (int i = 0; i < SEGLEN; i++) { const uint32_t volX = i * volSqueeze * 64; - long vol = inoise16(volX0 + volX, volT); - vol = map(vol, volCutoff, 46000, 0, 255); + long vol = perlin16(volX0 + volX, volT); + vol = map(vol, volCutoff, volSaturate, 0, 255); vol = constrain(vol, 0, 255); const uint32_t hueX = i * hueSqueeze * 8; - uint8_t hue = inoise16(hueX0 + hueX, hueT) >> 7; + uint8_t hue = perlin16(hueX0 + hueX, hueT) >> 7; hue += hueOffset0; hue += hueOffset; - if (moreRed) - { - hue = cos8(128 + hue / 2); + if (moreRed) { + hue = cos8_t(128 + hue / 2); } - CRGB pixel = CHSV(hue, 255, vol); + uint32_t pixel; + if(SEGMENT.palette) { pixel = SEGMENT.color_from_palette(hue, false, true, 0, vol); } + else { hsv2rgb(CHSV32(hue, 255, vol), pixel); } + // Suppress extremely dark pixels to avoid flickering of plain r/g/b. - // Unfortunately this doesn't work anymore when gamma correction for color is enabled. + // Unfortunately this doesn't always work properly when gamma correction for color is enabled. // So, when using this effect standalone, also try it without color gamma correction. - if (int(pixel.r) + pixel.g + pixel.b <= 2) { - pixel = CRGB::Black; + if (int(R(pixel)) + G(pixel) + B(pixel) <= 2) { + pixel = 0; } SEGMENT.setPixelColor(i, pixel); @@ -5101,7 +5105,7 @@ uint16_t mode_ColorClouds() return FRAMETIME; } -static const char _data_FX_MODE_COLORCLOUDS[] PROGMEM = "Color Clouds@Cloud speed,Color speed,Clouds,Colors,Distance,,,More red;;;;sx=24,ix=32,c1=48,c2=64,c3=12"; +static const char _data_FX_MODE_COLORCLOUDS[] PROGMEM = "Color Clouds@Cloud speed,Color speed,Clouds,Colors,Distance,,,More red;;!;;sx=24,ix=32,c1=48,c2=64,c3=12,pal=0"; // WLED-SR effects