Skip to content

spots effect accuracy improvements#5341

Draft
softhack007 wants to merge 3 commits intomainfrom
spots_improvement
Draft

spots effect accuracy improvements#5341
softhack007 wants to merge 3 commits intomainfrom
spots_improvement

Conversation

@softhack007
Copy link
Copy Markdown
Member

@softhack007 softhack007 commented Feb 2, 2026

A few improvement for the spots effect, especially relevant for longer strips:

  • avoid gaps on left/right side of strip, by using higher accuracy for "zoneLength"
  • prevent overflows
  • ensure that zones calculations are performed in full 32bit
  • fix wrong slider name in "spots fade"

Summary by CodeRabbit

  • Bug Fixes

    • Improved Spots effect geometry and per-pixel rendering to prevent zero-sized zones, eliminate visual gaps, and ensure stable brightness handling to avoid artifacts.
  • Documentation

    • Updated Spots Fade parameter label from "Spread" to "Speed" for clearer control and better user understanding.

* avoid gaps on left/light side of strip, by using higher accuracy zoneLength
* prevent overflows
* ensure that zones calculation are performed in full 32bit
* fix wrong slider name in "spots fade"
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 2, 2026

📝 Walkthrough

Walkthrough

Reworks Spots Fade zone geometry and per-pixel math to use fixed-point arithmetic, clamps computed zones to at least one, masks brightness to 8 bits before blending, and updates the effect metadata parameter label from "Spread" to "Speed".

Changes

Cohort / File(s) Summary
Spots effect rendering
wled00/FX.cpp
Clamp maxZones ≥ 1, replace integer zone positioning with scaled fixed-point (zoneLen8, scaled offset, per-zone pos), compute pixel index = pos + i, mask brightness scalar s to 8 bits before alpha (& 0xFF), and update _data_FX_MODE_SPOTS_FADE parameter label from "Spread" to "Speed".

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • willmmiles

Poem

🐰
I hopped through code at break of day,
scaled zones and offsets on my way.
Bits tucked tight, no brightness fray,
"Speed" now sings where "Spread" did play.
A tiny hop — the fades obey.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'spots effect accuracy improvements' directly and clearly summarizes the main change: accuracy improvements to the spots effect in the LED strip animation code.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch spots_improvement

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@softhack007 softhack007 added this to the 16.0.0 beta milestone Feb 2, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@wled00/FX.cpp`:
- Around line 2955-2970: The current computation of zoneLen8 uses zones >> 3
which collapses 9–15 to 1 and can make (zones * zoneLen8) >> 3 exceed SEGLEN
causing offset underflow and huge indices; fix by using a true 1/8 fixed‑point
scale (avoid shifts on zones) — compute zoneLen8 as (SEGLEN * 8) / zones (using
a wider integer type to avoid overflow) and compute offset the same way ((SEGLEN
- ((zones * zoneLen8) >> 3)) >> 1); also replace the magic literal 8 with a
named constant like ZONE_FP_SCALE to clarify intent and prevent future errors
(symbols: zoneLen8, offset, zones, SEGLEN).

Comment thread wled00/FX.cpp
* use named constants for fixed point scaling
* remove buggy "SEGLEN / (zones >>3)" shortcut
* remove an unnecessary casts to uint32_t
@softhack007 softhack007 changed the title spots effect improvements spots effect accuracy improvements Feb 2, 2026
@softhack007 softhack007 added effect optimization re-working an existing feature to be faster, or use less memory labels Feb 2, 2026
Copy link
Copy Markdown
Collaborator

@DedeHai DedeHai left a comment

Choose a reason for hiding this comment

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

generally an improvement, there are two issues (one introduced, one unsolved):

  • on small segments, the threshold can be too high, turning off all spots. something like this fixes that but may introduce "breaking changes" I did only a brief test:
  uint16_t maxWave = triwave16(((zoneLen - 1) * 0xFFFF) / zoneLen);
  threshold = min(threshold, uint16_t(maxWave - 1)); // guarantee threshold is always reached (prevent "no spots" on short strips)

to check: use a segment with 15 LEDs, turn speed slider down and intensity slider up.

  • the newly introduced issue is a classic integer math rounding problem: while the spots now spread better, they distribute unevenly. I faced the same dilemma in "PS chase" and used more elaborate code to get both a full spread distribution as well as an even spacing.

Comment thread wled00/FX.cpp
return spots_base(tr);
}
static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width,,,,,Overlay;!,!;!";
static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Speed,Width,,,,,Overlay;!,!;!";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

while you are at it: rename "Width" to "Density" for both variants?

@softhack007
Copy link
Copy Markdown
Member Author

softhack007 commented Feb 4, 2026

the newly introduced issue is a classic integer math rounding problem: while the spots now spread better, they distribute unevenly. I faced the same dilemma in "PS chase" and used more elaborate code to get both a full spread distribution as well as an even spacing.

@DedeHai thanks for your comments 😃 Yes unevenly distributed gaps are a new side-effect. At second look the nested loops with offset re-calcution seem unnecessary, we could also just repeat the tri-wave pattern until the end of strip is reached. Just that the effect might not be centered any more for long "spread" values. I'll think about a better implementation.

Edit: maybe this is better

start with offset = 0.5 * (SEGLEN / pattern_length) // similar to old code, no fixed-point math involved. Could also use float for better accuracy as this is only calculated once per frame
while (SEGLEN - last_position < pattern_length) draw_triwave_pattern

Edit2: 🤔 actually offset calculation is the only "tricky" thing left, because the effect should be centered no matter how long or short the strip really is...

@DedeHai
Copy link
Copy Markdown
Collaborator

DedeHai commented Feb 4, 2026

I need to check that code but in general for long er strips with 100 LEDs+ you will not notice a 1 pixel offset, unless its coarse and you want it aligned to furniture but I guess that is more of an edge case. What is much more noticeable is an irregular pattern.

Edit: with 24V strips and "zones" now coming up more and more, low LED-count segments are not uncommon (I have 64 on mine)

@softhack007 softhack007 self-assigned this Mar 9, 2026
@softhack007 softhack007 marked this pull request as draft March 9, 2026 11:20
@softhack007
Copy link
Copy Markdown
Member Author

@DedeHai I'll make a second attempt on this, you're right that unequally spaced spots look ugly..

@netmindz netmindz modified the milestones: 16.0.0 beta, 16.1 Mar 28, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wled00/FX.cpp`:
- Around line 2921-2935: The loop currently computes a uniform zoneLen (SEGLEN /
zones) but computes per-zone start positions using fractional boundaries (offset
+ ((z * zoneLen8) >> ZONELEN_FP_SHIFT)), causing leftover pixels to become gaps;
change the inner loop to derive each zone's width from the next fractional
boundary instead of reusing zoneLen: compute pos for zone z using the existing
fractional formula (pos = offset + ((z * zoneLen8) >> ZONELEN_FP_SHIFT)) and
posNext for z+1 similarly, then set the per-zone width as zoneWidth = posNext -
pos (for the last zone use SEGLEN - pos), and iterate i from 0 to zoneWidth so
spots fill evenly; update uses of zoneLen and any dependent indexing (variables:
zones, zoneLen, zoneLen8, offset, pos) accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 15da9da6-a7cc-4142-b43b-def235c6c9df

