Berry animation change color parsing (#23741)

This commit is contained in:
s-hadinger 2025-08-01 19:34:23 +02:00 committed by GitHub
parent 156bc447ce
commit 3ef60018f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
123 changed files with 579 additions and 8257 deletions

View File

@ -5,20 +5,20 @@
# Define aurora color palette
palette aurora_colors = [
(0, #000022), # Dark night sky
(64, #004400), # Dark green
(128, #00AA44), # Aurora green
(192, #44AA88), # Light green
(255, #88FFAA) # Bright aurora
(0, 0x000022), # Dark night sky
(64, 0x004400), # Dark green
(128, 0x00AA44), # Aurora green
(192, 0x44AA88), # Light green
(255, 0x88FFAA) # Bright aurora
]
# Secondary purple palette
palette aurora_purple = [
(0, #220022), # Dark purple
(64, #440044), # Medium purple
(128, #8800AA), # Bright purple
(192, #AA44CC), # Light purple
(255, #CCAAFF) # Pale purple
(0, 0x220022), # Dark purple
(64, 0x440044), # Medium purple
(128, 0x8800AA), # Bright purple
(192, 0xAA44CC), # Light purple
(255, 0xCCAAFF) # Pale purple
]
# Base aurora animation with slow flowing colors

View File

@ -4,20 +4,20 @@
strip length 60
# Define breathing colors
color breathe_red = #FF0000
color breathe_green = #00FF00
color breathe_blue = #0000FF
color breathe_purple = #800080
color breathe_orange = #FF8000
color breathe_red = 0xFF0000
color breathe_green = 0x00FF00
color breathe_blue = 0x0000FF
color breathe_purple = 0x800080
color breathe_orange = 0xFF8000
# Create breathing animation that cycles through colors
palette breathe_palette = [
(0, #FF0000), # Red
(51, #FF8000), # Orange
(102, #FFFF00), # Yellow
(153, #00FF00), # Green
(204, #0000FF), # Blue
(255, #800080) # Purple
(0, 0xFF0000), # Red
(51, 0xFF8000), # Orange
(102, 0xFFFF00), # Yellow
(153, 0x00FF00), # Green
(204, 0x0000FF), # Blue
(255, 0x800080) # Purple
]
# Create a rich palette color provider

View File

@ -4,8 +4,8 @@
strip length 60
# Define stripe colors
color candy_red = #FF0000
color candy_white = #FFFFFF
color candy_red = 0xFF0000
color candy_white = 0xFFFFFF
# Create alternating red and white pattern
# Using multiple pulse positions to create stripes

View File

@ -4,16 +4,16 @@
strip length 60
# Green tree base
color tree_green = #006600
color tree_green = 0x006600
animation tree_base = solid(tree_green)
# Define ornament colors
palette ornament_colors = [
(0, #FF0000), # Red
(64, #FFD700), # Gold
(128, #0000FF), # Blue
(192, #FFFFFF), # White
(255, #FF00FF) # Magenta
(0, 0xFF0000), # Red
(64, 0xFFD700), # Gold
(128, 0x0000FF), # Blue
(192, 0xFFFFFF), # White
(255, 0xFF00FF) # Magenta
]
# Colorful ornaments as twinkling lights
@ -27,19 +27,19 @@ ornaments.priority = 10
# Star on top (bright yellow pulse)
animation tree_star = pulse_position_animation(
#FFFF00, # Bright yellow
58, # position (near the top)
3, # star size
1 # sharp edges
0xFFFF00, # Bright yellow
58, # position (near the top)
3, # star size
1 # sharp edges
)
tree_star.priority = 20
tree_star.opacity = smooth(200, 255, 2s) # Gentle pulsing
# Add some white sparkles for snow/magic
animation snow_sparkles = twinkle_animation(
#FFFFFF, # White snow
8, # density (sparkle count)
400ms # twinkle speed (quick sparkles)
0xFFFFFF, # White snow
8, # density (sparkle count)
400ms # twinkle speed (quick sparkles)
)
snow_sparkles.priority = 15

View File

@ -4,31 +4,31 @@
strip length 60
# Dark blue background
color space_blue = #000066 # Note: opaque 0xFF alpha channel is implicitly added
color space_blue = 0x000066 # Note: opaque 0xFF alpha channel is implicitly added
animation background = solid(space_blue)
# Main comet with bright white head
animation comet_main = comet_animation(
#FFFFFF, # White head
10, # tail length
2s # speed
0xFFFFFF, # White head
10, # tail length
2s # speed
)
comet_main.priority = 7
# Secondary comet in different color, opposite direction
animation comet_secondary = comet_animation(
#FF4500, # Orange head
8, # shorter tail
3s, # slower speed
-1 # other direction
0xFF4500, # Orange head
8, # shorter tail
3s, # slower speed
-1 # other direction
)
comet_secondary.priority = 5
# Add sparkle trail behind comets but on top of blue background
animation comet_sparkles = twinkle_animation(
#AAAAFF, # Light blue sparkles
8, # density (moderate sparkles)
400ms # twinkle speed (quick sparkle)
0xAAAAFF, # Light blue sparkles
8, # density (moderate sparkles)
400ms # twinkle speed (quick sparkle)
)
comet_sparkles.priority = 8

View File

@ -1,6 +1,6 @@
# DSL Compilation Report
Generated: Ven 1 aoû 2025 16:04:44 CEST
Generated: Ven 1 aoû 2025 18:49:41 CEST
## Summary

View File

@ -13,20 +13,20 @@
#
# # Define aurora color palette
# palette aurora_colors = [
# (0, #000022), # Dark night sky
# (64, #004400), # Dark green
# (128, #00AA44), # Aurora green
# (192, #44AA88), # Light green
# (255, #88FFAA) # Bright aurora
# (0, 0x000022), # Dark night sky
# (64, 0x004400), # Dark green
# (128, 0x00AA44), # Aurora green
# (192, 0x44AA88), # Light green
# (255, 0x88FFAA) # Bright aurora
# ]
#
# # Secondary purple palette
# palette aurora_purple = [
# (0, #220022), # Dark purple
# (64, #440044), # Medium purple
# (128, #8800AA), # Bright purple
# (192, #AA44CC), # Light purple
# (255, #CCAAFF) # Pale purple
# (0, 0x220022), # Dark purple
# (64, 0x440044), # Medium purple
# (128, 0x8800AA), # Bright purple
# (192, 0xAA44CC), # Light purple
# (255, 0xCCAAFF) # Pale purple
# ]
#
# # Base aurora animation with slow flowing colors

View File

@ -12,20 +12,20 @@
# strip length 60
#
# # Define breathing colors
# color breathe_red = #FF0000
# color breathe_green = #00FF00
# color breathe_blue = #0000FF
# color breathe_purple = #800080
# color breathe_orange = #FF8000
# color breathe_red = 0xFF0000
# color breathe_green = 0x00FF00
# color breathe_blue = 0x0000FF
# color breathe_purple = 0x800080
# color breathe_orange = 0xFF8000
#
# # Create breathing animation that cycles through colors
# palette breathe_palette = [
# (0, #FF0000), # Red
# (51, #FF8000), # Orange
# (102, #FFFF00), # Yellow
# (153, #00FF00), # Green
# (204, #0000FF), # Blue
# (255, #800080) # Purple
# (0, 0xFF0000), # Red
# (51, 0xFF8000), # Orange
# (102, 0xFFFF00), # Yellow
# (153, 0x00FF00), # Green
# (204, 0x0000FF), # Blue
# (255, 0x800080) # Purple
# ]
#
# # Create a rich palette color provider

View File

@ -12,8 +12,8 @@
# strip length 60
#
# # Define stripe colors
# color candy_red = #FF0000
# color candy_white = #FFFFFF
# color candy_red = 0xFF0000
# color candy_white = 0xFFFFFF
#
# # Create alternating red and white pattern
# # Using multiple pulse positions to create stripes

View File

@ -12,16 +12,16 @@
# strip length 60
#
# # Green tree base
# color tree_green = #006600
# color tree_green = 0x006600
# animation tree_base = solid(tree_green)
#
# # Define ornament colors
# palette ornament_colors = [
# (0, #FF0000), # Red
# (64, #FFD700), # Gold
# (128, #0000FF), # Blue
# (192, #FFFFFF), # White
# (255, #FF00FF) # Magenta
# (0, 0xFF0000), # Red
# (64, 0xFFD700), # Gold
# (128, 0x0000FF), # Blue
# (192, 0xFFFFFF), # White
# (255, 0xFF00FF) # Magenta
# ]
#
# # Colorful ornaments as twinkling lights
@ -35,19 +35,19 @@
#
# # Star on top (bright yellow pulse)
# animation tree_star = pulse_position_animation(
# #FFFF00, # Bright yellow
# 58, # position (near the top)
# 3, # star size
# 1 # sharp edges
# 0xFFFF00, # Bright yellow
# 58, # position (near the top)
# 3, # star size
# 1 # sharp edges
# )
# tree_star.priority = 20
# tree_star.opacity = smooth(200, 255, 2s) # Gentle pulsing
#
# # Add some white sparkles for snow/magic
# animation snow_sparkles = twinkle_animation(
# #FFFFFF, # White snow
# 8, # density (sparkle count)
# 400ms # twinkle speed (quick sparkles)
# 0xFFFFFF, # White snow
# 8, # density (sparkle count)
# 400ms # twinkle speed (quick sparkles)
# )
# snow_sparkles.priority = 15
#

View File

@ -12,31 +12,31 @@
# strip length 60
#
# # Dark blue background
# color space_blue = #000066 # Note: opaque 0xFF alpha channel is implicitly added
# color space_blue = 0x000066 # Note: opaque 0xFF alpha channel is implicitly added
# animation background = solid(space_blue)
#
# # Main comet with bright white head
# animation comet_main = comet_animation(
# #FFFFFF, # White head
# 10, # tail length
# 2s # speed
# 0xFFFFFF, # White head
# 10, # tail length
# 2s # speed
# )
# comet_main.priority = 7
#
# # Secondary comet in different color, opposite direction
# animation comet_secondary = comet_animation(
# #FF4500, # Orange head
# 8, # shorter tail
# 3s, # slower speed
# -1 # other direction
# 0xFF4500, # Orange head
# 8, # shorter tail
# 3s, # slower speed
# -1 # other direction
# )
# comet_secondary.priority = 5
#
# # Add sparkle trail behind comets but on top of blue background
# animation comet_sparkles = twinkle_animation(
# #AAAAFF, # Light blue sparkles
# 8, # density (moderate sparkles)
# 400ms # twinkle speed (quick sparkle)
# 0xAAAAFF, # Light blue sparkles
# 8, # density (moderate sparkles)
# 400ms # twinkle speed (quick sparkle)
# )
# comet_sparkles.priority = 8
#

View File

@ -13,13 +13,13 @@
#
# # Define disco color palette
# palette disco_colors = [
# (0, #FF0000), # Red
# (42, #FF8000), # Orange
# (85, #FFFF00), # Yellow
# (128, #00FF00), # Green
# (170, #0000FF), # Blue
# (213, #8000FF), # Purple
# (255, #FF00FF) # Magenta
# (0, 0xFF0000), # Red
# (42, 0xFF8000), # Orange
# (85, 0xFFFF00), # Yellow
# (128, 0x00FF00), # Green
# (170, 0x0000FF), # Blue
# (213, 0x8000FF), # Purple
# (255, 0xFF00FF) # Magenta
# ]
#
# # Fast color cycling base
@ -29,7 +29,7 @@
# disco_base.opacity = square(0, 255, 100ms, 30) # Fast strobe
#
# # Add white flash overlay
# animation white_flash = solid(#FFFFFF)
# animation white_flash = solid(0xFFFFFF)
# white_flash.opacity = square(0, 255, 50ms, 10) # Quick white flashes
# white_flash.priority = 20
#

View File

@ -13,11 +13,11 @@
#
# # Define fire palette from black to yellow
# palette fire_colors = [
# (0, #000000), # Black
# (64, #800000), # Dark red
# (128, #FF0000), # Red
# (192, #FF4500), # Orange red
# (255, #FFFF00) # Yellow
# (0, 0x000000), # Black
# (64, 0x800000), # Dark red
# (128, 0xFF0000), # Red
# (192, 0xFF4500), # Orange red
# (255, 0xFFFF00) # Yellow
# ]
#
# # Create base fire animation with palette

View File

@ -12,32 +12,32 @@
# strip length 60
#
# # Dark background
# color heart_bg = #110000
# color heart_bg = 0x110000
# animation background = solid(heart_bg)
#
# # Define heartbeat timing - double pulse pattern
# # First pulse (stronger)
# animation heartbeat1 = solid(#FF0000) # Bright red
# animation heartbeat1 = solid(0xFF0000) # Bright red
# heartbeat1.opacity = square(0, 255, 150ms, 20) # Quick strong pulse
# heartbeat1.priority = 10
#
# # Second pulse (weaker, slightly delayed)
# animation heartbeat2 = solid(#CC0000) # Slightly dimmer red
# animation heartbeat2 = solid(0xCC0000) # Slightly dimmer red
# # Delay the second pulse by adjusting the square wave phase
# heartbeat2.opacity = square(0, 180, 150ms, 15) # Weaker pulse
# heartbeat2.priority = 8
#
# # Add subtle glow effect
# animation heart_glow = solid(#660000) # Dim red glow
# animation heart_glow = solid(0x660000) # Dim red glow
# heart_glow.opacity = smooth(30, 100, 1s) # Gentle breathing glow
# heart_glow.priority = 5
#
# # Add center pulse for emphasis
# animation center_pulse = pulse_position_animation(
# #FFFFFF, # White center
# 30, # center of strip
# 4, # small center
# 2 # soft edges
# 0xFFFFFF, # White center
# 30, # center of strip
# 4, # small center
# 2 # soft edges
# )
# center_pulse.priority = 20
# center_pulse.opacity = square(0, 200, 100ms, 10) # Quick white flash

View File

@ -13,11 +13,11 @@
#
# # Define lava colors (warm oranges and reds)
# palette lava_colors = [
# (0, #330000), # Dark red
# (64, #660000), # Medium red
# (128, #CC3300), # Bright red
# (192, #FF6600), # Orange
# (255, #FFAA00) # Yellow-orange
# (0, 0x330000), # Dark red
# (64, 0x660000), # Medium red
# (128, 0xCC3300), # Bright red
# (192, 0xFF6600), # Orange
# (255, 0xFFAA00) # Yellow-orange
# ]
#
# # Base lava animation - very slow color changes

View File

@ -13,38 +13,38 @@
#
# # Dark stormy background with subtle purple/blue
# palette storm_colors = [
# (0, #000011), # Very dark blue
# (128, #110022), # Dark purple
# (255, #220033) # Slightly lighter purple
# (0, 0x000011), # Very dark blue
# (128, 0x110022), # Dark purple
# (255, 0x220033) # Slightly lighter purple
# ]
#
# animation storm_bg = rich_palette_animation(storm_colors, 12s, smooth, 100)
#
# # Random lightning flashes - full strip
# animation lightning_main = solid(#FFFFFF) # Bright white
# animation lightning_main = solid(0xFFFFFF) # Bright white
# lightning_main.opacity = square(0, 255, 80ms, 3) # Quick bright flashes
# lightning_main.priority = 20
#
# # Secondary lightning - partial strip
# animation lightning_partial = pulse_position_animation(
# #FFFFAA, # Slightly yellow white
# 30, # center position
# 20, # covers part of strip
# 5 # soft edges
# 0xFFFFAA, # Slightly yellow white
# 30, # center position
# 20, # covers part of strip
# 5 # soft edges
# )
# lightning_partial.priority = 15
# lightning_partial.opacity = square(0, 200, 120ms, 4) # Different timing
#
# # Add blue afterglow
# animation afterglow = solid(#4444FF) # Blue glow
# animation afterglow = solid(0x4444FF) # Blue glow
# afterglow.opacity = square(0, 80, 200ms, 8) # Longer, dimmer glow
# afterglow.priority = 10
#
# # Distant thunder (dim flashes)
# animation distant_flash = twinkle_animation(
# #666699, # Dim blue-white
# 4, # density (few flashes)
# 300ms # twinkle speed (medium duration)
# 0x666699, # Dim blue-white
# 4, # density (few flashes)
# 300ms # twinkle speed (medium duration)
# )
# distant_flash.priority = 5
#

View File

@ -12,16 +12,16 @@
# strip length 60
#
# # Dark background
# color matrix_bg = #000000
# color matrix_bg = 0x000000
# animation background = solid(matrix_bg)
#
# # Define matrix green palette
# palette matrix_greens = [
# (0, #000000), # Black
# (64, #003300), # Dark green
# (128, #006600), # Medium green
# (192, #00AA00), # Bright green
# (255, #00FF00) # Neon green
# (0, 0x000000), # Black
# (64, 0x003300), # Dark green
# (128, 0x006600), # Medium green
# (192, 0x00AA00), # Bright green
# (255, 0x00FF00) # Neon green
# ]
#
# # Create multiple cascading streams
@ -51,9 +51,9 @@
#
# # Add random bright flashes (like code highlights)
# animation code_flash = twinkle_animation(
# #00FFAA, # Bright cyan-green
# 3, # density (few flashes)
# 150ms # twinkle speed (quick flash)
# 0x00FFAA, # Bright cyan-green
# 3, # density (few flashes)
# 150ms # twinkle speed (quick flash)
# )
# code_flash.priority = 20
#

View File

@ -12,51 +12,51 @@
# strip length 60
#
# # Dark space background
# color space_bg = #000011
# color space_bg = 0x000011
# animation background = solid(space_bg)
#
# # Multiple meteors with different speeds and colors
# animation meteor1 = comet_animation(
# #FFFFFF, # Bright white
# 12, # long trail
# 1.5s # fast speed
# 0xFFFFFF, # Bright white
# 12, # long trail
# 1.5s # fast speed
# )
# meteor1.priority = 15
#
# animation meteor2 = comet_animation(
# #FFAA00, # Orange
# 10, # medium trail
# 2s # medium speed
# 0xFFAA00, # Orange
# 10, # medium trail
# 2s # medium speed
# )
# meteor2.priority = 12
#
# animation meteor3 = comet_animation(
# #AAAAFF, # Blue-white
# 8, # shorter trail
# 1.8s # fast speed
# 0xAAAAFF, # Blue-white
# 8, # shorter trail
# 1.8s # fast speed
# )
# meteor3.priority = 10
#
# animation meteor4 = comet_animation(
# #FFAAAA, # Pink-white
# 14, # long trail
# 2.5s # slower speed
# 0xFFAAAA, # Pink-white
# 14, # long trail
# 2.5s # slower speed
# )
# meteor4.priority = 8
#
# # Add distant stars
# animation stars = twinkle_animation(
# #CCCCCC, # Dim white
# 12, # density (many stars)
# 2s # twinkle speed (slow twinkle)
# 0xCCCCCC, # Dim white
# 12, # density (many stars)
# 2s # twinkle speed (slow twinkle)
# )
# stars.priority = 5
#
# # Add occasional bright flash (meteor explosion)
# animation meteor_flash = twinkle_animation(
# #FFFFFF, # Bright white
# 1, # density (single flash)
# 100ms # twinkle speed (very quick)
# 0xFFFFFF, # Bright white
# 1, # density (single flash)
# 100ms # twinkle speed (very quick)
# )
# meteor_flash.priority = 25
#

View File

@ -13,10 +13,10 @@
#
# # Define neon colors
# palette neon_colors = [
# (0, #FF0080), # Hot pink
# (85, #00FF80), # Neon green
# (170, #8000FF), # Electric purple
# (255, #FF8000) # Neon orange
# (0, 0xFF0080), # Hot pink
# (85, 0x00FF80), # Neon green
# (170, 0x8000FF), # Electric purple
# (255, 0xFF8000) # Neon orange
# ]
#
# # Main neon glow with color cycling
@ -26,7 +26,7 @@
# neon_main.opacity = smooth(220, 255, 200ms)
#
# # Add occasional electrical surge
# animation neon_surge = solid(#FFFFFF) # White surge
# animation neon_surge = solid(0xFFFFFF) # White surge
# neon_surge.opacity = square(0, 255, 50ms, 2) # Quick bright surges
# neon_surge.priority = 20
#
@ -58,9 +58,9 @@
#
# # Add electrical arcing between segments
# animation arc_sparkles = twinkle_animation(
# #AAAAFF, # Electric blue
# 4, # density (few arcs)
# 100ms # twinkle speed (quick arcs)
# 0xAAAAFF, # Electric blue
# 4, # density (few arcs)
# 100ms # twinkle speed (quick arcs)
# )
# arc_sparkles.priority = 15
#

View File

@ -13,11 +13,11 @@
#
# # Define ocean color palette
# palette ocean_colors = [
# (0, #000080), # Deep blue
# (64, #0040C0), # Ocean blue
# (128, #0080FF), # Light blue
# (192, #40C0FF), # Cyan
# (255, #80FFFF) # Light cyan
# (0, 0x000080), # Deep blue
# (64, 0x0040C0), # Ocean blue
# (128, 0x0080FF), # Light blue
# (192, 0x40C0FF), # Cyan
# (255, 0x80FFFF) # Light cyan
# ]
#
# # Base ocean animation with slow color cycling
@ -46,9 +46,9 @@
#
# # Add foam sparkles
# animation foam = twinkle_animation(
# #FFFFFF, # White foam
# 6, # density (sparkle count)
# 300ms # twinkle speed (quick sparkles)
# 0xFFFFFF, # White foam
# 6, # density (sparkle count)
# 300ms # twinkle speed (quick sparkles)
# )
# foam.priority = 15
#

View File

@ -13,20 +13,20 @@
#
# # Define a fire palette
# palette fire_colors = [
# (0, #000000), # Black
# (64, #800000), # Dark red
# (128, #FF0000), # Red
# (192, #FF8000), # Orange
# (255, #FFFF00) # Yellow
# (0, 0x000000), # Black
# (64, 0x800000), # Dark red
# (128, 0xFF0000), # Red
# (192, 0xFF8000), # Orange
# (255, 0xFFFF00) # Yellow
# ]
#
# # Define an ocean palette
# palette ocean_colors = [
# (0, #000080), # Navy blue
# (64, #0000FF), # Blue
# (128, #00FFFF), # Cyan
# (192, #00FF80), # Spring green
# (255, #008000) # Green
# (0, 0x000080), # Navy blue
# (64, 0x0000FF), # Blue
# (128, 0x00FFFF), # Cyan
# (192, 0x00FF80), # Spring green
# (255, 0x008000) # Green
# ]
#
# # Create animations using the palettes

View File

@ -13,15 +13,15 @@
#
# # Example 1: Fire palette with hex colors
# palette fire_gradient = [
# (0, #000000), # Black (no fire)
# (32, #330000), # Very dark red
# (64, #660000), # Dark red
# (96, #CC0000), # Red
# (128, #FF3300), # Red-orange
# (160, #FF6600), # Orange
# (192, #FF9900), # Light orange
# (224, #FFCC00), # Yellow-orange
# (255, #FFFF00) # Bright yellow
# (0, 0x000000), # Black (no fire)
# (32, 0x330000), # Very dark red
# (64, 0x660000), # Dark red
# (96, 0xCC0000), # Red
# (128, 0xFF3300), # Red-orange
# (160, 0xFF6600), # Orange
# (192, 0xFF9900), # Light orange
# (224, 0xFFCC00), # Yellow-orange
# (255, 0xFFFF00) # Bright yellow
# ]
#
# # Example 2: Ocean palette with named colors
@ -35,20 +35,20 @@
#
# # Example 3: Aurora palette (from the original example)
# palette aurora_borealis = [
# (0, #000022), # Dark night sky
# (64, #004400), # Dark green
# (128, #00AA44), # Aurora green
# (192, #44AA88), # Light green
# (255, #88FFAA) # Bright aurora
# (0, 0x000022), # Dark night sky
# (64, 0x004400), # Dark green
# (128, 0x00AA44), # Aurora green
# (192, 0x44AA88), # Light green
# (255, 0x88FFAA) # Bright aurora
# ]
#
# # Example 4: Sunset palette mixing hex and named colors
# palette sunset_sky = [
# (0, #191970), # Midnight blue
# (64, purple), # Purple twilight
# (128, #FF69B4), # Hot pink
# (192, orange), # Sunset orange
# (255, yellow) # Sun
# (0, 0x191970), # Midnight blue
# (64, purple), # Purple twilight
# (128, 0xFF69B4), # Hot pink
# (192, orange), # Sunset orange
# (255, yellow) # Sun
# ]
#
# # Create animations using each palette

View File

@ -13,12 +13,12 @@
#
# # Define plasma color palette with smooth transitions
# palette plasma_colors = [
# (0, #FF0080), # Magenta
# (51, #FF8000), # Orange
# (102, #FFFF00), # Yellow
# (153, #80FF00), # Yellow-green
# (204, #00FF80), # Cyan-green
# (255, #0080FF) # Blue
# (0, 0xFF0080), # Magenta
# (51, 0xFF8000), # Orange
# (102, 0xFFFF00), # Yellow
# (153, 0x80FF00), # Yellow-green
# (204, 0x00FF80), # Cyan-green
# (255, 0x0080FF) # Blue
# ]
#
# # Base plasma animation with medium speed

View File

@ -16,26 +16,26 @@
#
# # Left side red flashing
# animation left_red = pulse_position_animation(
# #FF0000, # Bright red
# 15, # center of left half
# 15, # half the strip
# 2 # sharp edges
# 0xFF0000, # Bright red
# 15, # center of left half
# 15, # half the strip
# 2 # sharp edges
# )
# left_red.priority = 10
# left_red.opacity = square(0, 255, 400ms, 50) # 50% duty cycle
#
# # Right side blue flashing (opposite phase)
# animation right_blue = pulse_position_animation(
# #0000FF, # Bright blue
# 45, # center of right half
# 15, # half the strip
# 2 # sharp edges
# 0x0000FF, # Bright blue
# 45, # center of right half
# 15, # half the strip
# 2 # sharp edges
# )
# right_blue.priority = 10
# right_blue.opacity = square(255, 0, 400ms, 50) # Opposite phase
#
# # Add white strobe overlay occasionally
# animation white_strobe = solid(#FFFFFF)
# animation white_strobe = solid(0xFFFFFF)
# white_strobe.opacity = square(0, 255, 100ms, 5) # Quick bright flashes
# white_strobe.priority = 20
#

View File

@ -12,9 +12,9 @@
# strip length 60
#
# # Define colors
# color red_custom = #FF0000
# color blue_custom = #0000FF
# color green_custom = #00FF00
# color red_custom = 0xFF0000
# color blue_custom = 0x0000FF
# color green_custom = 0x00FF00
#
# # Create animations
# animation left_pulse = pulse_position_animation(red_custom, 15, 15, 3)

View File

@ -13,7 +13,7 @@
#
# # Create smooth rainbow cycle animation
# animation rainbow_cycle = color_cycle_animation(
# [#FF0000, #FF8000, #FFFF00, #00FF00, #0000FF, #8000FF, #FF00FF], # rainbow colors
# [0xFF0000, 0xFF8000, 0xFFFF00, 0x00FF00, 0x0000FF, 0x8000FF, 0xFF00FF], # rainbow colors
# 5s # cycle period
# )
#

View File

@ -12,15 +12,15 @@
# strip length 60
#
# # Dark background
# color scanner_bg = #110000
# color scanner_bg = 0x110000
# animation background = solid(scanner_bg)
#
# # Main scanner pulse that bounces
# animation scanner = pulse_position_animation(
# #FF0000, # Bright red
# 2, # initial position
# 3, # pulse width
# 2 # fade region
# 0xFF0000, # Bright red
# 2, # initial position
# 3, # pulse width
# 2 # fade region
# )
# scanner.priority = 10
#
@ -29,10 +29,10 @@
#
# # Add trailing glow effect
# animation scanner_trail = pulse_position_animation(
# #660000, # Dim red trail
# 2, # initial position
# 6, # wider trail
# 4 # more fade
# 0x660000, # Dim red trail
# 2, # initial position
# 6, # wider trail
# 4 # more fade
# )
# scanner_trail.priority = 5
# scanner_trail.pos = triangle(2, 57, 2s)

View File

@ -13,15 +13,15 @@
#
# # Define time-of-day color palette
# palette daylight_colors = [
# (0, #000011), # Night - dark blue
# (32, #001133), # Pre-dawn
# (64, #FF4400), # Sunrise orange
# (96, #FFAA00), # Morning yellow
# (128, #FFFF88), # Midday bright
# (160, #FFAA44), # Afternoon
# (192, #FF6600), # Sunset orange
# (224, #AA2200), # Dusk red
# (255, #220011) # Night - dark red
# (0, 0x000011), # Night - dark blue
# (32, 0x001133), # Pre-dawn
# (64, 0xFF4400), # Sunrise orange
# (96, 0xFFAA00), # Morning yellow
# (128, 0xFFFF88), # Midday bright
# (160, 0xFFAA44), # Afternoon
# (192, 0xFF6600), # Sunset orange
# (224, 0xAA2200), # Dusk red
# (255, 0x220011) # Night - dark red
# ]
#
# # Main daylight cycle - very slow transition
@ -29,10 +29,10 @@
#
# # Add sun position effect - bright spot that moves
# animation sun_position = pulse_position_animation(
# #FFFFAA, # Bright yellow sun
# 5, # initial position
# 8, # sun size
# 4 # soft glow
# 0xFFFFAA, # Bright yellow sun
# 5, # initial position
# 8, # sun size
# 4 # soft glow
# )
# sun_position.priority = 10
# sun_position.pos = smooth(5, 55, 30s) # Sun arc across sky
@ -40,10 +40,10 @@
#
# # Add atmospheric glow around sun
# animation sun_glow = pulse_position_animation(
# #FFCC88, # Warm glow
# 5, # initial position
# 16, # larger glow
# 8 # very soft
# 0xFFCC88, # Warm glow
# 5, # initial position
# 16, # larger glow
# 8 # very soft
# )
# sun_glow.priority = 5
# sun_glow.pos = smooth(5, 55, 30s) # Follow sun
@ -51,9 +51,9 @@
#
# # Add twinkling stars during night phases
# animation stars = twinkle_animation(
# #FFFFFF, # White stars
# 6, # density (star count)
# 1s # twinkle speed (slow twinkle)
# 0xFFFFFF, # White stars
# 6, # density (star count)
# 1s # twinkle speed (slow twinkle)
# )
# stars.priority = 15
# stars.opacity = smooth(255, 0, 30s) # Fade out during day

View File

@ -12,22 +12,22 @@
# strip length 60
#
# # Dark blue background
# color night_sky = #000033
# color night_sky = 0x000033
# animation background = solid(night_sky)
#
# # White twinkling stars
# animation stars = twinkle_animation(
# #FFFFFF, # White stars
# 8, # density (number of stars)
# 500ms # twinkle speed (twinkle duration)
# 0xFFFFFF, # White stars
# 8, # density (number of stars)
# 500ms # twinkle speed (twinkle duration)
# )
# stars.priority = 10
#
# # Add occasional bright flash
# animation bright_flash = twinkle_animation(
# #FFFFAA, # Bright yellow-white
# 2, # density (fewer bright flashes)
# 300ms # twinkle speed (quick flash)
# 0xFFFFAA, # Bright yellow-white
# 2, # density (fewer bright flashes)
# 300ms # twinkle speed (quick flash)
# )
# bright_flash.priority = 15
#

View File

@ -5,13 +5,13 @@ strip length 60
# Define disco color palette
palette disco_colors = [
(0, #FF0000), # Red
(42, #FF8000), # Orange
(85, #FFFF00), # Yellow
(128, #00FF00), # Green
(170, #0000FF), # Blue
(213, #8000FF), # Purple
(255, #FF00FF) # Magenta
(0, 0xFF0000), # Red
(42, 0xFF8000), # Orange
(85, 0xFFFF00), # Yellow
(128, 0x00FF00), # Green
(170, 0x0000FF), # Blue
(213, 0x8000FF), # Purple
(255, 0xFF00FF) # Magenta
]
# Fast color cycling base
@ -21,7 +21,7 @@ animation disco_base = rich_palette_animation(disco_colors, 1s, linear, 255)
disco_base.opacity = square(0, 255, 100ms, 30) # Fast strobe
# Add white flash overlay
animation white_flash = solid(#FFFFFF)
animation white_flash = solid(0xFFFFFF)
white_flash.opacity = square(0, 255, 50ms, 10) # Quick white flashes
white_flash.priority = 20

View File

@ -5,11 +5,11 @@ strip length 60
# Define fire palette from black to yellow
palette fire_colors = [
(0, #000000), # Black
(64, #800000), # Dark red
(128, #FF0000), # Red
(192, #FF4500), # Orange red
(255, #FFFF00) # Yellow
(0, 0x000000), # Black
(64, 0x800000), # Dark red
(128, 0xFF0000), # Red
(192, 0xFF4500), # Orange red
(255, 0xFFFF00) # Yellow
]
# Create base fire animation with palette

View File

@ -4,32 +4,32 @@
strip length 60
# Dark background
color heart_bg = #110000
color heart_bg = 0x110000
animation background = solid(heart_bg)
# Define heartbeat timing - double pulse pattern
# First pulse (stronger)
animation heartbeat1 = solid(#FF0000) # Bright red
animation heartbeat1 = solid(0xFF0000) # Bright red
heartbeat1.opacity = square(0, 255, 150ms, 20) # Quick strong pulse
heartbeat1.priority = 10
# Second pulse (weaker, slightly delayed)
animation heartbeat2 = solid(#CC0000) # Slightly dimmer red
animation heartbeat2 = solid(0xCC0000) # Slightly dimmer red
# Delay the second pulse by adjusting the square wave phase
heartbeat2.opacity = square(0, 180, 150ms, 15) # Weaker pulse
heartbeat2.priority = 8
# Add subtle glow effect
animation heart_glow = solid(#660000) # Dim red glow
animation heart_glow = solid(0x660000) # Dim red glow
heart_glow.opacity = smooth(30, 100, 1s) # Gentle breathing glow
heart_glow.priority = 5
# Add center pulse for emphasis
animation center_pulse = pulse_position_animation(
#FFFFFF, # White center
30, # center of strip
4, # small center
2 # soft edges
0xFFFFFF, # White center
30, # center of strip
4, # small center
2 # soft edges
)
center_pulse.priority = 20
center_pulse.opacity = square(0, 200, 100ms, 10) # Quick white flash

View File

@ -5,11 +5,11 @@ strip length 60
# Define lava colors (warm oranges and reds)
palette lava_colors = [
(0, #330000), # Dark red
(64, #660000), # Medium red
(128, #CC3300), # Bright red
(192, #FF6600), # Orange
(255, #FFAA00) # Yellow-orange
(0, 0x330000), # Dark red
(64, 0x660000), # Medium red
(128, 0xCC3300), # Bright red
(192, 0xFF6600), # Orange
(255, 0xFFAA00) # Yellow-orange
]
# Base lava animation - very slow color changes

View File

@ -5,38 +5,38 @@ strip length 60
# Dark stormy background with subtle purple/blue
palette storm_colors = [
(0, #000011), # Very dark blue
(128, #110022), # Dark purple
(255, #220033) # Slightly lighter purple
(0, 0x000011), # Very dark blue
(128, 0x110022), # Dark purple
(255, 0x220033) # Slightly lighter purple
]
animation storm_bg = rich_palette_animation(storm_colors, 12s, smooth, 100)
# Random lightning flashes - full strip
animation lightning_main = solid(#FFFFFF) # Bright white
animation lightning_main = solid(0xFFFFFF) # Bright white
lightning_main.opacity = square(0, 255, 80ms, 3) # Quick bright flashes
lightning_main.priority = 20
# Secondary lightning - partial strip
animation lightning_partial = pulse_position_animation(
#FFFFAA, # Slightly yellow white
30, # center position
20, # covers part of strip
5 # soft edges
0xFFFFAA, # Slightly yellow white
30, # center position
20, # covers part of strip
5 # soft edges
)
lightning_partial.priority = 15
lightning_partial.opacity = square(0, 200, 120ms, 4) # Different timing
# Add blue afterglow
animation afterglow = solid(#4444FF) # Blue glow
animation afterglow = solid(0x4444FF) # Blue glow
afterglow.opacity = square(0, 80, 200ms, 8) # Longer, dimmer glow
afterglow.priority = 10
# Distant thunder (dim flashes)
animation distant_flash = twinkle_animation(
#666699, # Dim blue-white
4, # density (few flashes)
300ms # twinkle speed (medium duration)
0x666699, # Dim blue-white
4, # density (few flashes)
300ms # twinkle speed (medium duration)
)
distant_flash.priority = 5

View File

@ -4,16 +4,16 @@
strip length 60
# Dark background
color matrix_bg = #000000
color matrix_bg = 0x000000
animation background = solid(matrix_bg)
# Define matrix green palette
palette matrix_greens = [
(0, #000000), # Black
(64, #003300), # Dark green
(128, #006600), # Medium green
(192, #00AA00), # Bright green
(255, #00FF00) # Neon green
(0, 0x000000), # Black
(64, 0x003300), # Dark green
(128, 0x006600), # Medium green
(192, 0x00AA00), # Bright green
(255, 0x00FF00) # Neon green
]
# Create multiple cascading streams
@ -43,9 +43,9 @@ stream3.priority = 6
# Add random bright flashes (like code highlights)
animation code_flash = twinkle_animation(
#00FFAA, # Bright cyan-green
3, # density (few flashes)
150ms # twinkle speed (quick flash)
0x00FFAA, # Bright cyan-green
3, # density (few flashes)
150ms # twinkle speed (quick flash)
)
code_flash.priority = 20

View File

@ -4,51 +4,51 @@
strip length 60
# Dark space background
color space_bg = #000011
color space_bg = 0x000011
animation background = solid(space_bg)
# Multiple meteors with different speeds and colors
animation meteor1 = comet_animation(
#FFFFFF, # Bright white
12, # long trail
1.5s # fast speed
0xFFFFFF, # Bright white
12, # long trail
1.5s # fast speed
)
meteor1.priority = 15
animation meteor2 = comet_animation(
#FFAA00, # Orange
10, # medium trail
2s # medium speed
0xFFAA00, # Orange
10, # medium trail
2s # medium speed
)
meteor2.priority = 12
animation meteor3 = comet_animation(
#AAAAFF, # Blue-white
8, # shorter trail
1.8s # fast speed
0xAAAAFF, # Blue-white
8, # shorter trail
1.8s # fast speed
)
meteor3.priority = 10
animation meteor4 = comet_animation(
#FFAAAA, # Pink-white
14, # long trail
2.5s # slower speed
0xFFAAAA, # Pink-white
14, # long trail
2.5s # slower speed
)
meteor4.priority = 8
# Add distant stars
animation stars = twinkle_animation(
#CCCCCC, # Dim white
12, # density (many stars)
2s # twinkle speed (slow twinkle)
0xCCCCCC, # Dim white
12, # density (many stars)
2s # twinkle speed (slow twinkle)
)
stars.priority = 5
# Add occasional bright flash (meteor explosion)
animation meteor_flash = twinkle_animation(
#FFFFFF, # Bright white
1, # density (single flash)
100ms # twinkle speed (very quick)
0xFFFFFF, # Bright white
1, # density (single flash)
100ms # twinkle speed (very quick)
)
meteor_flash.priority = 25

View File

@ -5,10 +5,10 @@ strip length 60
# Define neon colors
palette neon_colors = [
(0, #FF0080), # Hot pink
(85, #00FF80), # Neon green
(170, #8000FF), # Electric purple
(255, #FF8000) # Neon orange
(0, 0xFF0080), # Hot pink
(85, 0x00FF80), # Neon green
(170, 0x8000FF), # Electric purple
(255, 0xFF8000) # Neon orange
]
# Main neon glow with color cycling
@ -18,7 +18,7 @@ animation neon_main = rich_palette_animation(neon_colors, 4s, linear, 255)
neon_main.opacity = smooth(220, 255, 200ms)
# Add occasional electrical surge
animation neon_surge = solid(#FFFFFF) # White surge
animation neon_surge = solid(0xFFFFFF) # White surge
neon_surge.opacity = square(0, 255, 50ms, 2) # Quick bright surges
neon_surge.priority = 20
@ -50,9 +50,9 @@ segment3.priority = 10
# Add electrical arcing between segments
animation arc_sparkles = twinkle_animation(
#AAAAFF, # Electric blue
4, # density (few arcs)
100ms # twinkle speed (quick arcs)
0xAAAAFF, # Electric blue
4, # density (few arcs)
100ms # twinkle speed (quick arcs)
)
arc_sparkles.priority = 15

View File

@ -5,11 +5,11 @@ strip length 60
# Define ocean color palette
palette ocean_colors = [
(0, #000080), # Deep blue
(64, #0040C0), # Ocean blue
(128, #0080FF), # Light blue
(192, #40C0FF), # Cyan
(255, #80FFFF) # Light cyan
(0, 0x000080), # Deep blue
(64, 0x0040C0), # Ocean blue
(128, 0x0080FF), # Light blue
(192, 0x40C0FF), # Cyan
(255, 0x80FFFF) # Light cyan
]
# Base ocean animation with slow color cycling
@ -38,9 +38,9 @@ wave2.pos = sawtooth(52, 8, 7s) # Opposite direction
# Add foam sparkles
animation foam = twinkle_animation(
#FFFFFF, # White foam
6, # density (sparkle count)
300ms # twinkle speed (quick sparkles)
0xFFFFFF, # White foam
6, # density (sparkle count)
300ms # twinkle speed (quick sparkles)
)
foam.priority = 15

View File

@ -5,20 +5,20 @@ strip length 30
# Define a fire palette
palette fire_colors = [
(0, #000000), # Black
(64, #800000), # Dark red
(128, #FF0000), # Red
(192, #FF8000), # Orange
(255, #FFFF00) # Yellow
(0, 0x000000), # Black
(64, 0x800000), # Dark red
(128, 0xFF0000), # Red
(192, 0xFF8000), # Orange
(255, 0xFFFF00) # Yellow
]
# Define an ocean palette
palette ocean_colors = [
(0, #000080), # Navy blue
(64, #0000FF), # Blue
(128, #00FFFF), # Cyan
(192, #00FF80), # Spring green
(255, #008000) # Green
(0, 0x000080), # Navy blue
(64, 0x0000FF), # Blue
(128, 0x00FFFF), # Cyan
(192, 0x00FF80), # Spring green
(255, 0x008000) # Green
]
# Create animations using the palettes

View File

@ -5,15 +5,15 @@ strip length 60
# Example 1: Fire palette with hex colors
palette fire_gradient = [
(0, #000000), # Black (no fire)
(32, #330000), # Very dark red
(64, #660000), # Dark red
(96, #CC0000), # Red
(128, #FF3300), # Red-orange
(160, #FF6600), # Orange
(192, #FF9900), # Light orange
(224, #FFCC00), # Yellow-orange
(255, #FFFF00) # Bright yellow
(0, 0x000000), # Black (no fire)
(32, 0x330000), # Very dark red
(64, 0x660000), # Dark red
(96, 0xCC0000), # Red
(128, 0xFF3300), # Red-orange
(160, 0xFF6600), # Orange
(192, 0xFF9900), # Light orange
(224, 0xFFCC00), # Yellow-orange
(255, 0xFFFF00) # Bright yellow
]
# Example 2: Ocean palette with named colors
@ -27,20 +27,20 @@ palette ocean_depths = [
# Example 3: Aurora palette (from the original example)
palette aurora_borealis = [
(0, #000022), # Dark night sky
(64, #004400), # Dark green
(128, #00AA44), # Aurora green
(192, #44AA88), # Light green
(255, #88FFAA) # Bright aurora
(0, 0x000022), # Dark night sky
(64, 0x004400), # Dark green
(128, 0x00AA44), # Aurora green
(192, 0x44AA88), # Light green
(255, 0x88FFAA) # Bright aurora
]
# Example 4: Sunset palette mixing hex and named colors
palette sunset_sky = [
(0, #191970), # Midnight blue
(64, purple), # Purple twilight
(128, #FF69B4), # Hot pink
(192, orange), # Sunset orange
(255, yellow) # Sun
(0, 0x191970), # Midnight blue
(64, purple), # Purple twilight
(128, 0xFF69B4), # Hot pink
(192, orange), # Sunset orange
(255, yellow) # Sun
]
# Create animations using each palette

View File

@ -5,12 +5,12 @@ strip length 60
# Define plasma color palette with smooth transitions
palette plasma_colors = [
(0, #FF0080), # Magenta
(51, #FF8000), # Orange
(102, #FFFF00), # Yellow
(153, #80FF00), # Yellow-green
(204, #00FF80), # Cyan-green
(255, #0080FF) # Blue
(0, 0xFF0080), # Magenta
(51, 0xFF8000), # Orange
(102, 0xFFFF00), # Yellow
(153, 0x80FF00), # Yellow-green
(204, 0x00FF80), # Cyan-green
(255, 0x0080FF) # Blue
]
# Base plasma animation with medium speed

View File

@ -8,26 +8,26 @@ set half_length = 30
# Left side red flashing
animation left_red = pulse_position_animation(
#FF0000, # Bright red
15, # center of left half
15, # half the strip
2 # sharp edges
0xFF0000, # Bright red
15, # center of left half
15, # half the strip
2 # sharp edges
)
left_red.priority = 10
left_red.opacity = square(0, 255, 400ms, 50) # 50% duty cycle
# Right side blue flashing (opposite phase)
animation right_blue = pulse_position_animation(
#0000FF, # Bright blue
45, # center of right half
15, # half the strip
2 # sharp edges
0x0000FF, # Bright blue
45, # center of right half
15, # half the strip
2 # sharp edges
)
right_blue.priority = 10
right_blue.opacity = square(255, 0, 400ms, 50) # Opposite phase
# Add white strobe overlay occasionally
animation white_strobe = solid(#FFFFFF)
animation white_strobe = solid(0xFFFFFF)
white_strobe.opacity = square(0, 255, 100ms, 5) # Quick bright flashes
white_strobe.priority = 20

View File

@ -4,9 +4,9 @@
strip length 60
# Define colors
color red_custom = #FF0000
color blue_custom = #0000FF
color green_custom = #00FF00
color red_custom = 0xFF0000
color blue_custom = 0x0000FF
color green_custom = 0x00FF00
# Create animations
animation left_pulse = pulse_position_animation(red_custom, 15, 15, 3)

View File

@ -5,7 +5,7 @@ strip length 60
# Create smooth rainbow cycle animation
animation rainbow_cycle = color_cycle_animation(
[#FF0000, #FF8000, #FFFF00, #00FF00, #0000FF, #8000FF, #FF00FF], # rainbow colors
[0xFF0000, 0xFF8000, 0xFFFF00, 0x00FF00, 0x0000FF, 0x8000FF, 0xFF00FF], # rainbow colors
5s # cycle period
)

View File

@ -4,15 +4,15 @@
strip length 60
# Dark background
color scanner_bg = #110000
color scanner_bg = 0x110000
animation background = solid(scanner_bg)
# Main scanner pulse that bounces
animation scanner = pulse_position_animation(
#FF0000, # Bright red
2, # initial position
3, # pulse width
2 # fade region
0xFF0000, # Bright red
2, # initial position
3, # pulse width
2 # fade region
)
scanner.priority = 10
@ -21,10 +21,10 @@ scanner.pos = triangle(2, 57, 2s)
# Add trailing glow effect
animation scanner_trail = pulse_position_animation(
#660000, # Dim red trail
2, # initial position
6, # wider trail
4 # more fade
0x660000, # Dim red trail
2, # initial position
6, # wider trail
4 # more fade
)
scanner_trail.priority = 5
scanner_trail.pos = triangle(2, 57, 2s)

View File

@ -5,15 +5,15 @@ strip length 60
# Define time-of-day color palette
palette daylight_colors = [
(0, #000011), # Night - dark blue
(32, #001133), # Pre-dawn
(64, #FF4400), # Sunrise orange
(96, #FFAA00), # Morning yellow
(128, #FFFF88), # Midday bright
(160, #FFAA44), # Afternoon
(192, #FF6600), # Sunset orange
(224, #AA2200), # Dusk red
(255, #220011) # Night - dark red
(0, 0x000011), # Night - dark blue
(32, 0x001133), # Pre-dawn
(64, 0xFF4400), # Sunrise orange
(96, 0xFFAA00), # Morning yellow
(128, 0xFFFF88), # Midday bright
(160, 0xFFAA44), # Afternoon
(192, 0xFF6600), # Sunset orange
(224, 0xAA2200), # Dusk red
(255, 0x220011) # Night - dark red
]
# Main daylight cycle - very slow transition
@ -21,10 +21,10 @@ animation daylight_cycle = rich_palette_animation(daylight_colors, 60s)
# Add sun position effect - bright spot that moves
animation sun_position = pulse_position_animation(
#FFFFAA, # Bright yellow sun
5, # initial position
8, # sun size
4 # soft glow
0xFFFFAA, # Bright yellow sun
5, # initial position
8, # sun size
4 # soft glow
)
sun_position.priority = 10
sun_position.pos = smooth(5, 55, 30s) # Sun arc across sky
@ -32,10 +32,10 @@ sun_position.opacity = smooth(0, 255, 30s) # Fade in and out
# Add atmospheric glow around sun
animation sun_glow = pulse_position_animation(
#FFCC88, # Warm glow
5, # initial position
16, # larger glow
8 # very soft
0xFFCC88, # Warm glow
5, # initial position
16, # larger glow
8 # very soft
)
sun_glow.priority = 5
sun_glow.pos = smooth(5, 55, 30s) # Follow sun
@ -43,9 +43,9 @@ sun_glow.opacity = smooth(0, 150, 30s) # Dimmer glow
# Add twinkling stars during night phases
animation stars = twinkle_animation(
#FFFFFF, # White stars
6, # density (star count)
1s # twinkle speed (slow twinkle)
0xFFFFFF, # White stars
6, # density (star count)
1s # twinkle speed (slow twinkle)
)
stars.priority = 15
stars.opacity = smooth(255, 0, 30s) # Fade out during day

View File

@ -4,22 +4,22 @@
strip length 60
# Dark blue background
color night_sky = #000033
color night_sky = 0x000033
animation background = solid(night_sky)
# White twinkling stars
animation stars = twinkle_animation(
#FFFFFF, # White stars
8, # density (number of stars)
500ms # twinkle speed (twinkle duration)
0xFFFFFF, # White stars
8, # density (number of stars)
500ms # twinkle speed (twinkle duration)
)
stars.priority = 10
# Add occasional bright flash
animation bright_flash = twinkle_animation(
#FFFFAA, # Bright yellow-white
2, # density (fewer bright flashes)
300ms # twinkle speed (quick flash)
0xFFFFAA, # Bright yellow-white
2, # density (fewer bright flashes)
300ms # twinkle speed (quick flash)
)
bright_flash.priority = 15

View File

@ -104,12 +104,13 @@ Adds temporal behavior to patterns.
**`animation.solid(color, priority=0, duration=0, loop=false, opacity=255, name="")`**
- Creates solid color animation
- **color**: ARGB color value (0xAARRGGBB)
- **color**: ARGB color value (0xAARRGGBB) or ValueProvider instance
- Returns: `PatternAnimation` instance
```berry
var red = animation.solid(0xFFFF0000)
var blue = animation.solid(0xFF0000FF, 10, 5000, true, 200, "blue_anim")
var dynamic = animation.solid(animation.smooth(0xFF000000, 0xFFFFFFFF, 3000))
```
**`animation.pulse(pattern, period_ms, min_brightness=0, max_brightness=255, priority=0, duration=0, loop=false, opacity=255, name="")`**
@ -126,12 +127,13 @@ 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
- **color**: ARGB color value or ValueProvider instance
- **period_ms**: Breathing period in milliseconds
- Returns: `BreatheAnimation` instance
```berry
var breathe_blue = animation.breathe(0xFF0000FF, 4000)
var dynamic_breathe = animation.breathe(animation.color_cycle_color_provider([0xFFFF0000, 0xFF00FF00], 2000), 4000)
```
### Palette-Based Animations
@ -152,48 +154,53 @@ var rainbow = animation.rich_palette_animation(animation.PALETTE_RAINBOW, 5000,
**`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
- **color**: ARGB color value or ValueProvider instance
- **pos**: Pixel position (0-based) or ValueProvider instance
- **pulse_size**: Width of pulse in pixels or ValueProvider instance
- **slew_size**: Fade region size in pixels or ValueProvider instance
- Returns: `PulsePositionAnimation` instance
```berry
var center_pulse = animation.pulse_position_animation(0xFFFFFFFF, 15, 3, 2)
var moving_pulse = animation.pulse_position_animation(0xFFFF0000, animation.smooth(0, 29, 3000), 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
- **color**: ARGB color value or ValueProvider instance
- **tail_length**: Length of comet tail in pixels
- **speed_ms**: Movement speed in milliseconds per pixel
- Returns: `CometAnimation` instance
```berry
var comet = animation.comet_animation(0xFF00FFFF, 8, 100)
var rainbow_comet = animation.comet_animation(animation.rich_palette_color_provider(animation.PALETTE_RAINBOW, 3000), 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
- **color**: ARGB color value or ValueProvider instance
- **density**: Number of twinkling pixels
- **speed_ms**: Twinkle speed in milliseconds
- Returns: `TwinkleAnimation` instance
```berry
var stars = animation.twinkle_animation(0xFFFFFFFF, 5, 500)
var color_changing_stars = animation.twinkle_animation(animation.color_cycle_color_provider([0xFFFF0000, 0xFF00FF00, 0xFF0000FF], 4000), 5, 500)
```
### Fire and Natural Effects
**`animation.fire_animation(intensity=200, speed_ms=100, priority=0, duration=0, loop=false, opacity=255, name="")`**
**`animation.fire_animation(color=nil, intensity=200, speed_ms=100, priority=0, duration=0, loop=false, opacity=255, name="")`**
- Creates realistic fire simulation
- **color**: ARGB color value, ValueProvider instance, or nil for default fire palette
- **intensity**: Fire intensity (0-255)
- **speed_ms**: Animation speed in milliseconds
- Returns: `FireAnimation` instance
```berry
var fire = animation.fire_animation(180, 150)
var fire = animation.fire_animation(nil, 180, 150) # Default fire palette
var blue_fire = animation.fire_animation(0xFF0066FF, 180, 150) # Blue fire
```
### Advanced Pattern Animations
@ -208,11 +215,12 @@ var fire = animation.fire_animation(180, 150)
**`animation.noise_single_color(color, scale, speed, strip_length, priority)`**
- Creates single-color noise pattern
- **color**: ARGB color value
- **color**: ARGB color value or ValueProvider instance
- Returns: `NoiseAnimation` instance
**`animation.noise_fractal(color_source, scale, speed, octaves, strip_length, priority)`**
**`animation.noise_fractal(color, scale, speed, octaves, strip_length, priority)`**
- Creates multi-octave fractal noise
- **color**: ARGB color value, ValueProvider instance, or nil for rainbow
- **octaves**: Number of noise octaves (1-4)
- Returns: `NoiseAnimation` instance
@ -229,7 +237,7 @@ var fractal = animation.noise_fractal(nil, 40, 50, 3, 30, 10)
**`animation.plasma_single_color(color, time_speed, strip_length, priority)`**
- Creates single-color plasma effect
- **color**: ARGB color value
- **color**: ARGB color value or ValueProvider instance
- Returns: `PlasmaAnimation` instance
```berry
@ -245,7 +253,7 @@ var purple_plasma = animation.plasma_single_color(0xFF8800FF, 60, 30, 10)
**`animation.sparkle_colored(color, density, fade_speed, strip_length, priority)`**
- Creates colored sparkles
- **color**: ARGB color value
- **color**: ARGB color value or ValueProvider instance
- Returns: `SparkleAnimation` instance
**`animation.sparkle_rainbow(density, fade_speed, strip_length, priority)`**
@ -266,11 +274,12 @@ var rainbow_sparkles = animation.sparkle_rainbow(60, 40, 30, 10)
**`animation.wave_single_sine(color, amplitude, wave_speed, strip_length, priority)`**
- Creates single-color sine wave
- **color**: ARGB color value
- **color**: ARGB color value or ValueProvider instance
- Returns: `WaveAnimation` instance
**`animation.wave_custom(color_source, wave_type, amplitude, frequency, strip_length, priority)`**
**`animation.wave_custom(color, wave_type, amplitude, frequency, strip_length, priority)`**
- Creates custom wave with specified type
- **color**: ARGB color value, ValueProvider instance, or nil for rainbow
- **wave_type**: 0=sine, 1=triangle, 2=square, 3=sawtooth
- **frequency**: Wave frequency/density (0-255)
- Returns: `WaveAnimation` instance
@ -447,11 +456,19 @@ var static_position = 15
- Returns: `OscillatorValueProvider`
**`animation.linear(start, end, period_ms)`**
- Triangle wave oscillation
- Triangle wave oscillation (goes from start to end, then back to start)
- Returns: `OscillatorValueProvider`
**`animation.triangle(start, end, period_ms)`**
- Alias for `linear()` - triangle wave oscillation
- Returns: `OscillatorValueProvider`
**`animation.ramp(start, end, period_ms)`**
- Sawtooth wave oscillation
- Sawtooth wave oscillation (linear progression from start to end)
- Returns: `OscillatorValueProvider`
**`animation.sawtooth(start, end, period_ms)`**
- Alias for `ramp()` - sawtooth wave oscillation
- Returns: `OscillatorValueProvider`
**`animation.square(start, end, period_ms, duty_cycle=50)`**

View File

@ -9,7 +9,7 @@ This document explains the organization of the Tasmota Berry Animation Framework
├── docs/ # User documentation
├── lib/libesp32/berry_animation/ # Framework source code
├── anim_examples/ # DSL animation examples (.anim files)
├── compiled/ # Compiled Berry code from DSL examples
├── anim_examples/compiled/ # Compiled Berry code from DSL examples
├── .kiro/ # Project specifications and design docs
└── .docs_archive/ # Archived technical implementation docs
```
@ -113,12 +113,12 @@ anim_examples/
└── simple_pulse.anim # Basic pulsing effect
```
## Compiled Examples (`compiled/`)
## Compiled Examples (`anim_examples/compiled/`)
Berry code generated from DSL examples (for reference):
```
compiled/
anim_examples/compiled/
├── aurora_borealis.be # Compiled from aurora_borealis.anim
├── breathing_colors.be # Compiled from breathing_colors.anim
└── ... (compiled versions of .anim files)
@ -200,7 +200,7 @@ Technical implementation documents moved from active documentation:
### DSL Files
- **`*.anim`** - DSL animation files
- **`*.be`** (in compiled/) - Compiled Berry code from DSL
- **`*.be`** (in anim_examples/compiled/) - Compiled Berry code from DSL
## Navigation Tips

View File

@ -58,7 +58,9 @@ class DSLLexer
self.column = 1
return
elif ch == '#'
self.scan_comment_or_color()
self.scan_comment()
elif ch == '0' && self.peek() == 'x'
self.scan_hex_color_0x()
elif self.is_alpha(ch) || ch == '_'
self.scan_identifier_or_keyword()
elif self.is_digit(ch)
@ -72,30 +74,27 @@ class DSLLexer
end
end
# Scan comment or hex color (both start with #)
def scan_comment_or_color()
# Scan comment (now unambiguous - only starts with #)
def scan_comment()
var start_pos = self.position - 1
var start_column = self.column - 1
# Look ahead to see if this is a hex color
if self.position < size(self.source) && self.is_hex_digit(self.source[self.position])
# This is a hex color
self.scan_hex_color()
else
# This is a comment - consume until end of line
while !self.at_end() && self.peek() != '\n'
self.advance()
end
var comment_text = self.source[start_pos..self.position-1]
self.add_token(37 #-animation.Token.COMMENT-#, comment_text, self.position - start_pos)
# This is a comment - consume until end of line
while !self.at_end() && self.peek() != '\n'
self.advance()
end
var comment_text = self.source[start_pos..self.position-1]
self.add_token(37 #-animation.Token.COMMENT-#, comment_text, self.position - start_pos)
end
# Scan hex color (#RRGGBB, #RGB, #AARRGGBB, or #ARGB)
def scan_hex_color()
var start_pos = self.position - 1 # Include the #
# Scan hex color (0xRRGGBB, 0xAARRGGBB)
def scan_hex_color_0x()
var start_pos = self.position - 1 # Include the '0'
var start_column = self.column - 1
# Advance past 'x'
self.advance()
var hex_digits = 0
# Count hex digits
@ -106,11 +105,11 @@ class DSLLexer
var color_value = self.source[start_pos..self.position-1]
# Validate hex color format - support alpha channel
if hex_digits == 3 || hex_digits == 4 || hex_digits == 6 || hex_digits == 8
# Validate hex color format - support 6 (RGB) or 8 (ARGB) digits
if hex_digits == 6 || hex_digits == 8
self.add_token(4 #-animation.Token.COLOR-#, color_value, size(color_value))
else
self.add_error("Invalid hex color format: " + color_value)
self.add_error("Invalid hex color format: " + color_value + " (expected 0xRRGGBB or 0xAARRGGBB)")
self.add_token(39 #-animation.Token.ERROR-#, color_value, size(color_value))
end
end

View File

@ -870,7 +870,16 @@ class SimpleDSLTranspiler
# Conversion helpers
def convert_color(color_str)
import string
# Handle hex colors
# Handle 0x hex colors (new format)
if string.startswith(color_str, "0x")
if size(color_str) == 10 # 0xAARRGGBB (with alpha channel)
return color_str
elif size(color_str) == 8 # 0xRRGGBB (without alpha channel - add opaque alpha)
return f"0xFF{color_str[2..]}"
end
end
# Handle legacy # hex colors (for backward compatibility during transition)
if string.startswith(color_str, "#")
if size(color_str) == 9 # #AARRGGBB (with alpha channel)
return f"0x{color_str[1..]}"

View File

@ -1,170 +0,0 @@
# Ported Examples - Legacy to Modern Animation Framework
This directory contains examples that demonstrate the evolution from the legacy `animate` module to the modern Berry Animation Framework. Each example is provided in three versions to show different approaches and capabilities.
## Overview
The examples are organized into three categories:
- **Option A: Direct 1:1 Ports** (`ported/`) - Exact functionality using new framework
- **Option B: Enhanced Modern Versions** (`enhanced/`) - Improved versions showcasing new capabilities
- **Option C: DSL-Based Ports** (`dsl/`) - Declarative syntax versions
## Example Categories
### 1. Breathing Effect Examples
**Original**: `berry_animate_examples/animate_demo_breathe.be`
- Used old `animate.core()`, `animate.pulse()`, `animate.palette()`, `animate.oscillator()`
- Complex callback-based architecture
- ~25 lines of setup code
**Ported Versions**:
- **A**: `ported/breathe_demo_ported.be` - Direct port using `BreatheAnimation` + `RichPaletteColorProvider`
- **B**: `enhanced/modern_breathe_showcase.be` - Multi-layer breathing with events and dynamic parameters
- **C**: `dsl/breathe_demo.anim` - Clean DSL syntax (~15 lines)
### 2. Palette Background Examples
**Original**: `berry_animate_examples/animate_demo_palette_background.be`
- Used old `animate.core()` with `add_background_animator()`
- Simple rainbow cycling background
**Ported Versions**:
- **A**: `ported/palette_background_demo_ported.be` - Direct port using `FilledAnimation` + rainbow palette
- **B**: `enhanced/advanced_palette_demo.be` - Multiple palettes with layering and mode switching
- **C**: `dsl/palette_background_demo.anim` - Minimal DSL syntax
### 3. Pulse Effect Examples
**Original**: `berry_animate_examples/animate_demo_pulse.be`
- Used old `animate.core()`, `animate.pulse()`, `animate.oscillator()`, `animate.palette()`
- Moving pulse with oscillating position and cycling color
**Ported Versions**:
- **A**: `ported/pulse_demo_ported.be` - Direct port using `PulsePositionAnimation` + `OscillatorValueProvider`
- **B**: `enhanced/dynamic_pulse_demo.be` - Multiple pulse types with interactive control
- **C**: `dsl/pulse_demo.anim` - Declarative pulse definition
### 4. Blending Examples
**Original**: `berry_animate_examples/leds_blend_demo.be`
- Used old `animate.frame()` with manual blending
- Low-level frame buffer operations
**Ported Versions**:
- **A**: `ported/blend_demo_ported.be` - Direct port using new `FrameBuffer` blending
- **B**: `enhanced/comprehensive_blend_demo.be` - Advanced multi-layer blending with interactive control
- **C**: DSL blending is handled automatically by the animation engine
## Key Improvements in New Framework
### Code Simplicity
- **Legacy**: Complex callback chains and manual object management
- **Modern**: Clean object-oriented design with value providers
- **DSL**: Declarative syntax that's easy to read and modify
### Performance
- **Legacy**: Multiple separate objects with manual coordination
- **Modern**: Unified engine with optimized rendering pipeline
- **DSL**: Compiled to optimized Berry code
### Capabilities
- **Legacy**: Basic effects with manual parameter control
- **Modern**: Advanced layering, blending, dynamic parameters, event system
- **DSL**: Full framework capabilities with simple syntax
### Maintainability
- **Legacy**: Tightly coupled code, hard to modify
- **Modern**: Modular design, easy to extend
- **DSL**: Configuration-based, non-programmers can create animations
## Running the Examples
### Direct Ports (Option A)
```berry
# Run individual ported examples
load("lib/libesp32/berry_animation/examples/ported/breathe_demo_ported.be")
load("lib/libesp32/berry_animation/examples/ported/palette_background_demo_ported.be")
load("lib/libesp32/berry_animation/examples/ported/pulse_demo_ported.be")
load("lib/libesp32/berry_animation/examples/ported/blend_demo_ported.be")
```
### Enhanced Versions (Option B)
```berry
# Run enhanced examples with advanced features
load("lib/libesp32/berry_animation/examples/enhanced/modern_breathe_showcase.be")
load("lib/libesp32/berry_animation/examples/enhanced/advanced_palette_demo.be")
load("lib/libesp32/berry_animation/examples/enhanced/dynamic_pulse_demo.be")
load("lib/libesp32/berry_animation/examples/enhanced/comprehensive_blend_demo.be")
```
### DSL Versions (Option C)
```berry
# Run DSL examples using the demo runner
load("lib/libesp32/berry_animation/examples/dsl/run_dsl_demo.be")
# Edit the demo_file variable in run_dsl_demo.be to try different DSL files
```
## Interactive Features
Many enhanced examples include interactive event systems. You can trigger events from the Berry console:
```berry
# Speed up animations
animation.trigger_event("speed_up", {})
# Toggle layers
animation.trigger_event("toggle_layer", {"layer": "rainbow_comet"})
# Switch modes
animation.trigger_event("mode_switch", {})
# Adjust opacity
animation.trigger_event("adjust_opacity", {"layer": "all", "opacity": 100})
```
## Educational Value
These examples demonstrate:
1. **Migration Path**: How to convert legacy code to the new framework
2. **Architecture Evolution**: From callback-based to object-oriented to declarative
3. **Feature Progression**: Basic effects → Advanced layering → Simple DSL syntax
4. **Best Practices**: Modern Berry coding patterns and animation techniques
5. **Framework Capabilities**: Full range of new framework features
## File Structure
```
examples/
├── ported/ # Direct 1:1 ports (Option A)
│ ├── breathe_demo_ported.be
│ ├── palette_background_demo_ported.be
│ ├── pulse_demo_ported.be
│ └── blend_demo_ported.be
├── enhanced/ # Enhanced modern versions (Option B)
│ ├── modern_breathe_showcase.be
│ ├── advanced_palette_demo.be
│ ├── dynamic_pulse_demo.be
│ └── comprehensive_blend_demo.be
├── dsl/ # DSL-based ports (Option C)
│ ├── breathe_demo.anim
│ ├── palette_background_demo.anim
│ ├── pulse_demo.anim
│ ├── enhanced_breathe_showcase.anim
│ ├── advanced_palette_showcase.anim
│ ├── dynamic_pulse_showcase.anim
│ └── run_dsl_demo.be # DSL runner utility
└── PORTED_EXAMPLES_README.md # This file
```
## Next Steps
1. Try running each version to see the visual differences
2. Compare the code complexity between versions
3. Experiment with the interactive features in enhanced versions
4. Create your own DSL animations using the examples as templates
5. Use the ported examples as a reference for migrating your own legacy animations
The progression from legacy → modern → DSL demonstrates the evolution of the animation framework and provides multiple approaches for different use cases and skill levels.

View File

@ -1,123 +0,0 @@
# Comprehensive demo of all easing types in OscillatorValueProvider
#
# This demo shows all available easing waveforms:
# EASE_IN, EASE_OUT, ELASTIC, and BOUNCE
import global
import tasmota
# Mock tasmota functions for testing
if !global.contains("tasmota")
tasmota = {}
tasmota.millis = def() return 1000 end
tasmota.scale_uint = def(value, from_min, from_max, to_min, to_max)
if from_max == from_min return to_min end
return to_min + ((value - from_min) * (to_max - to_min)) / (from_max - from_min)
end
tasmota.sine_int = def(angle)
import math
return int(4096 * math.sin(angle * math.pi / 16384))
end
end
# Load just the oscillator provider
import "providers/oscillator_value_provider.be" as osc_provider
print("=== Complete Easing Types Demo ===")
print("Showing all available easing waveforms (0->100 over 1000ms)")
# Create all easing types
var ease_in = osc_provider.ease_in(0, 100, 1000)
var ease_out = osc_provider.ease_out(0, 100, 1000)
var elastic = osc_provider.elastic(0, 100, 1000)
var bounce = osc_provider.bounce(0, 100, 1000)
var linear = osc_provider.linear(0, 100, 1000) # For comparison
print("\nTime% Linear Ease-In Ease-Out Elastic Bounce")
print("---- ------ ------- -------- ------- ------")
var start_time = 1000
for i: [0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
var percent = i / 10 # Convert to percentage
var linear_val = linear.get_value(start_time + i)
var ease_in_val = ease_in.get_value(start_time + i)
var ease_out_val = ease_out.get_value(start_time + i)
var elastic_val = elastic.get_value(start_time + i)
var bounce_val = bounce.get_value(start_time + i)
print(f"{percent:3.0f}% {linear_val:6d} {ease_in_val:7d} {ease_out_val:8d} {elastic_val:7d} {bounce_val:6d}")
end
print("\n=== Easing Type Characteristics ===")
print("\n1. EASE_IN (Quadratic Acceleration)")
print(" • Starts slow, accelerates")
print(" • Formula: f(t) = t²")
print(" • Use: Smooth start-up animations")
print(" • Constructor: animation.ease_in(start, end, duration)")
print("\n2. EASE_OUT (Quadratic Deceleration)")
print(" • Starts fast, decelerates")
print(" • Formula: f(t) = 1 - (1-t)²")
print(" • Use: Smooth stop animations")
print(" • Constructor: animation.ease_out(start, end, duration)")
print("\n3. ELASTIC (Spring-like)")
print(" • Overshoots and oscillates like a spring")
print(" • Shows spring-back behavior")
print(" • Use: Playful, attention-grabbing effects")
print(" • Constructor: animation.elastic(start, end, duration)")
print("\n4. BOUNCE (Ball-like)")
print(" • Bounces like a ball with decreasing amplitude")
print(" • Multiple bounces that settle")
print(" • Use: Drop animations, impact effects")
print(" • Constructor: animation.bounce(start, end, duration)")
print("\n=== Usage Examples ===")
print("\n# Smooth brightness fade-in")
print("var brightness = animation.ease_in(0, 255, 3000)")
print("var fade_anim = animation.filled(0xFF0000FF, brightness, 0, false, 'fade')")
print("\n# Gentle position movement")
print("var position = animation.ease_out(0, 29, 2000)")
print("var move_anim = animation.pulse_position(0xFF00FF00, 5, position, 1, 10, 0, true, 'move')")
print("\n# Playful spring effect")
print("var spring_size = animation.elastic(1, 10, 2500)")
print("var spring_anim = animation.pulse(0xFFFF0000, spring_size, 0, 0, true, 'spring')")
print("\n# Bouncing comet")
print("var bounce_pos = animation.bounce(0, 29, 3000)")
print("var comet_anim = animation.comet(0xFF00FFFF, bounce_pos, 8, 200, true, 'bouncy')")
print("\n# DSL Integration")
print("# animation smooth_pulse = pulse(red, ease_in(50, 255, 2s), 0, 0)")
print("# animation spring_move = comet(blue, elastic(0, 29, 3s), 5, 128)")
print("# animation bouncy_breathe = breathe(green, bounce(30, 255, 4s), 8000)")
print("\n=== Advanced Features ===")
print("\n• All easing types support phase shifts:")
var phased_elastic = osc_provider.elastic(0, 100, 2000)
phased_elastic.set_phase(25)
print(f" Elastic with 25% phase: {phased_elastic}")
print("\n• Method chaining works with all types:")
var chained = osc_provider.bounce(10, 90, 3000).set_phase(10)
print(f" Chained bounce: {chained}")
print("\n• All types work with any value range:")
print(" animation.elastic(-50, 150, 2000) # Negative to positive")
print(" animation.bounce(100, 105, 1000) # Small range")
print(" animation.ease_in(1000, 0, 3000) # Reverse direction")
print("\n=== Performance Notes ===")
print("• All calculations use integer arithmetic")
print("• Uses tasmota.scale_uint for efficient scaling")
print("• Minimal memory overhead")
print("• Suitable for embedded systems")
print("\n=== Demo Complete ===")
print("All easing types are now available in the Berry Animation Framework!")

View File

@ -1,311 +0,0 @@
# Animation Engine Demo
#
# This example demonstrates how to use the unified AnimationEngine
# to manage animations for an LED strip.
# Import the animation module
import animation
import math
import tasmota
import global
# Create a mock WS2812 class for testing
class WS2812
var length_value
var pixels
var show_called
var can_show_result
def init(length)
self.length_value = length
self.pixels = {}
self.show_called = false
self.can_show_result = true
end
def length()
return self.length_value
end
def set_pixel_color(index, r, g, b)
self.pixels[index] = {
"r": r,
"g": g,
"b": b
}
end
def show()
self.show_called = true
end
def can_show()
return self.can_show_result
end
end
# Create a simple animation that pulses a color
class PulseAnimation : animation.animation
var color
var min_brightness
var max_brightness
def init(color, min_brightness, max_brightness, duration)
# Initialize with priority 1, specified duration, and looping enabled
super(self).init(1, duration, true, "pulse")
# Store parameters
self.color = color
self.min_brightness = min_brightness
self.max_brightness = max_brightness
# Register parameters with validation
self.register_param("color", {"default": 0xFF0000}) # Default to red
self.register_param("min_brightness", {"min": 0, "max": 100, "default": 10})
self.register_param("max_brightness", {"min": 0, "max": 100, "default": 100})
# Set initial values
self.set_param("color", color)
self.set_param("min_brightness", min_brightness)
self.set_param("max_brightness", max_brightness)
end
def render(frame)
if !self.is_running || frame == nil
return false
end
# Calculate current brightness based on progress
var progress = self.get_progress()
# Convert progress to 0.0-1.0 range and use sine wave for smooth pulsing (0 to 1 to 0)
var progress_float = progress / 255.0
var brightness_factor = math.sin(progress_float * math.pi)
# Scale brightness between min and max
var brightness_range = self.max_brightness - self.min_brightness
var brightness = self.min_brightness + (brightness_factor * brightness_range)
# Extract color components
var r = self.color & 0xFF
var g = (self.color >> 8) & 0xFF
var b = (self.color >> 16) & 0xFF
# Apply brightness
r = tasmota.scale_uint(r, 0, 255, 0, tasmota.scale_uint(brightness, 0, 100, 0, 255))
g = tasmota.scale_uint(g, 0, 255, 0, tasmota.scale_uint(brightness, 0, 100, 0, 255))
b = tasmota.scale_uint(b, 0, 255, 0, tasmota.scale_uint(brightness, 0, 100, 0, 255))
# Fill the frame with the color at the calculated brightness
frame.fill_pixels(animation.frame_buffer.to_color(r, g, b, 255))
return true
end
def on_param_changed(name, value)
if name == "color"
self.color = value
elif name == "min_brightness"
self.min_brightness = value
elif name == "max_brightness"
self.max_brightness = value
end
end
end
# Create a simple animation that moves a dot across the strip
class MovingDotAnimation : animation.animation
var color
var background_color
var dot_size
var direction
var position
def init(color, background_color, dot_size, duration)
# Initialize with priority 2, specified duration, and looping enabled
super(self).init(2, duration, true, "moving_dot")
# Store parameters
self.color = color
self.background_color = background_color
self.dot_size = dot_size
self.direction = 1 # 1 for right, -1 for left
self.position = 0
# Register parameters
self.register_param("color", {"default": 0xFFFFFF}) # Default to white
self.register_param("background_color", {"default": 0x000000}) # Default to black
self.register_param("dot_size", {"min": 1, "default": 3})
self.register_param("direction", {"enum": [1, -1], "default": 1})
# Set initial values
self.set_param("color", color)
self.set_param("background_color", background_color)
self.set_param("dot_size", dot_size)
self.set_param("direction", self.direction)
end
def render(frame)
if !self.is_running || frame == nil
return false
end
# Calculate current position based on progress
var progress = self.get_progress()
var width = frame.width
# Calculate position (0 to width-1) - convert progress from 0-255 to 0.0-1.0 range
var progress_float = progress / 255.0
self.position = int(progress_float * width)
# Fill background
frame.fill_pixels(animation.frame_buffer.to_color(
self.background_color & 0xFF,
(self.background_color >> 8) & 0xFF,
(self.background_color >> 16) & 0xFF,
255
))
# Draw dot
var half_size = self.dot_size / 2
var start_pos = self.position - half_size
var end_pos = self.position + half_size
# Ensure dot is within bounds
if start_pos < 0
start_pos = 0
end
if end_pos >= width
end_pos = width - 1
end
# Draw the dot
for i: start_pos..end_pos
frame.set_pixel_color(i,
animation.frame_buffer.to_color(
self.color & 0xFF,
(self.color >> 8) & 0xFF,
(self.color >> 16) & 0xFF
)
)
end
return true
end
def on_param_changed(name, value)
if name == "color"
self.color = value
elif name == "background_color"
self.background_color = value
elif name == "dot_size"
self.dot_size = value
elif name == "direction"
self.direction = value
end
end
end
# Main demo function
def run_demo()
# Create a WS2812 LED strip (adjust parameters for your setup)
var strip_length = 30
var strip = WS2812(strip_length)
# Create the animation engine
var engine = animation.create_engine(strip)
# Create animations
var pulse = PulseAnimation(0xFF0000, 10, 100, 2000) # Red pulse, 2 seconds duration
var dot = MovingDotAnimation(0x00FF00, 0x000000, 3, 5000) # Green dot, 5 seconds duration
# Add animations to the engine
engine.add_animation(pulse)
engine.add_animation(dot)
# Start the engine
engine.start()
print("Animation engine demo started")
print("Press 'b+' to increase brightness")
print("Press 'b-' to decrease brightness")
print("Press 's' to stop animations")
print("Press 'r' to restart animations")
print("Press 'p' to pause animations (keeps fast_loop active)")
print("Press 'c' to resume animations")
print("Press 'i' to show controller info")
print("Press 'q' to quit")
# Set up a simple command handler
def handle_command(cmd)
if cmd == "b+"
# Brightness is now handled by the strip object
var current_bri = strip.get_bri()
var new_bri = current_bri + 25 # Increase by ~10% (25/255)
if new_bri > 255
new_bri = 255
end
strip.set_bri(new_bri)
print(f"Brightness set to {tasmota.scale_uint(new_bri, 0, 255, 0, 100)}%")
elif cmd == "b-"
# Brightness is now handled by the strip object
var current_bri = strip.get_bri()
var new_bri = current_bri - 25 # Decrease by ~10% (25/255)
if new_bri < 0
new_bri = 0
end
strip.set_bri(new_bri)
print(f"Brightness set to {tasmota.scale_uint(new_bri, 0, 255, 0, 100)}%")
elif cmd == "s"
engine.stop()
print("Animations stopped")
elif cmd == "r"
engine.start()
print("Animations restarted")
elif cmd == "p"
# Pause individual animations
for anim : engine.get_animations()
anim.pause()
end
print("Animations paused (fast_loop still active)")
elif cmd == "c"
# Resume individual animations
for anim : engine.get_animations()
anim.resume()
end
print("Animations resumed")
elif cmd == "i"
print(engine)
print(f"Last update: {engine.last_update} ms")
print(f"Current time: {tasmota.millis()} ms")
elif cmd == "q"
engine.stop()
print("Demo ended")
return false
end
return true
end
# In a real application, you would integrate with Tasmota's command system
# For this demo, we'll just return the engine and handler for manual testing
return {
"engine": engine,
"handler": handle_command
}
end
# Run the demo if this file is executed directly
try
if tasmota != nil
# When running in Tasmota
var demo = run_demo()
return demo
end
except .. as e
# When running in standalone Berry or if tasmota is not available
print("This demo is designed to run in Tasmota")
print("Running in simulation mode...")
var demo = run_demo()
print("Demo initialized successfully in simulation mode")
return demo
end

View File

@ -1,98 +0,0 @@
# Breathe Animation Demo with LED Values
#
# This example demonstrates the Breathe animation effect
# which creates a smooth, natural breathing effect with customizable parameters.
#
# The demo creates a blue breathing effect with a 3-second period and shows actual LED values.
#
# Command to run demo:
# ./berry -s -g -m lib/libesp32/berry_animation lib/libesp32/berry_animation/examples/breathe_animation_demo.be
import global
import tasmota
import animation
def dump_rgb(strip)
var output = "LEDs: ["
for i:0..strip.length()-1
var color = strip.get_pixel_color(i)
var r = (color >> 16) & 0xFF
var g = (color >> 8) & 0xFF
var b = color & 0xFF
if i > 0
output += ", "
end
output += format("R:%d,G:%d,B:%d", r, g, b)
end
output += "]"
print(output)
end
def dump(strip)
var output = "["
for i:0..strip.length()-1
if i > 0
output += ", "
end
output += format("0x%06X", strip.get_pixel_color(i) & 0xFFFFFF)
end
output += "]"
print(output)
end
print("Starting Breathe animation demo with LED values...")
# Create a mock LED strip with 5 pixels (reduced for readability)
var strip = global.Leds(5)
# Create an animation controller for the strip
var controller = animation.animation_controller(strip)
# Create a breathe animation with blue color
# Parameters:
# - Color: 0xFF0000FF (blue)
# - Min brightness: 10
# - Max brightness: 200
# - Breathe period: 3000ms (3 seconds)
# - Curve factor: 3 (medium-high curve for more natural breathing)
# - Priority: 1
# - Duration: 0 (infinite)
# - Loop: true
var breathe_anim = animation.breathe_animation(0xFF0000FF, 10, 200, 3000, 3, 1, 255, 0, true)
# Add the animation to the controller and start it
controller.add_animation(breathe_anim)
breathe_anim.start()
# Start the controller
controller.start()
# Simulate the fast_loop for a full breathing cycle
print("Simulating animation updates for one full breathing cycle...")
var start_time = tasmota.millis()
var end_time = start_time + 3500 # Run for slightly more than one cycle
var update_interval = 300 # Update every 300ms for demonstration
# Simulate updates
var current_time = start_time
while current_time < end_time
# Update the controller with the current time
controller.on_tick(current_time)
# Show the current state with detailed LED values
print(f"Time: {current_time - start_time}ms, Brightness: {breathe_anim.current_brightness}")
dump_rgb(strip) # Show RGB components
dump(strip) # Show hex values for reference
# Increment time
current_time += update_interval
end
print("Breathe animation demo completed")
# Stop the animation
controller.stop()
return true

View File

@ -1,147 +0,0 @@
# Clean API Demo
# Demonstrates the simplified, unified animation API
import animation
import tasmota
print("=== Clean Animation API Demo ===")
# Mock LED strip for demonstration
class MockStrip
var length_val
var pixels
def init(length)
self.length_val = length
self.pixels = []
for i : 0..length-1
self.pixels.push(0x00000000)
end
end
def length()
return self.length_val
end
def set_pixel_color(index, color)
if index >= 0 && index < self.length_val
self.pixels[index] = color
end
end
def show()
print(f"✓ Strip updated with {self.length_val} pixels")
end
def can_show()
return true
end
end
print("\n--- Simple Setup ---")
# Create LED strip
var strip = MockStrip(30)
print(f"Created strip with {strip.length()} pixels")
# Create animation engine - ONE LINE SETUP!
var engine = animation.create_engine(strip)
print(f"Created engine: {engine}")
print("\n--- Add Animations ---")
# Create some animations
var red_fill = animation.solid(0xFFFF0000, 10) # Solid red, priority 10
var blue_pulse = animation.pulse_animation(0xFF0000FF, 2000, 5) # Blue pulse, 2s, priority 5
var rainbow = animation.rich_palette_animation(animation.PALETTE_RAINBOW, 5000, 1, 255, 15) # Rainbow, priority 15
print("Created animations:")
print(f" Red fill: priority {red_fill.priority}")
print(f" Blue pulse: priority {blue_pulse.priority}")
print(f" Rainbow: priority {rainbow.priority}")
# Add animations to engine
engine.add_animation(red_fill)
engine.add_animation(blue_pulse)
engine.add_animation(rainbow)
print(f"Engine now managing {engine.size()} animations")
print("\n--- Start Animation System ---")
# Start the engine
engine.start()
print(f"Engine started: {engine.is_active()}")
print("\n--- Simulate Animation Loop ---")
# Simulate some animation frames
var current_time = tasmota.millis()
for i : 0..5
print(f"\nFrame {i+1}:")
engine.on_tick(current_time + (i * 50)) # 50ms intervals
var active_animations = engine.get_animations()
print(f" Active animations: {size(active_animations)}")
for anim : active_animations
if anim.is_running
print(f" ✓ {anim.name} (priority: {anim.priority})")
end
end
end
print("\n--- Sequence Management ---")
# Create and run a sequence
var seq_manager = animation.SequenceManager(engine)
var steps = []
# Build sequence: red for 1s, wait 0.5s, rainbow for 2s
steps.push(animation.create_play_step(red_fill, 1000))
steps.push(animation.create_wait_step(500))
steps.push(animation.create_play_step(rainbow, 2000))
print(f"Created sequence with {size(steps)} steps")
# Add sequence to engine and start
engine.add_sequence_manager(seq_manager)
seq_manager.start_sequence(steps)
print("Sequence started - simulating execution...")
# Simulate sequence execution
for i : 0..8
print(f"Sequence frame {i+1}:")
engine.on_tick(current_time + 1000 + (i * 250)) # 250ms intervals
if seq_manager.is_sequence_running()
var step_info = seq_manager.get_current_step_info()
print(f" Current step: {step_info}")
else
print(" ✓ Sequence completed")
break
end
end
print("\n--- Cleanup ---")
# Stop the engine
engine.stop()
print(f"Engine stopped: {engine.is_active()}")
# Clear all animations
engine.clear()
print(f"Animations cleared: {engine.size()} remaining")
print("\n=== API Summary ===")
print("The unified animation API provides:")
print("✓ Single object creation: animation.create_engine(strip)")
print("✓ Simple animation management: engine.add_animation()")
print("✓ Easy lifecycle control: engine.start() / engine.stop()")
print("✓ Integrated sequence support: engine.add_sequence_manager()")
print("✓ Clean, intuitive interface with no deprecated components")
print("✓ High performance through unified architecture")
print("\n=== Demo Complete ===")
print("This demonstrates the clean, simplified animation framework")
print("that replaces the previous complex multi-object architecture")

View File

@ -1,186 +0,0 @@
# Color Ambiguity Resolution Demo
# Demonstrates how the DSL handles color name conflicts between predefined and user-defined colors
#
# Command to run demo:
# ./berry -s -g -m lib/libesp32/berry_animation lib/libesp32/berry_animation/examples/color_ambiguity_demo.be
import tasmota
import animation
print("=== Color Ambiguity Resolution Demo ===")
print("This demo shows how the DSL resolves conflicts between predefined and user-defined colors.")
print("")
# Test Case 1: Using predefined colors without redefinition
print("--- Test Case 1: Predefined Colors (No Conflicts) ---")
var test1_dsl = "strip length 30\n" +
"color primary = red\n" + # 'red' is predefined
"color secondary = blue\n" + # 'blue' is predefined
"pattern red_pattern = solid(red)\n" + # Should use predefined red
"pattern blue_pattern = solid(blue)\n" # Should use predefined blue
print("DSL Input:")
print(test1_dsl)
print("")
var test1_berry = animation.compile_dsl(test1_dsl)
if test1_berry != nil
print("Generated Berry Code:")
print(test1_berry)
print("✅ Test 1 PASSED: Predefined colors used correctly")
else
print("❌ Test 1 FAILED: Compilation error")
end
print("")
# Test Case 2: User redefining predefined color names
print("--- Test Case 2: User Redefining Predefined Colors ---")
var test2_dsl = "strip length 30\n" +
"color red = #0000FF\n" + # User redefines 'red' as blue!
"color blue = #FF0000\n" + # User redefines 'blue' as red!
"pattern red_pattern = solid(red)\n" + # Should use user's red (blue)
"pattern blue_pattern = solid(blue)\n" # Should use user's blue (red)
print("DSL Input:")
print(test2_dsl)
print("")
var test2_berry = animation.compile_dsl(test2_dsl)
if test2_berry != nil
print("Generated Berry Code:")
print(test2_berry)
print("✅ Test 2 PASSED: User-defined colors take precedence")
else
print("❌ Test 2 FAILED: Compilation error")
end
print("")
# Test Case 3: Mixed usage - some predefined, some user-defined
print("--- Test Case 3: Mixed Predefined and User-Defined Colors ---")
var test3_dsl = "strip length 30\n" +
"color red = #FF8000\n" + # User redefines 'red' as orange
"# 'blue' is not redefined, so it remains predefined\n" +
"color custom = #00FF80\n" + # User defines a new color
"pattern red_pattern = solid(red)\n" + # Should use user's red (orange)
"pattern blue_pattern = solid(blue)\n" + # Should use predefined blue
"pattern custom_pattern = solid(custom)\n" # Should use user's custom color
print("DSL Input:")
print(test3_dsl)
print("")
var test3_berry = animation.compile_dsl(test3_dsl)
if test3_berry != nil
print("Generated Berry Code:")
print(test3_berry)
print("✅ Test 3 PASSED: Mixed color resolution works correctly")
else
print("❌ Test 3 FAILED: Compilation error")
end
print("")
# Test Case 4: Forward references with redefined colors
print("--- Test Case 4: Forward References with Color Redefinition ---")
var test4_dsl = "strip length 30\n" +
"pattern early_pattern = solid(red)\n" + # Forward reference to 'red'
"color red = #FFFF00\n" + # User redefines 'red' as yellow (after reference)
"pattern late_pattern = solid(red)\n" # Direct reference to user's red
print("DSL Input:")
print(test4_dsl)
print("")
var test4_berry = animation.compile_dsl(test4_dsl)
if test4_berry != nil
print("Generated Berry Code:")
print(test4_berry)
print("✅ Test 4 PASSED: Forward references with redefinition work")
else
print("❌ Test 4 FAILED: Compilation error")
end
print("")
# Test Case 5: Complex scenario with multiple redefinitions
print("--- Test Case 5: Complex Color Redefinition Scenario ---")
var test5_dsl = "strip length 60\n" +
"# Swap the meanings of red and blue\n" +
"color red = #0000FF\n" + # red is now blue
"color blue = #FF0000\n" + # blue is now red
"color green = #FFFF00\n" + # green is now yellow
"# white and black remain predefined\n" +
"\n" +
"# Create patterns using the redefined colors\n" +
"pattern fire_pattern = solid(red)\n" + # This will be blue!
"pattern water_pattern = solid(blue)\n" + # This will be red!
"pattern earth_pattern = solid(green)\n" + # This will be yellow!
"pattern air_pattern = solid(white)\n" + # This remains white (predefined)
"\n" +
"# Create animations\n" +
"animation fire_anim = fire_pattern\n" +
"animation water_anim = water_pattern\n" +
"\n" +
"# Create a sequence\n" +
"sequence color_swap_demo {\n" +
" play fire_anim for 2s\n" +
" play water_anim for 2s\n" +
"}\n" +
"\n" +
"run color_swap_demo\n"
print("DSL Input:")
print(test5_dsl)
print("")
var test5_berry = animation.compile_dsl(test5_dsl)
if test5_berry != nil
print("Generated Berry Code:")
print(test5_berry)
print("✅ Test 5 PASSED: Complex color redefinition scenario works")
else
print("❌ Test 5 FAILED: Compilation error")
end
print("")
# Test Case 6: Error case - undefined color
print("--- Test Case 6: Error Handling for Undefined Colors ---")
var test6_dsl = "strip length 30\n" +
"pattern mystery_pattern = solid(undefined_color)\n" # This should cause an error
print("DSL Input:")
print(test6_dsl)
print("")
var test6_berry = animation.compile_dsl(test6_dsl)
if test6_berry != nil
print("Generated Berry Code:")
print(test6_berry)
print("⚠️ Test 6: Code generated despite undefined color (will be caught at runtime)")
else
print("✅ Test 6 PASSED: Undefined color properly detected as error")
end
print("")
print("=== Color Resolution Summary ===")
print("The DSL color resolution system works as follows:")
print("")
print("1. SCOPED RESOLUTION: User-defined colors always take precedence over predefined ones")
print(" - If user defines 'color red = #0000FF', then 'red' means blue in that DSL scope")
print(" - Predefined colors are only used if the user hasn't redefined them")
print("")
print("2. FORWARD REFERENCE SUPPORT: Colors can be referenced before they are defined")
print(" - The transpiler scans ahead to detect user color definitions")
print(" - This ensures consistent behavior regardless of definition order")
print("")
print("3. CLEAR PRECEDENCE RULES:")
print(" - User-defined colors (highest precedence)")
print(" - Predefined color names (medium precedence)")
print(" - Undefined colors (error - lowest precedence)")
print("")
print("4. BENEFITS:")
print(" - No ambiguity: clear, predictable color resolution")
print(" - User control: users can redefine any color name")
print(" - Backward compatibility: existing DSL code continues to work")
print(" - Forward compatibility: new predefined colors won't break user code")
print("")
print("This approach solves the color ambiguity problem while maintaining")
print("intuitive behavior and full user control over color definitions.")

View File

@ -1,48 +0,0 @@
# ColorCycle Animation Demo
#
# This example demonstrates the Filled animation with a color cycle provider
# which smoothly transitions between colors in a palette.
# Import the animation module
import global
import tasmota
import animation
# Create an animation controller for a strip of 30 LEDs
var strip = global.Leds(30, 1) # Assuming global.Leds class is available in Tasmota
var controller = animation.animation_controller(strip)
# Create a color cycle animation with a custom palette
var palette = [
0xFFFF0000, # Red
0xFFFF7F00, # Orange
0xFFFFFF00, # Yellow
0xFF00FF00, # Green
0xFF0000FF, # Blue
0xFF4B0082, # Indigo
0xFF8F00FF # Violet
]
# Create the animation with a 5-second cycle period and sine transition
# Using the factory method for color_cycle
var rainbow_cycle = animation.color_cycle_animation(palette, 5000, 1, 0, 255)
# Add the animation to the controller
controller.add_animation(rainbow_cycle)
# Start the animation
controller.start()
print("Running ColorCycle animation demo")
print("Press Ctrl+C to stop")
# In a real application, the animation would continue running
# Here we'll just wait for a while to demonstrate
tasmota.delay(30000) # Run for 30 seconds
# Stop the animation
controller.stop()
print("ColorCycle animation demo completed")
return true

View File

@ -1,133 +0,0 @@
# Color Provider Demo for Berry Animation Framework
#
# This example demonstrates the use of color providers to generate colors
# for different purposes, including filling frames and creating patterns.
import tasmota
import animation
# Create a frame buffer for testing
var frame_width = 30
var frame = animation.frame_buffer(frame_width, 1)
# Create a rich palette color provider
print("Creating a rich palette color provider...")
var palette_provider = animation.rich_palette_color_provider(
animation.PALETTE_RAINBOW, # Use the rainbow palette
5000, # 5 second cycle period
1, # Sine transition
255 # Full brightness
)
# Create a color cycle color provider
print("Creating a color cycle color provider...")
var cycle_provider = animation.color_cycle_color_provider(
[0xFF0000FF, 0xFF00FF00, 0xFFFF0000], # RGB colors
3000, # 3 second cycle period
1 # Sine transition
)
# Create a solid color provider
print("Creating a solid color provider...")
var solid_provider = animation.solid_color_provider(0xFFFF0000) # Red
# Create a composite color provider that combines the palette and cycle providers
print("Creating a composite color provider...")
var composite_provider = animation.composite_color_provider(
[palette_provider, cycle_provider], # List of providers to combine
0 # Overlay blend mode
)
# Demonstrate getting colors from providers
print("Demonstrating color providers...")
# Get colors at different times
var time_ms = tasmota.millis()
print(f"Current time: {time_ms} ms")
print("Colors at current time:")
print(f" Palette provider: 0x{palette_provider.get_color(time_ms):08X}")
print(f" Cycle provider: 0x{cycle_provider.get_color(time_ms):08X}")
print(f" Solid provider: 0x{solid_provider.get_color(time_ms):08X}")
print(f" Composite provider: 0x{composite_provider.get_color(time_ms):08X}")
# Get colors for different values
print("Colors for value 50:")
print(f" Palette provider: 0x{palette_provider.get_color_for_value(50, time_ms):08X}")
print(f" Cycle provider: 0x{cycle_provider.get_color_for_value(50, time_ms):08X}")
print(f" Solid provider: 0x{solid_provider.get_color_for_value(50, time_ms):08X}")
print(f" Composite provider: 0x{composite_provider.get_color_for_value(50, time_ms):08X}")
# Create a pattern function that generates a wave pattern
def wave_pattern(pixel_index, time_ms, animation)
var wave_period = 2000 # 2 second period
var wave_length = 30 # 30 pixel wavelength
# Calculate the wave position
var position = (time_ms % wave_period) / wave_period
var offset = int(position * wave_length)
# Calculate the wave value (0-100)
var pos_in_wave = (pixel_index + offset) % wave_length
var angle = tasmota.scale_uint(pos_in_wave, 0, wave_length, 0, 32767) # 0 to 2π in fixed-point
var sine_value = tasmota.sine_int(angle) # -4096 to 4096
# Map sine value from -4096..4096 to 0..100
var value = tasmota.scale_int(sine_value, -4096, 4096, 0, 100)
return value
end
# Fill the frame with colors from different providers
print("Filling frame with colors from different providers...")
# Fill with palette provider
frame.clear()
for i:0..frame_width-1
var value = wave_pattern(i, time_ms, nil)
var color = palette_provider.get_color_for_value(value, time_ms)
frame.set_pixel_color(i, color)
end
print("Frame filled with palette provider colors")
# Fill with cycle provider
frame.clear()
for i:0..frame_width-1
var value = wave_pattern(i, time_ms, nil)
var color = cycle_provider.get_color_for_value(value, time_ms)
frame.set_pixel_color(i, color)
end
print("Frame filled with cycle provider colors")
# Fill with composite provider
frame.clear()
for i:0..frame_width-1
var value = wave_pattern(i, time_ms, nil)
var color = composite_provider.get_color_for_value(value, time_ms)
frame.set_pixel_color(i, color)
end
print("Frame filled with composite provider colors")
# Create a PalettePatternAnimation that uses a color provider
print("Creating a PalettePatternAnimation with a color provider...")
var pattern_animation = animation.palette_pattern(
palette_provider, # Use the palette provider as the color source
wave_pattern, # Use the wave pattern function
frame_width, # Frame width
10, # Priority
0, # Duration (0 = infinite)
true, # Loop
"wave_pattern" # Name
)
# Start the animation
pattern_animation.start()
# Update and render the animation
print("Updating and rendering the animation...")
pattern_animation.update(time_ms)
frame.clear()
pattern_animation.render(frame, time_ms)
print("Animation rendered to frame")
print("Color Provider Demo completed successfully!")

View File

@ -1,98 +0,0 @@
# Comet Animation Demo
# Demonstrates the comet animation effect with different configurations
import tasmota
import animation
print("=== Comet Animation Demo ===")
# Test 1: Basic solid color comet
print("\n--- Test 1: Basic Solid Color Comet ---")
var comet1 = animation.comet.solid(0xFFFF0000, 5, 2560, 30, 10) # Red comet, 5-pixel tail, 10 pixels/sec, 30-pixel strip
print("Created:", comet1)
# Test the parameter system
print("Setting tail length to 8...")
comet1.set_tail_length(8)
print("Tail length:", comet1.get_param("tail_length"))
print("Setting speed to 15.0...")
comet1.set_speed(3840)
print("Speed:", comet1.get_param("speed"))
# Test 2: Color cycling comet
print("\n--- Test 2: Color Cycling Comet ---")
var rainbow_colors = [0xFFFF0000, 0xFFFF8000, 0xFFFFFF00, 0xFF00FF00, 0xFF0000FF, 0xFF8000FF]
var comet2 = animation.comet.color_cycle(rainbow_colors, 3000, 7, 2048, 30, 15)
print("Created:", comet2)
# Test 3: Rich palette comet
print("\n--- Test 3: Rich Palette Comet ---")
var comet3 = animation.comet.rich_palette(animation.PALETTE_FIRE, 4000, 6, 3072, 30, 20)
print("Created:", comet3)
# Test 4: Custom configuration
print("\n--- Test 4: Custom Configuration ---")
var comet4 = animation.comet(
0xFF00FFFF, # Cyan color
10, # 10-pixel tail
1280, # 5 pixels/sec (5 * 256)
-1, # Backward direction
false, # No wrap around (bounce)
204, # Slower fade (80% = 204/255)
25, # 25-pixel strip
25, # Priority 25
0, # Infinite duration
true, # Loop
"custom_comet"
)
print("Created:", comet4)
# Test parameter validation
print("\n--- Test 5: Parameter Validation ---")
print("Testing invalid tail length...")
var result = comet1.set_param("tail_length", -1)
print("Set tail_length to -1:", result ? "SUCCESS" : "FAILED (expected)")
print("Testing invalid speed...")
result = comet1.set_param("speed", 0)
print("Set speed to 0:", result ? "SUCCESS" : "FAILED (expected)")
print("Testing invalid direction...")
result = comet1.set_param("direction", 2)
print("Set direction to 2:", result ? "SUCCESS" : "FAILED (expected)")
print("Testing valid direction...")
result = comet1.set_param("direction", -1)
print("Set direction to -1:", result ? "SUCCESS (expected)" : "FAILED")
# Test 6: Animation lifecycle
print("\n--- Test 6: Animation Lifecycle ---")
print("Starting comet1...")
comet1.start()
print("Is running:", comet1.is_running)
print("Stopping comet1...")
comet1.stop()
print("Is running:", comet1.is_running)
# Test 7: Frame buffer rendering
print("\n--- Test 7: Frame Buffer Rendering ---")
var frame = animation.frame_buffer(30)
print("Created frame buffer:", frame)
# Start the animation and simulate a few updates
comet1.start()
var start_time = tasmota.millis()
print("Simulating animation updates...")
var i = 0
while i < 5
var current_time = start_time + (i * 100) # 100ms intervals
comet1.update(current_time)
comet1.render(frame, current_time)
print(f"Frame {i}: head_pos={comet1.head_position:.2f}")
i += 1
end
print("\n=== Comet Animation Demo Complete ===")

View File

@ -1,153 +0,0 @@
# CrenelPositionAnimation Color Demo
#
# This example demonstrates the fixed CrenelPositionAnimation that can handle
# both integer colors and ColorProvider instances.
import animation
print("=== CrenelPositionAnimation Color Demo ===")
# Create a frame buffer for testing
var frame_width = 20
var frame = animation.frame_buffer(frame_width)
# Create an animation engine
var strip = global.Leds(frame_width, 1)
var engine = animation.create_engine(strip)
print("1. Creating CrenelPositionAnimation with integer color...")
# Create a crenel animation with a static red color
var red_crenel = animation.crenel_position_animation(
0xFFFF0000, # Red color (integer)
0, # pos
3, # pulse_size
2, # low_size
4, # nb_pulse
10, # priority
0, # duration (infinite)
true, # loop
"red_crenel"
)
# Add to engine and render
engine.add_animation(red_crenel)
engine.start()
# Simulate a frame update
engine.on_tick(tasmota.millis())
print("✓ Red crenel animation created and rendered successfully")
print("2. Creating CrenelPositionAnimation with SolidColorProvider...")
# Create a solid color provider for blue
var blue_provider = animation.solid_color_provider(0xFF0000FF) # Blue
# Create a crenel animation with the color provider
var blue_crenel = animation.crenel_position_animation(
blue_provider, # Blue ColorProvider
5, # pos
2, # pulse_size
3, # low_size
3, # nb_pulse
15, # priority (higher than red)
0, # duration (infinite)
true, # loop
"blue_crenel"
)
# Add to engine
engine.add_animation(blue_crenel)
# Simulate another frame update
engine.on_tick(tasmota.millis())
print("✓ Blue crenel animation with ColorProvider created and rendered successfully")
print("3. Creating CrenelPositionAnimation with dynamic RichPaletteColorProvider...")
# Create a dynamic color provider that cycles through rainbow colors
var rainbow_provider = animation.rich_palette_color_provider(
animation.PALETTE_RAINBOW, # Rainbow palette
3000, # 3 second cycle
1, # Sine transition
255 # Full brightness
)
# Create a crenel animation with the dynamic color provider
var rainbow_crenel = animation.crenel_position_animation(
rainbow_provider, # Dynamic rainbow ColorProvider
10, # pos
4, # pulse_size
1, # low_size
2, # nb_pulse
20, # priority (highest)
0, # duration (infinite)
true, # loop
"rainbow_crenel"
)
# Add to engine
engine.add_animation(rainbow_crenel)
# Simulate frame updates at different times to show color changes
for time_offset : [0, 1000, 2000, 3000]
engine.on_tick(tasmota.millis() + time_offset)
print(f"✓ Rainbow crenel rendered at time offset {time_offset}ms")
end
print("4. Testing set_color method with both types...")
# Test changing from integer to ColorProvider
var test_crenel = animation.crenel_position_animation(
0xFF00FF00, # Start with green integer
15, 2, 1, 1, 5, 0, true, "test_crenel"
)
engine.add_animation(test_crenel)
engine.on_tick(tasmota.millis())
print("✓ Test crenel created with integer color")
# Change to a ColorProvider
var yellow_provider = animation.solid_color_provider(0xFFFFFF00) # Yellow
test_crenel.set_color(yellow_provider)
engine.on_tick(tasmota.millis())
print("✓ Test crenel color changed to ColorProvider")
# Change back to integer color
test_crenel.set_color(0xFFFF00FF) # Magenta
engine.on_tick(tasmota.millis())
print("✓ Test crenel color changed back to integer")
print("5. Displaying string representations...")
print(f"Red crenel: {red_crenel}")
print(f"Blue crenel: {blue_crenel}")
print(f"Rainbow crenel: {rainbow_crenel}")
print(f"Test crenel: {test_crenel}")
print("6. Testing with generic ValueProvider (not ColorProvider)...")
# Create a static value provider with a color value
var static_provider = animation.static_value_provider(0xFFFFFF00) # Yellow
var static_crenel = animation.crenel_position_animation(
static_provider, # Generic ValueProvider
0, 1, 4, 1, 5, 0, true, "static_provider_crenel"
)
engine.add_animation(static_crenel)
engine.on_tick(tasmota.millis())
print("✓ Generic ValueProvider crenel created and rendered successfully")
print("=== CrenelPositionAnimation Color Demo completed successfully! ===")
print("")
print("Summary of the enhanced fix:")
print("- CrenelPositionAnimation now correctly handles integer colors and ANY ValueProvider subclass")
print("- The parameter system accepts ValueProvider instances for integer parameters")
print("- ColorProvider instances use get_color(time_ms) for optimal color handling")
print("- Generic ValueProvider instances use get_value(time_ms) for flexibility")
print("- Range validation is bypassed for ValueProviders (since they provide dynamic values)")
print("- The set_color() method accepts integers, ColorProviders, and any ValueProvider")
print("- String representation handles all types appropriately")
print("- All existing functionality with integer colors remains unchanged")
print("- The type system is now extensible for future ValueProvider subclasses")
print("- Clean, single method call: var color = self.get_param_value('color', tasmota.millis())")

View File

@ -1,155 +0,0 @@
# Crenel Position Animation Demo with LED Values
#
# This example demonstrates the Crenel Position animation effect
# which creates repeating rectangular pulses (square wave pattern) on the LED strip.
#
# The demo creates a green crenel pattern with customizable parameters and shows actual LED values.
#
# Command to run demo:
# ./berry -s -g -m lib/libesp32/berry_animation lib/libesp32/berry_animation/examples/crenel_position_animation_demo.be
import global
import tasmota
import animation
def dump_rgb(strip)
var output = "LEDs: ["
for i:0..strip.length()-1
var color = strip.get_pixel_color(i)
var r = (color >> 16) & 0xFF
var g = (color >> 8) & 0xFF
var b = color & 0xFF
if i > 0
output += ", "
end
output += format("R:%d,G:%d,B:%d", r, g, b)
end
output += "]"
print(output)
end
def dump(strip)
var output = "["
for i:0..strip.length()-1
if i > 0
output += ", "
end
output += format("0x%06X", strip.get_pixel_color(i) & 0xFFFFFF)
end
output += "]"
print(output)
end
print("Starting Crenel Position animation demo with LED values...")
# Create a mock LED strip with 12 pixels for better pattern visibility
var strip = global.Leds(12)
# Create an animation engine for the strip
var engine = animation.create_engine(strip)
print("=== Demo 1: Basic crenel pattern ===")
# Create a crenel animation with green color
# Parameters:
# - Color: 0xFF00FF00 (green)
# - Pulse size: 2 pixels
# - Low size: 3 pixels (spacing between pulses)
# - Number of pulses: -1 (infinite)
# - Priority: 1
# - Duration: 0 (infinite)
# - Loop: true
var crenel_anim = animation.crenel_position(0xFF00FF00, 2, 3, -1, 1, 0, true, "demo_crenel")
# Add the animation to the engine and start it
engine.add_animation(crenel_anim)
crenel_anim.start()
# Start the engine
engine.start()
# Show the static pattern
engine.on_tick(tasmota.millis())
print("Basic crenel pattern (2 pixels on, 3 pixels off, infinite):")
dump_rgb(strip)
dump(strip)
print()
print("=== Demo 2: Crenel with background color ===")
# Set a dark blue background
crenel_anim.set_back_color(0xFF000080)
engine.on_tick(tasmota.millis() + 10) # Force update with new time
print("Crenel with dark blue background:")
dump_rgb(strip)
dump(strip)
print()
print("=== Demo 3: Different pulse and spacing sizes ===")
# Change to 3 pixels on, 2 pixels off
crenel_anim.set_back_color(0xFF000000) # Back to transparent
crenel_anim.set_pulse_size(3)
crenel_anim.set_low_size(2)
engine.on_tick(tasmota.millis() + 20) # Force update with new time
print("Modified pattern (3 pixels on, 2 pixels off):")
dump_rgb(strip)
dump(strip)
print()
print("=== Demo 4: Limited number of pulses ===")
# Show only 2 pulses
crenel_anim.set_nb_pulse(2)
crenel_anim.set_pos(1) # Start at position 1
engine.on_tick(tasmota.millis() + 30) # Force update with new time
print("Limited to 2 pulses starting at position 1:")
dump_rgb(strip)
dump(strip)
print()
print("=== Demo 5: Single pixel pulses ===")
# Reset to infinite and show single pixel pulses
crenel_anim.set_nb_pulse(-1)
crenel_anim.set_pos(0)
crenel_anim.set_pulse_size(1)
crenel_anim.set_low_size(2)
crenel_anim.set_color(0xFFFF0000) # Change to red
engine.on_tick(tasmota.millis() + 40) # Force update with new time
print("Single pixel red pulses (1 pixel on, 2 pixels off):")
dump_rgb(strip)
dump(strip)
print()
print("=== Demo 6: Edge case - zero pulse size ===")
# Test with zero pulse size (should show nothing)
crenel_anim.set_pulse_size(0)
engine.on_tick(tasmota.millis() + 50) # Force update with new time
print("Zero pulse size (should be empty):")
dump_rgb(strip)
dump(strip)
print()
print("=== Demo 7: Position offset ===")
# Reset pulse size and test position offset
crenel_anim.set_pulse_size(2)
crenel_anim.set_low_size(3)
crenel_anim.set_pos(2) # Start at position 2
crenel_anim.set_color(0xFF0000FF) # Change to blue
engine.on_tick(tasmota.millis() + 60) # Force update with new time
print("Pattern starting at position 2 (blue):")
dump_rgb(strip)
dump(strip)
print()
print("=== Demo 8: Negative position (wrapping) ===")
# Test negative position
crenel_anim.set_pos(-1)
engine.on_tick(tasmota.millis() + 70) # Force update with new time
print("Pattern with negative position -1:")
dump_rgb(strip)
dump(strip)
print("Crenel Position animation demo completed")
# Stop the animation
engine.stop()
return true

View File

@ -1,121 +0,0 @@
# Advanced DSL palette demonstration
# Showcases: Multiple palettes, layering, dynamic switching
# Demonstrates: Complex palette compositions, event-driven control
#
# This creates a sophisticated multi-palette display with interactive control
strip length 60
# Define multiple custom palettes
palette sunset = [
(0, #FF4500), # Orange red
(64, #FF8C00), # Dark orange
(128, #FFD700), # Gold
(192, #FF69B4), # Hot pink
(255, #800080) # Purple
]
palette ocean = [
(0, #000080), # Navy blue
(64, #0000FF), # Blue
(128, #00FFFF), # Cyan
(192, #00FF80), # Spring green
(255, #008000) # Green
]
palette fire = [
(0, #000000), # Black
(64, #800000), # Dark red
(128, #FF0000), # Red
(192, #FF8000), # Orange
(255, #FFFF00) # Yellow
]
# Create base palette animations with different speeds
animation sunset_base = filled(
rich_palette(sunset, 8s, smooth, 200),
loop
)
sunset_base.opacity = smooth(100, 255, 15s)
sunset_base.priority = 0
animation ocean_layer = filled(
rich_palette(ocean, 12s, smooth, 180),
loop
)
ocean_layer.opacity = linear(50, 200, 10s)
ocean_layer.priority = 5
animation fire_overlay = filled(
rich_palette(fire, 4s, linear, 220),
loop
)
fire_overlay.opacity = square(0, 180, 6s, 30) # Strobe effect
fire_overlay.priority = 10
# Create moving effects using composite colors
animation palette_comet = comet(
composite([
rich_palette(sunset, 8s, smooth, 255),
rich_palette(ocean, 12s, smooth, 255),
rich_palette(fire, 4s, linear, 255)
], overlay),
8, # length
3, # trail
2s, # speed
loop
)
palette_comet.priority = 20
animation palette_sparkles = twinkle(
composite([
rich_palette(sunset, 8s, smooth, 255),
rich_palette(ocean, 12s, smooth, 255)
], overlay),
8, # count
300ms, # duration
loop
)
palette_sparkles.priority = 25
# Event handlers for mode switching
variable current_mode = 0
on mode_switch:
current_mode = (current_mode + 1) % 5
# Clear all current animations
stop all
# Switch to different display modes
if current_mode == 0:
# All layers mode
run sunset_base
run ocean_layer
run fire_overlay
run palette_comet
run palette_sparkles
elif current_mode == 1:
# Sunset only
run sunset_base
elif current_mode == 2:
# Ocean only
run ocean_layer
elif current_mode == 3:
# Fire only
run fire_overlay
elif current_mode == 4:
# Effects only
run palette_comet
run palette_sparkles
# Auto-mode switching every 20 seconds
on timer(20s):
trigger mode_switch
# Start with all layers
run sunset_base
run ocean_layer
run fire_overlay
run palette_comet
run palette_sparkles

View File

@ -1,31 +0,0 @@
# DSL version of the breathing effect
# Original: Complex Berry code with multiple objects and callbacks
# DSL: Simple declarative syntax that's easy to read and modify
#
# This recreates the same visual effect as animate_demo_breathe.be
# but with much cleaner, more readable syntax
strip length 25
# Define the same palette as original (black to red to orange)
palette fire_palette = [
(0, #000000), # black
(136, #880000), # red
(255, #FF5500) # orange
]
# Create breathing effect with palette colors
# This replaces the complex animate.pulse + animate.palette + animate.oscillator setup
animation breathing = breathe(
rich_palette(fire_palette, 3s, smooth, 255),
150, # base opacity
3s, # duration matches original
loop
)
# Add brightness oscillation like original (50-255 range, cosine curve)
# This replaces the animate.oscillator(50, 255, duration, animate.COSINE) callback
breathing.opacity = smooth(50, 255, 3s)
# Start the animation
run breathing

View File

@ -1,120 +0,0 @@
# Dynamic pulse DSL demonstration
# Showcases: Multiple pulse types, dynamic parameters, interactive control
# Demonstrates: Advanced DSL features, value providers, event system
#
# This creates multiple pulse types with different characteristics
strip length 50
# Define background with subtle color cycling
palette bg_colors = [
(0, #001122),
(85, #002211),
(170, #112200),
(255, #220011)
]
animation cycling_bg = filled(
color_cycle(bg_colors, 30s, smooth),
loop
)
# Create multiple pulse types with different characteristics
# 1. Breathing pulse with oscillating size
animation breathe_pulse = pulse_position(
#FF0000, # red
5, # initial size
1, # slew
10, # priority
loop
)
breathe_pulse.pulse_size = smooth(2, 12, 4s)
breathe_pulse.pos = linear(5, 35, 8s) # 50-15 = 35
# 2. Strobe pulse with square wave intensity
animation strobe_pulse = pulse_position(
#00FF00, # green
3, # size
1, # slew
15, # priority
loop
)
strobe_pulse.opacity = square(50, 255, 800ms, 25) # Fast strobe, 25% duty
strobe_pulse.pos = linear(40, 5, 6s) # Opposite direction
# 3. Rainbow pulse with dynamic color
animation rainbow_pulse = pulse_position(
#0000FF, # blue (will be overridden)
8, # size
2, # slew
20, # priority
loop
)
rainbow_pulse.color = rainbow(5s, smooth, 255)
rainbow_pulse.pos = smooth(12, 37, 10s) # 50/4 to 3*50/4
# 4. Fire pulse with fire palette
palette fire_colors = [
(0, #000000), # Black
(64, #800000), # Dark red
(128, #FF0000), # Red
(192, #FF8000), # Orange
(255, #FFFF00) # Yellow
]
animation fire_pulse = pulse_position(
#FF4400, # orange (will be overridden)
6, # size
3, # slew
25, # priority
loop
)
fire_pulse.color = rich_palette(fire_colors, 3s, linear, 255)
fire_pulse.pulse_size = linear(4, 15, 7s)
fire_pulse.pos = 25 # Fixed center position
# Interactive event handlers for dynamic control
on speed_up:
# Double all animation speeds by halving durations
breathe_pulse.pulse_size.duration = 2s
breathe_pulse.pos.duration = 4s
strobe_pulse.opacity.duration = 400ms
strobe_pulse.pos.duration = 3s
rainbow_pulse.color.duration = 2.5s
rainbow_pulse.pos.duration = 5s
fire_pulse.color.duration = 1.5s
fire_pulse.pulse_size.duration = 3.5s
on slow_down:
# Halve all animation speeds by doubling durations
breathe_pulse.pulse_size.duration = 8s
breathe_pulse.pos.duration = 16s
strobe_pulse.opacity.duration = 1600ms
strobe_pulse.pos.duration = 12s
rainbow_pulse.color.duration = 10s
rainbow_pulse.pos.duration = 20s
fire_pulse.color.duration = 6s
fire_pulse.pulse_size.duration = 14s
on randomize_positions:
# Set random positions for all pulses
breathe_pulse.pos = random(5, 35)
strobe_pulse.pos = random(5, 35)
rainbow_pulse.pos = random(12, 37)
# fire_pulse keeps center position
on toggle_pulse:
# Toggle individual pulses (would need pulse name in event data)
# This is a simplified version - real implementation would check event data
if breathe_pulse.running:
stop breathe_pulse
else:
run breathe_pulse
# Start all animations
run cycling_bg
run breathe_pulse
run strobe_pulse
run rainbow_pulse
run fire_pulse

View File

@ -1,68 +0,0 @@
# Enhanced DSL version with multiple breathing layers
# Showcases: Multiple colors, layering, dynamic parameters
# Demonstrates: Advanced DSL features, event system integration
#
# This creates a more sophisticated breathing effect with multiple layers
strip length 30
# Define multiple colors for layered breathing
color red = #FF0000
color green = #00FF00
color blue = #0000FF
color yellow = #FFFF00
color magenta = #FF00FF
# Create background rainbow that slowly cycles
animation rainbow_bg = filled(
rainbow(20s, smooth, 50), # Slow, dim rainbow
loop
)
# Create multiple breathing layers with different phases and speeds
animation breathe_red = breathe(red, 150, 3s, loop)
breathe_red.opacity = smooth(30, 200, 3s)
breathe_red.priority = 2
animation breathe_green = breathe(green, 150, 4s, loop)
breathe_green.opacity = smooth(30, 200, 4s)
breathe_green.opacity.phase = 20 # 20% phase offset
breathe_green.priority = 4
animation breathe_blue = breathe(blue, 150, 5s, loop)
breathe_blue.opacity = smooth(30, 200, 5s)
breathe_blue.opacity.phase = 40 # 40% phase offset
breathe_blue.priority = 6
animation breathe_yellow = breathe(yellow, 150, 3.5s, loop)
breathe_yellow.opacity = smooth(30, 200, 3.5s)
breathe_yellow.opacity.phase = 60 # 60% phase offset
breathe_yellow.priority = 8
animation breathe_magenta = breathe(magenta, 150, 4.5s, loop)
breathe_magenta.opacity = smooth(30, 200, 4.5s)
breathe_magenta.opacity.phase = 80 # 80% phase offset
breathe_magenta.priority = 10
# Event handlers for interactive control
on button_press:
# Speed up all breathing animations
breathe_red.duration = 1.5s
breathe_green.duration = 2s
breathe_blue.duration = 2.5s
breathe_yellow.duration = 1.75s
breathe_magenta.duration = 2.25s
on timer(10s):
# Add temporary sparkle overlay every 10 seconds
animation sparkles = twinkle(#FFFFFF, 5, 500ms, 2s, once)
sparkles.priority = 100
run sparkles
# Start all animations
run rainbow_bg
run breathe_red
run breathe_green
run breathe_blue
run breathe_yellow
run breathe_magenta

View File

@ -1,18 +0,0 @@
# DSL version of the palette background effect
# Original: animate_demo_palette_background.be
# DSL: Clean declarative syntax for rainbow background
#
# This recreates the cycling rainbow background effect
# but with much simpler syntax
strip length 25
# Create rainbow background that cycles over 10 seconds
# This replaces animate.core() + add_background_animator() + animate.palette()
animation rainbow_bg = filled(
rainbow(10s, smooth, 255), # Built-in rainbow palette
loop
)
# Start the animation
run rainbow_bg

View File

@ -1,45 +0,0 @@
# DSL version of the moving pulse effect
# Original: animate_demo_pulse.be with complex oscillator and palette setup
# DSL: Clean declarative syntax for moving pulse with color cycling
#
# This recreates the moving pulse with oscillating position and cycling color
strip length 25
# Define background color (matches original anim.set_back_color(0x2222AA))
color background_blue = #2222AA
# Create background animation
animation background = solid(background_blue, loop)
# Define color palette for the pulse (matches PALETTE_STANDARD_VAL)
palette standard_colors = [
(0, #FF0000), # Red
(64, #FFFF00), # Yellow
(128, #00FF00), # Green
(192, #00FFFF), # Cyan
(255, #0000FF) # Blue
]
# Create moving pulse with dynamic properties
# This replaces animate.pulse(0xFF4444, 2, 1) + oscillator callbacks
animation moving_pulse = pulse_position(
#FF4444, # base color (will be overridden by palette)
2, # pulse size
1, # slew (fade region)
10, # priority (higher than background)
loop
)
# Set dynamic position (matches animate.oscillator(-3, 26, 5000, animate.COSINE))
moving_pulse.pos = smooth(-3, 26, 5s)
# Set cycling color (matches animate.palette(animate.PALETTE_STANDARD_VAL, 30000))
moving_pulse.color = rich_palette(standard_colors, 30s, smooth, 255)
# Set brightness to 60% (matches original anim.set_bri(60))
moving_pulse.opacity = 153 # 60% of 255
# Run both animations
run background
run moving_pulse

View File

@ -1,48 +0,0 @@
#
# DSL Demo Runner
# Loads and runs DSL animation files (.anim extension)
# Usage: Modify the 'demo_file' variable to run different DSL demos
#
import animation
# Configuration - change this to run different DSL demos
var demo_file = "breathe_demo.anim" # Options:
# - breathe_demo.anim
# - palette_background_demo.anim
# - pulse_demo.anim
# - enhanced_breathe_showcase.anim
# - advanced_palette_showcase.anim
# - dynamic_pulse_showcase.anim
var leds = 30 # Adjust based on your LED strip
# Create LED strip
var strip = global.Leds(leds, gpio.pin(gpio.WS2812, 0))
# Create DSL runtime
var runtime = animation.create_dsl_runtime(strip)
# Load and run the DSL file
print("Loading DSL demo:", demo_file)
print("=" * 50)
var success = runtime.load_dsl_file("lib/libesp32/berry_animation/examples/dsl/" + demo_file)
if success
print("DSL demo loaded and running successfully!")
print("Visual effect should now be visible on your LED strip")
print("\nTo try different demos, edit the 'demo_file' variable above")
print("Available DSL demos:")
print("- breathe_demo.anim (simple breathing effect)")
print("- palette_background_demo.anim (rainbow background)")
print("- pulse_demo.anim (moving pulse with color cycling)")
print("- enhanced_breathe_showcase.anim (multi-layer breathing)")
print("- advanced_palette_showcase.anim (complex palette effects)")
print("- dynamic_pulse_showcase.anim (multiple pulse types)")
else
print("Failed to load DSL demo!")
print("Check that the file exists and the DSL syntax is correct")
end
print("\nPress Ctrl+C to stop")

View File

@ -1,149 +0,0 @@
# DSL Core Features Demo
# Demonstrates all implemented core processing methods in the DSL transpiler
#
# This example shows:
# - Color definitions (hex, named colors)
# - Pattern definitions (solid, gradient)
# - Animation definitions (pulse, breathe, simple references)
# - Variable assignments (numbers, percentages, times)
# - Sequence definitions with control flow
# - Play statements with duration
# - With statements for parallel animations
# - Repeat statements (forever, N times, range)
# - If/else statements
# - Wait statements
# - Loop statements
# - Run statements
import animation
# Comprehensive DSL example showcasing all core features
var comprehensive_dsl = "# LED Strip Animation DSL - Core Features Demo\n" +
"\n" +
"# Strip Configuration\n" +
"strip length 60\n" +
"\n" +
"# Color Definitions\n" +
"color red = #FF0000\n" +
"color blue = #0000FF\n" +
"color green = #00FF00\n" +
"color white = white\n" +
"color warm_orange = #FF8000\n" +
"\n" +
"# Variable Assignments\n" +
"set brightness_level = 80%\n" +
"set cycle_duration = 5s\n" +
"set repeat_count = 3\n" +
"set fade_time = 2s\n" +
"\n" +
"# Pattern Definitions\n" +
"pattern solid_red = solid(red)\n" +
"pattern solid_blue = solid(blue)\n" +
"pattern fire_gradient = gradient(red, warm_orange)\n" +
"\n" +
"# Animation Definitions\n" +
"animation red_pulse = pulse(solid_red, 2s, 20%, 100%)\n" +
"animation blue_breathe = breathe(solid_blue, 4s)\n" +
"animation simple_red = solid_red\n" +
"animation fade_effect = fade(red, blue, 3s)\n" +
"\n" +
"# Main Sequence with All Control Flow Features\n" +
"sequence comprehensive_demo {\n" +
" # Basic play statement\n" +
" play red_pulse for 3s\n" +
" \n" +
" # Wait statement\n" +
" wait 1s\n" +
" \n" +
" # Repeat N times\n" +
" repeat 2 times:\n" +
" play blue_breathe for 2s\n" +
" wait 500ms\n" +
" \n" +
" # Conditional statement\n" +
" if brightness_level > 50:\n" +
" play red_pulse for 4s\n" +
" else:\n" +
" play blue_breathe for 4s\n" +
" \n" +
" # Parallel animation with modifiers\n" +
" with simple_red for 6s opacity 60%\n" +
" \n" +
" # Wait before final effect\n" +
" wait 2s\n" +
" \n" +
" # Final play\n" +
" play fade_effect for 5s\n" +
"}\n" +
"\n" +
"# Simple sequence for comparison\n" +
"sequence simple_demo {\n" +
" play red_pulse for 10s\n" +
"}\n" +
"\n" +
"# Run the comprehensive demo\n" +
"run comprehensive_demo"
print("=== DSL Core Features Demo ===")
print()
print("This demo showcases all implemented core processing methods:")
print("✓ Color definitions (hex colors, named colors)")
print("✓ Pattern definitions (solid, gradient)")
print("✓ Animation definitions (pulse, breathe, references)")
print("✓ Variable assignments (percentages, times, numbers)")
print("✓ Sequence definitions with control flow")
print("✓ Play statements with duration")
print("✓ With statements for parallel animations")
print("✓ Repeat statements (N times)")
print("✓ If/else conditional statements")
print("✓ Wait statements for delays")
print("✓ Run statements for execution")
print()
print("Compiling comprehensive DSL...")
var berry_code = animation.compile_dsl(comprehensive_dsl)
if berry_code != nil
print("✅ Compilation successful!")
print()
print("Generated Berry Code:")
print("============================================================")
print(berry_code)
print("============================================================")
print()
print("🎉 All core processing methods are working correctly!")
print()
print("Key features demonstrated:")
print("- Forward reference resolution (animations using patterns)")
print("- Deferred code generation for complex expressions")
print("- Proper symbol table management")
print("- Control flow statement generation")
print("- Expression parsing and code generation")
print("- Error handling and recovery")
else
print("❌ Compilation failed")
# Detailed error analysis
var lexer = animation.DSLLexer(comprehensive_dsl)
var tokens = lexer.tokenize()
if lexer.has_errors()
print()
print("Lexical errors:")
print(lexer.get_error_report())
else
print("✓ Lexical analysis passed")
var transpiler = animation.SinglePassDSLTranspiler(tokens)
var result = transpiler.transpile()
if transpiler.has_errors()
print()
print("Transpilation errors:")
print(transpiler.get_error_report())
end
end
end
print()
print("=== Demo Complete ===")

View File

@ -1,266 +0,0 @@
# DSL Runtime Integration Demo
# Demonstrates complete DSL execution lifecycle with practical examples
import global
import tasmota
import animation
def demo_basic_dsl_runtime()
print("=== Basic DSL Runtime Demo ===")
# Create LED strip (30 pixels)
var strip = global.Leds(30, 1)
# Create DSL runtime with debug mode
var runtime = animation.create_dsl_runtime(strip, true)
# Define a simple animation DSL
var campfire_dsl =
"# Campfire animation DSL\n" +
"strip length 30\n" +
"\n" +
"# Define fire colors\n" +
"color red = #FF0000\n" +
"color orange = #FF8000\n" +
"\n" +
"# Create fire animation\n" +
"animation flames = solid(red)\n" +
"\n" +
"# Define the campfire sequence\n" +
"sequence campfire {\n" +
" play flames for 5s\n" +
"}\n" +
"\n" +
"# Start the campfire\n" +
"run campfire"
print("Loading campfire DSL...")
print("Runtime created successfully")
print("```")
print(campfire_dsl)
print("```")
if runtime.load_dsl(campfire_dsl)
print("✓ Campfire DSL loaded successfully!")
# Show generated Berry code (first 200 characters)
var generated_code = runtime.get_generated_code()
if generated_code != nil
print("Generated Berry code preview:")
# var preview = size(generated_code) > 200 ? generated_code[0..199] + "..." : generated_code
# print(generated_code)
print(generated_code)
end
print("Campfire animation is now running!")
print("(In real usage, this would continue until stopped)")
else
print("✗ Failed to load campfire DSL")
end
end
def demo_dsl_hot_reloading()
print("\n=== DSL Hot Reloading Demo ===")
var strip = global.Leds(20, 1)
var runtime = animation.create_dsl_runtime(strip, true)
# Load initial animation
var initial_dsl = "strip length 20\n" +
"color blue = #0000FF\n" +
"animation blue_anim = solid(blue)\n" +
"sequence initial {\n" +
" play blue_anim for 3s\n" +
"}\n" +
"run initial"
print("Loading initial blue animation...")
if runtime.load_dsl(initial_dsl)
print("✓ Initial animation loaded")
# Simulate development workflow - modify and reload
var updated_dsl = "strip length 20\n" +
"color red = #FF0000\n" +
"animation red_anim = solid(red)\n" +
"sequence updated {\n" +
" play red_anim for 5s\n" +
"}\n" +
"run updated"
print("Updating to red/white strobe animation...")
if runtime.load_dsl(updated_dsl)
print("✓ Animation updated successfully!")
else
print("✗ Failed to update animation")
end
else
print("✗ Failed to load initial animation")
end
end
def demo_dsl_error_handling()
print("\n=== DSL Error Handling Demo ===")
var strip = global.Leds(15, 1)
var runtime = animation.create_dsl_runtime(strip, true)
# Try to load DSL with various errors
var error_cases = [
{
"name": "Syntax Error",
"dsl": "color red = \n" +
"pattern broken = solid(red)"
},
{
"name": "Undefined Reference",
"dsl": "strip length 15\n" +
"pattern test = solid(undefined_color)\n" +
"sequence demo { play test for 1s }\n" +
"run demo"
},
{
"name": "Invalid Color Format",
"dsl": "strip length 15\n" +
"color bad = #GGGGGG\n" +
"sequence demo { play solid(bad) for 1s }\n" +
"run demo"
}
]
for case : error_cases
print(f"\nTesting {case['name']}:")
if runtime.load_dsl(case["dsl"])
print(f"✗ Expected {case['name']} to fail, but it succeeded")
else
print(f"✓ {case['name']} correctly rejected")
end
end
# Show that runtime is still functional after errors
var valid_dsl = "strip length 15\n" +
"color green = #00FF00\n" +
"animation green_anim = solid(green)\n" +
"sequence recovery {\n" +
" play green_anim for 2s\n" +
"}\n" +
"run recovery"
print("\nTesting recovery with valid DSL:")
if runtime.load_dsl(valid_dsl)
print("✓ Runtime recovered successfully after errors")
else
print("✗ Runtime failed to recover")
end
end
def demo_dsl_caching_performance()
print("\n=== DSL Caching Performance Demo ===")
var strip = global.Leds(25, 1)
var runtime = animation.create_dsl_runtime(strip, false) # Disable debug for cleaner output
var test_dsl = "strip length 25\n" +
"color cyan = #00FFFF\n" +
"animation wave = solid(cyan)\n" +
"sequence performance_test {\n" +
" play wave for 5s\n" +
"}\n" +
"run performance_test"
print("Testing compilation performance...")
# First load (compilation)
var start_time = tasmota.millis()
var success1 = runtime.load_dsl(test_dsl)
var first_load_time = tasmota.millis() - start_time
if success1
print(f"✓ DSL compilation: {first_load_time}ms")
else
print("✗ Performance test failed")
end
end
def demo_advanced_dsl_features()
print("\n=== Advanced DSL Features Demo ===")
var strip = global.Leds(40, 1)
var runtime = animation.create_dsl_runtime(strip, true)
# Complex DSL with multiple patterns and sequences
var advanced_dsl = "# Advanced LED Animation Demo\n" +
"strip length 40\n" +
"\n" +
"# Color palette\n" +
"color blue = #0000FF\n" +
"color white = #FFFFFF\n" +
"color gold = #FFD700\n" +
"\n" +
"# Multiple animations\n" +
"animation ocean_waves = solid(blue)\n" +
"animation sunset_glow = solid(gold)\n" +
"animation lighthouse = solid(white)\n" +
"\n" +
"# Complex sequence with multiple phases\n" +
"sequence coastal_scene {\n" +
" play ocean_waves for 3s\n" +
" play sunset_glow for 3s\n" +
" play lighthouse for 2s\n" +
"}\n" +
"\n" +
"run coastal_scene"
print("Loading advanced coastal scene DSL...")
if runtime.load_dsl(advanced_dsl)
print("✓ Advanced DSL loaded successfully!")
print("Coastal scene animation with multiple phases is now running")
# Show the complexity of generated code
var generated_code = runtime.get_generated_code()
if generated_code != nil
var lines = 0
for i : 0..size(generated_code)-1
if generated_code[i] == '\n'
lines += 1
end
end
print(f"Generated {lines} lines of Berry code from DSL")
end
else
print("✗ Failed to load advanced DSL")
end
end
# Main demo function
def run_dsl_runtime_demos()
print("🌟 DSL Runtime Integration Demos 🌟")
print("Demonstrating complete DSL execution lifecycle\n")
demo_basic_dsl_runtime()
demo_dsl_hot_reloading()
demo_dsl_error_handling()
demo_dsl_caching_performance()
demo_advanced_dsl_features()
print("\n🎉 DSL Runtime demos completed!")
print("The DSL Runtime provides:")
print(" • Complete DSL-to-animation execution")
print(" • Intelligent compilation caching")
print(" • Hot reloading for development")
print(" • Robust error handling")
print(" • File-based DSL loading")
print(" • Performance optimization")
end
run_dsl_runtime_demos()
return {
"run_dsl_runtime_demos": run_dsl_runtime_demos,
"demo_basic_dsl_runtime": demo_basic_dsl_runtime,
"demo_dsl_hot_reloading": demo_dsl_hot_reloading,
"demo_dsl_error_handling": demo_dsl_error_handling,
"demo_dsl_caching_performance": demo_dsl_caching_performance,
"demo_advanced_dsl_features": demo_advanced_dsl_features
}

View File

@ -1,220 +0,0 @@
# DSL Transpiler Demo
# Demonstrates the single-pass DSL transpiler functionality
#
# Command to run demo is:
# ./berry -s -g -m lib/libesp32/berry_animation lib/libesp32/berry_animation/examples/dsl_transpiler_demo.be
import tasmota
import animation
print("=== Animation DSL Transpiler Demo ===")
# Example 1: Simple color and strip configuration
print("\n--- Example 1: Basic Configuration ---")
var basic_dsl = "strip length 30\n" +
"color red = #FF0000\n" +
"color blue = #0000FF\n"
print("DSL Input:")
print(basic_dsl)
var basic_berry = animation.compile_dsl(basic_dsl)
if basic_berry != nil
print("\nGenerated Berry Code:")
print(basic_berry)
else
print("❌ Compilation failed")
end
# Example 2: Pattern and animation definitions
print("\n--- Example 2: Patterns and Animations ---")
var pattern_dsl = "color green = #00FF00\n" +
"pattern solid_green = solid(green)\n"
print("DSL Input:")
print(pattern_dsl)
var pattern_berry = animation.compile_dsl(pattern_dsl)
if pattern_berry != nil
print("\nGenerated Berry Code:")
print(pattern_berry)
else
print("❌ Compilation failed")
end
# Example 3: Complete sequence with execution
print("\n--- Example 3: Complete Animation Sequence ---")
var sequence_dsl = "# LED Strip Setup\n" +
"strip length 60\n" +
"\n" +
"# Colors\n" +
"color red = #FF0000\n" +
"color white = white\n" +
"\n" +
"# Patterns\n" +
"pattern red_solid = solid(red)\n" +
"\n" +
"# Variables\n" +
"set duration = 3s\n" +
"\n" +
"# Sequence\n" +
"sequence blink {\n" +
" play red_solid for 2s\n" +
"}\n" +
"\n" +
"# Run the sequence\n" +
"run blink\n"
print("DSL Input:")
print(sequence_dsl)
var sequence_berry = animation.compile_dsl(sequence_dsl)
if sequence_berry != nil
print("\nGenerated Berry Code:")
print(sequence_berry)
else
print("❌ Compilation failed")
end
# Example 4: Variable assignments and time conversions
print("\n--- Example 4: Variables and Time Conversions ---")
var variables_dsl = "set strip_length = 60\n" +
"set brightness = 75%\n" +
"set short_time = 500ms\n" +
"set long_time = 2s\n" +
"set very_long = 1m\n"
print("DSL Input:")
print(variables_dsl)
var variables_berry = animation.compile_dsl(variables_dsl)
if variables_berry != nil
print("\nGenerated Berry Code:")
print(variables_berry)
else
print("❌ Compilation failed")
end
# Example 5: Error handling demonstration
print("\n--- Example 5: Error Handling ---")
var error_dsl = "# This should produce errors\n" +
"invalid_keyword test = value\n" +
"color incomplete = \n" +
"strip length\n"
print("DSL Input (with intentional errors):")
print(error_dsl)
var lexer = animation.DSLLexer(error_dsl)
var tokens = lexer.tokenize()
if lexer.has_errors()
print("\nLexical Errors:")
print(lexer.get_error_report())
end
var transpiler = animation.SimpleDSLTranspiler(tokens)
var error_berry = transpiler.transpile()
if transpiler.has_errors()
print("\nTranspilation Errors:")
print(transpiler.get_error_report())
end
if error_berry != nil
print("\nGenerated Berry Code (despite errors):")
print(error_berry)
else
print("❌ Compilation failed due to errors")
end
# Example 6: Demonstrate deferred resolution (forward references)
print("\n--- Example 6: Forward References ---")
var forward_ref_dsl = "# This pattern references colors defined later\n" +
"animation test_anim = red_pattern\n" +
"pattern red_pattern = solid(red)\n" +
"color red = #FF0000\n"
print("DSL Input (with forward references):")
print(forward_ref_dsl)
var forward_berry = animation.compile_dsl(forward_ref_dsl)
if forward_berry != nil
print("\nGenerated Berry Code:")
print(forward_berry)
else
print("❌ Forward reference resolution not yet fully implemented")
# Show what the transpiler attempted
var lexer2 = animation.DSLLexer(forward_ref_dsl)
var tokens2 = lexer2.tokenize()
var transpiler2 = animation.SimpleDSLTranspiler(tokens2)
var result = transpiler2.transpile()
if transpiler2.has_errors()
print("\nTranspilation Errors:")
print(transpiler2.get_error_report())
end
end
# Example 7: Practical LED animation
print("\n--- Example 7: Practical LED Animation ---")
var practical_dsl = "# Campfire effect setup\n" +
"strip length 60\n" +
"\n" +
"# Fire colors\n" +
"color deep_red = #8B0000\n" +
"color red = #FF0000\n" +
"color orange = #FF4500\n" +
"color yellow = #FFD700\n" +
"\n" +
"# Simple solid patterns for now\n" +
"pattern fire_base = solid(red)\n" +
"\n" +
"# Animation\n" +
"animation campfire = fire_base\n" +
"\n" +
"# Show the fire\n" +
"sequence fire_show {\n" +
" play campfire for 10s\n" +
"}\n" +
"\n" +
"run fire_show\n"
print("DSL Input:")
print(practical_dsl)
var practical_berry = animation.compile_dsl(practical_dsl)
if practical_berry != nil
print("\nGenerated Berry Code:")
print(practical_berry)
print("\n--- Compilation Summary ---")
print("✅ DSL successfully compiled to Berry code")
print("✅ Strip configuration generated")
print("✅ Color definitions converted")
print("✅ Pattern definitions created")
print("✅ Animation definitions prepared")
print("✅ Sequence function generated")
print("✅ Execution code added")
else
print("❌ Compilation failed")
end
print("\n=== Demo Complete ===")
print("The DSL transpiler can now handle:")
print("• Strip configuration (length)")
print("• Color definitions (hex colors and named colors)")
print("• Simple pattern definitions (solid patterns)")
print("• Variable assignments with type conversion")
print("• Sequence definitions with play statements")
print("• Run statements for execution")
print("• Basic error detection and reporting")
print("")
print("Next steps for full DSL implementation:")
print("• Complex pattern functions (gradient, sparkle, etc.)")
print("• Advanced animation functions (shift, pulse, etc.)")
print("• Control flow statements (repeat, if, etc.)")
print("• Function definitions and calls")
print("• Event handlers")
print("• Full forward reference resolution")

View File

@ -1,83 +0,0 @@
# Demonstration of fully dynamic crenel_position animation
#
# This example shows how all parameters of the crenel_position animation
# can now be made dynamic using value providers.
import global
import tasmota
import animation
print("=== Dynamic Crenel Position Animation Demo ===")
print("\n1. Creating dynamic value providers for all parameters:")
# Create dynamic providers for all parameters
var dynamic_color = animation.solid_color_provider(0xFF00FF00) # Green color
var dynamic_back_color = animation.static_value_provider(0xFF000000) # Transparent background
var dynamic_pos = animation.static_value_provider(1) # Position 1
var dynamic_pulse_size = animation.static_value_provider(3) # 3 pixels wide
var dynamic_low_size = animation.static_value_provider(2) # 2 pixels gap
var dynamic_nb_pulse = animation.static_value_provider(5) # 5 pulses
print(" ✓ Dynamic color provider: " + str(dynamic_color))
print(" ✓ Dynamic background color provider: " + str(dynamic_back_color))
print(" ✓ Dynamic position provider: " + str(dynamic_pos))
print(" ✓ Dynamic pulse size provider: " + str(dynamic_pulse_size))
print(" ✓ Dynamic low size provider: " + str(dynamic_low_size))
print(" ✓ Dynamic nb_pulse provider: " + str(dynamic_nb_pulse))
print("\n2. Creating crenel animation with all dynamic parameters:")
# Create a crenel animation where ALL parameters are dynamic
var fully_dynamic_crenel = animation.crenel_position_animation(
dynamic_color, # Dynamic color
dynamic_pos, # Dynamic position
dynamic_pulse_size, # Dynamic pulse size
dynamic_low_size, # Dynamic low size
dynamic_nb_pulse, # Dynamic number of pulses
10, # Static priority
0, # Infinite duration
false, # No loop
"fully_dynamic_crenel"
)
print(" ✓ Fully dynamic crenel created: " + str(fully_dynamic_crenel))
print("\n3. Testing parameter resolution:")
# Test that resolve_value works for all parameters
var test_time = tasmota.millis()
print(" Testing resolve_value() on all parameters:")
var resolved_color = fully_dynamic_crenel.resolve_value(dynamic_color, "color", test_time)
var resolved_pos = fully_dynamic_crenel.resolve_value(dynamic_pos, "pos", test_time)
var resolved_pulse_size = fully_dynamic_crenel.resolve_value(dynamic_pulse_size, "pulse_size", test_time)
var resolved_low_size = fully_dynamic_crenel.resolve_value(dynamic_low_size, "low_size", test_time)
var resolved_nb_pulse = fully_dynamic_crenel.resolve_value(dynamic_nb_pulse, "nb_pulse", test_time)
print(" ✓ Color resolved to: 0x" + format("%08x", resolved_color))
print(" ✓ Position resolved to: " + str(resolved_pos))
print(" ✓ Pulse size resolved to: " + str(resolved_pulse_size))
print(" ✓ Low size resolved to: " + str(resolved_low_size))
print(" ✓ Number of pulses resolved to: " + str(resolved_nb_pulse))
print(" ✓ All parameters resolved successfully!")
print("\n4. Benefits of fully dynamic parameters:")
print(" ✓ Color can change over time (e.g., rainbow effects)")
print(" ✓ Position can animate (moving pulses)")
print(" ✓ Pulse size can vary (breathing effect)")
print(" ✓ Gap size can change (rhythm variations)")
print(" ✓ Number of pulses can be time-based")
print(" ✓ Background color can fade or cycle")
print("\n5. Example use cases:")
print(" • Animated progress bars with changing colors")
print(" • Breathing effects with variable pulse sizes")
print(" • Moving patterns with position animation")
print(" • Rhythm-based lighting with variable gaps")
print(" • Dynamic backgrounds that fade in/out")
print("\n=== Demo Complete ===")
print("All parameters in crenel_position can now be dynamic!")
return true

View File

@ -1,77 +0,0 @@
# Demonstration of fully dynamic pulse_position animation
#
# This example shows how all parameters of the pulse_position animation
# can now be made dynamic using value providers.
import global
import tasmota
import animation
print("=== Dynamic Pulse Position Animation Demo ===")
print("\n1. Creating dynamic value providers for all parameters:")
# Create dynamic providers for all parameters
var dynamic_color = animation.solid_color_provider(0xFF0000FF) # Blue color
var dynamic_back_color = animation.static_value_provider(0xFF000000) # Transparent background
var dynamic_pos = animation.static_value_provider(2) # Position 2
var dynamic_pulse_size = animation.static_value_provider(4) # 4 pixels wide
var dynamic_slew_size = animation.static_value_provider(1) # 1 pixel fade
print(" ✓ Dynamic color provider: " + str(dynamic_color))
print(" ✓ Dynamic background color provider: " + str(dynamic_back_color))
print(" ✓ Dynamic position provider: " + str(dynamic_pos))
print(" ✓ Dynamic pulse size provider: " + str(dynamic_pulse_size))
print(" ✓ Dynamic slew size provider: " + str(dynamic_slew_size))
print("\n2. Creating pulse animation with all dynamic parameters:")
# Create a pulse animation where ALL parameters are dynamic
var fully_dynamic_pulse = animation.pulse_position_animation(
dynamic_color, # Dynamic color
dynamic_pos, # Dynamic position
dynamic_pulse_size, # Dynamic pulse size
dynamic_slew_size, # Dynamic slew size
10, # Static priority
0, # Infinite duration
false, # No loop
"fully_dynamic_pulse"
)
print(" ✓ Fully dynamic pulse created: " + str(fully_dynamic_pulse))
print("\n3. Testing parameter resolution:")
# Test that resolve_value works for all parameters
var test_time = tasmota.millis()
print(" Testing resolve_value() on all parameters:")
var resolved_color = fully_dynamic_pulse.resolve_value(dynamic_color, "color", test_time)
var resolved_pos = fully_dynamic_pulse.resolve_value(dynamic_pos, "pos", test_time)
var resolved_pulse_size = fully_dynamic_pulse.resolve_value(dynamic_pulse_size, "pulse_size", test_time)
var resolved_slew_size = fully_dynamic_pulse.resolve_value(dynamic_slew_size, "slew_size", test_time)
print(" ✓ Color resolved to: 0x" + format("%08x", resolved_color))
print(" ✓ Position resolved to: " + str(resolved_pos))
print(" ✓ Pulse size resolved to: " + str(resolved_pulse_size))
print(" ✓ Slew size resolved to: " + str(resolved_slew_size))
print(" ✓ All parameters resolved successfully!")
print("\n4. Benefits of fully dynamic parameters:")
print(" ✓ Color can change over time (e.g., rainbow effects)")
print(" ✓ Position can animate (moving pulses)")
print(" ✓ Pulse size can vary (breathing effect)")
print(" ✓ Slew size can change (fade intensity variations)")
print(" ✓ Background color can fade or cycle")
print("\n5. Example use cases:")
print(" • Moving spotlight effects with animated positions")
print(" • Breathing effects with variable pulse sizes and fade")
print(" • Color-changing indicators with dynamic backgrounds")
print(" • Animated progress indicators with smooth edges")
print(" • Dynamic lighting that responds to music or sensors")
print("\n=== Demo Complete ===")
print("All parameters in pulse_position can now be dynamic!")
return true

View File

@ -1,85 +0,0 @@
# Demo of ease_in and ease_out functionality in OscillatorValueProvider
#
# This demo shows how to use the new EASE_IN and EASE_OUT waveforms
# for creating smooth acceleration and deceleration effects.
import animation
import tasmota
print("=== Ease In/Out Demo ===")
# Create different easing providers
var ease_in_brightness = animation.ease_in(0, 255, 3000) # 3-second ease-in from 0 to 255
var ease_out_brightness = animation.ease_out(255, 0, 2000) # 2-second ease-out from 255 to 0
var ease_in_position = animation.ease_in(0, 30, 4000) # 4-second ease-in position
var ease_out_size = animation.ease_out(1, 10, 1500) # 1.5-second ease-out size
print("Created easing providers:")
print(f" Ease-in brightness: {ease_in_brightness}")
print(f" Ease-out brightness: {ease_out_brightness}")
print(f" Ease-in position: {ease_in_position}")
print(f" Ease-out size: {ease_out_size}")
# Simulate time progression and show values
print("\nEase-in brightness progression (0->255 over 3 seconds):")
var start_time = tasmota.millis()
for i: [0, 750, 1500, 2250, 3000]
var value = ease_in_brightness.get_value(start_time + i)
var percent = (i * 100) / 3000
print(f" {percent:3.0f}% ({i:4d}ms): brightness = {value:3d}")
end
print("\nEase-out brightness progression (255->0 over 2 seconds):")
start_time = tasmota.millis()
for i: [0, 500, 1000, 1500, 2000]
var value = ease_out_brightness.get_value(start_time + i)
var percent = (i * 100) / 2000
print(f" {percent:3.0f}% ({i:4d}ms): brightness = {value:3d}")
end
# Show comparison with linear interpolation
print("\nComparison: Ease-in vs Linear vs Ease-out (0->100 over 2 seconds):")
var linear_provider = animation.linear(0, 100, 2000)
var ease_in_demo = animation.ease_in(0, 100, 2000)
var ease_out_demo = animation.ease_out(0, 100, 2000)
start_time = tasmota.millis()
print("Time% Linear Ease-In Ease-Out")
print("---- ------ ------- --------")
for i: [0, 500, 1000, 1500, 2000]
var percent = (i * 100) / 2000
var linear_val = linear_provider.get_value(start_time + i)
var ease_in_val = ease_in_demo.get_value(start_time + i)
var ease_out_val = ease_out_demo.get_value(start_time + i)
print(f"{percent:3.0f}% {linear_val:6d} {ease_in_val:7d} {ease_out_val:8d}")
end
# Show how to use with phase shifts
print("\nEase-in with 25% phase shift:")
var phased_ease = animation.ease_in(0, 100, 2000)
phased_ease.set_phase(25)
start_time = tasmota.millis()
for i: [0, 500, 1000, 1500, 2000]
var value = phased_ease.get_value(start_time + i)
var percent = (i * 100) / 2000
print(f" {percent:3.0f}% ({i:4d}ms): value = {value:3d}")
end
# Example usage in animation context
print("\nExample: Using ease providers in animations")
print("# Create a breathing effect with ease-in/out")
print("var breathing_brightness = animation.ease_in(50, 255, 2000)")
print("var pulse_anim = animation.pulse(0xFF0000FF, breathing_brightness, 0, 0, true, 'breathing')")
print("")
print("# Create a smooth position animation")
print("var smooth_position = animation.ease_out(0, 29, 3000)")
print("var comet_anim = animation.comet(0xFF00FF00, smooth_position, 5, 128, true, 'smooth_comet')")
print("\n=== Demo Complete ===")
print("The new ease_in and ease_out functions provide:")
print("• EASE_IN: Quadratic acceleration (starts slow, speeds up)")
print("• EASE_OUT: Quadratic deceleration (starts fast, slows down)")
print("• Both work with all existing OscillatorValueProvider features")
print("• Phase shifts, duty cycles, and method chaining all supported")
print("• Use animation.ease_in(start, end, duration_ms) and animation.ease_out(start, end, duration_ms)")

View File

@ -1,136 +0,0 @@
#
# Advanced palette demonstration with multiple palettes and layering
# Showcases: Multiple palettes, composite providers, dynamic switching
# Demonstrates: Rich palette system, blending modes, palette transitions
#
import animation
var leds = 60 # More LEDs for better palette display
# Create LED strip
var strip = global.Leds(leds, gpio.pin(gpio.WS2812, 0))
var engine = animation.create_engine(strip)
# Define multiple custom palettes
var sunset_palette = bytes(
"00FF4500" # Orange red
"40FF8C00" # Dark orange
"80FFD700" # Gold
"C0FF69B4" # Hot pink
"FF800080" # Purple
)
var ocean_palette = bytes(
"00000080" # Navy blue
"400000FF" # Blue
"8000FFFF" # Cyan
"C000FF80" # Spring green
"FF008000" # Green
)
var fire_palette = bytes(
"00000000" # Black
"40800000" # Dark red
"80FF0000" # Red
"C0FF8000" # Orange
"FFFFFF00" # Yellow
)
# Create palette providers with different speeds and transitions
var sunset_provider = animation.rich_palette_color_provider(sunset_palette, 8000, 1, 200)
var ocean_provider = animation.rich_palette_color_provider(ocean_palette, 12000, 1, 180)
var fire_provider = animation.rich_palette_color_provider(fire_palette, 4000, 0, 220) # Linear transition
# Create base palette animations
var sunset_anim = animation.filled_animation(sunset_provider, 0, 0, true, "sunset_base")
var ocean_anim = animation.filled_animation(ocean_provider, 5, 0, true, "ocean_layer")
var fire_anim = animation.filled_animation(fire_provider, 10, 0, true, "fire_overlay")
# Add opacity oscillators for dynamic blending
var sunset_opacity = animation.smooth(100, 255, 15000)
var ocean_opacity = animation.linear(50, 200, 10000)
var fire_opacity = animation.square(0, 180, 6000, 30) # Strobe effect
sunset_anim.set_param_value("opacity", sunset_opacity)
ocean_anim.set_param_value("opacity", ocean_opacity)
fire_anim.set_param_value("opacity", fire_opacity)
# Add all palette layers
engine.add_animation(sunset_anim)
engine.add_animation(ocean_anim)
engine.add_animation(fire_anim)
# Create a composite color provider that blends multiple palettes
var composite_provider = animation.composite_color_provider([
sunset_provider,
ocean_provider,
fire_provider
], 0) # Overlay blend mode
# Add moving effects using the composite provider
var comet_anim = animation.comet(composite_provider, 8, 3, 2000, true, true, "palette_comet")
comet_anim.priority = 20
engine.add_animation(comet_anim)
# Add sparkle effects with palette colors
var sparkle_anim = animation.twinkle_animation(composite_provider, 8, 300, 0, true, "palette_sparkles")
sparkle_anim.priority = 25
engine.add_animation(sparkle_anim)
# Event handlers for palette switching
var current_mode = 0
var modes = ["all_layers", "sunset_only", "ocean_only", "fire_only", "composite_only"]
animation.register_event_handler("mode_switch",
def(event_data)
current_mode = (current_mode + 1) % 5
var mode = modes[current_mode]
print("Switching to mode:", mode)
# Clear current animations
engine.clear()
if mode == "all_layers"
engine.add_animation(sunset_anim)
engine.add_animation(ocean_anim)
engine.add_animation(fire_anim)
engine.add_animation(comet_anim)
engine.add_animation(sparkle_anim)
elif mode == "sunset_only"
engine.add_animation(sunset_anim)
elif mode == "ocean_only"
engine.add_animation(ocean_anim)
elif mode == "fire_only"
engine.add_animation(fire_anim)
elif mode == "composite_only"
engine.add_animation(comet_anim)
engine.add_animation(sparkle_anim)
end
end,
10, nil, {"description": "Switch between palette display modes"}
)
# Auto-mode switching every 20 seconds
animation.register_event_handler("auto_switch",
def(event_data)
animation.trigger_event("mode_switch", {})
end,
5, nil, {"description": "Automatic mode switching"}
)
engine.start()
print("Advanced Palette Demo - Multiple palettes with layering and effects")
print("Features:")
print("- 3 custom palettes (sunset, ocean, fire)")
print("- Dynamic opacity blending")
print("- Composite color provider")
print("- Moving comet with palette colors")
print("- Sparkle effects")
print("- Mode switching system")
print("\nModes:", modes)
print("\nTrigger mode switch:")
print("- animation.trigger_event('mode_switch', {})")
print("\nPress Ctrl+C to stop")

View File

@ -1,210 +0,0 @@
#
# Comprehensive blending demonstration with multiple animations
# Showcases: Advanced blending, multiple layers, dynamic composition
# Demonstrates: Frame buffer blending, animation layering, blend modes
#
import animation
var leds = 40 # Good size for blending demonstration
# Create LED strip
var strip = global.Leds(leds, gpio.pin(gpio.WS2812, 0))
var engine = animation.create_engine(strip)
# Layer 1: Base gradient background
var gradient_colors = [0x440000, 0x004400, 0x000044, 0x444400]
var gradient_provider = animation.color_cycle_color_provider(gradient_colors, 20000, 1)
var gradient_bg = animation.filled_animation(gradient_provider, 0, 0, true, "gradient_background")
gradient_bg.set_param_value("opacity", 120) # Semi-transparent base
engine.add_animation(gradient_bg)
# Layer 2: Moving comet with trail
var comet_color = animation.rich_palette_color_provider.rainbow(8000, 1, 255)
var comet = animation.comet(comet_color, 12, 6, 4000, true, true, "rainbow_comet")
comet.priority = 10
comet.set_param_value("opacity", 200)
engine.add_animation(comet)
# Layer 3: Breathing pulse overlay
var pulse_color = animation.color_cycle_color_provider([
0xFFFFFF, 0xFF8080, 0x80FF80, 0x8080FF
], 6000, 1)
var breathe = animation.breathe_animation(pulse_color, 180, 3000, true, "color_breathe")
breathe.priority = 20
var breathe_opacity = animation.smooth(80, 220, 5000)
breathe.set_param_value("opacity", breathe_opacity)
engine.add_animation(breathe)
# Layer 4: Sparkle effects
var sparkle = animation.twinkle_animation(0xFFFFFF, 6, 200, 0, true, "white_sparkles")
sparkle.priority = 30
sparkle.set_param_value("opacity", 150)
engine.add_animation(sparkle)
# Layer 5: Position-based pulse that moves
var moving_pulse = animation.pulse_position(0xFF00FF, 8, 2, 35, 0, true, "moving_pulse")
var pulse_pos = animation.linear(2, leds-10, 7000)
var pulse_size = animation.smooth(4, 16, 4500)
moving_pulse.set_param_value("pos", pulse_pos)
moving_pulse.set_param_value("pulse_size", pulse_size)
moving_pulse.priority = 25
moving_pulse.set_param_value("opacity", 180)
engine.add_animation(moving_pulse)
# Demonstration of manual frame buffer blending
def demonstrate_manual_blending()
print("\n--- Manual Frame Buffer Blending Demo ---")
# Create separate frame buffers
var frame1 = animation.frame_buffer(leds)
var frame2 = animation.frame_buffer(leds)
var frame3 = animation.frame_buffer(leds)
# Fill frame1 with red gradient
for i: 0..leds-1
var intensity = int(tasmota.scale_uint(i, 0, leds-1, 50, 255))
frame1.set_pixel(i, intensity, 0, 0, 200)
end
# Fill frame2 with green wave pattern
import math
for i: 0..leds-1
var wave = int((math.sin(i * 0.3) + 1) * 127)
frame2.set_pixel(i, 0, wave, 0, 150)
end
# Fill frame3 with blue sparkles
for i: 0..leds-1
if (i % 7) == 0 # Every 7th pixel
frame3.set_pixel(i, 0, 0, 255, 180)
end
end
# Blend all frames together
frame1.blend(frame2, 255) # Blend green wave onto red gradient
frame1.blend(frame3, 255) # Blend blue sparkles on top
print("Manual blending result:")
print("Frame1 (red gradient):", frame1.pixels[0..20].tohex())
print("Combined result shows additive blending of RGB channels")
return frame1
end
# Event handlers for blending control
animation.register_event_handler("toggle_layer",
def(event_data)
var layer_name = event_data.find("layer", "rainbow_comet")
print("Toggling layer:", layer_name)
var found = false
for anim: engine.get_animations()
if anim.name == layer_name
engine.remove_animation(anim)
found = true
break
end
end
if !found
# Re-add the animation based on name
if layer_name == "rainbow_comet"
engine.add_animation(comet)
elif layer_name == "color_breathe"
engine.add_animation(breathe)
elif layer_name == "white_sparkles"
engine.add_animation(sparkle)
elif layer_name == "moving_pulse"
engine.add_animation(moving_pulse)
end
end
end,
10, nil, {"description": "Toggle individual layers"}
)
animation.register_event_handler("adjust_opacity",
def(event_data)
var layer = event_data.find("layer", "all")
var opacity = event_data.find("opacity", 128)
print("Adjusting opacity for", layer, "to", opacity)
if layer == "all"
for anim: engine.get_animations()
if anim.name != "gradient_background"
anim.set_param_value("opacity", opacity)
end
end
else
for anim: engine.get_animations()
if anim.name == layer
anim.set_param_value("opacity", opacity)
break
end
end
end
end,
8, nil, {"description": "Adjust layer opacity"}
)
animation.register_event_handler("demo_manual_blend",
def(event_data)
demonstrate_manual_blending()
end,
5, nil, {"description": "Demonstrate manual frame buffer blending"}
)
animation.register_event_handler("blend_mode_info",
def(event_data)
print("\n--- Blending Information ---")
print("Current layers (bottom to top):")
var anims = engine.get_animations()
# Sort by priority for display
for i: 0..anims.size()-1
for j: i+1..anims.size()-1
if anims[i].priority > anims[j].priority
var temp = anims[i]
anims[i] = anims[j]
anims[j] = temp
end
end
end
for anim: anims
var opacity = anim.get_param("opacity", 255)
print("- " + anim.name + " (priority: " + str(anim.priority) + ", opacity: " + str(opacity) + ")")
end
print("\nBlending occurs in priority order (low to high)")
print("Each layer blends with the accumulated result below it")
print("Alpha values control transparency and blending intensity")
end,
1, nil, {"description": "Show current blending configuration"}
)
# Start the engine
engine.start()
# Show initial manual blending demo
demonstrate_manual_blending()
print("Comprehensive Blend Demo - Advanced layering and blending")
print("Features:")
print("- 5 animation layers with different priorities")
print("- Dynamic opacity control using value providers")
print("- Multiple blend types (gradient, comet, breathe, sparkle, pulse)")
print("- Manual frame buffer blending demonstration")
print("- Interactive layer control")
print("\nLayers (priority order):")
print("0. Gradient background (priority 0)")
print("1. Rainbow comet (priority 10)")
print("2. Color breathe (priority 20)")
print("3. Moving pulse (priority 25)")
print("4. White sparkles (priority 30)")
print("\nInteractive events:")
print("- animation.trigger_event('toggle_layer', {'layer': 'rainbow_comet'})")
print("- animation.trigger_event('adjust_opacity', {'layer': 'all', 'opacity': 100})")
print("- animation.trigger_event('demo_manual_blend', {})")
print("- animation.trigger_event('blend_mode_info', {})")
print("\nPress Ctrl+C to stop")

View File

@ -1,166 +0,0 @@
#
# Dynamic pulse demonstration with value providers and events
# Showcases: Multiple pulse types, dynamic parameters, interactive control
# Demonstrates: Value provider system, event-driven parameter changes
#
import animation
var leds = 50 # More LEDs for better pulse effects
# Create LED strip
var strip = global.Leds(leds, gpio.pin(gpio.WS2812, 0))
var engine = animation.create_engine(strip)
# Create background with subtle color cycling
var bg_provider = animation.color_cycle_color_provider([
0x001122, 0x002211, 0x112200, 0x220011
], 30000, 1)
var background = animation.filled_animation(bg_provider, 0, 0, true, "cycling_background")
engine.add_animation(background)
# Create multiple pulse types with different characteristics
# 1. Breathing pulse with oscillating size
var breathe_pulse = animation.pulse_position(0xFF0000, 5, 1, 10, 0, true, "breathe_pulse")
var size_osc = animation.smooth(2, 12, 4000)
var pos_osc = animation.linear(5, leds-15, 8000)
breathe_pulse.set_param_value("pulse_size", size_osc)
breathe_pulse.set_param_value("pos", pos_osc)
breathe_pulse.priority = 10
engine.add_animation(breathe_pulse)
# 2. Strobe pulse with square wave intensity
var strobe_pulse = animation.pulse_position(0x00FF00, 3, 1, 15, 0, true, "strobe_pulse")
var strobe_intensity = animation.square(50, 255, 800, 25) # Fast strobe, 25% duty cycle
var strobe_pos = animation.linear(leds-10, 5, 6000) # Opposite direction
strobe_pulse.set_param_value("opacity", strobe_intensity)
strobe_pulse.set_param_value("pos", strobe_pos)
strobe_pulse.priority = 15
engine.add_animation(strobe_pulse)
# 3. Color-cycling pulse with dynamic color
var rainbow_pulse = animation.pulse_position(0x0000FF, 8, 2, 20, 0, true, "rainbow_pulse")
var rainbow_color = animation.rich_palette_color_provider.rainbow(5000, 1, 255)
var center_pos = animation.smooth(leds/4, 3*leds/4, 10000)
rainbow_pulse.set_param_value("color", rainbow_color)
rainbow_pulse.set_param_value("pos", center_pos)
rainbow_pulse.priority = 20
engine.add_animation(rainbow_pulse)
# 4. Fire pulse with fire palette
var fire_palette = animation.PALETTE_FIRE
var fire_color = animation.rich_palette_color_provider(fire_palette, 3000, 0, 255)
var fire_pulse = animation.pulse_position(0xFF4400, 6, 3, 25, 0, true, "fire_pulse")
var fire_size = animation.linear(4, 15, 7000)
fire_pulse.set_param_value("color", fire_color)
fire_pulse.set_param_value("pulse_size", fire_size)
fire_pulse.set_param_value("pos", leds/2) # Fixed center position
fire_pulse.priority = 25
engine.add_animation(fire_pulse)
# Interactive event handlers for dynamic control
animation.register_event_handler("speed_up",
def(event_data)
print("Speed up event - doubling all animation speeds")
for anim: engine.get_animations()
if anim.name != "cycling_background"
# Speed up oscillators by halving their duration
for param_name: ["pulse_size", "pos", "opacity", "color"]
var param_value = anim.get_param(param_name, nil)
if animation.is_value_provider(param_value)
if param_value.find("duration_ms") != nil
param_value.duration_ms = param_value.duration_ms / 2
end
end
end
end
end
end,
10, nil, {"description": "Double animation speeds"}
)
animation.register_event_handler("slow_down",
def(event_data)
print("Slow down event - halving all animation speeds")
for anim: engine.get_animations()
if anim.name != "cycling_background"
# Slow down oscillators by doubling their duration
for param_name: ["pulse_size", "pos", "opacity", "color"]
var param_value = anim.get_param(param_name, nil)
if animation.is_value_provider(param_value)
if param_value.find("duration_ms") != nil
param_value.duration_ms = param_value.duration_ms * 2
end
end
end
end
end
end,
10, nil, {"description": "Halve animation speeds"}
)
animation.register_event_handler("randomize_positions",
def(event_data)
print("Randomize positions event - setting random pulse positions")
import math
for anim: engine.get_animations()
if anim.name[0..4] == "pulse" || anim.name[-5..-1] == "pulse"
var random_pos = int(math.rand() % (leds - 10)) + 5
anim.set_param_value("pos", random_pos)
end
end
end,
5, nil, {"description": "Randomize pulse positions"}
)
animation.register_event_handler("toggle_pulse",
def(event_data)
var pulse_name = event_data.find("pulse_name", "breathe_pulse")
print("Toggle pulse event - toggling", pulse_name)
var found = false
for anim: engine.get_animations()
if anim.name == pulse_name
engine.remove_animation(anim)
found = true
break
end
end
if !found
# Re-add the pulse based on name
if pulse_name == "breathe_pulse"
engine.add_animation(breathe_pulse)
elif pulse_name == "strobe_pulse"
engine.add_animation(strobe_pulse)
elif pulse_name == "rainbow_pulse"
engine.add_animation(rainbow_pulse)
elif pulse_name == "fire_pulse"
engine.add_animation(fire_pulse)
end
end
end,
8, nil, {"description": "Toggle individual pulses on/off"}
)
engine.start()
print("Dynamic Pulse Demo - Multiple pulse types with interactive control")
print("Features:")
print("- 4 different pulse types with unique characteristics")
print("- Dynamic parameters using value providers")
print("- Interactive event system for real-time control")
print("- Background color cycling")
print("- Layered composition with priorities")
print("\nPulse types:")
print("- Breathe: Red pulse with oscillating size and position")
print("- Strobe: Green pulse with square wave intensity")
print("- Rainbow: Color-cycling pulse with smooth movement")
print("- Fire: Fire-colored pulse with growing size")
print("\nInteractive events:")
print("- animation.trigger_event('speed_up', {})")
print("- animation.trigger_event('slow_down', {})")
print("- animation.trigger_event('randomize_positions', {})")
print("- animation.trigger_event('toggle_pulse', {'pulse_name': 'breathe_pulse'})")
print("\nPress Ctrl+C to stop")

View File

@ -1,90 +0,0 @@
#
# Enhanced modern version of the breathing effect
# Showcases: Multiple colors, layering, value providers, events
# Demonstrates: Advanced color providers, dynamic parameters, event system
#
import animation
var leds = 30 # More LEDs for better effect
# Create LED strip
var strip = global.Leds(leds, gpio.pin(gpio.WS2812, 0))
var engine = animation.create_engine(strip)
# Create multiple breathing layers with different colors and speeds
var colors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF]
var durations = [3000, 4000, 5000, 3500, 4500]
# Create breathing animations with different phases
for i: 0..4
var color = colors[i]
var duration = durations[i]
# Create oscillator with phase offset to create wave effect
var phase_offset = int(tasmota.scale_uint(i, 0, 4, 0, 100))
var brightness_osc = animation.smooth(30, 200, duration)
brightness_osc.set_phase(phase_offset)
# Create position oscillator for moving breathe effect
var pos_osc = animation.linear(0, leds-5, duration * 2)
pos_osc.set_phase(phase_offset)
# Create breathe animation
var breathe_anim = animation.breathe_animation(color, 150, duration, true, "breathe_" + str(i))
breathe_anim.set_param_value("opacity", brightness_osc)
# Add slight priority differences for layering
breathe_anim.priority = i * 2
engine.add_animation(breathe_anim)
end
# Add a background rainbow that slowly cycles
var rainbow_bg = animation.filled_animation(
animation.rich_palette_color_provider.rainbow(20000, 1, 50), # Slow, dim rainbow
0, 0, true, "rainbow_background"
)
engine.add_animation(rainbow_bg)
# Register event handlers for interactive control
animation.register_event_handler("button_press",
def(event_data)
print("Button pressed - changing breathing speed")
# Speed up all animations
for anim: engine.get_animations()
if anim.name[0..7] == "breathe_"
# Double the breathing speed
var current_duration = anim.get_param("duration", 3000)
anim.set_param("duration", current_duration / 2)
end
end
end,
10, nil, {"description": "Speed up breathing on button press"}
)
animation.register_event_handler("timer",
def(event_data)
if event_data.find("interval") == 10000 # Every 10 seconds
print("Timer event - adding sparkle effect")
# Add temporary sparkle overlay
var sparkle = animation.twinkle_animation(0xFFFFFF, 5, 500, 2000, false, "sparkle_overlay")
sparkle.priority = 100 # High priority overlay
engine.add_animation(sparkle)
end
end,
5, nil, {"description": "Add sparkles every 10 seconds"}
)
engine.start()
print("Modern Breathe Showcase - Enhanced breathing with multiple layers")
print("Features:")
print("- 5 breathing layers with different colors and phases")
print("- Background rainbow effect")
print("- Event system for interactive control")
print("- Dynamic parameter updates")
print("- Layered composition")
print("\nTrigger events:")
print("- animation.trigger_event('button_press', {})")
print("- animation.trigger_event('timer', {'interval': 10000})")
print("\nPress Ctrl+C to stop")

View File

@ -1,242 +0,0 @@
# Event System Demo
# Demonstrates the event handling capabilities of the Berry Animation Framework
import string
# Import animation module
var animation = global.animation
print("=== Event System Demo ===")
print()
# Create a mock LED strip for demonstration
var mock_strip = {
"length": def() return 30 end,
"show": def() end,
"can_show": def() return true end,
"set_pixel": def(i, color) end
}
# Create animation engine
var engine = animation.create_engine(mock_strip)
print("1. Basic Event Handler Registration")
print("-----------------------------------")
# Register a simple event handler
var button_handler = animation.register_event_handler(
"button_press",
def(event_data)
print(f"Button pressed! Data: {event_data}")
# Add a flash animation
var flash_anim = animation.solid(0xFFFFFFFF) # White flash
engine.add_animation(flash_anim)
end,
10, # High priority
nil, # No condition
{} # No metadata
)
print("✓ Registered button_press event handler")
# Trigger the event
print("Triggering button_press event...")
animation.trigger_event("button_press", {"button": "main", "timestamp": tasmota.millis()})
print()
print("2. Event Handler with Conditions")
print("--------------------------------")
# Register a conditional event handler
var brightness_handler = animation.register_event_handler(
"brightness_change",
def(event_data)
var brightness = event_data["brightness"]
if brightness > 80
print("High brightness detected - switching to day mode")
else
print("Low brightness detected - switching to night mode")
end
end,
5, # Medium priority
def(event_data) return event_data.contains("brightness") end, # Condition
{"type": "brightness_monitor"} # Metadata
)
print("✓ Registered brightness_change event handler with condition")
# Trigger with valid data
print("Triggering brightness_change with brightness=90...")
animation.trigger_event("brightness_change", {"brightness": 90})
# Trigger with invalid data (should be ignored due to condition)
print("Triggering brightness_change without brightness data (should be ignored)...")
animation.trigger_event("brightness_change", {"other_data": "test"})
print()
print("3. Timer Event with Metadata")
print("----------------------------")
# Register a timer event handler
var timer_handler = animation.register_event_handler(
"timer",
def(event_data)
print(f"Timer event triggered! Interval: {event_data['interval']}ms")
# Add a pulse animation
var pulse_anim = animation.pulse_animation(animation.solid(0xFF00FF00), 1000, 100, 255) # Green pulse
engine.add_animation(pulse_anim)
end,
0, # Normal priority
nil, # No condition
{"interval": 5000, "repeat": true} # 5-second timer
)
print("✓ Registered timer event handler")
# Simulate timer trigger
print("Simulating timer trigger...")
animation.trigger_event("timer", {"interval": 5000})
print()
print("4. Global Event Handler")
print("-----------------------")
# Register a global event handler that responds to all events
var global_handler = animation.register_event_handler(
"*", # Global event name
def(event_data)
var event_name = event_data["event_name"]
print(f"Global handler: Event '{event_name}' was triggered")
end,
1, # Low priority (runs after specific handlers)
nil, # No condition
{"type": "global_monitor"}
)
print("✓ Registered global event handler")
# Trigger various events to show global handler
print("Triggering various events to demonstrate global handler...")
animation.trigger_event("test_event_1", {"data": "test1"})
animation.trigger_event("test_event_2", {"data": "test2"})
print()
print("5. DSL Event Handler Compilation")
print("--------------------------------")
# Demonstrate DSL event handler compilation
var dsl_code =
"strip length 30\n"
"color red = #FF0000\n"
"color blue = #0000FF\n"
"color white = #FFFFFF\n"
"\n"
"# Event handlers\n"
"on button_press: solid(red)\n"
"on timer(3s): solid(blue)\n"
"on startup: solid(white)\n"
"\n"
"# Main sequence\n"
"sequence main {\n"
" play solid(red) for 2s\n"
" play solid(blue) for 2s\n"
"}\n"
"\n"
"run main"
print("Compiling DSL with event handlers...")
var compiled_code = animation.compile_dsl(dsl_code)
if compiled_code != nil
print("✓ DSL compilation successful!")
print("Generated Berry code contains:")
if string.find(compiled_code, "register_event_handler") >= 0
print(" - Event handler registrations")
end
if string.find(compiled_code, "button_press") >= 0
print(" - Button press event")
end
if string.find(compiled_code, "timer") >= 0
print(" - Timer event")
end
if string.find(compiled_code, "startup") >= 0
print(" - Startup event")
end
else
print("✗ DSL compilation failed")
end
print()
print("6. Event System Status")
print("---------------------")
# Show registered events
var registered_events = animation.get_registered_events()
print(f"Registered events: {registered_events}")
# Show handlers for a specific event
var button_handlers = animation.get_event_handlers("button_press")
print(f"Button press handlers: {size(button_handlers)}")
for handler_info : button_handlers
print(f" - Priority: {handler_info['priority']}, Active: {handler_info['is_active']}")
end
print()
print("7. Animation Engine Integration")
print("-------------------------------")
# Demonstrate animation engine event integration
print("Testing animation engine interrupt methods...")
# Add some test animations
engine.add_animation(animation.solid(0xFF00FF00)) # Green
engine.add_animation(animation.solid(0xFF0000FF)) # Blue
print(f"Animations before interrupt: {engine.size()}")
# Test interrupt current
engine.interrupt_current()
print("✓ interrupt_current() executed")
# Add more animations
engine.add_animation(animation.solid(0xFFFF0000)) # Red
engine.add_animation(animation.solid(0xFFFFFF00)) # Yellow
print(f"Animations after adding more: {engine.size()}")
# Test interrupt all
engine.interrupt_all()
print("✓ interrupt_all() executed")
print(f"Animations after interrupt_all: {engine.size()}")
print()
print("8. Cleanup")
print("----------")
# Clean up event handlers
animation.unregister_event_handler(button_handler)
animation.unregister_event_handler(brightness_handler)
animation.unregister_event_handler(timer_handler)
animation.unregister_event_handler(global_handler)
print("✓ All event handlers unregistered")
# Verify cleanup
var remaining_events = animation.get_registered_events()
print(f"Remaining registered events: {size(remaining_events)}")
print()
print("=== Event System Demo Complete ===")
print("The event system is ready for use!")
print()
print("Key Features Demonstrated:")
print("- Basic event handler registration and triggering")
print("- Event priority ordering")
print("- Conditional event handlers")
print("- Global event handlers")
print("- Timer events with metadata")
print("- DSL event handler compilation")
print("- Animation engine integration")
print("- Event handler cleanup")

View File

@ -1,158 +0,0 @@
# Fast Loop Integration Demo
#
# This example demonstrates how the AnimationController integrates
# with Tasmota's fast_loop system for efficient animation updates.
# Import the animation module
import global
import tasmota
import animation
# Create a mock WS2812 class for testing
class WS2812
var length_value
var pixels
var show_called
var can_show_result
def init(length)
self.length_value = length
self.pixels = {}
self.show_called = false
self.can_show_result = true
end
def length()
return self.length_value
end
def set_pixel_color(index, color)
self.pixels[index] = {
"r": color & 0xFF,
"g": (color >> 8) & 0xFF,
"b": (color >> 16) & 0xFF
}
end
def show()
self.show_called = true
end
def can_show()
return self.can_show_result
end
end
# Create a simple animation that shows the fast_loop timing
class TimingAnimation : animation.animation
var color
var last_update
var update_count
def init(color)
# Initialize with priority 1, 1 second duration, and looping enabled
super(self).init(1, 1000, true, "timing_animation")
# Store parameters
self.color = color
self.last_update = 0
self.update_count = 0
end
def update(time_ms)
# Track update timing
if self.last_update > 0
var delta = time_ms - self.last_update
# Print timing information every second
if self.update_count % 200 == 0 # Roughly every second at ~200 updates/sec
print(format("Animation update delta: %dms", delta))
end
end
self.last_update = time_ms
self.update_count += 1
return super(self).update(time_ms)
end
def render(frame)
if !self.is_running || frame == nil
return false
end
# Extract color components
var r = self.color & 0xFF
var g = (self.color >> 8) & 0xFF
var b = (self.color >> 16) & 0xFF
# Fill the frame with the color
frame.fill_pixels(animation.frame_buffer.to_color(r, g, b, 255))
return true
end
end
# Main demo function
def run_demo()
# Create a WS2812 LED strip (adjust parameters for your setup)
var strip_length = 30
var strip = WS2812(strip_length)
# Create the animation controller
var controller = animation.animation_controller(strip)
# Create timing animation
var timing_anim = TimingAnimation(0x0000FF) # Blue color
# Add animation to the controller
controller.add_animation(timing_anim)
# Start the controller
controller.start()
print("Fast loop integration demo started")
print("This demo shows the fast_loop integration with timing information")
print("Press 's' to stop animations")
print("Press 'r' to restart animations")
print("Press 'q' to quit")
# Set up a simple command handler
def handle_command(cmd)
if cmd == "s"
controller.stop()
print("Animations stopped")
elif cmd == "r"
controller.start()
print("Animations restarted")
elif cmd == "q"
controller.stop()
print("Demo ended")
return false
end
return true
end
# In a real application, you would integrate with Tasmota's command system
# For this demo, we'll just return the controller and handler for manual testing
return {
"controller": controller,
"handler": handle_command
}
end
# Run the demo if this file is executed directly
try
if tasmota != nil
# When running in Tasmota
var demo = run_demo()
return demo
end
except .. as e
# When running in standalone Berry or if tasmota is not available
print("This demo is designed to run in Tasmota")
print("Running in simulation mode...")
var demo = run_demo()
print("Demo initialized successfully in simulation mode")
return demo
end

View File

@ -1,113 +0,0 @@
# Filled Animation Demo for Berry Animation Framework
#
# This example demonstrates the use of the animation.filled_animation class with different color providers.
import animation
# Create a strip and controller
var strip_width = 30
var controller = animation.animation_controller(strip_width)
print("animation.filled_animation Demo")
print("====================")
# Example 1: Solid color
print("\n1. Creating a filled animation with a solid color...")
var solid_anim = animation.filled_animation(0xFF0000FF, 10, 255, 0, true, "red_fill")
controller.add_animation(solid_anim)
solid_anim.start()
# Wait a moment to see the solid color
tasmota.delay(2000)
solid_anim.stop()
controller.remove_animation(solid_anim)
# Example 2: Color cycle provider
print("\n2. Creating a filled animation with a color cycle provider...")
var cycle_anim = animation.color_cycle_animation(
[0xFF0000FF, 0xFF00FF00, 0xFFFF0000], # RGB colors
3000, # 3 second cycle period
1, # Sine transition
10 # Priority
)
controller.add_animation(cycle_anim)
cycle_anim.start()
# Let the color cycle run for a few seconds
tasmota.delay(5000)
cycle_anim.stop()
controller.remove_animation(cycle_anim)
# Example 3: Rich palette provider
print("\n3. Creating a filled animation with a rich palette provider...")
var rainbow_anim = animation.rich_palette_animation(
animation.PALETTE_RAINBOW, # Use the rainbow palette
5000, # 5 second cycle period
1, # Sine transition
255, # Full brightness
10 # Priority
)
controller.add_animation(rainbow_anim)
rainbow_anim.start()
# Let the rainbow animation run for a few seconds
tasmota.delay(5000)
rainbow_anim.stop()
controller.remove_animation(rainbow_anim)
# Example 4: Composite provider
print("\n4. Creating a filled animation with a composite provider...")
var palette_provider = animation.rich_palette_color_provider(
animation.PALETTE_RAINBOW, # Use the rainbow palette
5000, # 5 second cycle period
1, # Sine transition
255 # Full brightness
)
var cycle_provider = animation.color_cycle_color_provider(
[0xFF0000FF, 0xFF00FF00, 0xFFFF0000], # RGB colors
3000, # 3 second cycle period
1 # Sine transition
)
var composite_anim = animation.composite(
[palette_provider, cycle_provider], # List of providers to combine
0, # Overlay blend mode
10 # Priority
)
controller.add_animation(composite_anim)
composite_anim.start()
# Let the composite animation run for a few seconds
tasmota.delay(5000)
composite_anim.stop()
controller.remove_animation(composite_anim)
# Example 5: Changing color provider dynamically
print("\n5. Changing color provider dynamically...")
var dynamic_anim = animation.filled_animation(0xFF0000FF, 10, 255, 0, true, "dynamic")
controller.add_animation(dynamic_anim)
dynamic_anim.start()
# Show solid color first
tasmota.delay(2000)
# Change to color cycle provider
print(" Changing to color cycle provider...")
dynamic_anim.set_color_provider(cycle_provider)
tasmota.delay(3000)
# Change to rich palette provider
print(" Changing to rich palette provider...")
dynamic_anim.set_color_provider(palette_provider)
tasmota.delay(3000)
# Change back to solid color
print(" Changing back to solid color...")
dynamic_anim.set_color(0x00FF00FF) # Green
tasmota.delay(2000)
dynamic_anim.stop()
controller.remove_animation(dynamic_anim)
print("\nanimation.filled Demo completed!")

View File

@ -1,186 +0,0 @@
# Fire Animation Demo
# Demonstrates the FireAnimation class with various configurations
import "animation" as animation
print("=== Fire Animation Demo ===")
# Demo configuration
var STRIP_LENGTH = 30
var DEMO_DURATION = 10000 # 10 seconds per demo
print(f"Strip length: {STRIP_LENGTH} pixels")
print(f"Demo duration: {DEMO_DURATION}ms per animation")
# Demo 1: Classic Fire Effect
print("\n--- Demo 1: Classic Fire Effect ---")
var classic_fire = animation.fire_animation.classic(180, STRIP_LENGTH, 10)
print(f"Created classic fire: {classic_fire}")
print("This creates a realistic fire effect with warm colors")
print("- Base intensity: 180/255")
print("- Flicker speed: 8 Hz")
print("- Uses built-in fire palette (black -> dark red -> red -> orange -> yellow)")
# Demo 2: Intense Fire
print("\n--- Demo 2: Intense Fire ---")
var intense_fire = animation.fire_animation(nil, 255, 12, 150, 40, 180, STRIP_LENGTH, 10, 0, true, "intense_fire")
print(f"Created intense fire: {intense_fire}")
print("This creates a more intense fire with:")
print("- Maximum intensity: 255/255")
print("- Faster flicker: 12 Hz")
print("- More flicker variation: 150/255")
print("- Faster cooling: 40/255")
print("- More sparks: 180/255")
# Demo 3: Gentle Fire
print("\n--- Demo 3: Gentle Fire ---")
var gentle_fire = animation.fire_animation(nil, 120, 4, 50, 80, 80, STRIP_LENGTH, 10, 0, true, "gentle_fire")
print(f"Created gentle fire: {gentle_fire}")
print("This creates a gentler fire with:")
print("- Lower intensity: 120/255")
print("- Slower flicker: 4 Hz")
print("- Less flicker variation: 50/255")
print("- Slower cooling: 80/255")
print("- Fewer sparks: 80/255")
# Demo 4: Single Color Fire
print("\n--- Demo 4: Single Color Fire (Blue Flame) ---")
var blue_fire = animation.fire_animation.solid(0xFF0080FF, 200, STRIP_LENGTH, 10)
print(f"Created blue fire: {blue_fire}")
print("This creates a blue flame effect using a single color")
print("- Color: Blue (0xFF0080FF)")
print("- Intensity: 200/255")
# Demo 5: Custom Palette Fire
print("\n--- Demo 5: Custom Palette Fire (Green Flame) ---")
# Create a green fire palette
var green_fire_palette = bytes(
"00000000" # Black (value 0)
"40004000" # Dark green (value 64)
"8000FF00" # Green (value 128)
"C080FF80" # Light green (value 192)
"FFFFFF80" # Very light green (value 255)
)
var green_fire = animation.fire_animation.palette(green_fire_palette, 180, STRIP_LENGTH, 10)
print(f"Created green fire: {green_fire}")
print("This creates a green flame effect using a custom palette")
# Demo 6: Animation Controller Integration
print("\n--- Demo 6: Animation Controller Integration ---")
print("Creating animation controller and adding multiple fire effects...")
# Create a mock LED strip (in real usage, this would be a real strip)
class MockStrip
var pixels
var strip_length
def init(length)
self.strip_length = length
self.pixels = []
self.pixels.resize(length)
for i: 0..length-1
self.pixels[i] = 0
end
end
def set_pixel_color(index, color)
if index >= 0 && index < self.strip_length
self.pixels[index] = color
end
end
def show()
# In real usage, this would update the physical LEDs
return true
end
def get_pixel_color(index)
if index >= 0 && index < self.strip_length
return self.pixels[index]
end
return 0
end
def length()
return self.strip_length
end
end
var mock_strip = MockStrip(STRIP_LENGTH)
var controller = animation.animation_controller(mock_strip, 255)
# Add multiple fire animations with different priorities
controller.add_animation(classic_fire)
controller.add_animation(blue_fire.set_priority(5)) # Lower priority
print("Added classic fire (priority 10) and blue fire (priority 5)")
print("The classic fire will render on top of the blue fire")
# Demo 7: Real-time Parameter Updates
print("\n--- Demo 7: Real-time Parameter Updates ---")
var dynamic_fire = animation.fire_animation.classic(100, STRIP_LENGTH, 10)
print(f"Created dynamic fire with initial intensity: {dynamic_fire.get_param('intensity')}")
# Simulate parameter changes over time
var intensities = [100, 150, 200, 255, 180, 120]
for i: 0..size(intensities)-1
var new_intensity = intensities[i]
dynamic_fire.set_intensity(new_intensity)
print(f"Updated intensity to: {new_intensity}")
end
# Demo 8: Performance Considerations
print("\n--- Demo 8: Performance Considerations ---")
print("Fire animation performance tips:")
print("- Lower flicker_speed reduces CPU usage (fewer updates per second)")
print("- Smaller strip_length reduces memory usage and computation")
print("- Lower flicker_amount reduces random number generation overhead")
print("- Use solid colors instead of palettes for maximum performance")
# Create a performance-optimized fire
var perf_fire = animation.fire_animation.solid(0xFFFF4500, 150, STRIP_LENGTH, 10)
perf_fire.set_flicker_speed(4) # Slower updates
perf_fire.set_flicker_amount(30) # Less randomness
print(f"Created performance-optimized fire: {perf_fire}")
# Demo 9: Simulation Test
print("\n--- Demo 9: Fire Simulation Test ---")
print("Running fire simulation for a few cycles...")
var test_fire = animation.fire_animation.classic(180, 10, 10) # Smaller strip for easier visualization
test_fire.start()
var frame = animation.frame_buffer(10)
var start_time = 1000
for cycle: 0..4
var current_time = start_time + (cycle * 125) # 8 Hz = 125ms intervals
test_fire.update(current_time)
test_fire.render(frame, current_time)
print(f"Cycle {cycle + 1}:")
var heat_info = " Heat pattern: "
for i: 0..9
var color = frame.get_pixel_color(i)
var brightness = 0
if color != 0xFF000000
# Extract brightness from color (simple approximation)
var r = (color >> 16) & 0xFF
var g = (color >> 8) & 0xFF
var b = color & 0xFF
brightness = (r + g + b) / 3
end
heat_info += f"{brightness:3d} "
end
print(heat_info)
end
print("\n=== Fire Animation Demo Complete ===")
print("The fire animation provides realistic flame effects with:")
print("- Heat-based simulation with cooling and sparking")
print("- Configurable intensity, flicker, and timing")
print("- Support for custom colors and palettes")
print("- Real-time parameter updates")
print("- Integration with the animation framework")
return true

View File

@ -1,82 +0,0 @@
# FrameBuffer Demo
#
# This example demonstrates the basic usage of the FrameBuffer class.
import global
import tasmota
import animation
# Create a frame buffer with 10 pixels
var fb = animation.frame_buffer(10)
# Clear the buffer (set all pixels to transparent black)
fb.clear()
print(f"After clear: {fb.tohex()}")
# Set individual pixels
fb.set_pixel_color(0, 0xFFFF0000) # Red
fb.set_pixel_color(1, 0xFF00FF00) # Green
fb.set_pixel_color(2, 0xFF0000FF) # Blue
fb.set_pixel_color(3, 0xFFFFFF00) # Yellow
fb.set_pixel_color(4, 0xFFFF00FF) # Purple
print(f"After setting pixels: {fb.tohex()}")
# Fill the buffer with a single color
fb.fill_pixels(0xFF00FFFF) # Cyan
print(f"After fill with cyan: {fb.tohex()}")
# Create a second buffer for blending
var fb2 = animation.frame_buffer(10)
fb2.fill_pixels(0x80FF0000) # Red with 50% alpha
# Blend the two buffers using per-pixel alpha
fb.blend_pixels(fb2) # Blend using per-pixel alpha with default normal blend mode
print(f"After blending with red using per-pixel alpha (normal mode): {fb.tohex()}")
# Create a gradient fill
fb.gradient_fill(0xFFFF0000, 0xFF0000FF, 0, 9) # Red to blue gradient
print(f"After gradient fill: {fb.tohex()}")
# Demonstrate region-specific blending
var region_buffer = animation.frame_buffer(10)
region_buffer.fill_pixels(0xC800FF00) # Green with ~78% alpha (200/255)
fb.blend_pixels(region_buffer, fb.BLEND_MODE_NORMAL, 0, 4) # Blend green into first half
print(f"After blending green into first half: {fb.tohex()}")
# Using array-like access
fb[9] = 0xFFFF0000 # Set last pixel to red
print(f"After setting last pixel to red: {fb.tohex()}")
# Demonstrate apply_opacity method
print("\nDemonstrating apply_opacity method:")
# Create a test buffer with various alpha values
var opacity_demo = animation.frame_buffer(5)
opacity_demo.set_pixel_color(0, 0xFF0000FF) # Red, full alpha
opacity_demo.set_pixel_color(1, 0x800000FF) # Red, 50% alpha
opacity_demo.set_pixel_color(2, 0x400000FF) # Red, 25% alpha
opacity_demo.set_pixel_color(3, 0x200000FF) # Red, 12.5% alpha
opacity_demo.set_pixel_color(4, 0x100000FF) # Red, 6.25% alpha
print(f"Original alpha values: {opacity_demo.dump()}")
# Reduce opacity by 50%
var reduced_demo = opacity_demo.copy()
reduced_demo.apply_opacity(128) # 50% opacity
print(f"After 50% opacity reduction: {reduced_demo.dump()}")
# Increase opacity by 50%
var increased_demo = opacity_demo.copy()
increased_demo.apply_opacity(384) # 150% opacity (256 + 128)
print(f"After 50% opacity increase: {increased_demo.dump()}")
# Make fully transparent
var transparent_demo = opacity_demo.copy()
transparent_demo.apply_opacity(0) # 0% opacity
print(f"After making fully transparent: {transparent_demo.dump()}")
# Make maximum opaque
var max_demo = opacity_demo.copy()
max_demo.apply_opacity(511) # Maximum opacity
print(f"After maximum opacity: {max_demo.dump()}")
print("Frame buffer demo completed!")

View File

@ -1,229 +0,0 @@
# Animation Layering Demo
#
# This example demonstrates how to use the AnimationManager to layer multiple animations
# with different priorities and opacities.
#
# Command to run:
# ./berry -s -g -m lib/libesp32/berry_animation lib/libesp32/berry_animation/examples/layering_demo.be
import global
import tasmota
import animation
# Create a simple animation class that fills with a solid color
class SolidAnimation : animation.animation
var color
def init(priority, color, name)
super(self).init(priority, 0, false, name)
self.color = color
# Register parameters
self.register_param("color", {"default": 0xFF0000})
# Set initial values
self.set_param("color", color)
end
def render(frame)
if !self.is_running || frame == nil
return false
end
# Extract components from color
var r = self.color & 0xFF
var g = (self.color >> 8) & 0xFF
var b = (self.color >> 16) & 0xFF
# Fill the frame with the color
frame.fill_pixels(animation.frame_buffer.to_color(r, g, b))
return true
end
def on_param_changed(name, value)
if name == "color"
self.color = value
end
end
end
# Create a simple animation class that creates a gradient
class GradientAnimation : animation.animation
var color_start
var color_end
def init(priority, color_start, color_end, name)
super(self).init(priority, 0, false, name)
self.color_start = color_start
self.color_end = color_end
# Register parameters
self.register_param("color_start", {"default": 0xFF0000})
self.register_param("color_end", {"default": 0x0000FF})
# Set initial values
self.set_param("color_start", color_start)
self.set_param("color_end", color_end)
end
def render(frame)
if !self.is_running || frame == nil
return false
end
# Create a gradient from start to end color
frame.gradient_fill(self.color_start, self.color_end)
return true
end
def on_param_changed(name, value)
if name == "color_start"
self.color_start = value
elif name == "color_end"
self.color_end = value
end
end
end
# Create a simple animation class that creates a pattern
class PatternAnimation : animation.animation
var pattern_width
var color1
var color2
def init(priority, pattern_width, color1, color2, name)
super(self).init(priority, 0, false, name)
self.pattern_width = pattern_width
self.color1 = color1
self.color2 = color2
# Register parameters
self.register_param("pattern_width", {"min": 1, "default": 1})
self.register_param("color1", {"default": 0xFFFFFF})
self.register_param("color2", {"default": 0x000000})
# Set initial values
self.set_param("pattern_width", pattern_width)
self.set_param("color1", color1)
self.set_param("color2", color2)
end
def render(frame)
if !self.is_running || frame == nil
return false
end
# Create a pattern of alternating colors
var i = 0
while i < frame.width
var color = (i / self.pattern_width) % 2 == 0 ? self.color1 : self.color2
# Extract components from color
var r = color & 0xFF
var g = (color >> 8) & 0xFF
var b = (color >> 16) & 0xFF
# Set the pixel
frame.set_pixel_color(i, animation.frame_buffer.to_color(r, g, b))
i += 1
end
return true
end
def on_param_changed(name, value)
if name == "pattern_width"
self.pattern_width = value
elif name == "color1"
self.color1 = value
elif name == "color2"
self.color2 = value
end
end
end
# Create a frame buffer for rendering
var width = 20 # 20 pixels
var frame = animation.frame_buffer(width)
# Create a renderer
var renderer = animation.renderer(width)
# Create an animation manager with the renderer
var manager = animation.animation_manager(nil, renderer)
# Create some animations with different priorities
var background = SolidAnimation(10, 0x000080FF, "background") # Dark blue background (fully opaque)
var gradient = GradientAnimation(20, 0xFF000080, 0x00FF0080, "gradient") # Red to green gradient with 50% alpha
var pattern = PatternAnimation(30, 2, 0xFFFFFF40, 0x00000040, "pattern") # White/black pattern with 25% alpha
# Add animations to the manager
manager.add(background)
manager.add(gradient)
manager.add(pattern)
print("Added animations to manager:", manager)
print("Number of animations:", manager.size())
# Start all animations
var start_time = tasmota.millis()
manager.start_all(start_time)
# Render the animations to the frame buffer
var rendered = manager.render_animations(frame, start_time)
print("Rendered:", rendered)
# Print the first few pixels to see the blending result
print("Pixel colors (first 5):")
var i = 0
while i < 5
var color = frame.get_pixel_color(i)
var r = color & 0xFF
var g = (color >> 8) & 0xFF
var b = (color >> 16) & 0xFF
print(" Pixel", i, ":", format("R:%d G:%d B:%d", r, g, b))
i += 1
end
# Demonstrate changing priorities
print("\nChanging priorities:")
background.set_priority(40) # Move background to top
manager._sort_animations() # Resort animations
# Render again
manager.render_animations(frame, start_time)
# Print the first few pixels again
print("Pixel colors after priority change (first 5):")
i = 0
while i < 5
var color = frame.get_pixel_color(i)
var r = color & 0xFF
var g = (color >> 8) & 0xFF
var b = (color >> 16) & 0xFF
print(" Pixel", i, ":", format("R:%d G:%d B:%d", r, g, b))
i += 1
end
# Note: Opacity is now controlled through per-pixel alpha channels
print("\nNote: Opacity is now controlled through per-pixel alpha channels")
# Render again
manager.render_animations(frame, start_time)
# Print the first few pixels again
print("Pixel colors with per-pixel alpha (first 5):")
i = 0
while i < 5
var color = frame.get_pixel_color(i)
var r = color & 0xFF
var g = (color >> 8) & 0xFF
var b = (color >> 16) & 0xFF
print(" Pixel", i, ":", format("R:%d G:%d B:%d", r, g, b))
i += 1
end
print("\nLayering demo complete!")

View File

@ -1,97 +0,0 @@
# Nested Function Calls Demo
#
# This example demonstrates the new nested function calls feature in the DSL transpiler.
# It shows how complex animations can be expressed more concisely using nested syntax.
import global
import string
import animation
# Example DSL code using nested function calls
var dsl_code =
"strip length 60\n"
"\n"
"# Define colors\n"
"color sunset_red = #FF4500\n"
"color ocean_blue = #0077AA\n"
"color star_white = #FFFFFF\n"
"color deep_blue = #000080\n"
"\n"
"# Simple nested call\n"
"animation breathing_red = pulse(solid(sunset_red), 4s)\n"
"\n"
"# Complex nested animation with multiple levels\n"
"animation evening_sky = fade(\n"
" overlay(\n"
" shift_right(gradient(sunset_red, orange, yellow), 400ms),\n"
" sparkle(star_white, deep_blue, 8%)\n"
" ),\n"
" 10s\n"
")\n"
"\n"
"# Nested calls in array parameters\n"
"animation color_wheel = color_cycle(\n"
" [solid(sunset_red), solid(ocean_blue), solid(star_white)],\n"
" 3s\n"
")\n"
"\n"
"# Run the complex animation\n"
"run evening_sky"
def demo_nested_calls()
print("=== Nested Function Calls Demo ===")
print()
print("DSL Code:")
print(dsl_code)
print()
# Compile the DSL
var compiler = animation.SimpleDSLTranspiler()
var lexer = animation.DSLLexer(dsl_code)
var tokens = lexer.tokenize()
if lexer.has_errors()
print("Lexer errors:")
print(lexer.get_error_report())
return false
end
compiler.tokens = tokens
var berry_code = compiler.transpile()
if compiler.has_errors()
print("Compiler errors:")
print(compiler.get_error_report())
return false
end
print("Generated Berry Code:")
print("============================================================")
print(berry_code)
print("============================================================")
print()
# Verify the code compiles
try
var compiled = compile(berry_code)
print("✓ Generated code compiles successfully!")
print()
# Show the benefits of nested syntax
print("Benefits of Nested Function Calls:")
print("- More concise: No need for intermediate pattern variables")
print("- More readable: Natural expression of complex animations")
print("- Less verbose: Reduces DSL code length significantly")
print("- Better composition: Easy to build complex effects from simple parts")
return true
except .. as e, msg
print(f"✗ Generated code compilation failed: {e} - {msg}")
return false
end
end
# Run the demo
demo_nested_calls()
return demo_nested_calls

View File

@ -1,148 +0,0 @@
# OscillatorValueProvider Demo
#
# This example demonstrates how to use the OscillatorValueProvider
# with different waveforms and parameters.
import global
import animation
import tasmota
print("=== OscillatorValueProvider Demo ===")
# Create different types of oscillators
print("\n1. Creating different oscillator types:")
# Sawtooth oscillator (ramp from 0 to 100 over 2 seconds)
var sawtooth = animation.ramp(0, 100, 2000)
print(f"Sawtooth: {sawtooth}")
# Triangle oscillator (0 to 100 and back over 3 seconds)
var triangle = animation.linear(0, 100, 3000)
print(f"Triangle: {triangle}")
# Smooth cosine oscillator (0 to 100 smoothly over 4 seconds)
var smooth = animation.smooth(0, 100, 4000)
print(f"Smooth: {smooth}")
# Square wave oscillator (0 to 100 with 30% duty cycle over 1 second)
var square = animation.square(0, 100, 1000, 30)
print(f"Square: {square}")
# Custom oscillator with phase shift and duty cycle (using direct constructor)
var custom = animation.oscillator_value_provider(10, 90, 1500, animation.TRIANGLE)
custom.set_phase(25).set_duty_cycle(75)
print(f"Custom: {custom}")
print("\n2. Demonstrating oscillator values over time:")
# Simulate time progression for sawtooth oscillator
var start_time = tasmota.millis()
sawtooth.origin = start_time
print("Sawtooth oscillator values:")
for i: 0..10
var time_offset = i * 200 # Every 200ms
var current_time = start_time + time_offset
var value = sawtooth.get_value(current_time)
var progress = (time_offset * 100) / 2000 # Percentage through cycle
print(f" t+{time_offset}ms ({progress}%): {value}")
end
print("\nTriangle oscillator values:")
triangle.origin = start_time
for i: 0..15
var time_offset = i * 200 # Every 200ms
var current_time = start_time + time_offset
var value = triangle.get_value(current_time)
var progress = (time_offset * 100) / 3000 # Percentage through cycle
print(f" t+{time_offset}ms ({progress:.1f}%): {value}")
end
print("\n3. Demonstrating phase shift:")
# Create two identical oscillators with different phase
var osc1 = animation.ramp(0, 100, 1000)
var osc2 = animation.ramp(0, 100, 1000)
osc2.set_phase(50) # 50% phase shift
osc1.origin = start_time
osc2.origin = start_time
print("Phase shift comparison (0% vs 50% phase):")
for i: 0..8
var time_offset = i * 125 # Every 125ms (1/8 of cycle)
var current_time = start_time + time_offset
var value1 = osc1.get_value(current_time)
var value2 = osc2.get_value(current_time)
var progress = (time_offset * 100) / 1000
print(f" t+{time_offset}ms ({progress}%): no phase={value1}, 50% phase={value2}")
end
print("\n4. Demonstrating duty cycle with square wave:")
# Create square waves with different duty cycles
var square25 = animation.square(0, 100, 1000, 25)
var square50 = animation.square(0, 100, 1000, 50)
var square75 = animation.square(0, 100, 1000, 75)
square25.origin = start_time
square50.origin = start_time
square75.origin = start_time
print("Duty cycle comparison (25%, 50%, 75%):")
for i: 0..10
var time_offset = i * 100 # Every 100ms (10% of cycle)
var current_time = start_time + time_offset
var value25 = square25.get_value(current_time)
var value50 = square50.get_value(current_time)
var value75 = square75.get_value(current_time)
var progress = (time_offset * 100) / 1000
print(f" t+{time_offset}ms ({progress}%): 25%={value25}, 50%={value50}, 75%={value75}")
end
print("\n5. Using oscillators with animations:")
# Example of how you might use an oscillator with an animation parameter
print("Example: Using oscillator for dynamic pulse size")
# Create a pulse size oscillator that varies from 1 to 8 pixels
var pulse_size_osc = animation.ramp(1, 8, 2000)
pulse_size_osc.origin = start_time
print("Dynamic pulse sizes over time:")
for i: 0..10
var time_offset = i * 200
var current_time = start_time + time_offset
var pulse_size = pulse_size_osc.get_value(current_time)
print(f" t+{time_offset}ms: pulse size = {pulse_size} pixels")
end
print("\n6. Demonstrating update() method:")
# Show how update() method tracks value changes
var change_detector = animation.smooth(0, 255, 1000)
change_detector.origin = start_time
print("Value change detection:")
var last_time = start_time
for i: 1..5
var time_offset = i * 100
var current_time = start_time + time_offset
var changed = change_detector.update(current_time)
var value = change_detector.value
print(f" t+{time_offset}ms: value={value}, changed={changed}")
# Update again with same time (should not change)
var changed_again = change_detector.update(current_time)
print(f" (same time): changed={changed_again}")
end
print("\n=== Demo Complete ===")
# Practical usage example comment:
print("\n# Practical Usage Example:")
print("# var brightness_osc = animation.smooth(50, 255, 3000)")
print("# var animation = animation.pulse_position_animation(10, brightness_osc, 0xFF00FF00)")
print("# animation.set_pulse_size(brightness_osc) # Dynamic brightness AND size!")
return "OscillatorValueProvider demo completed"

View File

@ -1,188 +0,0 @@
# OscillatorValueProvider with Animations Example
#
# This example shows how to use OscillatorValueProvider with actual animations
# to create dynamic, time-varying effects.
import global
import animation
import tasmota
print("=== OscillatorValueProvider with Animations ===")
# Create LED strip using global.Leds
var strip = global.Leds(20, 1) # 20 LEDs, GPIO 1
var engine = animation.create_engine(strip)
print("\n1. Pulse Position with Oscillating Size")
print("Creating a pulse that changes size over time...")
# Create oscillators for dynamic parameters
var size_oscillator = animation.linear(1, 5, 2000) # Size varies 1-5 pixels over 2 seconds
var brightness_oscillator = animation.smooth(100, 255, 3000) # Brightness varies smoothly over 3 seconds
# Create a pulse position animation with static parameters first
var pulse_anim = animation.pulse_position(0xFF00FF00, 5, 1, 10, 0, true, "dynamic_pulse")
# Set dynamic parameters using the oscillators
pulse_anim.set_param_value("pulse_size", size_oscillator)
pulse_anim.set_param_value("opacity", brightness_oscillator)
# Add to engine
engine.add_animation(pulse_anim)
engine.start()
# Simulate animation over time
var start_time = tasmota.millis()
print("Animation frames (size and brightness changing):")
for frame: 0..10
var current_time = start_time + frame * 300 # Every 300ms
# Update animations
engine.on_tick(current_time)
# Show current state
var pulse_size = size_oscillator.get_value(current_time)
var brightness = brightness_oscillator.get_value(current_time)
print(f"Frame {frame}: size={pulse_size}, brightness={brightness}")
strip.show()
end
print("\n2. Multiple Oscillating Animations")
print("Creating multiple animations with different oscillating parameters...")
# Clear previous animation
engine.clear()
strip.clear()
# Create different oscillators
var pos1_osc = animation.ramp(2, 8, 2500) # Position oscillates 2-8
var pos2_osc = animation.ramp(12, 18, 3000) # Position oscillates 12-18
var color_osc = animation.linear(0, 255, 1500) # Color component oscillates
# Create multiple pulse animations with static parameters first
var pulse1 = animation.pulse_position(0xFF0000FF, 2, 1, 10, 0, true, "pulse1") # Blue
var pulse2 = animation.pulse_position(0xFFFF0000, 2, 1, 20, 0, true, "pulse2") # Red
# Set dynamic positions using oscillators
pulse1.set_param_value("pos", pos1_osc)
pulse2.set_param_value("pos", pos2_osc)
# Add animations
engine.add_animation(pulse1)
engine.add_animation(pulse2)
print("Two pulses with oscillating positions:")
for frame: 0..8
var current_time = start_time + frame * 400 # Every 400ms
# Update animations
engine.on_tick(current_time)
# Show current positions
var pos1 = pos1_osc.get_value(current_time)
var pos2 = pos2_osc.get_value(current_time)
print(f"Frame {frame}: pos1={pos1}, pos2={pos2}")
strip.show()
end
print("\n3. Square Wave Strobe Effect")
print("Creating a strobe effect using square wave oscillator...")
# Clear previous animations
engine.clear()
strip.clear()
# Create a square wave oscillator for strobe effect
var strobe_osc = animation.square(0, 255, 500, 20) # Fast strobe, 20% duty cycle
# Create a filled animation with oscillating brightness
var strobe_anim = animation.filled_animation.solid(0xFFFFFFFF, 30, 255, 0, true, "strobe")
strobe_anim.set_param_value("opacity", strobe_osc) # Use oscillator for opacity
engine.add_animation(strobe_anim)
print("Strobe effect (square wave oscillator):")
for frame: 0..12
var current_time = start_time + frame * 100 # Every 100ms (fast)
# Update animations
engine.on_tick(current_time)
# Show strobe state
var opacity = strobe_osc.get_value(current_time)
var state = opacity > 128 ? "ON " : "OFF"
print(f"Frame {frame}: opacity={opacity} ({state})")
strip.show()
end
print("\n4. Breathing Effect with Color Shift")
print("Creating a breathing effect with color temperature shift...")
# Clear previous animations
engine.clear()
strip.clear()
# Create oscillators for breathing and color shift
var breathing_osc = animation.smooth(50, 255, 4000) # 4-second breathing cycle
var color_temp_osc = animation.ramp(0, 255, 8000) # 8-second color shift
# Create a custom color provider that uses the oscillators
class DynamicColorProvider : animation.color_provider
var brightness_osc
var color_osc
def init(brightness_osc, color_osc)
self.brightness_osc = brightness_osc
self.color_osc = color_osc
end
def get_color(time_ms)
var brightness = self.brightness_osc.get_value(time_ms)
var color_shift = self.color_osc.get_value(time_ms)
# Create a color that shifts from warm (red) to cool (blue)
var red = tasmota.scale_uint(255 - color_shift, 0, 255, 0, brightness)
var green = tasmota.scale_uint(128, 0, 255, 0, brightness)
var blue = tasmota.scale_uint(color_shift, 0, 255, 0, brightness)
return (0xFF << 24) | (red << 16) | (green << 8) | blue
end
def update(time_ms)
var changed1 = self.brightness_osc.update(time_ms)
var changed2 = self.color_osc.update(time_ms)
return changed1 || changed2
end
end
var dynamic_color = DynamicColorProvider(breathing_osc, color_temp_osc)
var breathing_anim = animation.filled_animation(dynamic_color, 40, 255, 0, true, "breathing")
engine.add_animation(breathing_anim)
print("Breathing effect with color temperature shift:")
for frame: 0..10
var current_time = start_time + frame * 500 # Every 500ms
# Update animations
engine.on_tick(current_time)
# Show current state
var brightness = breathing_osc.get_value(current_time)
var color_temp = color_temp_osc.get_value(current_time)
var temp_desc = color_temp < 85 ? "warm" : (color_temp < 170 ? "neutral" : "cool")
print(f"Frame {frame}: brightness={brightness}, color_temp={color_temp} ({temp_desc})")
strip.show()
end
print("\n=== Integration Demo Complete ===")
# Stop the engine
engine.stop()
print("\nThis example demonstrates how OscillatorValueProvider can be used to create")
print("dynamic, time-varying effects in animations. The oscillators provide smooth,")
print("predictable parameter changes that can be applied to any animation property.")
return "OscillatorValueProvider integration demo completed"

View File

@ -1,125 +0,0 @@
# PalettePattern Animation Demo
#
# This example demonstrates how to use the RichPaletteAnimation as a color provider
# for the PalettePatternAnimation to create complex visual effects.
# Import the animation module
import global
import tasmota
import animation
# Create an animation controller for a strip of 30 LEDs
var strip = global.Leds(30, 1) # Assuming global.Leds class is available in Tasmota
var controller = animation.animation_controller(strip)
# Example 1: Wave pattern with rainbow palette
print("Example 1: Wave pattern with rainbow palette")
# Create a rainbow palette that doesn't animate on its own (no rendering)
var rainbow_palette = animation.rich_palette_animation(animation.PALETTE_RAINBOW, 5000)
# Create a wave pattern that uses the rainbow palette as a color source
var wave_pattern = animation.palette_pattern.wave(rainbow_palette, 30, 3000, 15, 10, 255)
# Add the animations to the controller
controller.add_animation(rainbow_palette)
controller.add_animation(wave_pattern)
# Start the animations
controller.start()
tasmota.delay(10000) # Run for 10 seconds
controller.stop()
controller.clear()
# Example 2: Gradient pattern with fire palette
print("Example 2: Gradient pattern with fire palette")
# Create a fire palette
var fire_palette = animation.rich_palette_animation(animation.PALETTE_FIRE, 3000)
# Create a gradient pattern that uses the fire palette as a color source
var gradient_pattern = animation.palette_pattern.gradient(fire_palette, 30, 5000, 10, 255)
# Add the animations to the controller
controller.add_animation(fire_palette)
controller.add_animation(gradient_pattern)
# Start the animations
controller.start()
tasmota.delay(10000) # Run for 10 seconds
controller.stop()
controller.clear()
# Example 3: Value meter with ocean palette
print("Example 3: Value meter with ocean palette")
# Create an ocean palette
var ocean_palette = animation.rich_palette_animation(animation.PALETTE_OCEAN, 1000)
# Create a value function that oscillates between 0 and 100
def value_function(time_ms, animation)
# Oscillate between 0 and 100 over 5 seconds using scale_uint and sine_int for better precision
var angle = tasmota.scale_uint(time_ms % 5000, 0, 5000, 0, 32767) # 0 to 2π in fixed-point
var cosine_value = tasmota.sine_int(angle + 8192) # Offset by π/2 to get cosine
# Map cosine value from -4096..4096 to 0..100
return tasmota.scale_int(cosine_value, -4096, 4096, 0, 100)
end
# Create a value meter that uses the ocean palette as a color source
var meter_pattern = animation.palette_pattern.value_meter(ocean_palette, 30, value_function, 10, 255)
# Add the animations to the controller
controller.add_animation(ocean_palette)
controller.add_animation(meter_pattern)
# Start the animations
controller.start()
tasmota.delay(10000) # Run for 10 seconds
controller.stop()
controller.clear()
# Example 4: Custom pattern with custom palette
print("Example 4: Custom pattern with custom palette")
# Create a custom palette
var custom_palette = animation.rich_palette_animation.from_bytes(bytes(
"00FF0000" # Red (value 0)
"3200FF00" # Green (value 50)
"64FFFF00" # Yellow (value 100)
"96FF00FF" # Purple (value 150)
"C80000FF" # Blue (value 200)
"FFFFFFFF" # White (value 255)
), 5000)
# Set the range for the palette (0-200 instead of 0-100)
custom_palette.set_range(0, 200)
# Create a custom pattern function
def custom_pattern_func(pixel_index, time_ms, animation)
# Create a pattern that depends on both position and time using scale_uint for better precision
var time_factor = tasmota.scale_uint(time_ms % 10000, 0, 10000, 0, 100)
var position_factor = tasmota.scale_uint(pixel_index, 0, animation.frame_width - 1, 0, 100)
# Calculate a value between 0 and 200
var value = position_factor + time_factor
return value
end
# Create a custom pattern that uses the custom palette as a color source
var custom_pattern = animation.palette_pattern(custom_palette, custom_pattern_func, 30, 10, 255)
# Add the animations to the controller
controller.add_animation(custom_palette)
controller.add_animation(custom_pattern)
# Start the animations
controller.start()
tasmota.delay(10000) # Run for 10 seconds
controller.stop()
controller.clear()
print("PalettePattern animation demo completed")
return true

View File

@ -1,147 +0,0 @@
# Example demonstrating the parameter handling functionality
# of the Berry Animation Framework
#
# Command to run:
# ./berry -s -g -m lib/libesp32/berry_animation lib/libesp32/berry_animation/examples/parameter_demo.be
import global
import tasmota
import animation
import math
# Create a custom animation that uses parameters
class PulseAnimation : animation.animation
# Initialize with custom parameters
def init()
animation.animation.init(self, 1, 255, 0, true, "pulse")
# Register custom parameters with validation
# Note: Parameter system now only accepts integers, so color is stored as integer
self.register_param("color", {
"min": 1, # 1=red, 2=green, 3=blue, 4=white
"max": 4,
"default": 1
})
self.register_param("speed", {
"min": 1,
"max": 10,
"default": 5
})
self.register_param("intensity", {
"min": 0,
"max": 100,
"default": 50
})
# Set initial values
self.set_param("color", 1) # 1 = red
self.set_param("speed", 5)
self.set_param("intensity", 50)
end
# Handle parameter changes
def on_param_changed(name, value)
print(format("Parameter '%s' changed to: %s", name, str(value)))
# Recalculate derived values based on parameters
if name == "speed"
# Adjust duration based on speed (higher speed = lower duration)
self.set_duration(2000 / value)
end
end
# Render the animation
def render(frame)
if !self.is_running || self.frame_buffer == nil
return false
end
# Get current parameters
var color = self.get_param("color", 1) # 1 = red
var intensity = self.get_param("intensity", 50)
# Calculate pulse value based on progress (0 to 255)
var progress = self.get_progress()
# Convert progress to 0.0-1.0 range for math.sin calculation
var progress_float = progress / 255.0
var pulse_value = math.sin(progress_float * 2 * math.pi) * 0.5 + 0.5
# Scale by intensity
pulse_value = tasmota.scale_uint(pulse_value, 0, 255, 0, tasmota.scale_uint(intensity, 0, 100, 0, 255))
# Set color based on parameter (1=red, 2=green, 3=blue, 4=white)
var r = 0
var g = 0
var b = 0
if color == 1 # red
r = int(255 * pulse_value)
elif color == 2 # green
g = int(255 * pulse_value)
elif color == 3 # blue
b = int(255 * pulse_value)
elif color == 4 # white
r = int(255 * pulse_value)
g = int(255 * pulse_value)
b = int(255 * pulse_value)
end
# Fill the frame with the calculated color
frame.fill_pixels(animation.frame_buffer.to_color(r, g, b, 255))
return true
end
end
# Create a mock frame buffer for demonstration
var frame = animation.frame_buffer(10)
# Create the pulse animation
var pulse = PulseAnimation()
pulse.start()
# Simulate animation updates
print("Initial parameters:")
print(format(" color: %s", pulse.get_param("color", nil)))
print(format(" speed: %d", pulse.get_param("speed", nil)))
print(format(" intensity: %d", pulse.get_param("intensity", nil)))
print(format(" duration: %d", pulse.duration))
print("\nUpdating parameters:")
pulse.set_param("color", 3) # 3 = blue
pulse.set_param("speed", 8)
pulse.set_param("intensity", 75)
print("\nFinal parameters:")
print(format(" color: %s", pulse.get_param("color", nil)))
print(format(" speed: %d", pulse.get_param("speed", nil)))
print(format(" intensity: %d", pulse.get_param("intensity", nil)))
print(format(" duration: %d", pulse.duration))
# Demonstrate validation
print("\nValidation tests:")
print(format("Set invalid color: %s", pulse.set_param("color", 5) ? "accepted" : "rejected")) # 5 is not in enum [1,2,3,4]
print(format("Set invalid speed: %s", pulse.set_param("speed", 20) ? "accepted" : "rejected"))
print(format("Set invalid intensity: %s", pulse.set_param("intensity", -10) ? "accepted" : "rejected"))
# Demonstrate individual parameter updates (update_params method removed)
print("\nIndividual parameter updates:")
var color_result = pulse.set_param("color", 2) # 2 = green
var speed_result = pulse.set_param("speed", 3)
var intensity_result = pulse.set_param("intensity", 90)
var all_success = color_result && speed_result && intensity_result
print(format("Update result: %s", all_success ? "success" : "partial failure"))
print("\nUpdated parameters:")
print(format(" color: %s", pulse.get_param("color", nil)))
print(format(" speed: %d", pulse.get_param("speed", nil)))
print(format(" intensity: %d", pulse.get_param("intensity", nil)))
print(format(" duration: %d", pulse.duration))
# Render a frame to demonstrate the animation
pulse.render(frame, tasmota.millis())
print("\nRendered frame with current parameters")
print("\nParameter demo completed!")

View File

@ -1,126 +0,0 @@
# Pattern vs Animation Example
# This example demonstrates the correct usage of patterns and animations
import animation
# Example: Creating patterns (ColorProviders)
def create_patterns()
print("Creating patterns...")
# Patterns define WHAT the strip should look like (spatial)
var red_pattern = animation.solid(0xFFFF0000) # Solid red pattern
var blue_pattern = animation.solid(0xFF0000FF) # Solid blue pattern
var white_pattern = animation.solid(0xFFFFFFFF) # Solid white pattern
print("✅ Created solid color patterns")
return [red_pattern, blue_pattern, white_pattern]
end
# Example: Creating animations from patterns
def create_animations(patterns)
print("Creating animations...")
var red_pattern = patterns[0]
var blue_pattern = patterns[1]
var white_pattern = patterns[2]
# Animations define HOW patterns change over time (temporal)
var red_fill = animation.filled(red_pattern, 0) # Fill strip with red pattern
var blue_fill = animation.filled(blue_pattern, 5) # Fill strip with blue pattern (higher priority)
var white_fill = animation.filled(white_pattern, 10) # Fill strip with white pattern (highest priority)
print("✅ Created filled animations")
return [red_fill, blue_fill, white_fill]
end
# Example: Demonstrating reusability
def demonstrate_reusability()
print("Demonstrating pattern reusability...")
# One pattern, multiple animations
var red_pattern = animation.solid(0xFFFF0000)
# Use the same pattern in different ways
var static_red = animation.filled(red_pattern, 0, 0, true, "static")
var priority_red = animation.filled(red_pattern, 10, 0, true, "priority")
var timed_red = animation.filled(red_pattern, 0, 5000, false, "timed") # 5 second duration
print("✅ One pattern used in multiple animations:")
print(f" - Static: {static_red.name}, priority={static_red.priority}")
print(f" - Priority: {priority_red.name}, priority={priority_red.priority}")
print(f" - Timed: {timed_red.name}, duration={timed_red.duration}")
end
# Example: DSL-style composition
def demonstrate_dsl_style()
print("Demonstrating DSL-style composition...")
# This is how the DSL would work:
# pattern solid_red = solid(red)
var solid_red = animation.solid(0xFFFF0000)
# animation red_anim = filled(solid_red)
var red_anim = animation.filled(solid_red)
# The animation can be used with an engine
print(f"✅ Created DSL-style animation: {red_anim.name}")
print(f" - Uses pattern: {red_anim.color_provider}")
print(f" - Priority: {red_anim.priority}")
print(f" - Loop: {red_anim.loop}")
end
# Example: Testing with a mock strip
def test_with_mock_strip()
print("Testing with mock strip...")
try
# Create a simple LED strip simulation
var strip_length = 10
var mock_strip = global.Leds(strip_length, 1)
# Create pattern and animation
var green_pattern = animation.solid(0xFF00FF00)
var green_anim = animation.filled(green_pattern)
# Create engine and add animation
var engine = animation.create_engine(mock_strip)
engine.add_animation(green_anim)
# Start the engine (this would normally be called by Tasmota's fast_loop)
engine.start()
# Simulate one update cycle
engine.on_tick(0)
print("✅ Successfully tested with mock strip")
except .. as e, msg
print(f"⚠️ Mock strip test failed (expected in test environment): {msg}")
end
end
# Main example function
def run_example()
print("Pattern vs Animation Example")
print("=" * 40)
# Demonstrate the concepts
var patterns = create_patterns()
var animations = create_animations(patterns)
demonstrate_reusability()
demonstrate_dsl_style()
test_with_mock_strip()
print("=" * 40)
print("Example completed!")
print("\nKey Takeaways:")
print("- Patterns define WHAT (spatial color distribution)")
print("- Animations define HOW (temporal behavior)")
print("- Patterns are reusable across multiple animations")
print("- This separation enables powerful composition")
end
# Export the example function
return {'run_example': run_example}

View File

@ -1,94 +0,0 @@
#
# Direct port of leds_blend_demo.be to new animation framework
# Original: Uses old animate.frame() with manual blending
# Ported: Uses new FrameBuffer with integrated blending capabilities
#
# Visual effect: Demonstrates frame buffer blending with gradient overlay
#
import animation
var LEDS_LENGTH = 25
# Create LED strip (same as original)
var strip = global.Leds(LEDS_LENGTH, gpio.pin(gpio.WS2812, 0))
var bri = 70
# Create animation engine
var engine = animation.create_engine(strip)
# Create frame buffers (replaces animate.frame)
var back_frame = animation.frame_buffer(LEDS_LENGTH)
var front_frame = animation.frame_buffer(LEDS_LENGTH)
# Fill background frame with red color at 80 opacity (replaces back.fill_pixels)
back_frame.fill(0xFF, 0x22, 0x00, 80) # Red with alpha 80
# Fill front frame with green gradient (replaces the for loop)
for i: 0..LEDS_LENGTH-1
var alpha = int(tasmota.scale_uint(i, 0, LEDS_LENGTH-1, 0, 255))
front_frame.set_pixel(i, 0x00, 0xFF, 0x00, alpha) # Green with varying alpha
end
# Blend frames (replaces back.blend_pixels)
back_frame.blend(front_frame, 255)
# Display debug information (same as original)
print("front=", front_frame.pixels.tohex())
print("back =", back_frame.pixels.tohex())
# Get strip buffer and apply blended result
var pixels_buffer = strip.pixels_buffer()
print("pixs =", pixels_buffer.tohex())
# Apply brightness and paste to strip buffer (replaces back.paste_pixels)
# Note: In new framework, this is typically handled by the engine
# For demonstration, we'll manually copy the blended result
for i: 0..LEDS_LENGTH-1
var pixel = back_frame.get_pixel(i)
var r = (pixel >> 16) & 0xFF
var g = (pixel >> 8) & 0xFF
var b = pixel & 0xFF
var a = (pixel >> 24) & 0xFF
# Apply brightness scaling
r = int(tasmota.scale_uint(r * bri, 0, 255 * 100, 0, 255))
g = int(tasmota.scale_uint(g * bri, 0, 255 * 100, 0, 255))
b = int(tasmota.scale_uint(b * bri, 0, 255 * 100, 0, 255))
# Set pixel in strip buffer (GRB format for WS2812)
var offset = i * 3
pixels_buffer[offset] = g # Green
pixels_buffer[offset + 1] = r # Red
pixels_buffer[offset + 2] = b # Blue
end
# Update strip
strip.dirty()
strip.show()
print("Blend demo ported - frame buffer blending demonstration")
print("Background: Red with alpha 80")
print("Foreground: Green gradient with varying alpha")
print("Result: Blended frames displayed on strip")
# Alternative: Using the animation engine approach
print("\n--- Alternative using Animation Engine ---")
# Create animations that demonstrate the same blending
var bg_anim = animation.solid(0x50FF2200, 0, 0, true, "red_background") # Red with alpha
var fg_anim = animation.filled_animation(
# Create a custom color provider that generates the green gradient
def(time_ms)
# This would need a custom gradient provider - simplified for demo
return 0x8000FF00 # Green with alpha
end,
10, 0, true, "green_overlay"
)
engine.add_animation(bg_anim)
engine.add_animation(fg_anim)
engine.start()
print("Animation engine version running - demonstrates same blending concept")
print("Press Ctrl+C to stop")

View File

@ -1,48 +0,0 @@
#
# Direct port of animate_demo_breathe.be to new animation framework
# Original: Uses old animate.core(), animate.pulse(), animate.palette(), animate.oscillator()
# Ported: Uses new AnimationEngine, BreatheAnimation, RichPaletteColorProvider, OscillatorValueProvider
#
# Visual effect: Breathing red/orange pulse that oscillates in brightness
#
import animation
# Same palette as original (black to red to orange)
var PALETTE_BLACK_RED = bytes(
"00000000" # black (value 0)
"88880000" # red (value 136)
"FFFF5500" # orange (value 255)
)
var duration = 3000
var leds = 25
# Create LED strip (same as original)
var strip = global.Leds(leds, gpio.pin(gpio.WS2812, 0))
# Create animation engine (replaces animate.core)
var engine = animation.create_engine(strip)
# Create palette color provider (replaces animate.palette)
var palette_provider = animation.rich_palette_color_provider(PALETTE_BLACK_RED, duration, 1, 255)
palette_provider.set_range(0, 255)
# Create oscillator for brightness control (replaces animate.oscillator)
var brightness_osc = animation.smooth(50, 255, duration)
# Create breathe animation (replaces animate.pulse)
var breathe_anim = animation.breathe_animation(0xFF0000, 100, duration, true, "breathe_port")
# Use oscillator to control the color provider's brightness dynamically
# This simulates the original callback mechanism
breathe_anim.set_param_value("color", palette_provider)
breathe_anim.set_param_value("opacity", brightness_osc)
# Add animation to engine and start
engine.add_animation(breathe_anim)
engine.start()
print("Breathe demo ported - breathing red/orange pulse")
print("Duration:", duration, "ms, LEDs:", leds)
print("Press Ctrl+C to stop")

View File

@ -1,33 +0,0 @@
#
# Direct port of animate_demo_palette_background.be to new animation framework
# Original: Uses old animate.core() with add_background_animator()
# Ported: Uses new AnimationEngine with animation.filled_animation and rainbow palette
#
# Visual effect: Cycling rainbow background across all LEDs
#
import animation
var duration = 10000
var leds = 5 * 5 # 25 LEDs for M5Stack matrix
# Create LED strip (same as original)
var strip = global.Leds(leds, gpio.pin(gpio.WS2812, 0))
# Create animation engine (replaces animate.core)
var engine = animation.create_engine(strip)
# Create rainbow palette background (replaces animate.palette with PALETTE_RAINBOW_WHITE)
# Using the built-in rainbow palette with smooth transitions
var rainbow_provider = animation.rich_palette_color_provider.rainbow(duration, 1, 255)
# Create filled animation as background (replaces add_background_animator)
var background_anim = animation.filled_animation(rainbow_provider, 0, 0, true, "rainbow_background")
# Add animation to engine and start
engine.add_animation(background_anim)
engine.start()
print("Palette background demo ported - cycling rainbow background")
print("Duration:", duration, "ms, LEDs:", leds)
print("Press Ctrl+C to stop")

View File

@ -1,60 +0,0 @@
#
# Direct port of animate_demo_pulse.be to new animation framework
# Original: Uses old animate.core(), animate.pulse(), animate.oscillator(), animate.palette()
# Ported: Uses new AnimationEngine, PulsePositionAnimation, OscillatorValueProvider, RichPaletteColorProvider
#
# Visual effect: Moving pulse with oscillating position and cycling color
#
import animation
var duration = 10000
var leds = 5 * 5 # 25 LEDs for M5Stack matrix
# Create LED strip (same as original)
var strip = global.Leds(leds, gpio.pin(gpio.WS2812, 0))
# Create animation engine (replaces animate.core)
var engine = animation.create_engine(strip)
# Set background color (replaces anim.set_back_color)
# Note: In new framework, we create a background animation instead
var background_anim = animation.solid(0x2222AA, 0, 0, true, "background")
engine.add_animation(background_anim)
# Create position oscillator (replaces animate.oscillator(-3, 26, 5000, animate.COSINE))
var pos_oscillator = animation.smooth(-3, 26, 5000)
# Create color palette provider (replaces animate.palette(animate.PALETTE_STANDARD_VAL, 30000))
# Using a custom palette that matches PALETTE_STANDARD_VAL behavior
var color_palette = bytes(
"00FF0000" # Red (value 0)
"40FFFF00" # Yellow (value 64)
"8000FF00" # Green (value 128)
"C000FFFF" # Cyan (value 192)
"FF0000FF" # Blue (value 255)
)
var color_provider = animation.rich_palette_color_provider(color_palette, 30000, 1, 255)
# Create pulse animation (replaces animate.pulse(0xFF4444, 2, 1))
var pulse_anim = animation.pulse_position(0xFF4444, 2, 1, 10, 0, true, "moving_pulse")
# Apply dynamic parameters using value providers
pulse_anim.set_param_value("pos", pos_oscillator) # Oscillating position
pulse_anim.set_param_value("color", color_provider) # Cycling color
# Add pulse animation with higher priority than background
pulse_anim.priority = 10
engine.add_animation(pulse_anim)
# Simulate brightness setting (original had anim.set_bri(60))
# In new framework, this would be handled by the LED strip or global opacity
# For demonstration, we'll set the pulse opacity
pulse_anim.set_param_value("opacity", 153) # 60% of 255
engine.start()
print("Pulse demo ported - moving pulse with oscillating position and cycling color")
print("Duration:", duration, "ms, LEDs:", leds)
print("Background: Blue, Pulse: Moving with color cycling")
print("Press Ctrl+C to stop")

View File

@ -1,87 +0,0 @@
# Pulse Animation Demo with LED Values
#
# This example demonstrates how to use the Pulse animation effect
# to create a pulsing light effect on an LED strip.
#
# The demo creates a pulse animation with customizable parameters
# and shows how to integrate it with the animation controller.
# It also displays the actual LED values.
import global
import tasmota
import animation
def dump_rgb(strip)
var output = "LEDs: ["
for i:0..strip.length()-1
var color = strip.get_pixel_color(i)
var r = (color >> 16) & 0xFF
var g = (color >> 8) & 0xFF
var b = color & 0xFF
if i > 0
output += ", "
end
output += format("R:%d,G:%d,B:%d", r, g, b)
end
output += "]"
print(output)
end
def dump(strip)
var output = "["
for i:0..strip.length()-1
if i > 0
output += ", "
end
output += format("0x%06X", strip.get_pixel_color(i) & 0xFFFFFF)
end
output += "]"
print(output)
end
# Create a mock LED strip with 5 pixels (reduced for readability)
var strip = global.Leds(5)
# Create an animation controller for the strip
var controller = animation.animation_controller(strip)
# Create a pulse animation with blue color
# Parameters: color, min_brightness, max_brightness, pulse_period, priority
var blue_pulse = animation.pulse_animation(0xFF0000FF, 20, 200, 2000, 1)
# Add the animation to the controller
controller.add_animation(blue_pulse)
# Start the animation
blue_pulse.start()
controller.start()
# Simulate the fast_loop for a few seconds
print("Starting pulse animation demo with LED values...")
print("Simulating animation updates for one full pulse cycle...")
var start_time = tasmota.millis()
var end_time = start_time + 2500 # Run for slightly more than one cycle
var update_interval = 200 # Update every 200ms for demonstration
# Simulate updates
var current_time = start_time
while current_time < end_time
# Update the controller with the current time
controller.on_tick(current_time)
# Show the current state with detailed LED values
print(f"Time: {current_time - start_time}ms, Pulse state: {(current_time - start_time) % 2000 / 2000 * 100}%")
dump_rgb(strip) # Show RGB components
dump(strip) # Show hex values for reference
# Increment time
current_time += update_interval
end
# Stop the animation
controller.stop()
print("Pulse animation demo completed")
return true

View File

@ -1,137 +0,0 @@
# Pulse Position Animation Demo with LED Values
#
# This example demonstrates the Pulse Position animation effect
# which creates a pulse at a specific position with optional slew (fade) regions.
#
# The demo creates various pulse configurations and shows actual LED values.
#
# Command to run demo:
# ./berry -s -g -m lib/libesp32/berry_animation lib/libesp32/berry_animation/examples/pulse_position_animation_demo.be
import global
import tasmota
import animation
def dump_rgb(strip)
var output = "LEDs: ["
for i:0..strip.length()-1
var color = strip.get_pixel_color(i)
var r = (color >> 16) & 0xFF
var g = (color >> 8) & 0xFF
var b = color & 0xFF
if i > 0
output += ", "
end
output += format("R:%d,G:%d,B:%d", r, g, b)
end
output += "]"
print(output)
end
def dump(strip)
var output = "["
for i:0..strip.length()-1
if i > 0
output += ", "
end
output += format("0x%06X", strip.get_pixel_color(i) & 0xFFFFFF)
end
output += "]"
print(output)
end
def test_pulse_position(name, pulse_anim, strip, controller)
print(f"\n=== {name} ===")
# Clear any existing animations
controller.clear()
# Add and start the animation
controller.add_animation(pulse_anim)
pulse_anim.start()
controller.start()
# Update once to render the pulse
controller.on_tick()
# Show the results
print(f"Animation: {pulse_anim}")
dump_rgb(strip)
dump(strip)
# Stop the animation
controller.stop()
end
print("Starting Pulse Position animation demo with LED values...")
# Create a mock LED strip with 10 pixels for better visualization
var strip = global.Leds(10)
# Create an animation engine for the strip
var controller = animation.create_engine(strip)
print("Testing various pulse position configurations...")
# Test 1: Basic pulse without slew
var basic_pulse = animation.pulse_position(0xFF00FF00, 3, 0, 1, 0, true, "basic_pulse")
basic_pulse.set_pos(2)
test_pulse_position("Basic Pulse (Green, pos=2, size=3, no slew)", basic_pulse, strip, controller)
# Test 2: Pulse with slew
var slew_pulse = animation.pulse_position(0xFFFF0000, 2, 2, 1, 0, true, "slew_pulse")
slew_pulse.set_pos(4)
test_pulse_position("Pulse with Slew (Red, pos=4, size=2, slew=2)", slew_pulse, strip, controller)
# Test 3: Pulse with background color
var bg_pulse = animation.pulse_position(0xFFFFFF00, 1, 1, 1, 0, true, "bg_pulse")
bg_pulse.set_pos(6)
bg_pulse.set_back_color(0xFF000080) # Dark blue background
test_pulse_position("Pulse with Background (Yellow on Blue, pos=6, size=1, slew=1)", bg_pulse, strip, controller)
# Test 4: Wide pulse with large slew
var wide_pulse = animation.pulse_position(0xFF0080FF, 2, 3, 1, 0, true, "wide_pulse")
wide_pulse.set_pos(3)
test_pulse_position("Wide Pulse (Purple, pos=3, size=2, slew=3)", wide_pulse, strip, controller)
# Test 5: Edge case - pulse at beginning
var edge_pulse1 = animation.pulse_position(0xFFFF8000, 2, 1, 1, 0, true, "edge_pulse1")
edge_pulse1.set_pos(0)
test_pulse_position("Edge Pulse at Start (Orange, pos=0, size=2, slew=1)", edge_pulse1, strip, controller)
# Test 6: Edge case - pulse at end
var edge_pulse2 = animation.pulse_position(0xFF8000FF, 2, 1, 1, 0, true, "edge_pulse2")
edge_pulse2.set_pos(8)
test_pulse_position("Edge Pulse at End (Magenta, pos=8, size=2, slew=1)", edge_pulse2, strip, controller)
# Test 7: Zero-width pulse (should show only slew)
var zero_pulse = animation.pulse_position(0xFF00FFFF, 0, 2, 1, 0, true, "zero_pulse")
zero_pulse.set_pos(5)
test_pulse_position("Zero-width Pulse (Cyan, pos=5, size=0, slew=2)", zero_pulse, strip, controller)
# Test 8: Parameter updates - demonstrate different configurations
print("\n=== Parameter Variations ===")
# Test different colors
var red_pulse = animation.pulse_position(0xFFFF0000, 1, 0, 1, 0, true, "red_pulse")
red_pulse.set_pos(2)
test_pulse_position("Red Pulse", red_pulse, strip, controller)
var blue_pulse = animation.pulse_position(0xFF0000FF, 1, 0, 1, 0, true, "blue_pulse")
blue_pulse.set_pos(2)
test_pulse_position("Blue Pulse (same position)", blue_pulse, strip, controller)
# Test different sizes
var small_pulse = animation.pulse_position(0xFF00FF00, 1, 1, 1, 0, true, "small_pulse")
small_pulse.set_pos(4)
test_pulse_position("Small Pulse with Slew", small_pulse, strip, controller)
var large_pulse = animation.pulse_position(0xFF00FF00, 4, 1, 1, 0, true, "large_pulse")
large_pulse.set_pos(2)
test_pulse_position("Large Pulse with Slew", large_pulse, strip, controller)
print("\nPulse Position animation demo completed")
print("All tests demonstrate the pulse positioning with optional slew regions")
return true

View File

@ -1,251 +0,0 @@
# Example: PulsePositionAnimation with ValueProvider support
#
# This example demonstrates how to modify an animation to support both static values
# and dynamic ValueProvider instances for its parameters.
# Import the animation framework
import animation
# Create a modified PulsePositionAnimation that supports ValueProviders
class PulsePositionAnimationWithProviders : animation.pulse_position_animation
# Override the render method to use value providers
def render(frame)
if !self.is_running || frame == nil
return false
end
var current_time = tasmota.millis()
var pixel_size = frame.width
# Get values using the value provider system
var back_color = self.get_param_value("back_color", current_time)
var pos = self.get_param_value("pos", current_time)
var slew_size = self.get_param_value("slew_size", current_time)
var pulse_size = self.get_param_value("pulse_size", current_time)
var color = self.get_param_value("color", current_time)
# Ensure we have valid values (fallback to defaults if providers return nil)
if back_color == nil back_color = 0xFF000000 end
if pos == nil pos = 0 end
if slew_size == nil slew_size = 0 end
if pulse_size == nil pulse_size = 1 end
if color == nil color = 0xFFFFFFFF end
# Ensure non-negative values
if slew_size < 0 slew_size = 0 end
if pulse_size < 0 pulse_size = 0 end
# Fill background if not transparent
if back_color != 0xFF000000
frame.fill_pixels(back_color)
end
# Calculate pulse boundaries
var pulse_min = pos
var pulse_max = pos + pulse_size
# Clamp to frame boundaries
if pulse_min < 0
pulse_min = 0
end
if pulse_max >= pixel_size
pulse_max = pixel_size
end
# Draw the main pulse
var i = pulse_min
while i < pulse_max
frame.set_pixel_color(i, color)
i += 1
end
# Draw slew regions if slew_size > 0
if slew_size > 0
# Left slew (fade from background to pulse color)
var left_slew_min = pos - slew_size
var left_slew_max = pos
if left_slew_min < 0
left_slew_min = 0
end
if left_slew_max >= pixel_size
left_slew_max = pixel_size
end
i = left_slew_min
while i < left_slew_max
# Calculate blend factor (255 = background, 0 = pulse color)
var blend_factor
if slew_size == 1
# For single pixel slew, use 50% blend
blend_factor = 128
else
blend_factor = tasmota.scale_uint(i, pos - slew_size, pos - 1, 255, 0)
end
# Create color with appropriate alpha for blending
var alpha = 255 - blend_factor # Invert so 0 = transparent, 255 = opaque
var blend_color = (alpha << 24) | (color & 0x00FFFFFF)
var blended_color = frame.blend(back_color, blend_color)
frame.set_pixel_color(i, blended_color)
i += 1
end
# Right slew (fade from pulse color to background)
var right_slew_min = pos + pulse_size
var right_slew_max = pos + pulse_size + slew_size
if right_slew_min < 0
right_slew_min = 0
end
if right_slew_max >= pixel_size
right_slew_max = pixel_size
end
i = right_slew_min
while i < right_slew_max
# Calculate blend factor (0 = pulse color, 255 = background)
var blend_factor
if slew_size == 1
# For single pixel slew, use 50% blend
blend_factor = 128
else
blend_factor = tasmota.scale_uint(i, pos + pulse_size, pos + pulse_size + slew_size - 1, 0, 255)
end
# Create color with appropriate alpha for blending
var alpha = 255 - blend_factor # Start opaque, fade to transparent
var blend_color = (alpha << 24) | (color & 0x00FFFFFF)
var blended_color = frame.blend(back_color, blend_color)
frame.set_pixel_color(i, blended_color)
i += 1
end
end
return true
end
# Override parameter setters to support both static values and providers
def set_color(color_or_provider)
self.set_param_value("color", color_or_provider)
return self
end
def set_back_color(color_or_provider)
self.set_param_value("back_color", color_or_provider)
return self
end
def set_pos(pos_or_provider)
self.set_param_value("pos", pos_or_provider)
return self
end
def set_slew_size(size_or_provider)
self.set_param_value("slew_size", size_or_provider)
return self
end
def set_pulse_size(size_or_provider)
self.set_param_value("pulse_size", size_or_provider)
return self
end
end
# Example usage demonstrating both static values and value providers
# Create some simple example value providers
class SimpleTimeProvider : animation.value_provider
var multiplier, offset
def init(multiplier, offset)
self.multiplier = multiplier != nil ? multiplier : 1
self.offset = offset != nil ? offset : 0
end
def get_value(time_ms)
# Simple time-based value that changes every second
return self.offset + ((time_ms / 1000) * self.multiplier) % 60
end
# Specific method for position parameter
def get_pos(time_ms)
return int(self.get_value(time_ms))
end
# Specific method for pulse_size parameter
def get_pulse_size(time_ms)
var value = int(self.get_value(time_ms)) % 8 + 1 # 1-8 pixels
return value
end
end
class AlternatingColorProvider : animation.value_provider
var color1, color2, switch_period
def init(color1, color2, switch_period)
self.color1 = color1 != nil ? color1 : 0xFFFF0000 # Red
self.color2 = color2 != nil ? color2 : 0xFF0000FF # Blue
self.switch_period = switch_period != nil ? switch_period : 1000 # 1 second
end
def get_value(time_ms)
# Alternate between two colors based on time
var cycle = (time_ms / self.switch_period) % 2
return cycle < 1 ? self.color1 : self.color2
end
# Specific method for color parameter
def get_color(time_ms)
return self.get_value(time_ms)
end
end
# Demo function
def demo_value_providers()
print("=== ValueProvider Demo ===")
# Create LED strip (60 pixels)
var strip = global.Leds(60, 1)
var engine = animation.create_engine(strip)
# Create value providers
var moving_pos = SimpleTimeProvider(2, 10) # Position moves slowly across strip
var changing_size = SimpleTimeProvider(1, 1) # Size changes over time
var alternating_color = AlternatingColorProvider(0xFFFF0000, 0xFF00FF00, 2000) # Red/green every 2s
# Create animation with mixed static and dynamic parameters
var pulse_anim = PulsePositionAnimationWithProviders(
0xFFFFFFFF, # Static white color (will be overridden)
3, # Static pulse size (will be overridden)
1, # Static slew size
10, # Priority
0, # Infinite duration
false, # No loop
"dynamic_pulse"
)
# Set some parameters to use value providers
pulse_anim.set_pos(moving_pos) # Dynamic position
pulse_anim.set_pulse_size(changing_size) # Dynamic size
pulse_anim.set_color(alternating_color) # Dynamic color
# back_color and slew_size remain static
# Add to engine and start
engine.add_animation(pulse_anim)
engine.start()
print("Animation started with dynamic parameters:")
print("- Position: Moves across strip over time")
print("- Pulse size: Changes from 1 to 8 pixels cyclically")
print("- Color: Alternates between red and green every 2 seconds")
print("- Background and slew: Static values")
return engine
end
# Export the demo function
animation.demo_value_providers = demo_value_providers
print("ValueProvider example loaded. Run animation.demo_value_providers() to see it in action.")
return PulsePositionAnimationWithProviders

View File

@ -1,105 +0,0 @@
# Demonstration of the new resolve_value() method
#
# This example shows how the new resolve_value() method simplifies
# parameter handling compared to the old get_param_value() approach.
import global
import tasmota
import animation
print("=== resolve_value() Method Demonstration ===")
# Note: In a real Tasmota environment, you would create an LED strip like:
# var strip = global.Leds(10, 1)
# var engine = animation.create_engine(strip)
print("\n1. Creating animations with static values:")
# Create a crenel animation with static values
var static_crenel = animation.crenel_position_animation(
0xFF00FF00, # Green color
0, # Position
2, # Pulse size
3, # Low size
-1, # Infinite pulses
10, # Priority
0, # Infinite duration
false, # No loop
"static_crenel"
)
print(" Static crenel: " + str(static_crenel))
print("\n2. Creating animations with dynamic values (ValueProviders):")
# Create dynamic parameters using value providers
print(" Creating dynamic color provider...")
var dynamic_color = animation.solid_color_provider(0xFF0000FF) # Blue
print(" Creating dynamic position provider...")
var dynamic_pos = animation.static_value_provider(1) # Position 1
print(" Creating dynamic pulse size provider...")
var dynamic_pulse_size = animation.static_value_provider(3) # 3 pixels
print(" Creating crenel animation with dynamic values...")
# Create a crenel animation with dynamic values
var dynamic_crenel = animation.crenel_position_animation(
dynamic_color, # Dynamic color
dynamic_pos, # Dynamic position (wrapped in provider)
dynamic_pulse_size, # Dynamic pulse size
2, # Static low size
5, # 5 pulses
20, # Higher priority
0, # Infinite duration
false, # No loop
"dynamic_crenel"
)
print(" Dynamic crenel: " + str(dynamic_crenel))
print("\n3. Demonstrating resolve_value() usage:")
# Show how resolve_value() works with both static and dynamic values
var test_anim = animation.animation(10, 0, false, "test")
var static_value = 42
var dynamic_value = animation.static_value_provider(84)
var time_ms = tasmota.millis()
print(" Static value (42): " + str(test_anim.resolve_value(static_value, "test_param", time_ms)))
print(" Dynamic value (84): " + str(test_anim.resolve_value(dynamic_value, "test_param", time_ms)))
print("\n4. Comparison with old approach:")
# Old approach (still works but more complex)
test_anim.register_param("test_param", {"default": 0})
test_anim.set_param("test_param", dynamic_value)
var old_result = test_anim.get_param_value("test_param", time_ms)
# New approach (simpler and more direct)
var new_result = test_anim.resolve_value(dynamic_value, "test_param", time_ms)
print(" Old approach result: " + str(old_result))
print(" New approach result: " + str(new_result))
print(" Results match: " + str(old_result == new_result))
print("\n5. Benefits of resolve_value():")
print(" ✓ No string parameter names required")
print(" ✓ Direct access to parameter values")
print(" ✓ Better performance (no string lookup)")
print(" ✓ Type safety (direct parameter access)")
print(" ✓ Simpler API (one method for static and dynamic)")
print(" ✓ Works with any value type")
print("\n6. Usage in animation render() methods:")
print(" Old: var color = self.get_param_value(\"color\", time_ms)")
print(" New: var color = self.resolve_value(self.color, \"color\", time_ms)")
print("")
print(" The new approach is:")
print(" - More efficient (no parameter registration/lookup)")
print(" - Supports specific get_XXX() methods on providers")
print(" - More readable (direct parameter access)")
print(" - Allows providers to have specialized methods")
print("\n=== Demonstration Complete ===")
return true

Some files were not shown because too many files have changed in this diff Show More