- SUMMARY documents ANIM_REGISTRY name strings for Pi-side use
- W auto-derive formula documented for Phase 2 reference
- FW-03 (8 animations) and FW-04 (configurable params) requirements marked complete
- STATE updated: plan 4/4, progress 75%, decisions added
AnimTickFn pattern: function pointer signature (uint32_t tick, const AnimParams& params, uint16_t ledCount, bool isRGBW) used by all 8 animations
isRGBW branch pattern: every animation handles RGBW (stripWand) and RGB (stripSchrank) via isRGBW param
autoWhite call pattern: check w==0 before calling autoWhite() — explicit W values always honored
brightness pattern: bright = params.intensity * g_brightness — never access BRIGHTNESS_MAX directly in animations
FW-03
FW-04
14min
2026-04-03
Phase 01 Plan 03: Animation Engine + 8 Animations Summary
50fps FreeRTOS animation engine with ANIM_REGISTRY, zone state machines, W-channel auto-derive, and all 8 named animations (Chase/Pulse/Rainbow/Strobe/ColorWash/Breathe/Sparkle/GradientSweep) with palette-based RGBW support
Performance
Duration: ~14 min
Started: 2026-04-03T11:23:05Z
Completed: 2026-04-03T11:28:39Z
Tasks: 2
Files created: 11
Accomplishments
Animation engine with 50fps FreeRTOS task using vTaskDelayUntil for drift-free timing
ANIM_REGISTRY mapping 8 exact name strings to AnimTickFn pointers (used by Pi JSON "animation" field)
W-channel auto-derive from RGB (D-02): min(r, g, b) / 2 warm-white approximation
All 8 animations implementing AnimTickFn signature with isRGBW dual-strip support
Startup breathing animation (D-11): both zones breathe at 15% brightness before WiFi connects
Only triggered when params.colors[i][3] == 0 on RGBW strips (isRGBW=true)
Explicit W values (non-zero) always honored — user can override
Formula: warm-white approximation — only produces white for near-neutral RGB inputs
Phase 2 Pi-side: send [R, G, B, 0] to use auto-derive; send [R, G, B, W] to override
Task Commits
Task
Name
Commit
Files
1
animation_base.h + animation_engine.h/.cpp
230be99 (included in Plan 02 commit)
3 files
2
8 animation implementations
cba4b17
8 files
Note: Task 1 files were committed as part of Plan 02's final commit (230be99) because Plan 02's agent staged all untracked files in firmware/src/. The content is correct and matches the plan spec.
Files Created
File
Purpose
firmware/src/animations/animation_base.h
AnimTickFn typedef, AnimEntry struct, 8 function declarations, ANIM_REGISTRY extern
Moving window animation, speed scales position advance, wraps strip end
firmware/src/animations/pulse.cpp
Sine wave brightness pulse on solid palette color
firmware/src/animations/rainbow.cpp
HSV rainbow via HsbColor, hue offset advances with tick, ignores palette
firmware/src/animations/strobe.cpp
On/off flicker, period = 20/speed ticks
firmware/src/animations/color_wash.cpp
Linear fade between palette colors, hold_ticks = 50/speed
firmware/src/animations/breathe.cpp
Slow sine envelope, 5% minimum brightness, D-11 alive indicator
firmware/src/animations/sparkle.cpp
Random pixel flash with esp_random() hardware RNG
firmware/src/animations/gradient_sweep.cpp
2-color gradient sweeps with offset advance
Decisions Made
vTaskDelayUntil over vTaskDelay: Corrects for tick processing time — ensures exactly 50fps regardless of how long animations take to compute. vTaskDelay would drift by the compute time each frame.
Non-blocking commandQueue drain:xQueueReceive(..., 0) with timeout=0 — never stalls the animation frame for an incoming command. Commands apply on the next frame, acceptable for animation purposes.
Direct applyCommand at init (not via queue):initAnimationEngine() sets breathing animation directly on zone state, not via commandQueue, because the queue may not exist yet when init runs (before WiFi server starts).
sparkle uses esp_random(): ESP32 hardware RNG, no seeding required, better entropy than pseudo-random for visual effects.
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] wifi_server.h existed with correct function signature
Plan 03 expected to find wifi_server.h missing (Plan 02 is "parallel"). In practice, Plan 02 had already run and created wifi_server.h with startUdpServer() and commandQueue extern. No stub was needed — used the actual Plan 02 file. The initial stub creation via bash heredoc was overwritten by the already-committed Plan 02 version.
2. [Rule 1 - Context] Task 1 files committed in Plan 02's commit
Plan 02's agent staged and committed animation_engine.h/.cpp and animation_base.h as part of its commit 230be99. The content matches Plan 03's spec exactly (no overwrite occurred). This is a parallel execution artifact — the files exist correctly in git with correct content.
Total deviations: 2 (both non-impactful parallel execution artifacts)
Impact: Zero — all files contain correct content and are properly committed.
Known Stubs
None — all animation functions are fully implemented. No placeholder data flows to LEDs.
Next Phase Readiness
Plan 04 (integration) can wire initAnimationEngine() into main.cpp alongside startUdpServer()
Animation engine is ready to consume LedCommand structs from commandQueue immediately
Phase 2 Pi-side needs: ANIM_REGISTRY name strings (documented above), W auto-derive behavior (documented above), UDP port 4210, JSON protocol from protocol.h
Startup breathing animation provides visual feedback — Plan 04 should restore BRIGHTNESS_CAP after WiFi connects