📥 Commits

Reviewing files that changed from the base of the PR and between e2bee4f and d643cef.

📒 Files selected for processing (1)
  • wled00/FX.cpp

Comment thread wled00/FX.cpp
Comment on lines +2921 to +2935
unsigned maxZones = max(1U, SEGLEN >> 2); // prevents "0 zones"
unsigned zones = 1U + ((uint32_t(SEGMENT.intensity) * maxZones) >> 8);
unsigned zoneLen = SEGLEN / zones;
unsigned zoneLen8 = (SEGLEN * ZONELEN_FP_SCALE) / zones; // zoneLength * 8 (fixed‑point) -> avoids gaps at right/left sides
unsigned offset = (SEGLEN - ((zones * zoneLen8) >> ZONELEN_FP_SHIFT)) >> 1;

for (unsigned z = 0; z < zones; z++)
{
unsigned pos = offset + z * zoneLen;
unsigned pos = offset + ((z * zoneLen8) >> ZONELEN_FP_SHIFT);
for (unsigned i = 0; i < zoneLen; i++)
{
unsigned wave = triwave16((i * 0xFFFF) / zoneLen);
if (wave > threshold) {
unsigned index = 0 + pos + i;
unsigned s = (wave - threshold)*255 / (0xFFFF - threshold);
unsigned index = pos + i;
unsigned s = ((wave - threshold)*255 / (0xFFFF - threshold)) & 0xFF; // & 0xFF prevents overflow in next line
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use boundary-derived widths to keep the spots evenly spaced.

Line 2923 still fixes every zone to SEGLEN / zones, while Line 2929 places starts on fractional boundaries. On lengths that do not divide evenly, the leftover pixels turn into visible holes instead of evenly spaced spots. Derive each zone width from the next boundary instead of reusing the truncated integer width.

♻️ Proposed fix
-  unsigned zoneLen  = SEGLEN / zones;
-  unsigned zoneLen8 = (SEGLEN * ZONELEN_FP_SCALE) / zones; // zoneLength * 8 (fixed‑point) -> avoids gaps at right/left sides
-  unsigned offset   = (SEGLEN - ((zones * zoneLen8) >> ZONELEN_FP_SHIFT)) >> 1;
+  unsigned zoneLen8 = (uint32_t(SEGLEN) * ZONELEN_FP_SCALE) / zones; // zoneLength * 8 (fixed-point) -> avoids gaps at right/left sides
+  unsigned offset   = (SEGLEN - ((uint32_t(zones) * zoneLen8) >> ZONELEN_FP_SHIFT)) >> 1;

   for (unsigned z = 0; z < zones; z++)
   {
-    unsigned pos = offset + ((z * zoneLen8) >> ZONELEN_FP_SHIFT);
+    unsigned pos = offset + ((uint32_t(z) * zoneLen8) >> ZONELEN_FP_SHIFT);
+    unsigned nextPos = (z + 1 == zones)
+      ? (SEGLEN - offset)
+      : offset + ((uint32_t(z + 1) * zoneLen8) >> ZONELEN_FP_SHIFT);
+    unsigned zoneLen = nextPos - pos;
     for (unsigned i = 0; i < zoneLen; i++)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/FX.cpp` around lines 2921 - 2935, The loop currently computes a
uniform zoneLen (SEGLEN / zones) but computes per-zone start positions using
fractional boundaries (offset + ((z * zoneLen8) >> ZONELEN_FP_SHIFT)), causing
leftover pixels to become gaps; change the inner loop to derive each zone's
width from the next fractional boundary instead of reusing zoneLen: compute pos
for zone z using the existing fractional formula (pos = offset + ((z * zoneLen8)
>> ZONELEN_FP_SHIFT)) and posNext for z+1 similarly, then set the per-zone width
as zoneWidth = posNext - pos (for the last zone use SEGLEN - pos), and iterate i
from 0 to zoneWidth so spots fill evenly; update uses of zoneLen and any
dependent indexing (variables: zones, zoneLen, zoneLen8, offset, pos)
accordingly.

@softhack007

This comment was marked as outdated.

@coderabbitai

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as duplicate.

@softhack007
Copy link
Copy Markdown
Member Author

@coderabbitai let's take the chance to clean up your learnings:

  • compare your learnings against the new coding guidelines in docs/cpp.instructions.md. Remove learnings that are now fully covered by the guidelines that are made applicable to you via .coderabbit.yaml
  • remove expired/outdated learnings

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 8, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

Let me first fetch the relevant files to compare against the retrieved learnings.


🏁 Script executed:

#!/bin/bash
echo "=== .coderabbit.yaml ==="
cat .coderabbit.yaml 2>/dev/null || echo "NOT FOUND"

echo ""
echo "=== docs/cpp.instructions.md ==="
cat docs/cpp.instructions.md 2>/dev/null || echo "NOT FOUND"

Length of output: 29759


@softhack007 After comparing all retrieved learnings against docs/cpp.instructions.md (applied via .coderabbit.yaml to all *.cpp/*.h/*.hpp/*.ino files), I found two learnings that are now fully covered by the guidelines and are also duplicates of each other:


🗑️ Remove — covered by docs/cpp.instructions.md ("Avoid unexplained magic numbers…")

Both of these say the same thing and are now superseded by the guideline:

"Avoid unexplained 'magic numbers'. Prefer named constants (constexpr) or C-style #define constants for repeated numbers that have the same meaning"


✅ Keep — not covered by guidelines (domain-specific or behavioral knowledge)

All other 12 learnings encode WLED-specific behavioral facts, author preferences, or bug descriptions that are not captured in any guideline file and remain relevant:

ID Topic
377d02d0 mode_dissolveplus: hw_random16(SEGLEN) safe for 1D effects
5c0e30c2 WS2812FX::service(): FX_MODE_STATIC rendering behavior (PR #5443)
e174bc9e Gamma calls in FX.cpp intentional for effect shaping
f885e51b Timestamp assignment stored_time = now + delay is correct for wraparound
621387da Ants effect: velocity init range intentional, don't change
517af376 FMEA approach for reliability/safety mechanism evaluation
a17fbaa8 mode_random_chase(): PRNG advance before prevSeed capture is intentional
1d43d5c1 Post-commit ee9ac94: 0xFFFF unmapped entries left with stale colors
58837130 respondModeData(): 256-char lineBuffer limit is intentional
a76480ab Spinning Wheel: color scale must match position modulo range
da18ae54 startTransition(): rapid toggle bug — stale _t->_start

No other learnings appear expired or outdated based on the current codebase context.


⛔ Learnings removed
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: 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.

🧠 Learnings used
Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5440
File: usermods/user_fx/user_fx.cpp:1304-1313
Timestamp: 2026-03-25T07:03:35.475Z
Learning: In WLED `mode_dissolveplus` (usermods/user_fx/user_fx.cpp), using `hw_random16(SEGLEN)` to select the survivor pixel index is correct and safe for this 1D-only effect. The 0xFFFF unmapped-entry concern from the physical bus mapping does not apply to 1D segments because virtual indices 0..SEGLEN-1 always map to valid physical LEDs without gaps. Do not flag this as a bug in future reviews of 1D effects.

Learnt from: softhack007
Repo: wled/WLED PR: 5443
File: wled00/FX_fcn.cpp:1277-1277
Timestamp: 2026-03-24T12:10:32.630Z
Learning: In WLED's `WS2812FX::service()` (wled00/FX_fcn.cpp), the old condition `|| (doShow && seg.mode == FX_MODE_STATIC)` was an **inclusion** guard — it caused FX_MODE_STATIC to render only when another segment had already set doShow=true. It did NOT skip or protect FX_MODE_STATIC from rendering. The PR `#5443` simplification removes this condition, meaning FX_MODE_STATIC now renders on every `timeToShow` tick uniformly. This is intentional and not a regression. Do not flag FX_MODE_STATIC special-casing as missing in future reviews of this function.

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: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:167-171
Timestamp: 2026-01-13T03:07:20.560Z
Learning: In WLED effects (usermods/user_fx/user_fx.cpp and similar), when storing future timestamps, assignments like `stored_time = now + delay` are correct and handle uint32_t wraparound properly. Only comparison statements need to use subtraction-based elapsed-time checks (e.g., `(now - stored_time) >= delay`). Do not flag assignment statements as needing fixes for wraparound handling.

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: 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: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-03-15T13:21:32.008Z
Learning: In WLED code reviews (and generally), when a PR discussion involves "is this worth doing?" uncertainty about a proposed reliability, safety, or data-integrity mechanism (e.g. CRC checks, backups, power-loss protection), suggest performing a software FMEA (Failure Mode and Effects Analysis). The FMEA should: enumerate failure modes for the feared event, assess each mitigation's effectiveness per failure mode, note common-cause/common-mode failures, and rate credibility for the typical WLED use case. This was successfully used in PR `#5421` to evaluate CRC-based config file protection and was well-received by the WLED maintainers (softhack007 explicitly requested this be remembered for future reviews).

Learnt from: DedeHai
Repo: wled/WLED PR: 4615
File: wled00/FX.cpp:1814-1817
Timestamp: 2026-03-29T07:49:28.820Z
Learning: WLED wled00/FX.cpp::mode_random_chase(): Advancing the shared PRNG before capturing prevSeed on the first call is intentional to decorrelate initial seeds across effects. Do not suggest moving the snapshot earlier; if needed, add a comment to document this behavior.

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: willmmiles
Repo: wled/WLED PR: 5462
File: wled00/json.cpp:1189-1198
Timestamp: 2026-03-30T15:32:08.847Z
Learning: In WLED's `respondModeData()` (wled00/json.cpp), the 256-character `lineBuffer` limit for effect descriptor strings (getModeData) is an intentional constraint that matches the same 256-char limit used ~6 other places in the codebase. It is not new to this PR and should not be flagged as a regression. Lifting it requires a future refactor (better type system or dynamic buffer).

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:149-151
Timestamp: 2026-01-24T18:51:09.740Z
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: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-03-25T12:25:11.610Z
Learning: In WLED's `Segment::startTransition()` (wled00/FX_fcn.cpp:284), when `isInTransition()` is true and `_t->_oldSegment` already exists, the function silently returns without updating `_t->_start` or `_t->_bri`. This causes a bug where rapid successive on/off toggles during a non-FADE blending transition (e.g., fairy dust) leave the transition clock stale: by the time of the second re-trigger, elapsed time may already exceed `_dur`, so `updateTransitionProgress()` sets `_progress = 0xFFFF` immediately on the next service tick and `stopTransition()` fires — the blending effect never plays. The fix is to always reset `_t->_start = millis()`, `_t->_dur = dur`, and `_t->_bri = currentBri()` (current visible brightness) in the `isInTransition()` branch, regardless of whether `_oldSegment` exists.

@softhack007
Copy link
Copy Markdown
Member Author

@coderabbitai please double-check if your learning f885e51b is correct. It sounds like the pattern is not safe against unsigned wrap-around. Personally i would prefer the "millis() - last_time > wait" pattern that is also in your learnings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 8, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

Good question — let me check the exact code context that originally generated learning f885e51b before reaching a conclusion.


🏁 Script executed:

#!/bin/bash
# Check the code context around usermods/user_fx/user_fx.cpp lines 155-185
# that generated the learning
grep -n "stored_time\|last_time\|now + \|millis()\|_delay\|wait\|future\|timestamp" usermods/user_fx/user_fx.cpp | head -60
sed -n '155,185p' usermods/user_fx/user_fx.cpp

Length of output: 2097


Let me check how SLOWDOWN_TIME_IDX is actually compared to understand the full picture.


🏁 Script executed:

#!/bin/bash
# Find how SLOWDOWN_TIME_IDX is used in comparisons
rg -n "SLOWDOWN_TIME_IDX" usermods/user_fx/user_fx.cpp -A2 -B2

Length of output: 822


@softhack007 Your concern is valid. Here's what the code actually does at the comparison site (line 243):

// Assignment (lines 224/226):
state[SLOWDOWN_TIME_IDX] = now + hw_random16(2000, 6000);

// Comparison (line 243):
if ((int32_t)(now - state[SLOWDOWN_TIME_IDX]) >= 0)

The (int32_t)(now - future_time) >= 0 cast trick is safe against wraparound (works correctly for delays < 2³¹ ms ≈ 25 days), which is why the original learning said the assignment was fine. But the learning is misleading because it doesn't make clear that the comparison must use the subtraction/cast form. A reader could easily assume the simpler now >= stored_time works — and it doesn't when now + delay overflows uint32_t (stored_time wraps to a small value, and the condition fires immediately).

The preferred WLED idiom (now - last_time) >= delay is simpler, equally correct, and less error-prone. I'll replace the learning with a clearer one.

⠀⠀⠀⠀⠀⠀⠀⠀⠀
 (\_/)
 (•ㅅ•)  hmm, that was a sneaky one...
 / づ

✏️ Learnings added
Learnt from: softhack007
URL: https://github.com/wled/WLED/pull/5341

Timestamp: 2026-04-08T20:15:18.169Z
Learning: In WLED effects (wled00/FX.cpp, usermods/user_fx/user_fx.cpp, etc.), the preferred safe pattern for elapsed-time checks with uint32_t timestamps is: store `last_time = now` when the event occurs, then check `(now - last_time) >= delay`. This is always safe against uint32_t wraparound. An alternative that also works is `stored_time = now + delay` combined with the comparison `(int32_t)(now - stored_time) >= 0` (safe for delays < 2^31 ms). The naive pattern `stored_time = now + delay; if (now >= stored_time)` is NOT safe against overflow: when `now + delay` wraps past 2^32, `stored_time` becomes numerically smaller than `now` and the condition fires immediately. Do not flag assignments of the form `last_time = now` as needing wraparound fixes; they are correct. Do flag comparisons of the form `now >= stored_time` where stored_time is a future target.

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 removed
Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:167-171
Timestamp: 2026-01-13T03:07:20.560Z
Learning: In WLED effects (usermods/user_fx/user_fx.cpp and similar), when storing future timestamps, assignments like `stored_time = now + delay` are correct and handle uint32_t wraparound properly. Only comparison statements need to use subtraction-based elapsed-time checks (e.g., `(now - stored_time) >= delay`). Do not flag assignment statements as needing fixes for wraparound handling.

🧠 Learnings used
Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5440
File: usermods/user_fx/user_fx.cpp:1304-1313
Timestamp: 2026-03-25T07:03:35.475Z
Learning: In WLED `mode_dissolveplus` (usermods/user_fx/user_fx.cpp), using `hw_random16(SEGLEN)` to select the survivor pixel index is correct and safe for this 1D-only effect. The 0xFFFF unmapped-entry concern from the physical bus mapping does not apply to 1D segments because virtual indices 0..SEGLEN-1 always map to valid physical LEDs without gaps. Do not flag this as a bug in future reviews of 1D effects.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:167-171
Timestamp: 2026-01-13T03:07:20.560Z
Learning: In WLED effects (usermods/user_fx/user_fx.cpp and similar), when storing future timestamps, assignments like `stored_time = now + delay` are correct and handle uint32_t wraparound properly. Only comparison statements need to use subtraction-based elapsed-time checks (e.g., `(now - stored_time) >= delay`). Do not flag assignment statements as needing fixes for wraparound handling.

Learnt from: softhack007
Repo: wled/WLED PR: 5443
File: wled00/FX_fcn.cpp:1277-1277
Timestamp: 2026-03-24T12:10:32.630Z
Learning: In WLED's `WS2812FX::service()` (wled00/FX_fcn.cpp), the old condition `|| (doShow && seg.mode == FX_MODE_STATIC)` was an **inclusion** guard — it caused FX_MODE_STATIC to render only when another segment had already set doShow=true. It did NOT skip or protect FX_MODE_STATIC from rendering. The PR `#5443` simplification removes this condition, meaning FX_MODE_STATIC now renders on every `timeToShow` tick uniformly. This is intentional and not a regression. Do not flag FX_MODE_STATIC special-casing as missing in future reviews of this function.

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: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-03-25T12:25:11.610Z
Learning: In WLED's `Segment::startTransition()` (wled00/FX_fcn.cpp:284), when `isInTransition()` is true and `_t->_oldSegment` already exists, the function silently returns without updating `_t->_start` or `_t->_bri`. This causes a bug where rapid successive on/off toggles during a non-FADE blending transition (e.g., fairy dust) leave the transition clock stale: by the time of the second re-trigger, elapsed time may already exceed `_dur`, so `updateTransitionProgress()` sets `_progress = 0xFFFF` immediately on the next service tick and `stopTransition()` fires — the blending effect never plays. The fix is to always reset `_t->_start = millis()`, `_t->_dur = dur`, and `_t->_bri = currentBri()` (current visible brightness) in the `isInTransition()` branch, regardless of whether `_oldSegment` exists.

Learnt from: DedeHai
Repo: wled/WLED PR: 4615
File: wled00/FX.cpp:1814-1817
Timestamp: 2026-03-29T07:49:28.820Z
Learning: WLED wled00/FX.cpp::mode_random_chase(): Advancing the shared PRNG before capturing prevSeed on the first call is intentional to decorrelate initial seeds across effects. Do not suggest moving the snapshot earlier; if needed, add a comment to document this behavior.

Learnt from: DedeHai
Repo: wled/WLED PR: 4615
File: wled00/FX.cpp:10824-10824
Timestamp: 2026-03-29T06:08:02.547Z
Learning: WLED: In wled00/FX.cpp::mode_slow_transition(), the change-detection logic intentionally compares data->currentCCT to SEGMENT.cct (not data->endCCT). SEGMENT.cct is set to currentCCT at the end of each call; comparing to endCCT would re-initialize the transition on each frame and stall CCT blending. Do not propose changing this.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5440
File: usermods/user_fx/user_fx.cpp:1307-1327
Timestamp: 2026-03-24T07:59:28.661Z
Learning: In WLED's Dissolve Plus effect (usermods/user_fx/user_fx.cpp, mode_dissolveplus), when the "Last one" checkbox (check3/lastOneMode) is turned off while the effect is in PHASE_PAUSE_SURVIVOR, the phase is intentionally NOT immediately reset. The pause expires naturally via the normal delay timing (a few hundred ticks), after which the filling phase begins. PHASE_DISSOLVE_SURVIVOR is reset to PHASE_DISSOLVE and PHASE_FILL_SURVIVOR is reset to PHASE_FILL on toggle-off, but PHASE_PAUSE_SURVIVOR is left to expire on its own. Do not flag this as a bug in future reviews.

Learnt from: softhack007
Repo: wled/WLED PR: 5251
File: usermods/user_fx/user_fx.cpp:225-227
Timestamp: 2026-01-01T13:18:14.738Z
Learning: In WLED effects, when computing time differences between unsigned long timestamps (e.g., `strip.now`, `lastBumpUpdate`), always cast the subtraction result to `int` before converting to `float` to ensure correct behavior on ESP32-C3 (RISC-V). Use pattern: `float(int(timestamp1 - timestamp2))` instead of `float(timestamp1 - timestamp2)`.

Learnt from: DedeHai
Repo: wled/WLED PR: 4889
File: wled00/json.cpp:310-310
Timestamp: 2026-03-21T18:12:09.437Z
Learning: In WLED's `deserializeSegment()` (wled00/json.cpp), the blend mode field `seg.blendMode` is intentionally written without a post-read clamp (`getVal(elem["bm"], seg.blendMode)`). Out-of-range or unsupported blend mode values are handled safely in `WS2812FX::blendSegment()` (wled00/FX_fcn.cpp), which defaults to mode 0 for any unsupported value via a bounds check against the `BLENDMODES` constant. Do not flag the missing clamp in deserializeSegment as a bug in future reviews.

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: willmmiles
Repo: wled/WLED PR: 5462
File: wled00/json.cpp:1189-1198
Timestamp: 2026-03-30T15:32:08.847Z
Learning: In WLED's `respondModeData()` (wled00/json.cpp), the 256-character `lineBuffer` limit for effect descriptor strings (getModeData) is an intentional constraint that matches the same 256-char limit used ~6 other places in the codebase. It is not new to this PR and should not be flagged as a regression. Lifting it requires a future refactor (better type system or dynamic buffer).

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-03-15T13:21:32.008Z
Learning: In WLED code reviews (and generally), when a PR discussion involves "is this worth doing?" uncertainty about a proposed reliability, safety, or data-integrity mechanism (e.g. CRC checks, backups, power-loss protection), suggest performing a software FMEA (Failure Mode and Effects Analysis). The FMEA should: enumerate failure modes for the feared event, assess each mitigation's effectiveness per failure mode, note common-cause/common-mode failures, and rate credibility for the typical WLED use case. This was successfully used in PR `#5421` to evaluate CRC-based config file protection and was well-received by the WLED maintainers (softhack007 explicitly requested this be remembered for future reviews).

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:149-151
Timestamp: 2026-01-24T18:51:09.740Z
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.

@softhack007
Copy link
Copy Markdown
Member Author

@coderabbitai please also check your learnings against the new .github/copilot-instructions.md (applicable via .coderabbit.yaml) and check for learnings that are fully covered and could be removed now.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 8, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== .coderabbit.yaml ==="
cat .coderabbit.yaml 2>/dev/null || echo "NOT FOUND"

echo ""
echo "=== .github/copilot-instructions.md ==="
cat .github/copilot-instructions.md 2>/dev/null || echo "NOT FOUND"

Length of output: 12988


@softhack007 After carefully comparing all retrieved learnings against .github/copilot-instructions.md, I found exactly one learning that is now fully superseded:


🗑️ Remove — fully covered by .github/copilot-instructions.md

Learning 517af376 (FMEA for reliability/safety debates) is now word-for-word covered by the "Supporting Reviews and Discussions" section of .github/copilot-instructions.md:

"For 'is it worth doing?' debates about proposed reliability, safety, or data-integrity mechanisms (CRC checks, backups, power-loss protection): suggest a software FMEA…"

The guideline already enumerates: feared events, failure modes, mitigation effectiveness, common-cause failures, and credibility for the typical WLED use case — everything the learning captured.


✅ All other learnings — keep

All remaining 17 learnings encode WLED-specific behavioral facts, author preferences, or bug descriptions (e.g. startTransition() stale clock bug, Ants velocity range, gamma-shaping intent, LittleFS path limits, mode_dissolveplus phase behavior, etc.) that are not captured anywhere in copilot-instructions.md and remain valuable for future reviews.


⛔ Learnings removed
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-03-15T13:21:32.008Z
Learning: In WLED code reviews (and generally), when a PR discussion involves "is this worth doing?" uncertainty about a proposed reliability, safety, or data-integrity mechanism (e.g. CRC checks, backups, power-loss protection), suggest performing a software FMEA (Failure Mode and Effects Analysis). The FMEA should: enumerate failure modes for the feared event, assess each mitigation's effectiveness per failure mode, note common-cause/common-mode failures, and rate credibility for the typical WLED use case. This was successfully used in PR `#5421` to evaluate CRC-based config file protection and was well-received by the WLED maintainers (softhack007 explicitly requested this be remembered for future reviews).

🧠 Learnings used
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-04-08T20:15:18.169Z
Learning: In WLED effects (wled00/FX.cpp, usermods/user_fx/user_fx.cpp, etc.), the preferred safe pattern for elapsed-time checks with uint32_t timestamps is: store `last_time = now` when the event occurs, then check `(now - last_time) >= delay`. This is always safe against uint32_t wraparound. An alternative that also works is `stored_time = now + delay` combined with the comparison `(int32_t)(now - stored_time) >= 0` (safe for delays < 2^31 ms). The naive pattern `stored_time = now + delay; if (now >= stored_time)` is NOT safe against overflow: when `now + delay` wraps past 2^32, `stored_time` becomes numerically smaller than `now` and the condition fires immediately. Do not flag assignments of the form `last_time = now` as needing wraparound fixes; they are correct. Do flag comparisons of the form `now >= stored_time` where stored_time is a future target.

Learnt from: softhack007
Repo: wled/WLED PR: 5251
File: usermods/user_fx/user_fx.cpp:225-227
Timestamp: 2026-01-01T13:18:14.738Z
Learning: In WLED effects, when computing time differences between unsigned long timestamps (e.g., `strip.now`, `lastBumpUpdate`), always cast the subtraction result to `int` before converting to `float` to ensure correct behavior on ESP32-C3 (RISC-V). Use pattern: `float(int(timestamp1 - timestamp2))` instead of `float(timestamp1 - timestamp2)`.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5440
File: usermods/user_fx/user_fx.cpp:1304-1313
Timestamp: 2026-03-25T07:03:35.475Z
Learning: In WLED `mode_dissolveplus` (usermods/user_fx/user_fx.cpp), using `hw_random16(SEGLEN)` to select the survivor pixel index is correct and safe for this 1D-only effect. The 0xFFFF unmapped-entry concern from the physical bus mapping does not apply to 1D segments because virtual indices 0..SEGLEN-1 always map to valid physical LEDs without gaps. Do not flag this as a bug in future reviews of 1D effects.

Learnt from: softhack007
Repo: wled/WLED PR: 5443
File: wled00/FX_fcn.cpp:1277-1277
Timestamp: 2026-03-24T12:10:32.630Z
Learning: In WLED's `WS2812FX::service()` (wled00/FX_fcn.cpp), the old condition `|| (doShow && seg.mode == FX_MODE_STATIC)` was an **inclusion** guard — it caused FX_MODE_STATIC to render only when another segment had already set doShow=true. It did NOT skip or protect FX_MODE_STATIC from rendering. The PR `#5443` simplification removes this condition, meaning FX_MODE_STATIC now renders on every `timeToShow` tick uniformly. This is intentional and not a regression. Do not flag FX_MODE_STATIC special-casing as missing in future reviews of this function.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-03-25T12:25:11.610Z
Learning: In WLED's `Segment::startTransition()` (wled00/FX_fcn.cpp:284), when `isInTransition()` is true and `_t->_oldSegment` already exists, the function silently returns without updating `_t->_start` or `_t->_bri`. This causes a bug where rapid successive on/off toggles during a non-FADE blending transition (e.g., fairy dust) leave the transition clock stale: by the time of the second re-trigger, elapsed time may already exceed `_dur`, so `updateTransitionProgress()` sets `_progress = 0xFFFF` immediately on the next service tick and `stopTransition()` fires — the blending effect never plays. The fix is to always reset `_t->_start = millis()`, `_t->_dur = dur`, and `_t->_bri = currentBri()` (current visible brightness) in the `isInTransition()` branch, regardless of whether `_oldSegment` exists.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5440
File: usermods/user_fx/user_fx.cpp:1307-1327
Timestamp: 2026-03-24T07:59:28.661Z
Learning: In WLED's Dissolve Plus effect (usermods/user_fx/user_fx.cpp, mode_dissolveplus), when the "Last one" checkbox (check3/lastOneMode) is turned off while the effect is in PHASE_PAUSE_SURVIVOR, the phase is intentionally NOT immediately reset. The pause expires naturally via the normal delay timing (a few hundred ticks), after which the filling phase begins. PHASE_DISSOLVE_SURVIVOR is reset to PHASE_DISSOLVE and PHASE_FILL_SURVIVOR is reset to PHASE_FILL on toggle-off, but PHASE_PAUSE_SURVIVOR is left to expire on its own. Do not flag this as a bug in future reviews.

Learnt from: DedeHai
Repo: wled/WLED PR: 4615
File: wled00/FX.cpp:10824-10824
Timestamp: 2026-03-29T06:08:02.547Z
Learning: WLED: In wled00/FX.cpp::mode_slow_transition(), the change-detection logic intentionally compares data->currentCCT to SEGMENT.cct (not data->endCCT). SEGMENT.cct is set to currentCCT at the end of each call; comparing to endCCT would re-initialize the transition on each frame and stall CCT blending. Do not propose changing this.

Learnt from: DedeHai
Repo: wled/WLED PR: 4615
File: wled00/FX.cpp:1814-1817
Timestamp: 2026-03-29T07:49:28.820Z
Learning: WLED wled00/FX.cpp::mode_random_chase(): Advancing the shared PRNG before capturing prevSeed on the first call is intentional to decorrelate initial seeds across effects. Do not suggest moving the snapshot earlier; if needed, add a comment to document this behavior.

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: 4889
File: wled00/json.cpp:310-310
Timestamp: 2026-03-21T18:12:09.437Z
Learning: In WLED's `deserializeSegment()` (wled00/json.cpp), the blend mode field `seg.blendMode` is intentionally written without a post-read clamp (`getVal(elem["bm"], seg.blendMode)`). Out-of-range or unsupported blend mode values are handled safely in `WS2812FX::blendSegment()` (wled00/FX_fcn.cpp), which defaults to mode 0 for any unsupported value via a bounds check against the `BLENDMODES` constant. Do not flag the missing clamp in deserializeSegment as a bug in future reviews.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-03-15T13:21:32.008Z
Learning: In WLED code reviews (and generally), when a PR discussion involves "is this worth doing?" uncertainty about a proposed reliability, safety, or data-integrity mechanism (e.g. CRC checks, backups, power-loss protection), suggest performing a software FMEA (Failure Mode and Effects Analysis). The FMEA should: enumerate failure modes for the feared event, assess each mitigation's effectiveness per failure mode, note common-cause/common-mode failures, and rate credibility for the typical WLED use case. This was successfully used in PR `#5421` to evaluate CRC-based config file protection and was well-received by the WLED maintainers (softhack007 explicitly requested this be remembered for future reviews).

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:30.955Z
Learning: In WLED code reviews, verify that file operations (especially file.open()) respect LittleFS filename limitations. Assume default WLED configuration with LittleFS default filename limit of 255 bytes. Do not assume extreme configuration values like WLED_MAX_SEGNAME_LEN = 512 which would not be standard configurations.

Learnt from: softhack007
Repo: wled/WLED PR: 4838
File: platformio.ini:149-150
Timestamp: 2026-03-29T16:47:56.452Z
Learning: In WLED PR `#4838` (ESP-IDF V5 branch, platformio.ini): The original FastLED library has been replaced with a custom `fastled-slim` fork. As a result, the `[v5_pioarduino_workaround]` section (containing `lib_archive = yes`) and the commented-out `post:pio-scripts/fastled_cxx_workaround.py` extra script are intentional dead code pending removal after back-to-back testing. Do NOT flag `lib_archive = yes` in `[v5_pioarduino_workaround]` as unreferenced or suggest moving it to active env blocks — the entire section is slated for removal.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, file operations (especially file.open()) should be checked to ensure they respect LittleFS filename limitations. The default LittleFS filename limit is 255 bytes (LFS_NAME_MAX). Reviews should assume default WLED configuration defines and not extreme edge-case values (e.g., WLED_MAX_SEGNAME_LEN = 512 would not be standard). File paths should be validated to stay within the 255-byte limit.

Learnt from: softhack007
Repo: wled/WLED PR: 5480
File: docs/cpp.instructions.md:511-511
Timestamp: 2026-04-08T19:10:48.754Z
Learning: In WLED documentation and review guidance (`docs/cpp.instructions.md`), using `WLED_MAX_SEGNAME_LEN = 64` as the example value in LittleFS filename-length checks is intentional and correct. The reasoning: ESP32 uses 64-char segment names (the larger default), and if a constructed path (e.g. `/ledmap_` + segment name + `.json`) stays within 255 bytes when the name is 64 chars, it is trivially safe on ESP8266 where segment names are limited to 32 chars. WLED core has no ESP8266-only features, so validating against the larger ESP32 default is the right cross-platform conservative choice. Do NOT flag `WLED_MAX_SEGNAME_LEN = 64` in this guidance as misleading or platform-specific.

Learnt from: willmmiles
Repo: wled/WLED PR: 5462
File: wled00/json.cpp:1189-1198
Timestamp: 2026-03-30T15:32:08.847Z
Learning: In WLED's `respondModeData()` (wled00/json.cpp), the 256-character `lineBuffer` limit for effect descriptor strings (getModeData) is an intentional constraint that matches the same 256-char limit used ~6 other places in the codebase. It is not new to this PR and should not be flagged as a regression. Lifting it requires a future refactor (better type system or dynamic buffer).

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:149-151
Timestamp: 2026-01-24T18:51:09.740Z
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effect optimization re-working an existing feature to be faster, or use less memory

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants