Tasmota/lib/libesp32/berry_animation/docs/API_REFERENCE.md
s-hadinger ca934bae33
Preview of Berry animation framework (#23740)
* Preview of Berry animation framework

* fix comet and compilation for safeboot
2025-08-01 18:02:02 +02:00

21 KiB

API Reference

Complete reference for the Tasmota Berry Animation Framework API.

Core Classes

AnimationEngine

The central controller for all animations.

var engine = animation.create_engine(strip)

Methods

add_animation(animation)

  • Adds an animation to the engine
  • Auto-starts the animation if engine is running
  • Returns: self (for method chaining)

remove_animation(animation)

  • Removes an animation from the engine
  • Returns: self

clear()

  • Removes all animations
  • Returns: self

start()

  • Starts the engine and all animations
  • Integrates with Tasmota's fast_loop
  • Returns: self

stop()

  • Stops the engine and all animations
  • Returns: self

size()

  • Returns: Number of active animations

is_active()

  • Returns: true if engine is running

Example

var strip = Leds(30)
var engine = animation.create_engine(strip)
var pulse = animation.pulse(animation.solid(0xFFFF0000), 2000, 50, 255)

engine.add_animation(pulse).start()

Pattern (Base Class)

Base class for all visual elements.

Properties

  • priority (int) - Rendering priority (higher = on top)
  • opacity (int) - Opacity 0-255 for blending
  • name (string) - Pattern identification
  • is_running (bool) - Whether pattern is active

Methods

start() / stop()

  • Control pattern lifecycle
  • Returns: self

set_priority(priority)

  • Set rendering priority
  • Returns: self

set_opacity(opacity)

  • Set opacity (0-255)
  • Returns: self

Animation (Extends Pattern)

Adds temporal behavior to patterns.

Additional Properties

  • duration (int) - Animation duration in ms (0 = infinite)
  • loop (bool) - Whether to loop when complete
  • start_time (int) - When animation started
  • current_time (int) - Current animation time

Additional Methods

set_duration(duration_ms)

  • Set animation duration
  • Returns: self

set_loop(loop)

  • Enable/disable looping
  • Returns: self

get_progress()

  • Returns: Animation progress (0-255)

Animation Functions

Basic Animations

animation.solid(color, priority=0, duration=0, loop=false, opacity=255, name="")

  • Creates solid color animation
  • color: ARGB color value (0xAARRGGBB)
  • Returns: PatternAnimation instance
var red = animation.solid(0xFFFF0000)
var blue = animation.solid(0xFF0000FF, 10, 5000, true, 200, "blue_anim")

animation.pulse(pattern, period_ms, min_brightness=0, max_brightness=255, priority=0, duration=0, loop=false, opacity=255, name="")

  • Creates pulsing animation
  • pattern: Base pattern to pulse
  • period_ms: Pulse period in milliseconds
  • min_brightness: Minimum brightness (0-255)
  • max_brightness: Maximum brightness (0-255)
  • Returns: PulseAnimation instance
var pulse_red = animation.pulse(animation.solid(0xFFFF0000), 2000, 50, 255)

animation.breathe(color, period_ms, priority=0, duration=0, loop=false, opacity=255, name="")

  • Creates smooth breathing effect
  • color: ARGB color value
  • period_ms: Breathing period in milliseconds
  • Returns: BreatheAnimation instance
var breathe_blue = animation.breathe(0xFF0000FF, 4000)

Palette-Based Animations

animation.rich_palette_animation(palette, period_ms, transition_type=1, brightness=255, priority=0, duration=0, loop=false, opacity=255, name="")

  • Creates palette-based color cycling animation
  • palette: Palette in VRGB bytes format or palette name
  • period_ms: Cycle period in milliseconds
  • transition_type: 0=linear, 1=smooth (sine)
  • brightness: Overall brightness (0-255)
  • Returns: FilledAnimation instance
var rainbow = animation.rich_palette_animation(animation.PALETTE_RAINBOW, 5000, 1, 255)

Position-Based Animations

animation.pulse_position_animation(color, pos, pulse_size, slew_size=0, priority=0, duration=0, loop=false, opacity=255, name="")

  • Creates pulse at specific position
  • color: ARGB color value
  • pos: Pixel position (0-based)
  • pulse_size: Width of pulse in pixels
  • slew_size: Fade region size in pixels
  • Returns: PulsePositionAnimation instance
var center_pulse = animation.pulse_position_animation(0xFFFFFFFF, 15, 3, 2)

animation.comet_animation(color, tail_length, speed_ms, priority=0, duration=0, loop=false, opacity=255, name="")

  • Creates moving comet effect
  • color: ARGB color value
  • tail_length: Length of comet tail in pixels
  • speed_ms: Movement speed in milliseconds per pixel
  • Returns: CometAnimation instance
var comet = animation.comet_animation(0xFF00FFFF, 8, 100)

animation.twinkle_animation(color, density, speed_ms, priority=0, duration=0, loop=false, opacity=255, name="")

  • Creates twinkling stars effect
  • color: ARGB color value
  • density: Number of twinkling pixels
  • speed_ms: Twinkle speed in milliseconds
  • Returns: TwinkleAnimation instance
var stars = animation.twinkle_animation(0xFFFFFFFF, 5, 500)

Fire and Natural Effects

animation.fire_animation(intensity=200, speed_ms=100, priority=0, duration=0, loop=false, opacity=255, name="")

  • Creates realistic fire simulation
  • intensity: Fire intensity (0-255)
  • speed_ms: Animation speed in milliseconds
  • Returns: FireAnimation instance
var fire = animation.fire_animation(180, 150)

Advanced Pattern Animations

animation.noise_rainbow(scale, speed, strip_length, priority)

  • Creates rainbow noise pattern with fractal complexity
  • scale: Noise frequency/detail (0-255, higher = more detail)
  • speed: Animation speed (0-255, 0 = static)
  • strip_length: LED strip length
  • priority: Rendering priority
  • Returns: NoiseAnimation instance

animation.noise_single_color(color, scale, speed, strip_length, priority)

  • Creates single-color noise pattern
  • color: ARGB color value
  • Returns: NoiseAnimation instance

animation.noise_fractal(color_source, scale, speed, octaves, strip_length, priority)

  • Creates multi-octave fractal noise
  • octaves: Number of noise octaves (1-4)
  • Returns: NoiseAnimation instance
var rainbow_noise = animation.noise_rainbow(60, 40, 30, 10)
var blue_noise = animation.noise_single_color(0xFF0066FF, 120, 60, 30, 10)
var fractal = animation.noise_fractal(nil, 40, 50, 3, 30, 10)

animation.plasma_rainbow(time_speed, strip_length, priority)

  • Creates rainbow plasma effect using sine wave interference
  • time_speed: Animation speed (0-255)
  • Returns: PlasmaAnimation instance

animation.plasma_single_color(color, time_speed, strip_length, priority)

  • Creates single-color plasma effect
  • color: ARGB color value
  • Returns: PlasmaAnimation instance
var plasma = animation.plasma_rainbow(80, 30, 10)
var purple_plasma = animation.plasma_single_color(0xFF8800FF, 60, 30, 10)

animation.sparkle_white(density, fade_speed, strip_length, priority)

  • Creates white twinkling sparkles
  • density: Sparkle creation probability (0-255)
  • fade_speed: Fade-out speed (0-255)
  • Returns: SparkleAnimation instance

animation.sparkle_colored(color, density, fade_speed, strip_length, priority)

  • Creates colored sparkles
  • color: ARGB color value
  • Returns: SparkleAnimation instance

animation.sparkle_rainbow(density, fade_speed, strip_length, priority)

  • Creates rainbow sparkles
  • Returns: SparkleAnimation instance
var white_sparkles = animation.sparkle_white(80, 60, 30, 10)
var red_sparkles = animation.sparkle_colored(0xFFFF0000, 100, 50, 30, 10)
var rainbow_sparkles = animation.sparkle_rainbow(60, 40, 30, 10)

animation.wave_rainbow_sine(amplitude, wave_speed, strip_length, priority)

  • Creates rainbow sine wave pattern
  • amplitude: Wave amplitude/intensity (0-255)
  • wave_speed: Wave movement speed (0-255)
  • Returns: WaveAnimation instance

animation.wave_single_sine(color, amplitude, wave_speed, strip_length, priority)

  • Creates single-color sine wave
  • color: ARGB color value
  • Returns: WaveAnimation instance

animation.wave_custom(color_source, wave_type, amplitude, frequency, strip_length, priority)

  • Creates custom wave with specified type
  • wave_type: 0=sine, 1=triangle, 2=square, 3=sawtooth
  • frequency: Wave frequency/density (0-255)
  • Returns: WaveAnimation instance
var sine_wave = animation.wave_rainbow_sine(40, 80, 30, 10)
var green_wave = animation.wave_single_sine(0xFF00FF00, 60, 40, 30, 10)
var triangle_wave = animation.wave_custom(nil, 1, 50, 70, 30, 10)

Motion Effect Animations

Motion effects transform existing animations by applying movement, scaling, and distortion effects.

animation.shift_scroll_right(source, speed, strip_length, priority)

  • Scrolls animation to the right with wrapping
  • source: Source animation to transform
  • speed: Scroll speed (0-255)
  • Returns: ShiftAnimation instance

animation.shift_scroll_left(source, speed, strip_length, priority)

  • Scrolls animation to the left with wrapping
  • Returns: ShiftAnimation instance

animation.shift_bounce_horizontal(source, speed, strip_length, priority)

  • Bounces animation horizontally at strip edges
  • Returns: ShiftAnimation instance
var base = animation.pulse_animation(0xFF0066FF, 80, 180, 3000, 5, 0, true, "base")
var scrolling = animation.shift_scroll_right(base, 100, 30, 10)

animation.bounce_gravity(source, speed, gravity, strip_length, priority)

  • Physics-based bouncing with gravity simulation
  • source: Source animation to transform
  • speed: Initial bounce speed (0-255)
  • gravity: Gravity strength (0-255)
  • Returns: BounceAnimation instance

animation.bounce_basic(source, speed, damping, strip_length, priority)

  • Basic bouncing without gravity
  • damping: Damping factor (0-255, 255=no damping)
  • Returns: BounceAnimation instance
var sparkles = animation.sparkle_white(80, 50, 30, 5)
var bouncing = animation.bounce_gravity(sparkles, 150, 80, 30, 10)
var elastic = animation.bounce_basic(sparkles, 120, 240, 30, 10)

animation.scale_static(source, scale_factor, strip_length, priority)

  • Static scaling of animation
  • source: Source animation to transform
  • scale_factor: Scale factor (128=1.0x, 64=0.5x, 255=2.0x)
  • Returns: ScaleAnimation instance

animation.scale_oscillate(source, speed, strip_length, priority)

  • Oscillating scale (breathing effect)
  • speed: Oscillation speed (0-255)
  • Returns: ScaleAnimation instance

animation.scale_grow(source, speed, strip_length, priority)

  • Growing scale effect
  • Returns: ScaleAnimation instance
var pattern = animation.gradient_rainbow_linear(0, 30, 5)
var breathing = animation.scale_oscillate(pattern, 60, 30, 10)
var zoomed = animation.scale_static(pattern, 180, 30, 10)  # 1.4x scale

animation.jitter_position(source, intensity, frequency, strip_length, priority)

  • Random position shake effects
  • source: Source animation to transform
  • intensity: Jitter intensity (0-255)
  • frequency: Jitter frequency (0-255, maps to 0-30 Hz)
  • Returns: JitterAnimation instance

animation.jitter_color(source, intensity, frequency, strip_length, priority)

  • Random color variations
  • Returns: JitterAnimation instance

animation.jitter_brightness(source, intensity, frequency, strip_length, priority)

  • Random brightness changes
  • Returns: JitterAnimation instance

animation.jitter_all(source, intensity, frequency, strip_length, priority)

  • Combination of position, color, and brightness jitter
  • Returns: JitterAnimation instance
var base = animation.gradient_rainbow_linear(0, 30, 5)
var glitch = animation.jitter_all(base, 120, 100, 30, 15)
var shake = animation.jitter_position(base, 60, 40, 30, 10)

Chaining Motion Effects

Motion effects can be chained together for complex transformations:

# Base animation
var base = animation.pulse_animation(0xFF0066FF, 80, 180, 3000, 5, 0, true, "base")

# Apply multiple transformations
var scaled = animation.scale_static(base, 150, 30, 8)        # 1.2x scale
var shifted = animation.shift_scroll_left(scaled, 60, 30, 12) # Scroll left
var jittered = animation.jitter_color(shifted, 40, 30, 30, 15) # Add color jitter

# Result: A scaled, scrolling, color-jittered pulse

Color System

Color Formats

ARGB Format: 0xAARRGGBB

  • AA: Alpha channel (opacity) - usually FF for opaque
  • RR: Red component (00-FF)
  • GG: Green component (00-FF)
  • BB: Blue component (00-FF)
var red = 0xFFFF0000      # Opaque red
var semi_blue = 0x800000FF # Semi-transparent blue
var white = 0xFFFFFFFF     # Opaque white
var black = 0xFF000000     # Opaque black

Predefined Colors

# Available as constants
animation.COLOR_RED     # 0xFFFF0000
animation.COLOR_GREEN   # 0xFF00FF00
animation.COLOR_BLUE    # 0xFF0000FF
animation.COLOR_WHITE   # 0xFFFFFFFF
animation.COLOR_BLACK   # 0xFF000000

Palette System

Creating Palettes

# VRGB format: Value(position), Red, Green, Blue
var fire_palette = bytes("00000000" "80FF0000" "FFFFFF00")
#                        ^pos=0     ^pos=128   ^pos=255
#                        black      red        yellow

Predefined Palettes

animation.PALETTE_RAINBOW  # Standard rainbow colors
animation.PALETTE_FIRE     # Fire effect colors
animation.PALETTE_OCEAN    # Ocean wave colors

Value Providers

Dynamic parameters that change over time.

Static Values

# Regular values are automatically wrapped
var static_color = 0xFFFF0000
var static_position = 15

Oscillator Providers

animation.smooth(start, end, period_ms)

  • Smooth cosine wave oscillation
  • Returns: OscillatorValueProvider

animation.linear(start, end, period_ms)

  • Triangle wave oscillation
  • Returns: OscillatorValueProvider

animation.ramp(start, end, period_ms)

  • Sawtooth wave oscillation
  • Returns: OscillatorValueProvider

animation.square(start, end, period_ms, duty_cycle=50)

  • Square wave oscillation
  • duty_cycle: Percentage of time at high value
  • Returns: OscillatorValueProvider
# Dynamic position that moves back and forth
var moving_pos = animation.smooth(0, 29, 3000)

# Dynamic color that cycles brightness
var breathing_color = animation.smooth(50, 255, 2000)

# Use with animations
var dynamic_pulse = animation.pulse_position_animation(
  0xFFFF0000,    # Static red color
  moving_pos,    # Dynamic position
  3,             # Static pulse size
  1              # Static slew size
)

Event System

Event Registration

animation.register_event_handler(event_name, callback, priority=0, condition=nil, metadata=nil)

  • Registers an event handler
  • event_name: Name of event to handle
  • callback: Function to call when event occurs
  • priority: Handler priority (higher = executed first)
  • condition: Optional condition function
  • metadata: Optional metadata map
  • Returns: EventHandler instance
def flash_white(event_data)
  var flash = animation.solid(0xFFFFFFFF)
  engine.add_animation(flash)
end

var handler = animation.register_event_handler("button_press", flash_white, 10)

Event Triggering

animation.trigger_event(event_name, event_data={})

  • Triggers an event
  • event_name: Name of event to trigger
  • event_data: Data to pass to handlers
animation.trigger_event("button_press", {"button": "main"})

DSL System

DSL Runtime

animation.DSLRuntime(engine, debug_mode=false)

  • Creates DSL runtime instance
  • engine: AnimationEngine instance
  • debug_mode: Enable debug output
  • Returns: DSLRuntime instance

Methods

load_dsl(source_code)

  • Compiles and executes DSL source code
  • source_code: DSL source as string
  • Returns: true on success, false on error

load_dsl_file(filename)

  • Loads and executes DSL from file
  • filename: Path to .anim file
  • Returns: true on success, false on error
var runtime = animation.DSLRuntime(engine, true)  # Debug mode on

var dsl_code = '''
color red = #FF0000
animation pulse_red = pulse(solid(red), 2s, 50%, 100%)
run pulse_red
'''

if runtime.load_dsl(dsl_code)
  print("Animation loaded successfully")
else
  print("Failed to load animation")
end

DSL Compilation

animation.compile_dsl(source_code)

  • Compiles DSL to Berry code
  • source_code: DSL source as string
  • Returns: Berry code string or raises exception
  • Raises: "dsl_compilation_error" on compilation failure
try
  var berry_code = animation.compile_dsl(dsl_source)
  print("Generated code:", berry_code)
  var compiled_func = compile(berry_code)
  compiled_func()
except "dsl_compilation_error" as e, msg
  print("Compilation error:", msg)
end

User Functions

Function Registration

animation.register_user_function(name, func)

  • Registers Berry function for DSL use
  • name: Function name for DSL
  • func: Berry function to register

animation.is_user_function(name)

  • Checks if function is registered
  • Returns: true if registered

animation.get_user_function(name)

  • Gets registered function
  • Returns: Function or nil

animation.list_user_functions()

  • Lists all registered function names
  • Returns: Array of function names
def custom_breathing(color, period)
  return animation.pulse(animation.solid(color), period, 50, 255)
end

animation.register_user_function("breathing", custom_breathing)

# Now available in DSL:
# animation my_effect = breathing(red, 3s)

Version Information

The framework uses a numeric version system for efficient comparison:

# Primary version (0xAABBCCDD format: AA=major, BB=minor, CC=patch, DD=build)
print(f"0x{animation.VERSION:08X}")     # 0x00010000

# Convert to string format (drops build number)
print(animation.version_string())       # "0.1.0"

# Convert any version number to string
print(animation.version_string(0x01020304))  # "1.2.3"

# Extract components manually
var major = (animation.VERSION >> 24) & 0xFF  # 0
var minor = (animation.VERSION >> 16) & 0xFF  # 1
var patch = (animation.VERSION >> 8) & 0xFF   # 0
var build = animation.VERSION & 0xFF          # 0

# Version comparison
var is_new_enough = animation.VERSION >= 0x00010000  # v0.1.0+

Utility Functions

Global Variable Access

animation.global(name)

  • Safely accesses global variables
  • name: Variable name
  • Returns: Variable value
  • Raises: "syntax_error" if variable doesn't exist
# Set global variable
global.my_color = 0xFFFF0000

# Access safely
var color = animation.global("my_color")  # Returns 0xFFFF0000
var missing = animation.global("missing") # Raises exception

Type Checking

animation.is_value_provider(obj)

  • Checks if object is a ValueProvider
  • Returns: true if object implements ValueProvider interface

animation.is_color_provider(obj)

  • Checks if object is a ColorProvider
  • Returns: true if object implements ColorProvider interface
var static_val = 42
var dynamic_val = animation.smooth(0, 100, 2000)

print(animation.is_value_provider(static_val))   # false
print(animation.is_value_provider(dynamic_val))  # true

Error Handling

Common Exceptions

  • "dsl_compilation_error" - DSL compilation failed
  • "syntax_error" - Variable not found or syntax error
  • "type_error" - Invalid parameter type
  • "runtime_error" - General runtime error

Best Practices

# Always use try/catch for DSL operations
try
  runtime.load_dsl(dsl_code)
except "dsl_compilation_error" as e, msg
  print("DSL Error:", msg)
except .. as e, msg
  print("Unexpected error:", msg)
end

# Check engine state before operations
if engine.is_active()
  engine.add_animation(new_animation)
else
  print("Engine not running")
end

# Validate parameters
if type(color) == "int" && color >= 0
  var anim = animation.solid(color)
else
  print("Invalid color value")
end

Performance Tips

Memory Management

# Clear animations when switching effects
engine.clear()
engine.add_animation(new_animation)

# Reuse animation objects when possible
var pulse_red = animation.pulse(animation.solid(0xFFFF0000), 2000, 50, 255)
# Use pulse_red multiple times instead of creating new instances

Timing Optimization

# Use longer periods for smoother performance
var smooth_pulse = animation.pulse(pattern, 3000, 50, 255)  # 3 seconds
var choppy_pulse = animation.pulse(pattern, 100, 50, 255)   # 100ms - may be choppy

# Limit simultaneous animations
# Good: 1-3 animations
# Avoid: 10+ animations running simultaneously

Value Provider Efficiency

# Efficient: Reuse providers
var breathing = animation.smooth(50, 255, 2000)
var anim1 = animation.pulse(pattern1, breathing)
var anim2 = animation.pulse(pattern2, breathing)  # Reuse same provider

# Inefficient: Create new providers
var anim1 = animation.pulse(pattern1, animation.smooth(50, 255, 2000))
var anim2 = animation.pulse(pattern2, animation.smooth(50, 255, 2000))  # Duplicate

This API reference covers the essential classes and functions. For more advanced usage, see the Examples and User Functions documentation.