This document introduces the FastLED core library housed under src/fl/, first by listing its headers, then by progressively expanding into an educational guide for two audiences:
- First‑time FastLED users who want to understand what lives below
FastLED.hand how to use common utilities - Experienced C++ developers exploring the
fl::API as a cross‑platform, STL‑free foundation
FastLED avoids direct dependencies on the C++ standard library in embedded contexts and offers its own STL‑like building blocks in the fl:: namespace.
- Overview and Quick Start
- Header Groups (5 major areas)
- Comprehensive Module Breakdown
- Guidance for New Users
- Guidance for C++ Developers
fl:: is FastLED’s cross‑platform foundation layer. It provides containers, algorithms, memory utilities, math, graphics primitives, async/concurrency, I/O, and platform shims designed to work consistently across embedded targets and host builds. It replaces common std:: facilities with equivalents tailored for embedded constraints and portability.
Key properties:
- Cross‑platform, embedded‑friendly primitives
- Minimal dynamic allocation where possible; clear ownership semantics
- Consistent naming and behavior across compilers/toolchains
- Prefer composable, header‑driven utilities
- Avoid fragile dependencies on
std::in embedded builds; preferfl::types - Emphasize deterministic behavior and low overhead
- Provide familiar concepts (vector, span, optional, variant, function) with embedded‑aware implementations
- Offer safe RAII ownership types and moveable wrappers for resource management
- Keep APIs flexible by preferring non‑owning views (
fl::span) as function parameters
- Names live in the
fl::namespace - Prefer
fl::span<T>as input parameters over owning containers - Use
fl::shared_ptr<T>/fl::unique_ptr<T>instead of raw pointers - Favor explicit ownership and lifetimes; avoid manual
new/delete
Include the top‑level header you need, or just include FastLED.h in sketches. When writing platform‑agnostic C++ within this repo, include the specific fl/ headers you use.
Common types to reach for:
- Containers and views:
fl::vector<T>,fl::deque<T>,fl::span<T>,fl::slice<T> - Strings and streams:
fl::string,fl::ostream,fl::sstream,fl::printf - Optionals and variants:
fl::optional<T>,fl::variant<...> - Memory/ownership:
fl::unique_ptr<T>,fl::shared_ptr<T>,fl::weak_ptr<T> - Functional:
fl::function<Signature>,fl::function_list<Signature> - Concurrency:
fl::thread,fl::mutex,fl::thread_local - Async:
fl::promise<T>,fl::task - Math:
fl::math,fl::sin32,fl::random,fl::gamma,fl::gradient - Graphics:
fl::raster,fl::screenmap,fl::rectangular_draw_buffer,fl::downscale,fl::supersample - Color:
fl::hsv,fl::hsv16,fl::colorutils - JSON:
fl::Jsonwith safe defaults and ergonomic access
Example: using containers, views, and ownership
#include "fl/vector.h"
#include "fl/span.h"
#include "fl/memory.h" // for fl::make_unique
void process(fl::span<const int> values) {
// Non-owning view over contiguous data
}
void example() {
fl::vector<int> data;
data.push_back(1);
data.push_back(2);
data.push_back(3);
process(fl::span<const int>(data));
auto ptr = fl::make_unique<int>(42);
// Exclusive ownership; automatically freed when leaving scope
}Example: JSON with safe default access
#include "fl/json.h"
void json_example(const fl::string& jsonStr) {
fl::Json json = fl::Json::parse(jsonStr);
int brightness = json["config"]["brightness"] | 128; // default if missing
bool enabled = json["enabled"] | false;
}Containers, views, algorithms, compile‑time utilities, memory/ownership, portability helpers.
- Containers:
vector.h,deque.h,queue.h,priority_queue.h,set.h,map.h,unordered_set.h,hash_map.h,hash_set.h,rbtree.h,bitset.h,bitset_dynamic.h - Views and ranges:
span.h,slice.h,range_access.h - Tuples and algebraic types:
tuple.h,pair.h,optional.h,variant.h - Algorithms and helpers:
algorithm.h,transform.h,comparators.h,range_access.h - Types and traits:
types.h,type_traits.h,initializer_list.h,utility.h,move.h,template_magic.h,stdint.h,cstddef.h,namespace.h - Memory/ownership:
unique_ptr.h,shared_ptr.h,weak_ptr.h,scoped_ptr.h,scoped_array.h,ptr.h,ptr_impl.h,referent.h,allocator.h,memory.h,memfill.h,inplacenew.h - Portability and compiler control:
compiler_control.h,force_inline.h,virtual_if_not_avr.h,has_define.h,register.h,warn.h,trace.h,dbg.h,assert.h,unused.h,export.h,dll.h,deprecated.h,avr_disallowed.h,bit_cast.h,id_tracker.h,insert_result.h,singleton.h
Per‑header quick descriptions:
vector.h: Dynamically sized contiguous container with embedded‑friendly API.deque.h: Double‑ended queue for efficient front/back operations.queue.h: FIFO adapter providing push/pop semantics over an underlying container.priority_queue.h: Heap‑based ordered queue for highest‑priority retrieval.set.h: Ordered unique collection with deterministic iteration.map.h: Ordered key‑value associative container.unordered_set.h: Hash‑based unique set for average O(1) lookups.hash_map.h: Hash‑based key‑value container tuned for embedded use.hash_set.h: Hash set implementation complementinghash_map.h.rbtree.h: Balanced tree primitive used by ordered containers.bitset.h: Fixed‑size compile‑time bitset operations.bitset_dynamic.h: Runtime‑sized bitset for flexible masks.span.h: Non‑owning view over contiguous memory (preferred function parameter).slice.h: Strided or sub‑range view utilities for buffers.range_access.h: Helpers to unify begin/end access over custom ranges.tuple.h: Heterogeneous fixed‑size aggregate with structured access.pair.h: Two‑value aggregate type for simple key/value or coordinate pairs.optional.h: Presence/absence wrapper to avoid sentinel values.variant.h: Type‑safe tagged union for sum types without heap allocation.algorithm.h: Core algorithms (search, sort helpers, transforms) adapted tofl::containers.transform.h: Functional style element‑wise transformations with spans/ranges.comparators.h: Reusable comparator utilities for ordering operations.types.h: Canonical type aliases and shared type definitions.type_traits.h: Compile‑time type inspection and enable_if‑style utilities.initializer_list.h: Lightweight initializer list support for container construction.utility.h: Miscellaneous helpers (swap, forward, etc.) suitable for embedded builds.move.h: Move/forward utilities mirroring standard semantics.template_magic.h: Metaprogramming helpers to simplify template code.stdint.h: Fixed‑width integer definitions for cross‑compiler consistency.cstddef.h: Size/ptrdiff and nullptr utilities for portability.namespace.h: Internal macros/utilities for managingfl::namespaces safely.unique_ptr.h: Exclusive ownership smart pointer with RAII semantics.shared_ptr.h: Reference‑counted shared ownership smart pointer.weak_ptr.h: Non‑owning reference toshared_ptr‑managed objects.scoped_ptr.h: Scope‑bound ownership (no move) for simple RAII cleanup.scoped_array.h: RAII wrapper for array allocations.ptr.h/ptr_impl.h: Pointer abstractions and shared machinery for smart pointers.referent.h: Base support for referent/observer relationships.allocator.h: Custom allocators tailored for embedded constraints.memory.h: Low‑level memory helpers (construct/destroy, address utilities).memfill.h: Zero‑cost fill utilities (prefer overmemsetin codebase).inplacenew.h: Placement new helpers for manual lifetime management.compiler_control.h: Unified compiler warning/pragma control macros.force_inline.h: Portable always‑inline control macros.virtual_if_not_avr.h: Virtual specifier abstraction for AVR compatibility.has_define.h: Preprocessor feature checks and conditional compilation helpers.register.h: Register annotation shims for portability.warn.h/trace.h/dbg.h: Logging, tracing, and diagnostics helpers.assert.h: Assertions suited for embedded/testing builds.unused.h: Intentional unused variable/function annotations.export.h/dll.h: Visibility/export macros for shared library boundaries.deprecated.h: Cross‑compiler deprecation annotations.avr_disallowed.h: Guardrails to prevent unsupported usage on AVR.bit_cast.h: Safe bit reinterpretation where supported, with fallbacks.id_tracker.h: ID generation/tracking utility for object registries.insert_result.h: Standardized result type for associative container inserts.singleton.h: Simple singleton helper for cases requiring global access.
Rasterization, coordinate mappings, paths, grids, resampling, draw buffers, and related glue.
- Raster and buffers:
raster.h,raster_sparse.h,rectangular_draw_buffer.h - Screen and tiles:
screenmap.h,tile2x2.h - Coordinates and mappings:
xmap.h,xymap.h,screenmap.h - Paths and traversal:
xypath.h,xypath_impls.h,xypath_renderer.h,traverse_grid.h,grid.h,line_simplification.h - Geometry primitives:
geometry.h,point.h - Resampling/scaling:
downscale.h,upscale.h,supersample.h - Glue and UI:
leds.h,ui.h,ui_impl.h,rectangular_draw_buffer.h - Specialized:
corkscrew.h,wave_simulation.h,wave_simulation_real.h,tile2x2.h,screenmap.h
Per‑header quick descriptions:
raster.h: Core raster interface and operations for pixel buffers.raster_sparse.h: Sparse/partial raster representation for memory‑efficient updates.rectangular_draw_buffer.h: Double‑buffered rectangular draw surface helpers.screenmap.h: Maps logical coordinates to physical LED indices/layouts.tile2x2.h: Simple 2×2 tiling utilities for composing larger surfaces.xmap.h: General coordinate mapping utilities.xymap.h: XY coordinate to index mapping helpers for matrices and panels.xypath.h: Path representation in XY space for drawing and effects.xypath_impls.h: Implementations and algorithms supportingxypath.h.xypath_renderer.h: Renders paths into rasters with configurable styles.traverse_grid.h: Grid traversal algorithms for curves/lines/fills.grid.h: Grid data structure and iteration helpers.line_simplification.h: Path simplification (e.g., Douglas‑Peucker‑style) for fewer segments.geometry.h: Basic geometric computations (distances, intersections, etc.).point.h: Small coordinate/vector primitive type.downscale.h: Resampling utilities to reduce resolution while preserving features.upscale.h: Upsampling utilities for enlarging frames.supersample.h: Anti‑aliasing via multi‑sample accumulation.leds.h: Integration helpers bridging LED buffers to rendering utilities.ui.h/ui_impl.h: Minimal UI adapter hooks for demos/tests.corkscrew.h: Experimental path/trajectory utilities for visual effects.wave_simulation.h/wave_simulation_real.h: Simulated wave dynamics for organic effects.
Color models, gradients, gamma, math helpers, random, noise, mapping, and basic DSP.
- Color and palettes:
colorutils.h,colorutils_misc.h,hsv.h,hsv16.h,gradient.h,fill.h,five_bit_hd_gamma.h,gamma.h - Math and mapping:
math.h,math_macros.h,sin32.h,map_range.h,random.h,lut.h,clamp.h,clear.h,splat.h,transform.h - Noise and waves:
noise_woryley.h,wave_simulation.h,wave_simulation_real.h - DSP and audio:
fft.h,fft_impl.h,audio.h,audio_reactive.h - Time utilities:
time.h,time_alpha.h
Per‑header quick descriptions:
colorutils.h: High‑level color operations (blend, scale, lerp) for LED pixels.colorutils_misc.h: Additional helpers and niche color operations.hsv.h/hsv16.h: HSV color types and conversions (8‑bit and 16‑bit variants).gradient.h: Gradient construction, sampling, and palette utilities.fill.h: Efficient buffer/palette filling operations for pixel arrays.five_bit_hd_gamma.h: Gamma correction tables tuned for high‑definition 5‑bit channels.gamma.h: Gamma correction functions and LUT helpers.math.h/math_macros.h: Core math primitives/macros for consistent numerics.sin32.h: Fast fixed‑point sine approximations for animations.map_range.h: Linear mapping and clamping between numeric ranges.random.h: Pseudorandom utilities for effects and dithering.lut.h: Lookup table helpers for precomputed transforms.clamp.h: Bounds enforcement for numeric types.clear.h: Clear/zero helpers for buffers with type awareness.splat.h: Vectorized repeat/write helpers for bulk operations.transform.h: Element transforms (listed here as it is often used for pixel ops too).noise_woryley.h: Worley/cellular noise generation utilities.wave_simulation*.h: Wavefield simulation (also referenced in graphics).fft.h/fft_impl.h: Fast Fourier Transform interfaces and backends.audio.h: Audio input/stream abstractions for host/platforms that support it.audio_reactive.h: Utilities to drive visuals from audio features.time.h: Timekeeping helpers (millis/micros abstractions when available).time_alpha.h: Smoothed/exponential time‑based interpolation helpers.
Threads, synchronization, async primitives, eventing, and callable utilities.
- Threads and sync:
thread.h,mutex.h,thread_local.h - Async primitives:
promise.h,promise_result.h,task.h,async.h - Functional:
function.h,function_list.h,functional.h - Events and engine hooks:
engine_events.h
Per‑header quick descriptions:
thread.h: Portable threading abstraction for supported hosts.mutex.h: Mutual exclusion primitive compatible withfl::thread. Almost all platforms these are fake implementations.thread_local.h: Thread‑local storage shim for supported compilers.promise.h: Moveable wrapper around asynchronous result delivery.promise_result.h: Result type accompanying promises/futures.task.h: Lightweight async task primitive for orchestration.async.h: Helpers for async composition and coordination.function.h: Type‑erased callable wrapper analogous tostd::function.function_list.h: Multicast list of callables with simple invoke semantics.functional.h: Adapters, binders, and predicates for composing callables.engine_events.h: Event channel definitions for engine‑style systems.
Streams, strings, formatted output, bytestreams, filesystem, JSON.
- Text and streams:
string.h,str.h,ostream.h,istream.h,sstream.h,strstream.h,printf.h - JSON:
json.h - Bytestreams and I/O:
bytestream.h,bytestreammemory.h,io.h,file_system.h,fetch.h
Per‑header quick descriptions:
string.h/str.h: String types and helpers without pulling instd::string.ostream.h/istream.h: Output/input stream interfaces for host builds.sstream.h/strstream.h: String‑backed stream buffers and helpers.printf.h: Small, portable formatted print utilities.json.h: Safe, ergonomicfl::JsonAPI with defaulting operator (|).bytestream.h: Sequential byte I/O abstraction for buffers/streams.bytestreammemory.h: In‑memory byte stream implementation.io.h: General I/O helpers for files/streams where available.file_system.h: Minimal filesystem adapter for host platforms.fetch.h: Basic fetch/request helpers for network‑capable hosts.
This section groups headers by domain, explains their role, and shows minimal usage snippets. Names shown are representative; see the header list above for the full inventory.
- Sequence and associative containers:
vector.h,deque.h,queue.h,priority_queue.h,set.h,map.h,unordered_set.h,hash_map.h,hash_set.h,rbtree.h - Non‑owning and slicing:
span.h,slice.h,range_access.h
Why: Embedded‑aware containers with predictable behavior across platforms. Prefer passing fl::span<T> to functions.
#include "fl/vector.h"
#include "fl/span.h"
size_t count_nonzero(fl::span<const uint8_t> bytes) {
size_t count = 0;
for (uint8_t b : bytes) { if (b != 0) { ++count; } }
return count;
}- Text types and streaming:
string.h,str.h,ostream.h,istream.h,sstream.h,strstream.h,printf.h
Why: Consistent string/stream facilities without pulling in the standard streams.
#include "fl/string.h"
#include "fl/sstream.h"
fl::string greet(const fl::string& name) {
fl::sstream ss;
ss << "Hello, " << name << "!";
return ss.str();
}- Smart pointers and utilities:
unique_ptr.h,shared_ptr.h,weak_ptr.h,scoped_ptr.h,scoped_array.h,allocator.h,memory.h,memfill.h
Why: RAII ownership with explicit semantics. Prefer fl::make_shared<T>()/fl::make_unique<T>() patterns where available, or direct constructors provided by these headers.
#include "fl/shared_ptr.h"
struct Widget { int value; };
void ownership_example() {
fl::shared_ptr<Widget> w(new Widget{123});
auto w2 = w; // shared ownership
}- Callables and lists:
function.h,function_list.h,functional.h
Why: Store callbacks and multicast them safely.
#include "fl/function_list.h"
void on_event(int code) { /* ... */ }
void register_handlers() {
fl::function_list<void(int)> handlers;
handlers.add(on_event);
handlers(200); // invoke all
}- Threads and synchronization:
thread.h,mutex.h,thread_local.h - Async primitives:
promise.h,promise_result.h,task.h
Why: Lightweight foundations for parallel work or async orchestration where supported.
#include "fl/promise.h"
fl::promise<int> compute_async(); // returns a moveable wrapper around a future-like result- Core math and helpers:
math.h,math_macros.h,sin32.h,random.h,map_range.h - Color math:
gamma.h,gradient.h,colorutils.h,colorutils_misc.h,hsv.h,hsv16.h,fill.h - FFT and analysis:
fft.h,fft_impl.h
Why: Efficient numeric operations for LED effects, audio reactivity, and transforms.
#include "fl/gamma.h"
uint8_t apply_gamma(uint8_t v) {
return fl::gamma::correct8(v);
}- Basic geometry:
point.h,geometry.h - Grid traversal and simplification:
grid.h,traverse_grid.h,line_simplification.h
Why: Building blocks for 2D/3D layouts and path operations.
- Raster and buffers:
raster.h,raster_sparse.h,rectangular_draw_buffer.h - Screen mapping and tiling:
screenmap.h,tile2x2.h,xmap.h,xymap.h - Paths and renderers:
xypath.h,xypath_impls.h,xypath_renderer.h,traverse_grid.h - Resampling and effects:
downscale.h,upscale.h,supersample.h
Why: Efficient frame manipulation for LED matrices and coordinate spaces.
#include "fl/downscale.h"
// Downscale a high‑res buffer to a target raster (API varies by adapter)This section explains how the major graphics utilities fit together and how to use them effectively for high‑quality, high‑performance rendering on LED strips, matrices, and complex shapes.
-
Wave simulation (1D/2D)
- Headers:
wave_simulation.h,wave_simulation_real.h - Concepts:
- Super‑sampling for quality: choose
SuperSamplefactors to run an internal high‑resolution simulation and downsample for display. - Consistent speed at higher quality: call
setExtraFrames(u8)to update the simulation multiple times per frame to maintain perceived speed when super‑sampling. - Output accessors:
getf,geti16,getu8return float/fixed/byte values; 2D version offers cylindrical wrapping viasetXCylindrical(true).
- Super‑sampling for quality: choose
- Tips for “faster” updates:
- Use
setExtraFrames()to advance multiple internal steps per visual frame without changing your outer timing. - Prefer
getu8(...)when feeding color functions or gradients on constrained devices.
- Use
- Headers:
-
fl::Leds – array and mapped matrix
- Header:
leds.h; mapping:xymap.h fl::Ledswraps aCRGB*so you can treat it as:- A plain
CRGB*via implicit conversion for classic FastLED APIs. - A 2D surface via
operator()(x, y)that respects anXYMap(serpentine, line‑by‑line, LUT, or custom function).
- A plain
- Construction:
Leds(CRGB* leds, u16 width, u16 height)for quick serpentine/rectangular usage.Leds(CRGB* leds, const XYMap& xymap)for full control (serpentine, rectangular, user function, or LUT).
- Access and safety:
at(x, y)/operator()(x, y)map to the correct LED index; out‑of‑bounds is safe and returns a sentinel.operator[]exposes row‑major access when the map is serpentine or line‑by‑line.
- Header:
-
Matrix mapping (XYMap)
- Header:
xymap.h - Create maps for common layouts:
XYMap::constructSerpentine(w, h)for typical pre‑wired panels.XYMap::constructRectangularGrid(w, h)for row‑major matrices.XYMap::constructWithUserFunction(w, h, XYFunction)for custom wiring.XYMap::constructWithLookUpTable(...)for arbitrary wiring via LUT.
- Utilities:
mapToIndex(x, y)maps coordinates to strip index.has(x, y)tests bounds;toScreenMap()converts to a float UI mapping.
- Header:
-
XY paths and path rendering (xypath)
- Headers:
xypath.h,xypath_impls.h,xypath_renderer.h, helpers intile2x2.h,transform.h. - Purpose: parameterized paths in ([0,1] \to (x,y)) for drawing lines/curves/shapes with subpixel precision.
- Ready‑made paths: point, line, circle, heart, Archimedean spiral, rose curves, phyllotaxis, Gielis superformula, and Catmull‑Rom splines with editable control points.
- Rendering:
- Subpixel sampling via
Tile2x2_u8enables high quality on low‑res matrices. - Use
XYPath::drawColorordrawGradientto rasterize into anfl::Ledssurface. XYPath::rasterizewrites into a sparse raster for advanced composition.
- Subpixel sampling via
- Transforms and bounds:
setDrawBounds(w, h)andsetTransform(TransformFloat)control framing and animation transforms.
- Headers:
-
Subpixel “splat” rendering (Tile2x2)
- Header:
tile2x2.h - Concept: represent a subpixel footprint as a 2×2 tile of coverage values (u8 alphas). When a subpixel position moves between LEDs, neighboring LEDs get proportional contributions.
- Use cases:
Tile2x2_u8::draw(color, xymap, out)to composite with color per‑pixel.- Custom blending:
tile.draw(xymap, visitor)to apply your own alpha/compositing. - Wrapped tiles:
Tile2x2_u8_wrapsupports cylindrical wrap with interpolation for continuous effects.
- Header:
-
Downscale
- Header:
downscale.h - Purpose: resample from a higher‑resolution buffer to a smaller target, preserving features.
- APIs:
downscale(src, srcXY, dst, dstXY)general case.downscaleHalf(...)optimized 2× reduction (square or mapped) used automatically when sizes match.
- Header:
-
Upscale
- Header:
upscale.h - Purpose: bilinear upsampling from a low‑res buffer to a larger target.
- APIs:
upscale(input, output, inW, inH, xyMap)auto‑selects optimized paths.upscaleRectangularandupscaleRectangularPowerOf2bypass XY mapping for straight row‑major layouts.- Float reference versions exist for validation.
- Header:
-
Corkscrew (cylindrical projection)
-
Header:
corkscrew.h -
Goal: draw into a rectangular buffer and project onto a tightly wrapped helical/cylindrical LED layout.
-
Inputs and sizing:
CorkscrewInput{ totalTurns, numLeds, Gap, invert }defines geometry; helpercalculateWidth()/calculateHeight()provide rectangle dimensions for buffer allocation.
-
Mapping and iteration:
Corkscrew::at_exact(i)returns the exact position for LED i;at_wrap(float)returns a wrappedTile2x2_u8_wrapfootprint for subpixel‑accurate sampling.- Use
toScreenMap(diameter)to produce aScreenMapfor UI overlays or browser visualization.
-
Rectangular buffer integration:
getBuffer()/data()provide a lazily‑initialized rectangle;fillBuffer/clearBuffermanage it.readFrom(source_grid, use_multi_sampling)projects from a high‑def source grid to the corkscrew using multi‑sampling for quality.
-
Examples
- Manual per‑frame draw (push every frame)
#include <FastLED.h> #include "fl/corkscrew.h" #include "fl/grid.h" #include "fl/time.h" // Your physical LED buffer constexpr uint16_t NUM_LEDS = 144; CRGB leds[NUM_LEDS]; // Define a corkscrew geometry (e.g., 19 turns tightly wrapped) fl::Corkscrew::Input input(/*totalTurns=*/19.0f, /*numLeds=*/NUM_LEDS); fl::Corkscrew cork(input); // A simple rectangular source grid to draw into (unwrapped cylinder) // Match the corkscrew's recommended rectangle const uint16_t W = cork.cylinder_width(); const uint16_t H = cork.cylinder_height(); fl::Grid<CRGB> rect(W, H); void draw_pattern(uint32_t t_ms) { // Example: time‑animated gradient on the unwrapped cylinder for (uint16_t y = 0; y < H; ++y) { for (uint16_t x = 0; x < W; ++x) { uint8_t hue = uint8_t((x * 255u) / (W ? W : 1)) + uint8_t((t_ms / 10) & 0xFF); rect(x, y) = CHSV(hue, 255, 255); } } } void project_to_strip() { // For each LED index i on the physical strip, sample the unwrapped // rectangle using the subpixel footprint from at_wrap(i) for (uint16_t i = 0; i < NUM_LEDS; ++i) { auto tile = cork.at_wrap(float(i)); // tile.at(u,v) gives {absolute_pos, alpha} // Blend the 2x2 neighborhood from the rectangular buffer uint16_t r = 0, g = 0, b = 0, a_sum = 0; for (uint16_t vy = 0; vy < 2; ++vy) { for (uint16_t vx = 0; vx < 2; ++vx) { auto entry = tile.at(vx, vy); // pair<vec2i16, u8> const auto pos = entry.first; // absolute cylinder coords const uint8_t a = entry.second; // alpha 0..255 if (pos.x >= 0 && pos.x < int(W) && pos.y >= 0 && pos.y < int(H) && a > 0) { const CRGB& c = rect(uint16_t(pos.x), uint16_t(pos.y)); r += uint16_t(c.r) * a; g += uint16_t(c.g) * a; b += uint16_t(c.b) * a; a_sum += a; } } } if (a_sum == 0) { leds[i] = CRGB::Black; } else { leds[i].r = uint8_t(r / a_sum); leds[i].g = uint8_t(g / a_sum); leds[i].b = uint8_t(b / a_sum); } } } void setup() { FastLED.addLeds<WS2812B, 5, GRB>(leds, NUM_LEDS); } void loop() { uint32_t t = fl::time(); draw_pattern(t); project_to_strip(); FastLED.show(); }
- Automate with task::before_frame (draw right before render)
Use the per‑frame task API; no direct EngineEvents binding is needed. Per‑frame tasks are scheduled via
fl::taskand integrated with the frame lifecycle by the async system.#include <FastLED.h> #include "fl/task.h" #include "fl/async.h" #include "fl/corkscrew.h" #include "fl/grid.h" constexpr uint16_t NUM_LEDS = 144; CRGB leds[NUM_LEDS]; fl::Corkscrew cork(fl::Corkscrew::Input(19.0f, NUM_LEDS)); const uint16_t W = cork.cylinder_width(); const uint16_t H = cork.cylinder_height(); fl::Grid<CRGB> rect(W, H); static void draw_pattern(uint32_t t_ms, fl::Grid<CRGB>& dst); static void project_to_strip(const fl::Corkscrew& c, const fl::Grid<CRGB>& src, CRGB* out, uint16_t n); void setup() { FastLED.addLeds<WS2812B, 5, GRB>(leds, NUM_LEDS); // Register a before_frame task that runs immediately before each render fl::task::before_frame().then([&](){ uint32_t t = fl::time(); draw_pattern(t, rect); project_to_strip(cork, rect, leds, NUM_LEDS); }); } void loop() { // The before_frame task is invoked automatically at the right time FastLED.show(); // Optionally pump other async work fl::async_yield(); }
- The manual approach gives explicit control each frame.
- The
task::before_frame()approach schedules work just‑in‑time before rendering without manual event wiring. Usetask::after_frame()for post‑render work.
-
-
High‑definition HSV16
- Headers:
hsv16.h, implementation inhsv16.cpp fl::HSV16stores 16‑bit H/S/V for high‑precision conversion toCRGBwithout banding; construct fromCRGBor manually, and convert viaToRGB()or implicit cast.- Color boost:
HSV16::colorBoost(EaseType saturation_function, EaseType luminance_function)applies a saturation‑space boost similar to gamma, tuned separately for saturation and luminance to counter LED gamut/compression (e.g., WS2812).
- Headers:
-
Easing functions (accurate 8/16‑bit)
- Header:
ease.h - Accurate ease‑in/out functions with 8‑ and 16‑bit variants for quad/cubic/sine families, plus dispatchers:
ease8(type, ...),ease16(type, ...). - Use to shape animation curves, palette traversal, or time alpha outputs.
- Header:
-
Time alpha
- Header:
time_alpha.h - Helpers for time‑based interpolation:
time_alpha8/16/fcompute progress in a window[start, end]. - Stateful helpers:
TimeRamp(rise, latch, fall)for a full rise‑hold‑fall cycle.TimeClampedTransition(duration)for a clamped one‑shot.
- Use cases: envelope control for brightness, effect blending, or gating simulation energy over time.
- Header:
- Safe JSON access:
json.h
Why: Ergonomic, crash‑resistant access with defaulting operator (|). Prefer the fl::Json API for new code.
fl::Json cfg = fl::Json::parse("{\"enabled\":true}");
bool enabled = cfg["enabled"] | false;- Basic I/O and streams:
io.h,ostream.h,istream.h,sstream.h,printf.h - Filesystem adapters:
file_system.h
Why: Cross‑platform text formatting, buffered I/O, and optional file access on host builds.
- Algorithms and transforms:
algorithm.h,transform.h,range_access.h - Compile‑time utilities:
type_traits.h,tuple.h,variant.h,optional.h,utility.h,initializer_list.h,template_magic.h,types.h,stdint.h,namespace.h - Platform shims and control:
compiler_control.h,force_inline.h,virtual_if_not_avr.h,has_define.h,register.h,warn.h,trace.h,dbg.h,assert.h,unused.h,export.h,dll.h
Why: Familiar patterns with embedded‑appropriate implementations and compiler‑portable controls.
FastLED includes a JSON‑driven UI layer that can expose controls (sliders, buttons, checkboxes, number fields, dropdowns, titles, descriptions, help, audio visualizers) for interactive demos and remote control.
-
Availability by platform
- AVR and other low‑memory chipsets: disabled by default. The UI is not compiled in on constrained targets.
- WASM build: enabled. The web UI is available and connects to the running sketch.
- Other platforms: can be enabled if the platform supplies a bridge. See
platforms/ui_defs.hfor the compile‑time gate and platform includes.
-
Key headers and switches
platforms/ui_defs.h: controlsFASTLED_USE_JSON_UI(defaults to 1 on WASM, 0 elsewhere).fl/ui.h: C++ UI element classes (UISlider, UIButton, UICheckbox, UINumberField, UIDropdown, UITitle, UIDescription, UIHelp, UIAudio, UIGroup).platforms/shared/ui/json/ui_manager.h: platform‑agnostic JSON UI manager that integrates withEngineEvents.platforms/shared/ui/json/readme.md: implementation guide and JSON protocol.
-
Lifecycle and data flow
- The UI system uses an update manager (
JsonUiManager) and is integrated withEngineEvents:- On frame lifecycle events, new UI elements are exported as JSON; inbound updates are processed after frames.
- This enables remote control: UI state can be driven locally (browser) or by remote senders issuing JSON updates.
- Send (sketch → UI): when components are added or changed,
JsonUiManageremits JSON to the platform bridge. - Receive (UI → sketch): the platform calls
JsonUiManager::updateUiComponents(const char*)with a JSON object; changes are applied ononEndFrame().
- The UI system uses an update manager (
-
Registering handlers to send/receive JSON
- Platform bridge constructs the manager with a function that forwards JSON to the UI:
JsonUiManager(Callback updateJs)whereupdateJs(const char*)transports JSON to the front‑end (WASM example uses JS bindings insrc/platforms/wasm/ui.cpp).
- To receive UI updates from the front‑end, call:
MyPlatformUiManager::instance().updateUiComponents(json_str)to queue changes;onEndFrame()applies them.
- Platform bridge constructs the manager with a function that forwards JSON to the UI:
-
Sketch‑side usage examples
Basic setup with controls and groups:
#include <FastLED.h> #include "fl/ui.h" UISlider brightness("Brightness", 128, 0, 255); UICheckbox enabled("Enabled", true); UIButton reset("Reset"); UIDropdown mode("Mode", {fl::string("Rainbow"), fl::string("Waves"), fl::string("Solid")}); UITitle title("Demo Controls"); UIDescription desc("Adjust parameters in real time"); UIHelp help("# Help\nUse the controls to tweak the effect."); void setup() { // Group controls visually in the UI UIGroup group("Main", title, desc, brightness, enabled, mode, reset, help); // Callbacks are pumped via EngineEvents; they trigger when values change brightness.onChanged([](UISlider& s){ FastLED.setBrightness((uint8_t)s); }); enabled.onChanged([](UICheckbox& c){ /* toggle effect */ }); mode.onChanged([](UIDropdown& d){ /* change program by d.as_int() */ }); reset.onClicked([](){ /* reset animation state */ }); }
Help component (see
examples/UITest/UITest.ino):UIHelp helpMarkdown( R"(# FastLED UI\nThis area supports markdown, code blocks, and links.)"); helpMarkdown.setGroup("Documentation");
Audio input UI (WASM‑enabled platforms):
UIAudio audio("Mic"); void loop() { while (audio.hasNext()) { auto sample = audio.next(); // Use sample data for visualizations } FastLED.show(); }
-
Platform bridge: sending and receiving JSON
- Sending from sketch to UI:
JsonUiManagerinvokes theupdateJs(const char*)callback with JSON representing either:- A JSON array of element definitions (on first export)
- A JSON object of state updates (on changes)
- Receiving from UI to sketch: the platform calls
JsonUiManager::updateUiComponents(const char* jsonStr)wherejsonStris a JSON object like:{ "id_123": {"value": 200}, "id_456": {"pressed": true } }
- The manager defers application until the end of the current frame via
onEndFrame()to ensure consistency.
- Sending from sketch to UI:
-
WASM specifics
- WASM builds provide the web UI and JS glue (see
src/platforms/wasm/ui.cppandsrc/platforms/wasm/compiler/modules/ui_manager.js). - Element definitions may be routed directly to the browser UI manager to avoid feedback loops; updates are logged to an inspector, and inbound messages drive
updateUiComponents.
- WASM builds provide the web UI and JS glue (see
-
Enabling on other platforms
- Implement a platform UI manager using
JsonUiManagerand provide the two weak functions the UI elements call:void addJsonUiComponent(fl::weak_ptr<JsonUiInternal>)void removeJsonUiComponent(fl::weak_ptr<JsonUiInternal>)
- Forward platform UI events into
updateUiComponents(jsonStr). - Ensure
EngineEventsare active so UI updates are exported and applied on frame boundaries.
- Implement a platform UI manager using
-
Audio adapters and analysis:
audio.h,audio_reactive.h -
Engine hooks:
engine_events.h
Why: Build effects that respond to input signals.
- Wave simulation:
wave_simulation.h,wave_simulation_real.h - Screen and LED glue:
leds.h,screenmap.h - Path/visual experimentation:
corkscrew.h
- If you are writing sketches: include
FastLED.hand follow examples inexamples/. Thefl::headers power those features under the hood. - If you are extending FastLED internals or building advanced effects: prefer
fl::containers andfl::spanover STL equivalents to maintain portability. - Favor smart pointers and moveable wrappers for resource management. Avoid raw pointers and manual
delete. - Use
fl::Jsonfor robust JSON handling with safe defaults.
- Treat
fl::as an embedded‑friendly STL. Many concepts mirror the standard library but are tuned for constrained targets and consistent compiler support. - When designing APIs, prefer non‑owning views (
fl::span<T>) for input parameters and explicit ownership types for storage. - Use
compiler_control.hmacros for warning control and portability instead of raw pragmas.
This README will evolve alongside the codebase. If you are exploring a specific subsystem, start from the relevant headers listed above and follow includes to supporting modules.