You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: usermods/user_fx/README.md
+129-3Lines changed: 129 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -242,6 +242,135 @@ The string format WLED uses is semicolon-separated sections, with commas used fo
242
242
Let’s split this into logical sections (delimited by semicolons ;):
243
243
**TODO**
244
244
245
+
246
+
247
+
## Understanding 1D WLED Effects
248
+
249
+
Next, we will look at a 1D WLED effect called `Sinelon`. This one is an especially interesting example because it shows how a single effect function can be used to create several different selectable effects in the UI.
250
+
we will break this effect down tep by step.
251
+
(This effect was originally one of the FastLED example effects; more information on FastLED can be found [here](https://fastled.io/).)
* On first call `(SEGENV.call == 0)`, stores initial position in `SEGENV.aux0`. (`SEGENV.aux0` is a temporary state variable to keep track of last position.)
282
+
283
+
The next lines of code help determine the colors to be used:
*`color1`: main moving dot color, chosen from palette using the current position as index.
289
+
*`color2`: secondary color from user-configured color slot 2.
290
+
291
+
The next part taked into account the optional argument for if a Rainbow colored palette is in use:
292
+
```cpp
293
+
if (rainbow) {
294
+
color1 = SEGMENT.color_wheel((pos & 0x07) * 32);
295
+
}
296
+
```
297
+
* If `rainbow` is true, override color1 using a rainbow wheel, producing rainbow cycling colors.
298
+
* `(pos & 0x07) * 32` ensures the color changes gradually with position.
299
+
300
+
```cpp
301
+
SEGMENT.setPixelColor(pos, color1);
302
+
```
303
+
* Lights up the computed position with the selected color.
304
+
305
+
The next line takes into account another one of the optional arguments for the effect to potentially handle dual mirrored dots which create the animation:
306
+
```cpp
307
+
if (dual) {
308
+
if (!color2) color2 = SEGMENT.color_from_palette(pos, true, false, 0);
309
+
if (rainbow) color2 = color1; // share rainbow color
310
+
SEGMENT.setPixelColor(SEGLEN-1-pos, color2);
311
+
}
312
+
```
313
+
* If dual is true:
314
+
* Uses `color2` for mirrored dot on opposite side.
315
+
* If `color2` is not set (0), fallback to same palette color as `color1`.
316
+
* In `rainbow` mode, force both dots to share the rainbow color.
317
+
* Sets pixel at `SEGLEN-1-pos` to `color2`.
318
+
319
+
This final part of the effect function will fill in the 'trailing' pixels to complete the animation:
320
+
```cpp
321
+
if (SEGENV.aux0 < pos) {
322
+
for (unsigned i = SEGENV.aux0; i < pos ; i++) {
323
+
SEGMENT.setPixelColor(i, color1);
324
+
if (dual) SEGMENT.setPixelColor(SEGLEN-1-i, color2);
325
+
}
326
+
} else {
327
+
for (unsigned i = SEGENV.aux0; i > pos ; i--) {
328
+
SEGMENT.setPixelColor(i, color1);
329
+
if (dual) SEGMENT.setPixelColor(SEGLEN-1-i, color2);
330
+
}
331
+
}
332
+
SEGENV.aux0 = pos;
333
+
}
334
+
```
335
+
* The first line checks if current position has changed since last frame. (Prevents holes if the dot moves quickly and "skips" pixels.) If the position has changed, then it will implement the logic to update the rest of the pixels.
336
+
* Fills in all pixels between previous position (SEGENV.aux0) and new position (pos) to ensure smooth continuous trail.
337
+
* Works in both directions: Forward (if new pos > old pos), and Backward (if new pos < old pos).
338
+
* Updates `SEGENV.aux0` to current position at the end.
339
+
340
+
Finally, we return the `FRAMETIME`, as with all effect functions:
341
+
```cpp
342
+
return FRAMETIME;
343
+
}
344
+
```
345
+
* Returns `FRAMETIME` constant to set effect update rate (usually ~16 ms).
346
+
347
+
The last part of this effect has the Wrapper functions for different Sinelon modes.
348
+
Notice that there are three different modes that we can define from the single effect definition by leveraging the arguments in the function:
349
+
```cpp
350
+
uint16_tmode_sinelon(void) {
351
+
return sinelon_base(false);
352
+
}
353
+
# Calls sinelon_base with dual = false and rainbow = false
354
+
355
+
uint16_t mode_sinelon_dual(void) {
356
+
return sinelon_base(true);
357
+
}
358
+
# Calls sinelon_base with dual = true and rainbow = false
359
+
360
+
uint16_t mode_sinelon_rainbow(void) {
361
+
return sinelon_base(false, true);
362
+
}
363
+
# Calls sinelon_base with dual = false and rainbow = true
364
+
```
365
+
366
+
And then the last part defines the metadata strings for each effect to speicfy how it will be portrayed in the UI:
The `UserFxUsermod` class registers the `mode_diffusionfire` effect with WLED. This section starts right after the effect function and metadata string, and is responsible for making the effect usable in the WLED interface:
@@ -290,9 +419,6 @@ REGISTER_USERMOD(user_fx);
290
419
* The last line is a macro that tells WLED: “This is a valid usermod — load it during startup.”
291
420
* WLED adds it to the list of active usermods, calls `setup()` and `loop()`, and lets it interact with the system.
0 commit comments