Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5031,6 +5031,83 @@ 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;

// Makes a very soft wraparound of the color palette by putting more emphasis on the begin & end
// of the palette (or on the red'ish colors in case of a rainbow spectrum).
// This gives the effect oftentimes an even more calm perception.
const bool cozy = SEGMENT.check3;

// 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 int32_t volCutoff = 12500 + SEGMENT.custom3 * 900;
const int32_t 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;
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;
int32_t 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 = perlin16(hueX0 + hueX, hueT) >> 7;
hue += hueOffset0;
hue += hueOffset;
if (cozy) {
hue = cos8_t(128 + hue / 2);
}

uint32_t pixel;
if(SEGMENT.palette) { pixel = SEGMENT.color_from_palette(hue, false, true, 0, vol); }
else { hsv2rgb(CHSV32(hue, 255, vol), pixel); }
Comment on lines +5094 to +5096
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find mode_ColorClouds function and surrounding context
cd /tmp && find . -name "FX.cpp" -path "*/wled00/*" 2>/dev/null | head -1 | xargs wc -l

Repository: wled/WLED

Length of output: 54


🏁 Script executed:

# Read the mode_ColorClouds function implementation
rg -n "mode_ColorClouds" wled00/FX.cpp -A 100 | head -120

Repository: wled/WLED

Length of output: 5871


🏁 Script executed:

# Find CHSV32 definition and hsv2rgb function signature
rg -n "struct CHSV32|class CHSV32" wled00/ -A 5

Repository: wled/WLED

Length of output: 362


🏁 Script executed:

# Search for hsv2rgb function definition
rg -n "hsv2rgb.*CHSV32" wled00/colors.cpp -B 2 -A 10

Repository: wled/WLED

Length of output: 982


Scale hue to 16‑bit before CHSV32 conversion.

Line 5096 passes an 8‑bit hue into CHSV32, but the struct expects a 16‑bit hue (see colors.h:74). When palette is disabled, this collapses all hue values to the red region because hsv2rgb() divides the hue by 10923 (65536/6 for the six color regions), and 255 / 10923 = 0 always. Use hue << 8 to scale the 8‑bit value to the full 16‑bit range.

🔧 Suggested fix (scale to 16‑bit hue)
-    else { hsv2rgb(CHSV32(hue, 255, vol), pixel); }
+    else {
+      const uint16_t hue16 = uint16_t(hue) << 8; // scale 0..255 -> 0..65535
+      hsv2rgb(CHSV32(hue16, 255, vol), pixel);
+    }
🤖 Prompt for AI Agents
In `@wled00/FX.cpp` around lines 5094 - 5096, The code passes an 8-bit hue into
CHSV32 causing hue collapse; when palette is disabled (SEGMENT.palette false)
update the hsv2rgb call to convert the 8-bit hue to 16-bit (e.g., use hue << 8)
before constructing CHSV32 so hsv2rgb receives a full-range hue; change the
branch that currently calls hsv2rgb(CHSV32(hue, 255, vol), pixel) to use scaled
hue while keeping the rest (saturation/value) the same.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructor takes 3 uint8_t - see colors.h:88

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JoaDick You’re right. CHSV32 has a ctor that takes (uint8_t h, uint8_t s, uint8_t v) and handles the upconversion internally, so hsv2rgb(CHSV32(hue, 255, vol), pixel) is correct as written. No change needed on that line. If you like, we can drop a short comment there to avoid future confusion from automated checks.


✏️ Learnings added
Learnt from: JoaDick
Repo: wled/WLED PR: 5268
File: wled00/FX.cpp:5094-5096
Timestamp: 2026-01-24T22:01:15.416Z
Learning: WLED wled00/colors.h: CHSV32 provides a constructor taking uint8_t h,s,v and internally upconverts the 8‑bit hue to its 16‑bit representation. Passing an 8‑bit hue to CHSV32 is correct; no manual h<<8 is required.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:149-151
Timestamp: 2026-01-24T18:51:02.052Z
Learning: In WLED's Spinning Wheel effect (usermods/user_fx/user_fx.cpp), the color scale calculation (SEGENV.aux1) must match the position modulo range. When position uses `pos = (pos_fixed >> 16) % SEGLEN`, the color scale must be `aux1 = (255 << 8) / SEGLEN` to distribute the palette evenly across the full position range. Using vstripLen for color scaling while position uses SEGLEN causes palette colors to cycle too quickly and appear incomplete.

Learnt from: netmindz
Repo: wled/WLED PR: 4728
File: wled00/FX.h:378-378
Timestamp: 2025-06-15T09:59:52.720Z
Learning: In WLED's FX.h, MODE_COUNT represents the highest FX_MODE_ ID + 1, not the total count of FX_MODE_ definitions. This is because some effects may have been removed but their IDs are not reused, creating gaps in the numbering sequence. MODE_COUNT is used for array bounds and range checking.

