mirror of
https://github.com/arendst/Tasmota.git
synced 2025-08-02 15:37:42 +00:00
Berry animation change color parsing (#23741)
This commit is contained in:
parent
156bc447ce
commit
3ef60018f0
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,7 +27,7 @@ ornaments.priority = 10
|
||||
|
||||
# Star on top (bright yellow pulse)
|
||||
animation tree_star = pulse_position_animation(
|
||||
#FFFF00, # Bright yellow
|
||||
0xFFFF00, # Bright yellow
|
||||
58, # position (near the top)
|
||||
3, # star size
|
||||
1 # sharp edges
|
||||
@ -37,7 +37,7 @@ tree_star.opacity = smooth(200, 255, 2s) # Gentle pulsing
|
||||
|
||||
# Add some white sparkles for snow/magic
|
||||
animation snow_sparkles = twinkle_animation(
|
||||
#FFFFFF, # White snow
|
||||
0xFFFFFF, # White snow
|
||||
8, # density (sparkle count)
|
||||
400ms # twinkle speed (quick sparkles)
|
||||
)
|
||||
|
@ -4,12 +4,12 @@
|
||||
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
|
||||
0xFFFFFF, # White head
|
||||
10, # tail length
|
||||
2s # speed
|
||||
)
|
||||
@ -17,7 +17,7 @@ comet_main.priority = 7
|
||||
|
||||
# Secondary comet in different color, opposite direction
|
||||
animation comet_secondary = comet_animation(
|
||||
#FF4500, # Orange head
|
||||
0xFF4500, # Orange head
|
||||
8, # shorter tail
|
||||
3s, # slower speed
|
||||
-1 # other direction
|
||||
@ -26,7 +26,7 @@ comet_secondary.priority = 5
|
||||
|
||||
# Add sparkle trail behind comets but on top of blue background
|
||||
animation comet_sparkles = twinkle_animation(
|
||||
#AAAAFF, # Light blue sparkles
|
||||
0xAAAAFF, # Light blue sparkles
|
||||
8, # density (moderate sparkles)
|
||||
400ms # twinkle speed (quick sparkle)
|
||||
)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,7 +35,7 @@
|
||||
#
|
||||
# # Star on top (bright yellow pulse)
|
||||
# animation tree_star = pulse_position_animation(
|
||||
# #FFFF00, # Bright yellow
|
||||
# 0xFFFF00, # Bright yellow
|
||||
# 58, # position (near the top)
|
||||
# 3, # star size
|
||||
# 1 # sharp edges
|
||||
@ -45,7 +45,7 @@
|
||||
#
|
||||
# # Add some white sparkles for snow/magic
|
||||
# animation snow_sparkles = twinkle_animation(
|
||||
# #FFFFFF, # White snow
|
||||
# 0xFFFFFF, # White snow
|
||||
# 8, # density (sparkle count)
|
||||
# 400ms # twinkle speed (quick sparkles)
|
||||
# )
|
||||
|
@ -12,12 +12,12 @@
|
||||
# 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
|
||||
# 0xFFFFFF, # White head
|
||||
# 10, # tail length
|
||||
# 2s # speed
|
||||
# )
|
||||
@ -25,7 +25,7 @@
|
||||
#
|
||||
# # Secondary comet in different color, opposite direction
|
||||
# animation comet_secondary = comet_animation(
|
||||
# #FF4500, # Orange head
|
||||
# 0xFF4500, # Orange head
|
||||
# 8, # shorter tail
|
||||
# 3s, # slower speed
|
||||
# -1 # other direction
|
||||
@ -34,7 +34,7 @@
|
||||
#
|
||||
# # Add sparkle trail behind comets but on top of blue background
|
||||
# animation comet_sparkles = twinkle_animation(
|
||||
# #AAAAFF, # Light blue sparkles
|
||||
# 0xAAAAFF, # Light blue sparkles
|
||||
# 8, # density (moderate sparkles)
|
||||
# 400ms # twinkle speed (quick sparkle)
|
||||
# )
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -12,29 +12,29 @@
|
||||
# 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
|
||||
# 0xFFFFFF, # White center
|
||||
# 30, # center of strip
|
||||
# 4, # small center
|
||||
# 2 # soft edges
|
||||
|
@ -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
|
||||
|
@ -13,21 +13,21 @@
|
||||
#
|
||||
# # 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
|
||||
# 0xFFFFAA, # Slightly yellow white
|
||||
# 30, # center position
|
||||
# 20, # covers part of strip
|
||||
# 5 # soft edges
|
||||
@ -36,13 +36,13 @@
|
||||
# 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
|
||||
# 0x666699, # Dim blue-white
|
||||
# 4, # density (few flashes)
|
||||
# 300ms # twinkle speed (medium duration)
|
||||
# )
|
||||
|
@ -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,7 +51,7 @@
|
||||
#
|
||||
# # Add random bright flashes (like code highlights)
|
||||
# animation code_flash = twinkle_animation(
|
||||
# #00FFAA, # Bright cyan-green
|
||||
# 0x00FFAA, # Bright cyan-green
|
||||
# 3, # density (few flashes)
|
||||
# 150ms # twinkle speed (quick flash)
|
||||
# )
|
||||
|
@ -12,33 +12,33 @@
|
||||
# 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
|
||||
# 0xFFFFFF, # Bright white
|
||||
# 12, # long trail
|
||||
# 1.5s # fast speed
|
||||
# )
|
||||
# meteor1.priority = 15
|
||||
#
|
||||
# animation meteor2 = comet_animation(
|
||||
# #FFAA00, # Orange
|
||||
# 0xFFAA00, # Orange
|
||||
# 10, # medium trail
|
||||
# 2s # medium speed
|
||||
# )
|
||||
# meteor2.priority = 12
|
||||
#
|
||||
# animation meteor3 = comet_animation(
|
||||
# #AAAAFF, # Blue-white
|
||||
# 0xAAAAFF, # Blue-white
|
||||
# 8, # shorter trail
|
||||
# 1.8s # fast speed
|
||||
# )
|
||||
# meteor3.priority = 10
|
||||
#
|
||||
# animation meteor4 = comet_animation(
|
||||
# #FFAAAA, # Pink-white
|
||||
# 0xFFAAAA, # Pink-white
|
||||
# 14, # long trail
|
||||
# 2.5s # slower speed
|
||||
# )
|
||||
@ -46,7 +46,7 @@
|
||||
#
|
||||
# # Add distant stars
|
||||
# animation stars = twinkle_animation(
|
||||
# #CCCCCC, # Dim white
|
||||
# 0xCCCCCC, # Dim white
|
||||
# 12, # density (many stars)
|
||||
# 2s # twinkle speed (slow twinkle)
|
||||
# )
|
||||
@ -54,7 +54,7 @@
|
||||
#
|
||||
# # Add occasional bright flash (meteor explosion)
|
||||
# animation meteor_flash = twinkle_animation(
|
||||
# #FFFFFF, # Bright white
|
||||
# 0xFFFFFF, # Bright white
|
||||
# 1, # density (single flash)
|
||||
# 100ms # twinkle speed (very quick)
|
||||
# )
|
||||
|
@ -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,7 +58,7 @@
|
||||
#
|
||||
# # Add electrical arcing between segments
|
||||
# animation arc_sparkles = twinkle_animation(
|
||||
# #AAAAFF, # Electric blue
|
||||
# 0xAAAAFF, # Electric blue
|
||||
# 4, # density (few arcs)
|
||||
# 100ms # twinkle speed (quick arcs)
|
||||
# )
|
||||
|
@ -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,7 +46,7 @@
|
||||
#
|
||||
# # Add foam sparkles
|
||||
# animation foam = twinkle_animation(
|
||||
# #FFFFFF, # White foam
|
||||
# 0xFFFFFF, # White foam
|
||||
# 6, # density (sparkle count)
|
||||
# 300ms # twinkle speed (quick sparkles)
|
||||
# )
|
||||
|
@ -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
|
||||
|
@ -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,18 +35,18 @@
|
||||
#
|
||||
# # 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
|
||||
# (0, 0x191970), # Midnight blue
|
||||
# (64, purple), # Purple twilight
|
||||
# (128, #FF69B4), # Hot pink
|
||||
# (128, 0xFF69B4), # Hot pink
|
||||
# (192, orange), # Sunset orange
|
||||
# (255, yellow) # Sun
|
||||
# ]
|
||||
|
@ -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
|
||||
|
@ -16,7 +16,7 @@
|
||||
#
|
||||
# # Left side red flashing
|
||||
# animation left_red = pulse_position_animation(
|
||||
# #FF0000, # Bright red
|
||||
# 0xFF0000, # Bright red
|
||||
# 15, # center of left half
|
||||
# 15, # half the strip
|
||||
# 2 # sharp edges
|
||||
@ -26,7 +26,7 @@
|
||||
#
|
||||
# # Right side blue flashing (opposite phase)
|
||||
# animation right_blue = pulse_position_animation(
|
||||
# #0000FF, # Bright blue
|
||||
# 0x0000FF, # Bright blue
|
||||
# 45, # center of right half
|
||||
# 15, # half the strip
|
||||
# 2 # sharp edges
|
||||
@ -35,7 +35,7 @@
|
||||
# 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
|
||||
#
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
# )
|
||||
#
|
||||
|
@ -12,12 +12,12 @@
|
||||
# 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
|
||||
# 0xFF0000, # Bright red
|
||||
# 2, # initial position
|
||||
# 3, # pulse width
|
||||
# 2 # fade region
|
||||
@ -29,7 +29,7 @@
|
||||
#
|
||||
# # Add trailing glow effect
|
||||
# animation scanner_trail = pulse_position_animation(
|
||||
# #660000, # Dim red trail
|
||||
# 0x660000, # Dim red trail
|
||||
# 2, # initial position
|
||||
# 6, # wider trail
|
||||
# 4 # more fade
|
||||
|
@ -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,7 +29,7 @@
|
||||
#
|
||||
# # Add sun position effect - bright spot that moves
|
||||
# animation sun_position = pulse_position_animation(
|
||||
# #FFFFAA, # Bright yellow sun
|
||||
# 0xFFFFAA, # Bright yellow sun
|
||||
# 5, # initial position
|
||||
# 8, # sun size
|
||||
# 4 # soft glow
|
||||
@ -40,7 +40,7 @@
|
||||
#
|
||||
# # Add atmospheric glow around sun
|
||||
# animation sun_glow = pulse_position_animation(
|
||||
# #FFCC88, # Warm glow
|
||||
# 0xFFCC88, # Warm glow
|
||||
# 5, # initial position
|
||||
# 16, # larger glow
|
||||
# 8 # very soft
|
||||
@ -51,7 +51,7 @@
|
||||
#
|
||||
# # Add twinkling stars during night phases
|
||||
# animation stars = twinkle_animation(
|
||||
# #FFFFFF, # White stars
|
||||
# 0xFFFFFF, # White stars
|
||||
# 6, # density (star count)
|
||||
# 1s # twinkle speed (slow twinkle)
|
||||
# )
|
||||
|
@ -12,12 +12,12 @@
|
||||
# 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
|
||||
# 0xFFFFFF, # White stars
|
||||
# 8, # density (number of stars)
|
||||
# 500ms # twinkle speed (twinkle duration)
|
||||
# )
|
||||
@ -25,7 +25,7 @@
|
||||
#
|
||||
# # Add occasional bright flash
|
||||
# animation bright_flash = twinkle_animation(
|
||||
# #FFFFAA, # Bright yellow-white
|
||||
# 0xFFFFAA, # Bright yellow-white
|
||||
# 2, # density (fewer bright flashes)
|
||||
# 300ms # twinkle speed (quick flash)
|
||||
# )
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -4,29 +4,29 @@
|
||||
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
|
||||
0xFFFFFF, # White center
|
||||
30, # center of strip
|
||||
4, # small center
|
||||
2 # soft edges
|
||||
|
@ -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
|
||||
|
@ -5,21 +5,21 @@ 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
|
||||
0xFFFFAA, # Slightly yellow white
|
||||
30, # center position
|
||||
20, # covers part of strip
|
||||
5 # soft edges
|
||||
@ -28,13 +28,13 @@ 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
|
||||
0x666699, # Dim blue-white
|
||||
4, # density (few flashes)
|
||||
300ms # twinkle speed (medium duration)
|
||||
)
|
||||
|
@ -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,7 +43,7 @@ stream3.priority = 6
|
||||
|
||||
# Add random bright flashes (like code highlights)
|
||||
animation code_flash = twinkle_animation(
|
||||
#00FFAA, # Bright cyan-green
|
||||
0x00FFAA, # Bright cyan-green
|
||||
3, # density (few flashes)
|
||||
150ms # twinkle speed (quick flash)
|
||||
)
|
||||
|
@ -4,33 +4,33 @@
|
||||
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
|
||||
0xFFFFFF, # Bright white
|
||||
12, # long trail
|
||||
1.5s # fast speed
|
||||
)
|
||||
meteor1.priority = 15
|
||||
|
||||
animation meteor2 = comet_animation(
|
||||
#FFAA00, # Orange
|
||||
0xFFAA00, # Orange
|
||||
10, # medium trail
|
||||
2s # medium speed
|
||||
)
|
||||
meteor2.priority = 12
|
||||
|
||||
animation meteor3 = comet_animation(
|
||||
#AAAAFF, # Blue-white
|
||||
0xAAAAFF, # Blue-white
|
||||
8, # shorter trail
|
||||
1.8s # fast speed
|
||||
)
|
||||
meteor3.priority = 10
|
||||
|
||||
animation meteor4 = comet_animation(
|
||||
#FFAAAA, # Pink-white
|
||||
0xFFAAAA, # Pink-white
|
||||
14, # long trail
|
||||
2.5s # slower speed
|
||||
)
|
||||
@ -38,7 +38,7 @@ meteor4.priority = 8
|
||||
|
||||
# Add distant stars
|
||||
animation stars = twinkle_animation(
|
||||
#CCCCCC, # Dim white
|
||||
0xCCCCCC, # Dim white
|
||||
12, # density (many stars)
|
||||
2s # twinkle speed (slow twinkle)
|
||||
)
|
||||
@ -46,7 +46,7 @@ stars.priority = 5
|
||||
|
||||
# Add occasional bright flash (meteor explosion)
|
||||
animation meteor_flash = twinkle_animation(
|
||||
#FFFFFF, # Bright white
|
||||
0xFFFFFF, # Bright white
|
||||
1, # density (single flash)
|
||||
100ms # twinkle speed (very quick)
|
||||
)
|
||||
|
@ -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,7 +50,7 @@ segment3.priority = 10
|
||||
|
||||
# Add electrical arcing between segments
|
||||
animation arc_sparkles = twinkle_animation(
|
||||
#AAAAFF, # Electric blue
|
||||
0xAAAAFF, # Electric blue
|
||||
4, # density (few arcs)
|
||||
100ms # twinkle speed (quick arcs)
|
||||
)
|
||||
|
@ -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,7 +38,7 @@ wave2.pos = sawtooth(52, 8, 7s) # Opposite direction
|
||||
|
||||
# Add foam sparkles
|
||||
animation foam = twinkle_animation(
|
||||
#FFFFFF, # White foam
|
||||
0xFFFFFF, # White foam
|
||||
6, # density (sparkle count)
|
||||
300ms # twinkle speed (quick sparkles)
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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,18 +27,18 @@ 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
|
||||
(0, 0x191970), # Midnight blue
|
||||
(64, purple), # Purple twilight
|
||||
(128, #FF69B4), # Hot pink
|
||||
(128, 0xFF69B4), # Hot pink
|
||||
(192, orange), # Sunset orange
|
||||
(255, yellow) # Sun
|
||||
]
|
||||
|
@ -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
|
||||
|
@ -8,7 +8,7 @@ set half_length = 30
|
||||
|
||||
# Left side red flashing
|
||||
animation left_red = pulse_position_animation(
|
||||
#FF0000, # Bright red
|
||||
0xFF0000, # Bright red
|
||||
15, # center of left half
|
||||
15, # half the strip
|
||||
2 # sharp edges
|
||||
@ -18,7 +18,7 @@ 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
|
||||
0x0000FF, # Bright blue
|
||||
45, # center of right half
|
||||
15, # half the strip
|
||||
2 # sharp edges
|
||||
@ -27,7 +27,7 @@ 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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -4,12 +4,12 @@
|
||||
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
|
||||
0xFF0000, # Bright red
|
||||
2, # initial position
|
||||
3, # pulse width
|
||||
2 # fade region
|
||||
@ -21,7 +21,7 @@ scanner.pos = triangle(2, 57, 2s)
|
||||
|
||||
# Add trailing glow effect
|
||||
animation scanner_trail = pulse_position_animation(
|
||||
#660000, # Dim red trail
|
||||
0x660000, # Dim red trail
|
||||
2, # initial position
|
||||
6, # wider trail
|
||||
4 # more fade
|
||||
|
@ -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,7 +21,7 @@ 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
|
||||
0xFFFFAA, # Bright yellow sun
|
||||
5, # initial position
|
||||
8, # sun size
|
||||
4 # soft glow
|
||||
@ -32,7 +32,7 @@ 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
|
||||
0xFFCC88, # Warm glow
|
||||
5, # initial position
|
||||
16, # larger glow
|
||||
8 # very soft
|
||||
@ -43,7 +43,7 @@ sun_glow.opacity = smooth(0, 150, 30s) # Dimmer glow
|
||||
|
||||
# Add twinkling stars during night phases
|
||||
animation stars = twinkle_animation(
|
||||
#FFFFFF, # White stars
|
||||
0xFFFFFF, # White stars
|
||||
6, # density (star count)
|
||||
1s # twinkle speed (slow twinkle)
|
||||
)
|
||||
|
@ -4,12 +4,12 @@
|
||||
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
|
||||
0xFFFFFF, # White stars
|
||||
8, # density (number of stars)
|
||||
500ms # twinkle speed (twinkle duration)
|
||||
)
|
||||
@ -17,7 +17,7 @@ stars.priority = 10
|
||||
|
||||
# Add occasional bright flash
|
||||
animation bright_flash = twinkle_animation(
|
||||
#FFFFAA, # Bright yellow-white
|
||||
0xFFFFAA, # Bright yellow-white
|
||||
2, # density (fewer bright flashes)
|
||||
300ms # twinkle speed (quick flash)
|
||||
)
|
||||
|
@ -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)`**
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,16 +74,11 @@ 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()
|
||||
@ -90,12 +87,14 @@ class DSLLexer
|
||||
var comment_text = self.source[start_pos..self.position-1]
|
||||
self.add_token(37 #-animation.Token.COMMENT-#, comment_text, self.position - start_pos)
|
||||
end
|
||||
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
|
||||
|
@ -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..]}"
|
||||
|
@ -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.
|
@ -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!")
|
@ -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
|
@ -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
|
@ -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")
|
@ -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.")
|
@ -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
|
@ -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!")
|
@ -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 ===")
|
@ -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())")
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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")
|
@ -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 ===")
|
@ -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
|
||||
}
|
@ -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")
|
@ -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
|
@ -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
|
@ -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)")
|
@ -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")
|
@ -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")
|
@ -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")
|
@ -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")
|
@ -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")
|
@ -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
|
@ -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!")
|
@ -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
|
@ -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!")
|
@ -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!")
|
@ -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
|
@ -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"
|
@ -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"
|
@ -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
|
@ -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!")
|
@ -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}
|
@ -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")
|
@ -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")
|
@ -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")
|
@ -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")
|
@ -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
|
@ -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
|
@ -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
|
@ -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
Loading…
x
Reference in New Issue
Block a user