feat(03-02): implement animation library — 7 types with registry and factory

- AnimationBase ABC with render(t, led_count) and from_params() contract
- SolidColorAnimation: time-independent uniform fill
- ChaseAnimation: moving lit segment with forward/reverse support
- PulseAnimation: sine-wave breathing effect (speed maps to period)
- RainbowAnimation: HSV hue cycle across strip via colorsys.hsv_to_rgb
- StrobeAnimation: on/off flashing at 1-20 Hz with configurable duty cycle
- ColorWipeAnimation: progressive fill from start or end
- FireAnimation: Fire2012 algorithm with cooling/sparking/heat-to-color mapping
- ANIMATION_REGISTRY + create_animation() factory function
- All 24 tests passing
This commit is contained in:
Claude
2026-04-06 21:47:39 +00:00
parent 920243fcae
commit f4da9564d4
10 changed files with 422 additions and 3 deletions

View File

@@ -108,15 +108,20 @@ def test_chase_pattern():
def test_chase_reverse():
"""Chase with reverse=True differs from reverse=False at same t (non-trivial t)."""
"""Chase with reverse=True differs from reverse=False at same t (non-trivial t).
Choose t such that offset is not a multiple of (size+spacing) to avoid symmetry.
"""
color = (255, 0, 0)
bg = (0, 0, 0)
# period = size + spacing = 3 + 7 = 10
# offset = int(t * speed * 60); use t=0.05 -> offset=3, not multiple of 10
anim_fwd = ChaseAnimation(color=color, bg_color=bg, speed=1.0, size=3, spacing=7, reverse=False, white=0)
anim_rev = ChaseAnimation(color=color, bg_color=bg, speed=1.0, size=3, spacing=7, reverse=True, white=0)
t = 1.5 # Non-zero t to show movement
t = 0.05 # offset=3, not a multiple of period=10, so fwd and rev patterns differ
frame_fwd = anim_fwd.render(t, 20)
frame_rev = anim_rev.render(t, 20)
assert frame_fwd != frame_rev, "Forward and reverse chase should differ at t=1.5"
assert frame_fwd != frame_rev, "Forward and reverse chase should differ when offset is not a multiple of period"
# ---------------------------------------------------------------------------