Repository navigation
Safari/webkit browsers show 2D transitions for 1D segments ( correctly hidden on PC) #5498
Description
Activity
screenshots please.
- addedcannot reproduceDevelopers are not able reproduce. Might be fixed already, or report is missing important detailsDevelopers are not able reproduce. Might be fixed already, or report is missing important details
on Apr 12, 2026 one shows 2D options, one shows 1D options. same setup? which browser?
Chrome browser.
Where do you see & adjust what dimension the transition is?
Where do you see & adjust what dimension the transition is?
He is talking about the dimensions of the LED device. If it's a 1D strip, it will have the 8 transition options. But if it's a 2D matrix, it will have a lot more transition options. So the device in your first screenshot is a 2D device (ip 192.168.86.111) and the second screenshot is for a 1D device.
Why does the mobile UI show 2D options and the desktop web UI show 1D options?
now asking the important questions :)
I tested what you proposed in your opening statement, and I see 2D options on both or 1D option on both.
I don't understand this statement, "and I see 2D options on both or 1D option on both." Can you clarify what you're saying for me?
if I connect to an ESP that has a 2D setup, I see the 2D options for transitions, on both mobile and PC.
Hrmm, I'm connecting to the same controller on both mobile and desktop yet I get different transition options.
I have zero 2D LED's, is there somewhere I can force WLED to only show me the 1D options?
@coderabbitai is there any reason the UI would show the options for 2D transistions on a setup that does not have 2D enabled?
Reacted by coderabbitai@remixmark github is to track bugs, if you have useability questions please move those to the forum or discord.
19 remaining items
coderabbitai commented
on Apr 16, 2026 coderabbitaiboton Apr 16, 2026 – with coderabbitaiContributorMore actions🧩 Analysis chain
@coderabbitai please give me the full code analysis, you got cut off once more
Reacted by coderabbitaicoderabbitai commented
on Apr 16, 2026 coderabbitaiboton Apr 16, 2026 – with coderabbitaiContributorMore actions🧩 Analysis chain
Lines 664–668 of
index.jscallo.style.display='none'on individual<option>elements, which iOS Safari/WebKit silently ignores because it renders<select>as a native picker.@coderabbitai please double-check your statement. Is this based on known difference between IOS / safari and chrome or firefox? Is hiding a select option via "display:none" allowed according to CSS and HTML standards?
Reacted by coderabbitaicoderabbitai commented
on Apr 16, 2026 coderabbitaiboton Apr 16, 2026 – with coderabbitaiContributorMore actions@softhack007— good catch, and thank you for pushing on this. My previous statement was directionally correct for iOS but oversimplified the broader picture. Here's the accurate, complete answer:1. Is it allowed by CSS/HTML standards?
The answer is: the spec explicitly does not guarantee it works. The HTML specification notes that user agents may "ignore certain CSS properties" on
<option>elements, as they are often implemented as platform-native controls. So applyingdisplay:noneto an<option>is not formally prohibited, but the spec provides no guarantee that browsers must honour it. This is a long-standing gap in the specification.2. Is it a known iOS/Safari-specific problem, or broader?
It is broader than just iOS. The behaviour is inconsistent across all major browsers and has been for years — the inconsistency is just most severe and most predictable on iOS:
- The CSS
display:noneis said to be fully supported on Safari for iOS per MDN browser-compat data, while it does not actually work on<option>HTML elements — the option is displayed on Safari for iOS regardless. - You cannot toggle
displayon<option>elements in Safari (including macOS Safari). This is part of a long and inconsistent tradition of Safari restricting CSS styling functionality on form elements, as it believes the visual language of interactive elements should be consistent with the OS. - Both Chrome and Safari on iOS devices display
<option>elements that havedisplay:none(or Bootstrap'sd-noneclass) — confirming this is an iOS platform issue affecting all browsers on that platform, since all iOS browsers must use WebKit. - Setting
display:nonedoes not remove an element from the DOM, it just hides it from the visual media — and since<option>elements are "still bound to the parent select element as an option," browsers may still show and allow selecting them.
Summary for the WLED case:
My earlier statement that "iOS WebKit ignores
display:noneon<option>" was correct, but incomplete. More precisely:Platform display:noneon<option>iOS Safari / iOS Chrome ❌ Does not work (confirmed) macOS Safari ❌ Does not work Desktop Chrome Inconsistent (has varied across versions) Desktop Firefox Generally works The HTML spec gives browsers explicit latitude to ignore CSS on form controls, so this behaviour is not a standards violation — it is undefined territory. The only reliable, cross-browser approach is DOM removal (
replaceChildren()oroption.remove()), as described in the fix I proposed earlier. That fix remains correct and is actually more broadly beneficial than just "fixing the iOS issue."
🧠 Learnings used
Learnt from: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-08T00:57:36.134Z Learning: In WLED (wled00/cfg.cpp), `deserializeConfig()` is called with an empty JsonObject when cfg.json doesn't exist on fresh install. Any value read without the ArduinoJSON `|` fallback operator or CJSON macro will override correct constructor defaults with 0/null. Known affected values: `strip.setTargetFps(hw_led["fps"])` at line 179 (sets FPS to 0/unlimited instead of WLED_FPS=42). Fix: `strip.setTargetFps(hw_led["fps"] | WLED_FPS)`. The gamma issue (gammaCorrectCol/Bri) had the same root cause and was fixed in commit d1d9dec402 (Jan 2026) using inline `| default` fallbacks.
Learnt from: DedeHai Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-04-15T15:54:12.393Z Learning: In WLED (wled00/FX_fcn.cpp), when `ledmap.json` (index 0) contains `width` or `height` fields, setting `isMatrix = true` and updating `Segment::maxWidth`/`maxHeight` is intentional and correct behaviour — a ledmap with those fields is by definition a 2D setup. Do not flag this as an unexpected or unintended trigger for 2D mode 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: 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: 2026-04-10T16:10:42.477Z Learning: In WLED (wled/WLED), the segments vector (`strip.segments`) is highly volatile: preset loads, effect changes, and JSON state updates in json.cpp can add/remove/reorder segments and change their active status at any time. Segments have no stable persistent identifier — only their ordinal index in the vector, which also changes. Code that tries to maintain a discovery-time binding from an external protocol (e.g., Espalexa/Alexa) to a specific segment using ordinal-among-active-segments as a key will silently map to wrong segments after any preset load. A correct implementation must store the init-time segment-index-to-device mapping explicitly and guard against the segment at that index changing identity after a vector rebuild.
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: 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: softhack007 Repo: wled/WLED PR: 5482 File: wled00/wled.h:579-579 Timestamp: 2026-04-08T21:25:44.777Z Learning: In WLED PR `#5482` (wled00/wled.h), the `denyWsecUpload` flag is confirmed to default to `false`. The complementary defence against malformed wsec.json content (bootloop/brick risk from malformed JSON) is handled by PR `#5484`, which hardens JSON file reading/parsing at load time. Do not suggest moving `denyWsecUpload` default to `true` or replacing JSON validation with upload blocking — both mechanisms serve different purposes and should coexist.
Learnt from: DedeHai Repo: wled/WLED PR: 4939 File: wled00/FX_fcn.cpp:1176-1187 Timestamp: 2025-09-16T18:08:42.848Z Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), intentionally allowing memory overruns when bus configurations exceed MAX_LED_MEMORY is a deliberate design choice. The trade-off prioritizes creating buses with reduced LED counts over completely failing to create buses, which would cause no LED output and UI failures. This approach forces users to update configurations after migrating to version 0.16 while maintaining basic functionality.
Learnt from: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-08T00:57:36.134Z Learning: In WLED (wled00/cfg.cpp), `deserializeConfigFromFS()` only sets `needsSave=true` (triggering a write of cfg.json) when usermod settings are present in the JSON (lines 758-761). On a fresh install with no usermods, `needsSave=false` so `serializeConfigToFS()` is never called at first boot. Correct defaults are never written to cfg.json until the user manually saves. Structural fix: set `needsSave = needsSave || !cfgExists` where `cfgExists = WLED_FS.exists(s_cfg_json)` checked before reading the file.
Learnt from: DedeHai Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-04-16T05:47:40.778Z Learning: In WLED (wled00/data/index.js), the `#bs` select element hides 2D blend/transition options via `option.style.display='none'`. iOS Safari (and all iOS browsers, which use WebKit) ignores `display:none` on `<option>` elements because the native iOS picker renders all DOM-present options regardless of their CSS. The correct fix is to remove 2D options from the DOM entirely using `replaceChildren()` with a pre-snapshot array (`bsOpts`), rather than toggling `style.display`. The snapshot should be taken lazily on the first `loadInfo()` call, when all options are still present in the HTML.
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: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-29T20:58:20.394Z Learning: In WLED PR `#5048`, /json/net is generated by wled00/json.cpp::serializeNetworks(), which now includes ssid, rssi, bssid, channel, and enc for each scanned network. Any “Ch undefined” in the UI applies only to legacy builds or empty-scan states.
Learnt from: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-29T20:58:20.394Z Learning: In WLED PR `#5048`, /json/net is generated by wled00/json.cpp::serializeNetworks(). It serializes for each network: ssid, rssi, bssid, and channel (node["channel"] is set inside the loop). UI pages (settings_wifi.htm) should rely on this field rather than guard for "undefined" except for legacy builds.
Learnt from: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-29T20:58:20.394Z Learning: In WLED PR `#5048`, /json/net is produced by wled00/json.cpp::serializeNetworks(), which serializes ssid, rssi, bssid, and channel (node["channel"] is set in the loop). The UI can rely on this field; “Ch undefined” only applies to legacy builds that predate this addition.
Learnt from: blazoncek Repo: wled/WLED PR: 4482 File: wled00/udp.cpp:147-149 Timestamp: 2025-02-19T12:43:34.199Z Learning: ESP8266 and ESP32 platforms have different maximum segment name lengths in WLED, which can cause truncation when syncing segment names between devices. This platform difference affects the user experience when using the segment name sync feature.
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: 5464 File: wled00/FX_fcn.cpp:1699-1701 Timestamp: 2026-04-09T07:26:14.510Z Learning: In WLED (wled00/util.cpp), `allocate_buffer()` processes `BFRALLOC_NOBYTEACCESS` in an `if` with an `else` that covers all other flags. On classic ESP32, this means `BFRALLOC_ENFORCE_PSRAM` and `BFRALLOC_PREFER_PSRAM` are silently ignored when `BFRALLOC_NOBYTEACCESS` is also set — IRAM (MALLOC_CAP_32BIT) is always tried first. Combining `BFRALLOC_CLEAR | BFRALLOC_NOBYTEACCESS` is unsafe: the allocator's internal `memset` at util.cpp:901 will perform byte-level access on a potentially IRAM-resident buffer. This affects `Segment::pixels` in `setGeometry()` (FX.h) and `_pixels` in `finalizeInit()` (FX_fcn.cpp). Additionally, `memcpy` on `Segment::pixels` in the copy constructor and copy assignment (FX_fcn.cpp lines ~73 and ~116) is also a byte-level violation when the buffer is in IRAM. The safe pattern is element-wise 32-bit access (for loops over `uint32_t*`) rather than `memset`/`memcpy` for all `BFRALLOC_NOBYTEACCESS` buffers.
Learnt from: DedeHai Repo: wled/WLED PR: 4923 File: wled00/FX.cpp:4883-4901 Timestamp: 2025-09-12T17:29:43.826Z Learning: In WLED’s web UI, only one slider value (e.g., SEGMENT.intensity or SEGMENT.custom1) changes at a time; code relying on this may use simplified change guards, though presets/JSON can still update multiple fields atomically.
Learnt from: softhack007 Repo: wled/WLED PR: 5480 File: docs/cpp.instructions.md:511-511 Timestamp: 2026-04-08T19:10:52.197Z 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: softhack007 Repo: wled/WLED PR: 5457 File: usermods/zigbee_rgb_light/usermod_zigbee_rgb_light.h:0-0 Timestamp: 2026-03-31T17:31:01.023Z Learning: In WLED PR `#5457` (zigbee_rgb_light usermod): The WLED_MAX_DIGITAL_CHANNELS=0 build flag used in the esp32c6_zigbee environment is a temporary workaround for rmt_tx_wait_all_done() timeout spam when the Zigbee/802.15.4 stack is active. The root cause is under investigation and is likely related to Zigbee light-sleep (CONFIG_PM_ENABLE) disrupting RMT's internal time base, or ISR latency due to cache-disable during flash ops — NOT the 802.15.4 radio "sharing" the RMT peripheral (they are separate hardware). Because a proper fix (rmt_enable()/rmt_disable() PM-lock wrapping, allow_pd=0, CONFIG_RMT_TX_ISR_CACHE_SAFE) may eliminate the need to disable digital channels entirely, do NOT add a compile-time `#error` guard requiring WLED_MAX_DIGITAL_CHANNELS=0; doing so would prematurely bake in a constraint that may be lifted once the investigation concludes.
Learnt from: DedeHai Repo: wled/WLED PR: 5464 File: wled00/FX_fcn.cpp:1699-1701 Timestamp: 2026-04-09T09:14:32.589Z Learning: In WLED, pixel buffers allocated with `BFRALLOC_NOBYTEACCESS` (both `WS2812FX::_pixels` and `Segment::pixels`) are intentionally placed in 32-bit-only accessible IRAM by design. Buffers up to ~1000 LEDs (~4 kB) easily fit within IRAM's ~50 kB pool. `memset` and `memcpy` on these buffers work correctly in practice because the Xtensa newlib assembly implementations use 32-bit stores for word-aligned, word-multiple-size buffers — satisfying the IRAM hardware constraint as an implementation property of the assembly code, which is unlikely to change across IDF versions. The risk of a future violation exists but is accepted as very low. Do not flag `memset`/`memcpy` usage on `BFRALLOC_NOBYTEACCESS` pixel buffers as a critical bug in WLED reviews; note it as a low-risk accepted pattern.
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: 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: 4889 File: wled00/FX_fcn.cpp:1380-1399 Timestamp: 2026-03-21T17:47:53.826Z Learning: In WLED's stencil blend mode (case 16 in `WS2812FX::blendSegment()`, `wled00/FX_fcn.cpp`), the transparency key is intentionally hardcoded to black (`t ? t : b`), not the segment's background color (`colors[1]`). This is a deliberate design choice to avoid additional parameters and overhead. It is the user's responsibility to not use a non-black background in combination with stencil mode. Do not flag this as a bug in future reviews.
Learnt from: softhack007 Repo: wled/WLED PR: 5482 File: wled00/wled.h:579-579 Timestamp: 2026-04-08T21:23:19.258Z Learning: In WLED PR `#5482` (wled00/wled.h), the `denyWsecUpload` flag MUST default to `false` (not `true`). Rationale confirmed via FMEA by softhack007: 1. Circular-dependency risk: `denyWsecUpload` is stored inside `wsec.json`; if that file is corrupted/deleted, `_INIT(true)` would permanently block the upload-recovery path without serial access. 2. Upgrade safety: `_INIT(true)` would silently break wsec.json upload recovery on all existing installations after a firmware upgrade. 3. Recovery parity: uploading wsec.json does not expose previous secrets; it is a legitimate recovery mechanism (e.g., after a flash wipe). The flag is valuable as an optional hardening opt-in for installations that do not need the upload-recovery path. The real defence against malformed-JSON bootloops should be input validation at load time, not upload blocking.
Learnt from: softhack007 Repo: wled/WLED PR: 5048 File: wled00/set.cpp:551-555 Timestamp: 2026-03-27T21:00:25.902Z Learning: In WLED PR `#5048` (wled00/set.cpp lines 551-555), the CONFIG_IDF_TARGET_ESP32C5 block that unconditionally forces ntpEnabled = false is an intentional **temporary hotfix** by softhack007 for a known ESP32-C5 crash: `assert failed: udp_new_ip_type udp.c:1278 (Required to lock TCPIP core functionality!)`. Do not flag this as a permanent design issue; the TODO comment in the code already notes it should be resolved properly once the underlying IDF/TCPIP bug on C5 is fixed. A future permanent solution should use a target capability flag rather than overwriting the user's setting.
Learnt from: DedeHai Repo: wled/WLED PR: 4939 File: wled00/data/index.js:2406-2413 Timestamp: 2025-09-28T09:53:42.670Z Learning: In WLED, code paths that appear unreachable may actually be safety fallbacks for low-heap conditions. These fallbacks are intentional defensive programming measures to ensure UI functionality is preserved when system resources are constrained.- The CSS
-
please check if settings_leds.htm or other settings pages are affected by the same problem
-
is there a standard compliant (and simple) method to reliably remove entries from a selection list?
Reacted by coderabbitai-
coderabbitai commented
on Apr 16, 2026 coderabbitaiboton Apr 16, 2026 – with coderabbitaiContributorMore actions🧩 Analysis chain
@softhack007Here’s the full check and the answer to both points:
Are settings_leds.htm or other settings pages affected?
-
Scan summary:
- No settings page toggles visibility of via style.display.
- settings_leds.htm uses the standard .disabled = true/false approach on elements and never sets option.style.display. This is iOS‑safe (visible but unselectable).
- No other settings_*.htm file uses option.style.display either.
-
File/line references from the scan:
- settings_leds.htm uses helpers that operate via the disabled attribute on options (e.g., disable/enable with sel.querySelectorAll('option[...]').forEach(o => o.disabled = true/false)). There are no occurrences of option.style.display in settings_leds.htm (see script output around Lines 940–1010 and the surrounding matches).
- The only place using style.display on in the whole UI is in wled00/data/index.js where 2D transition options for
#bsare shown/hidden. That’s the area we already discussed as problematic on iOS.
Conclusion: Only the index.js
#bsdropdown is affected. settings_leds.htm and the rest of the settings pages are not impacted by the iOS/WebKit limitation.A standard‑compliant, simple way to reliably remove entries from a selection list
Use DOM removal/rebuild (not CSS) so all browsers, including iOS WebKit, only render the allowed elements.
Pattern you can drop in anywhere:
- Snapshot once, then filter and rebuild
- Snapshot original options once (first time you need to filter) so you can swap between filtered and full lists later.
- Replace children with only the allowed options.
- Preserve the current selection if it’s still present; otherwise, fall back to a safe default.
Example:
// one-time snapshot when the page first learns device capabilities let selectAllOptions = null; function snapshotOptionsOnce(selectEl) { if (!selectAllOptions) { // Deep clones preserve text, value, dataset, disabled, etc. selectAllOptions = Array.from(selectEl.options).map(o => o.cloneNode(true)); } } function setSelectAllowed(selectEl, predicate, { fallbackValue = "" } = {}) { snapshotOptionsOnce(selectEl); // Build the new list from the snapshot const kept = selectAllOptions .filter(predicate) // e.g., o => is2D || o.dataset.type !== "2D" .map(o => o.cloneNode(true)); // never move originals out of the snapshot // Replace options atomically selectEl.replaceChildren(...kept); // Restore selection if possible, else fall back const prev = selectEl.value; if (!Array.from(selectEl.options).some(o => o.value === prev)) { // preferred fallback, else first option if missing const fb = Array.from(selectEl.options).some(o => o.value === String(fallbackValue)) ? String(fallbackValue) : (selectEl.options[0]?.value ?? ""); selectEl.value = fb; } else { selectEl.value = prev; } }
Usage for the
#bsdropdown (exactly what you need today):// Example: hide all 2D-only transitions when not a matrix const bs = gId('bs'); setSelectAllowed(bs, o => isM || o.dataset.type !== '2D', { fallbackValue: 0 /* Fade */ });
Notes:
- This is standards‑compliant (pure DOM operations) and works uniformly on iOS, Android, macOS, Windows, Chrome, Safari, Firefox, etc.
- If merely preventing selection (while still showing the items) is acceptable, using o.disabled = true is also standards‑compliant and iOS‑safe. But it does not remove items from the iOS native picker UI; they’ll still be listed (greyed out). For fully removing from the list, prefer DOM removal as above.
If you want, I can prep a minimal patch for index.js that switches the current option.style.display approach on
#bsto this replaceChildren() pattern.
🏁 Script executed:
#!/bin/bash set -e echo "== List settings pages ==" fd -p -i --full-path 'wled00/data/settings*.htm' | sort echo echo "== Any occurrences of option.style.display / style.display applied to option across data/ ==" rg -nPI --no-heading '(querySelectorAll\s*\(\s*[\'"]option|<option\b).*?style\.display|style\.display.*option' wled00/data | sed -n '1,160p' echo echo "== All style.display assignments in JS/HTM under data/ ==" rg -nPI --no-heading '\.style\.display\s*=' wled00/data | sed -n '1,200p' echo echo "== settings_leds.htm: show lines around option manipulation ==" # Show a reasonable window around potential helper functions and option logic rg -nPI --no-heading 'querySelectorAll\s*\(\s*[\'"]option|disabled\s*=' wled00/data/settings_leds.htm -n -C3 | sed -n '1,240p' echo echo "== settings_leds.htm: dump 940-1010 to capture helper defs and usage ==" sed -n '940,1010p' wled00/data/settings_leds.htm echo echo "== Other settings pages: scan for option handling / style.display ==" for f in $(fd -p -i --full-path 'wled00/data/settings*.htm'); do echo "--- $f ---" rg -nPI --no-heading 'querySelectorAll\s*\(\s*[\'"]option|<option\b|style\.display\s*=' "$f" -n -C2 || true done echo echo "== index.js: confirm the `#bs` option show/hide block ==" rg -nPI --no-heading 'option\[data-type="2D"\]|gId\([\'"]bs[\'"]\)|isM\s*=' wled00/data/index.js -n -C3 | sed -n '1,240p'Length of output: 760
🏁 Script executed:
#!/bin/bash set -e echo "== Settings pages present ==" fd -p -i --full-path 'wled00/data/settings*.htm' | sort || true echo echo "== All occurrences of style.display assignments under data/ (with context) ==" rg -nP --no-heading '\.style\s*\.\s*display\s*=' wled00/data -C3 || true echo echo "== Any lines that both mention <option> and style.display (HTML/JS) ==" rg -nP --no-heading '(?:<option\b.*?style\s*=)|(?:option[^\n]{0,200}\.style\s*\.\s*display\s*=)|(?:style\s*\.\s*display[^\n]{0,200}option)' wled00/data -C2 || true echo echo "== All places that programmatically iterate over <option> elements ==" rg -nP --no-heading 'querySelectorAll\s*\(\s*[\"\']option|\.options\b|new\s+Option\s*\(' wled00/data -C2 || true echo echo "== settings.htm: show any option-handling (disabled/display) ==" rg -nP --no-heading 'querySelectorAll\s*\(\s*[\"\']option|disabled\s*=|style\s*\.\s*display\s*=' wled00/data/settings.htm -C3 || true echo echo "== settings.htm: list selects/options snippet ==" rg -nN --no-heading '<select|<option' wled00/data/settings.htm -n -C2 | sed -n '1,200p' || true echo echo "== index.js: confirm `#bs` and data-type=2D logic ==" rg -nP --no-heading 'gId\s*\(\s*[\"\']bs[\"\']\s*\)|data-type\s*=\s*[\"\']2D[\"\']|isM\s*=' wled00/data/index.js -C3 || trueLength of output: 52116
@softhack007Scope check (settings pages)
- Affected: Only wled00/data/index.js uses style.display on elements:
- Line 665: gId('bs').querySelectorAll('option[data-type="2D"]').forEach(o => { o.style.display = 'none'; });
- Line 668: ... o.style.display = '';
- Not affected: All settings pages (settings_*.htm) toggle containers or messages via style.display, not individual s. Where options are altered, they use .disabled (which is iOS‑safe). Example:
- wled00/data/settings_leds.htm:337 — gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t);
Conclusion: The iOS/WebKit “can’t hide
<option>” problem is confined to the#bsdropdown in index.js; settings pages are not impacted.Standard‑compliant, simple way to remove entries from a
<select>- Do not rely on CSS. Remove/rebuild the option nodes in the DOM. This is fully standard (HTML/DOM) and works across Safari/WebKit (including iOS), Chrome, and Firefox.
Drop‑in helper:
let snapshotAll = null; function setSelectAllowed(selectEl, predicate, { fallbackValue = "0" } = {}) { if (!snapshotAll) snapshotAll = Array.from(selectEl.options).map(o => o.cloneNode(true)); const prev = selectEl.value; const kept = snapshotAll .filter(predicate) // e.g. (o) => isMatrix || o.dataset.type !== "2D" .map(o => o.cloneNode(true)); // clone so snapshot stays intact selectEl.replaceChildren(...kept); // restore selection if possible, otherwise fall back if (!Array.from(selectEl.options).some(o => o.value === prev)) { selectEl.value = Array.from(selectEl.options).some(o => o.value === String(fallbackValue)) ? String(fallbackValue) : (selectEl.options[0]?.value ?? ""); } else { selectEl.value = prev; } }
Usage for
#bsin index.js:const bs = gId('bs'); setSelectAllowed(bs, o => isM || o.dataset.type !== '2D', { fallbackValue: 0 }); // 0 = Fade
Note
- If it’s acceptable to show but not allow selection, using o.disabled = true is also standards‑compliant and iOS‑safe — but it won’t hide items in iOS’ native picker UI. DOM removal (above) is the reliable “hide” behavior.
🧠 Learnings used
Learnt from: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-08T00:57:36.134Z Learning: In WLED (wled00/cfg.cpp), `deserializeConfig()` is called with an empty JsonObject when cfg.json doesn't exist on fresh install. Any value read without the ArduinoJSON `|` fallback operator or CJSON macro will override correct constructor defaults with 0/null. Known affected values: `strip.setTargetFps(hw_led["fps"])` at line 179 (sets FPS to 0/unlimited instead of WLED_FPS=42). Fix: `strip.setTargetFps(hw_led["fps"] | WLED_FPS)`. The gamma issue (gammaCorrectCol/Bri) had the same root cause and was fixed in commit d1d9dec402 (Jan 2026) using inline `| default` fallbacks.
Learnt from: DedeHai Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-04-15T15:54:12.393Z Learning: In WLED (wled00/FX_fcn.cpp), when `ledmap.json` (index 0) contains `width` or `height` fields, setting `isMatrix = true` and updating `Segment::maxWidth`/`maxHeight` is intentional and correct behaviour — a ledmap with those fields is by definition a 2D setup. Do not flag this as an unexpected or unintended trigger for 2D mode 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: 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-04-10T16:10:42.477Z Learning: In WLED (wled/WLED), the segments vector (`strip.segments`) is highly volatile: preset loads, effect changes, and JSON state updates in json.cpp can add/remove/reorder segments and change their active status at any time. Segments have no stable persistent identifier — only their ordinal index in the vector, which also changes. Code that tries to maintain a discovery-time binding from an external protocol (e.g., Espalexa/Alexa) to a specific segment using ordinal-among-active-segments as a key will silently map to wrong segments after any preset load. A correct implementation must store the init-time segment-index-to-device mapping explicitly and guard against the segment at that index changing identity after a vector rebuild.
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: 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: softhack007 Repo: wled/WLED PR: 5482 File: wled00/wled.h:579-579 Timestamp: 2026-04-08T21:25:44.777Z Learning: In WLED PR `#5482` (wled00/wled.h), the `denyWsecUpload` flag is confirmed to default to `false`. The complementary defence against malformed wsec.json content (bootloop/brick risk from malformed JSON) is handled by PR `#5484`, which hardens JSON file reading/parsing at load time. Do not suggest moving `denyWsecUpload` default to `true` or replacing JSON validation with upload blocking — both mechanisms serve different purposes and should coexist.
Learnt from: DedeHai Repo: wled/WLED PR: 4939 File: wled00/FX_fcn.cpp:1176-1187 Timestamp: 2025-09-16T18:08:42.848Z Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), intentionally allowing memory overruns when bus configurations exceed MAX_LED_MEMORY is a deliberate design choice. The trade-off prioritizes creating buses with reduced LED counts over completely failing to create buses, which would cause no LED output and UI failures. This approach forces users to update configurations after migrating to version 0.16 while maintaining basic functionality.
Learnt from: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-08T00:57:36.134Z Learning: In WLED (wled00/cfg.cpp), `deserializeConfigFromFS()` only sets `needsSave=true` (triggering a write of cfg.json) when usermod settings are present in the JSON (lines 758-761). On a fresh install with no usermods, `needsSave=false` so `serializeConfigToFS()` is never called at first boot. Correct defaults are never written to cfg.json until the user manually saves. Structural fix: set `needsSave = needsSave || !cfgExists` where `cfgExists = WLED_FS.exists(s_cfg_json)` checked before reading the file.
Learnt from: DedeHai Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-04-16T05:47:40.778Z Learning: In WLED (wled00/data/index.js), the `#bs` select element hides 2D blend/transition options via `option.style.display='none'`. iOS Safari (and all iOS browsers, which use WebKit) ignores `display:none` on `<option>` elements because the native iOS picker renders all DOM-present options regardless of their CSS. The correct fix is to remove 2D options from the DOM entirely using `replaceChildren()` with a pre-snapshot array (`bsOpts`), rather than toggling `style.display`. The snapshot should be taken lazily on the first `loadInfo()` call, when all options are still present in the HTML.
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: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-29T20:58:20.394Z Learning: In WLED PR `#5048`, /json/net is generated by wled00/json.cpp::serializeNetworks(), which now includes ssid, rssi, bssid, channel, and enc for each scanned network. Any “Ch undefined” in the UI applies only to legacy builds or empty-scan states.
Learnt from: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-29T20:58:20.394Z Learning: In WLED PR `#5048`, /json/net is generated by wled00/json.cpp::serializeNetworks(). It serializes for each network: ssid, rssi, bssid, and channel (node["channel"] is set inside the loop). UI pages (settings_wifi.htm) should rely on this field rather than guard for "undefined" except for legacy builds.
Learnt from: softhack007 Repo: wled/WLED PR: 0 File: :0-0 Timestamp: 2026-03-29T20:58:20.394Z Learning: In WLED PR `#5048`, /json/net is produced by wled00/json.cpp::serializeNetworks(), which serializes ssid, rssi, bssid, and channel (node["channel"] is set in the loop). The UI can rely on this field; “Ch undefined” only applies to legacy builds that predate this addition.
Learnt from: blazoncek Repo: wled/WLED PR: 4482 File: wled00/udp.cpp:147-149 Timestamp: 2025-02-19T12:43:34.199Z Learning: ESP8266 and ESP32 platforms have different maximum segment name lengths in WLED, which can cause truncation when syncing segment names between devices. This platform difference affects the user experience when using the segment name sync feature.
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: 5464 File: wled00/FX_fcn.cpp:1699-1701 Timestamp: 2026-04-09T07:26:14.510Z Learning: In WLED (wled00/util.cpp), `allocate_buffer()` processes `BFRALLOC_NOBYTEACCESS` in an `if` with an `else` that covers all other flags. On classic ESP32, this means `BFRALLOC_ENFORCE_PSRAM` and `BFRALLOC_PREFER_PSRAM` are silently ignored when `BFRALLOC_NOBYTEACCESS` is also set — IRAM (MALLOC_CAP_32BIT) is always tried first. Combining `BFRALLOC_CLEAR | BFRALLOC_NOBYTEACCESS` is unsafe: the allocator's internal `memset` at util.cpp:901 will perform byte-level access on a potentially IRAM-resident buffer. This affects `Segment::pixels` in `setGeometry()` (FX.h) and `_pixels` in `finalizeInit()` (FX_fcn.cpp). Additionally, `memcpy` on `Segment::pixels` in the copy constructor and copy assignment (FX_fcn.cpp lines ~73 and ~116) is also a byte-level violation when the buffer is in IRAM. The safe pattern is element-wise 32-bit access (for loops over `uint32_t*`) rather than `memset`/`memcpy` for all `BFRALLOC_NOBYTEACCESS` buffers.
Learnt from: DedeHai Repo: wled/WLED PR: 4923 File: wled00/FX.cpp:4883-4901 Timestamp: 2025-09-12T17:29:43.826Z Learning: In WLED’s web UI, only one slider value (e.g., SEGMENT.intensity or SEGMENT.custom1) changes at a time; code relying on this may use simplified change guards, though presets/JSON can still update multiple fields atomically.
Learnt from: softhack007 Repo: wled/WLED PR: 5480 File: docs/cpp.instructions.md:511-511 Timestamp: 2026-04-08T19:10:52.197Z 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: softhack007 Repo: wled/WLED PR: 5457 File: usermods/zigbee_rgb_light/usermod_zigbee_rgb_light.h:0-0 Timestamp: 2026-03-31T17:31:01.023Z Learning: In WLED PR `#5457` (zigbee_rgb_light usermod): The WLED_MAX_DIGITAL_CHANNELS=0 build flag used in the esp32c6_zigbee environment is a temporary workaround for rmt_tx_wait_all_done() timeout spam when the Zigbee/802.15.4 stack is active. The root cause is under investigation and is likely related to Zigbee light-sleep (CONFIG_PM_ENABLE) disrupting RMT's internal time base, or ISR latency due to cache-disable during flash ops — NOT the 802.15.4 radio "sharing" the RMT peripheral (they are separate hardware). Because a proper fix (rmt_enable()/rmt_disable() PM-lock wrapping, allow_pd=0, CONFIG_RMT_TX_ISR_CACHE_SAFE) may eliminate the need to disable digital channels entirely, do NOT add a compile-time `#error` guard requiring WLED_MAX_DIGITAL_CHANNELS=0; doing so would prematurely bake in a constraint that may be lifted once the investigation concludes.
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: 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: 4889 File: wled00/FX_fcn.cpp:1380-1399 Timestamp: 2026-03-21T17:47:53.826Z Learning: In WLED's stencil blend mode (case 16 in `WS2812FX::blendSegment()`, `wled00/FX_fcn.cpp`), the transparency key is intentionally hardcoded to black (`t ? t : b`), not the segment's background color (`colors[1]`). This is a deliberate design choice to avoid additional parameters and overhead. It is the user's responsibility to not use a non-black background in combination with stencil mode. Do not flag this as a bug in future reviews.
Learnt from: softhack007 Repo: wled/WLED PR: 5482 File: wled00/wled.h:579-579 Timestamp: 2026-04-08T21:23:19.258Z Learning: In WLED PR `#5482` (wled00/wled.h), the `denyWsecUpload` flag MUST default to `false` (not `true`). Rationale confirmed via FMEA by softhack007: 1. Circular-dependency risk: `denyWsecUpload` is stored inside `wsec.json`; if that file is corrupted/deleted, `_INIT(true)` would permanently block the upload-recovery path without serial access. 2. Upgrade safety: `_INIT(true)` would silently break wsec.json upload recovery on all existing installations after a firmware upgrade. 3. Recovery parity: uploading wsec.json does not expose previous secrets; it is a legitimate recovery mechanism (e.g., after a flash wipe). The flag is valuable as an optional hardening opt-in for installations that do not need the upload-recovery path. The real defence against malformed-JSON bootloops should be input validation at load time, not upload blocking.
Learnt from: DedeHai Repo: wled/WLED PR: 5464 File: wled00/FX_fcn.cpp:1699-1701 Timestamp: 2026-04-09T09:14:32.589Z Learning: In WLED, pixel buffers allocated with `BFRALLOC_NOBYTEACCESS` (both `WS2812FX::_pixels` and `Segment::pixels`) are intentionally placed in 32-bit-only accessible IRAM by design. Buffers up to ~1000 LEDs (~4 kB) easily fit within IRAM's ~50 kB pool. `memset` and `memcpy` on these buffers work correctly in practice because the Xtensa newlib assembly implementations use 32-bit stores for word-aligned, word-multiple-size buffers — satisfying the IRAM hardware constraint as an implementation property of the assembly code, which is unlikely to change across IDF versions. The risk of a future violation exists but is accepted as very low. Do not flag `memset`/`memcpy` usage on `BFRALLOC_NOBYTEACCESS` pixel buffers as a critical bug in WLED reviews; note it as a low-risk accepted pattern.
Learnt from: softhack007 Repo: wled/WLED PR: 5508 File: wled00/FX.cpp:4137-4142 Timestamp: 2026-04-16T09:49:58.587Z Learning: WLED overlay behavior: Effects must operate via SEGMENT.* APIs (reads/writes) — global frame reads (strip.getPixelColor*) are reserved for copy_* style post‑processing. Blending between segments is performed later in WS2812FX::blendSegment(); effects should not try to composite with lower layers themselves.
Learnt from: softhack007 Repo: wled/WLED PR: 5048 File: wled00/set.cpp:551-555 Timestamp: 2026-03-27T21:00:25.902Z Learning: In WLED PR `#5048` (wled00/set.cpp lines 551-555), the CONFIG_IDF_TARGET_ESP32C5 block that unconditionally forces ntpEnabled = false is an intentional **temporary hotfix** by softhack007 for a known ESP32-C5 crash: `assert failed: udp_new_ip_type udp.c:1278 (Required to lock TCPIP core functionality!)`. Do not flag this as a permanent design issue; the TODO comment in the code already notes it should be resolved properly once the underlying IDF/TCPIP bug on C5 is fixed. A future permanent solution should use a target capability flag rather than overwriting the user's setting.
Learnt from: DedeHai Repo: wled/WLED PR: 4939 File: wled00/data/index.js:2406-2413 Timestamp: 2025-09-28T09:53:42.670Z Learning: In WLED, code paths that appear unreachable may actually be safety fallbacks for low-heap conditions. These fallbacks are intentional defensive programming measures to ensure UI functionality is preserved when system resources are constrained.-
- addedjavascriptPull requests that update Javascript codePull requests that update Javascript codeand removedcannot reproduceDevelopers are not able reproduce. Might be fixed already, or report is missing important detailsDevelopers are not able reproduce. Might be fixed already, or report is missing important details
on Apr 16, 2026 - changed the title
[-]All transitions not listed on pc version of browser UI[/-][+]Safafi/webkit browsers show 2D transitions for 1D segments ( correctly hidden on PC)[/+]on Apr 16, 2026 - changed the title
[-]Safafi/webkit browsers show 2D transitions for 1D segments ( correctly hidden on PC)[/-][+]Safari/webkit browsers show 2D transitions for 1D segments ( correctly hidden on PC)[/+]on Apr 16, 2026 I see the rabbit woke from its nap. So definitely need to fix some of the JS code for better compatibility
- addedconfirmedThe bug is reproducable and confirmedThe bug is reproducable and confirmed
on Apr 17, 2026 - added a commit that references this issue
on Apr 21, 2026


What happened?
You get an amended version of transitions when using the desktop browser (chrome) UI vs. the mobile UI on an apple device.
To Reproduce Bug
Check the transitions list on a mobile device (viewing the mobile/device toolbar in chrome doesn't work) vs the list provided on a computer.
Expected Behavior
The full list or transitions should be available on the desktop version of the UI.
Install Method
Binary from WLED.me
What version of WLED?
16.0.0-beta
Which microcontroller/board are you seeing the problem on?
ESP32
Relevant log/trace output
Anything else?
No response
Code of Conduct