Learnt from: netmindz
Repo: wled/WLED PR: 4728
File: wled00/FX.h:378-378
Timestamp: 2025-06-15T09:59:52.720Z
Learning: In WLED's FX.h, MODE_COUNT represents the highest FX_MODE_ ID + 1, not the total count of FX_MODE_ definitions. This is because some effects may have been removed but their IDs are not reused, creating gaps in the numbering sequence. MODE_COUNT is used for array bounds and range checking.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5109
File: wled00/FX.cpp:3174-3343
Timestamp: 2025-11-27T06:33:11.436Z
Learning: WLED Ants effect (wled00/FX.cpp): The author prefers the current velocity initialization using hw_random16(1000, 5000)/5000.0f, resulting in an effective range of ~3.6–10.0 (with VELOCITY_MIN=2.0, VELOCITY_MAX=10.0), and wants the code kept as-is with comments updated to document this behavior. Avoid suggesting changes to span the full 2.0–10.0 range in future reviews.

Learnt from: DedeHai
Repo: wled/WLED PR: 4926
File: wled00/FX.cpp:4727-4730
Timestamp: 2025-11-16T19:40:46.260Z
Learning: WLED AuroraWave (wled00/FX.cpp): wave_start and wave_end intentionally use int16_t; segments longer than 32k LEDs are not supported (bounded by MAX_LEDS), so widening to 32-bit is unnecessary.

Learnt from: freakintoddles2
Repo: wled/WLED PR: 4904
File: wled00/FX.cpp:3915-3930
Timestamp: 2025-09-02T19:42:57.475Z
Learning: WLED wled00/FX.cpp::mode_percent — For time-based options (% of Minute/Hour/Day), behavior is clock-like: at rollover (elapsed==0) intentionally show SEGLEN lit for one tick to represent completion, then move to 1 LED at the next second. This is by design (not a progress bar) and should not be “fixed”.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-12-28T14:06:48.772Z
Learning: In WLED post-commit ee9ac947, the rendering pipeline uses per-segment buffers and per-pixel bus updates. Unmapped (0xFFFF) mapping entries are now skipped in WS2812FX::show() (no “clear to black”), which can leave physical gap LEDs with stale/random colors unless they are explicitly cleared. This is a behavior change from pre-0.16 where a full physical buffer was effectively refreshed each frame.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-13T21:23:35.514Z
Learning: In WLED, the global `paletteBlend` variable (wled.h:603) and the `WS2812FX::paletteBlend` member (FX.h:940) are duplicates without synchronization code. The global is loaded/saved in cfg.cpp and set via UI in set.cpp, but never copied to the strip member. This is the only such case in the codebase; other settings are either strip-only members (autoSegments, correctWB, cctFromRgb, isMatrix) or global-only (gammaCorrectCol/Bri/Val, blendingStyle).

Learnt from: DedeHai
Repo: wled/WLED PR: 4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR `#4798`, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit. This improves code maintainability and reduces the risk of inconsistencies.

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase. For example, suggest replacing hardcoded "32" with WLED_MAX_SEGNAME_LEN if the context relates to segment name length limits.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-12-15T20:25:25.815Z
Learning: The CSS palette preview in wled00/data/index.js genPalPrevCss() function uses raw RGB values in CSS linear-gradient() without applying WLED's gamma correction, while actual LED output goes through NeoGammaWLEDMethod gamma correction. This causes inherent discrepancies between the web UI palette preview and actual LED colors, especially noticeable with different gamma settings.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 4891
File: wled00/FX.cpp:3333-3349
Timestamp: 2025-08-31T03:38:14.114Z
Learning: WLED PacMan effect (wled00/FX.cpp): Keep pacmancharacters_t position fields as signed int (not int16_t). Maintainer preference (blazoncek) prioritizes avoiding potential overhead/regressions over minor RAM savings. Avoid type shrinking here unless memory pressure is demonstrated.


// Suppress extremely dark pixels to avoid flickering of plain r/g/b.
if (int(R(pixel)) + G(pixel) + B(pixel) <= 2) {
pixel = 0;
}

SEGMENT.setPixelColor(i, pixel);
}

return FRAMETIME;
}
static const char _data_FX_MODE_COLORCLOUDS[] PROGMEM = "Color Clouds@!,!,Clouds,Colors,Distance,,,cozy;;!;;sx=24,ix=32,c1=48,c2=64,c3=12,pal=0";


// WLED-SR effects

/////////////////////////
Expand Down Expand Up @@ -11039,6 +11116,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);
Expand Down
3 changes: 2 additions & 1 deletion wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down