Consolidate legacy pattern ids into meteor, particles, sparkle, chase, and colour_cycle with n6/mode style selection; add pattern_modes helper, self-contained tests/all.py, and preset mode alias on wire. Co-authored-by: Cursor <cursoragent@cursor.com>
109 lines
3.9 KiB
Python
109 lines
3.9 KiB
Python
import random
|
|
import utime
|
|
|
|
from patterns.pattern_modes import style_mode
|
|
|
|
_LEGACY = {"starfall": 1}
|
|
|
|
|
|
class Particles:
|
|
def __init__(self, driver):
|
|
self.driver = driver
|
|
|
|
def _run_snowfall(self, preset, colors, flakes, last):
|
|
density = max(1, int(preset.n1) if int(preset.n1) > 0 else 20)
|
|
speed = max(1, int(preset.n2) if int(preset.n2) > 0 else 1)
|
|
d = max(1, int(preset.d))
|
|
now = utime.ticks_ms()
|
|
if utime.ticks_diff(now, last) < d:
|
|
return flakes, last, False
|
|
bg_color = self.driver.apply_brightness(preset.background_or(colors), preset.b)
|
|
if random.randint(0, 255) < density:
|
|
flakes.append([self.driver.num_leds - 1, random.randint(0, len(colors) - 1)])
|
|
for i in range(self.driver.num_leds):
|
|
self.driver.n[i] = bg_color
|
|
nf = []
|
|
for pos, ci in flakes:
|
|
if 0 <= pos < self.driver.num_leds:
|
|
self.driver.n[pos] = self.driver.apply_brightness(colors[ci], preset.b)
|
|
pos -= speed
|
|
if pos >= -1:
|
|
nf.append([pos, ci])
|
|
self.driver.n.write()
|
|
return nf, utime.ticks_add(last, d), True
|
|
|
|
def _run_starfall(self, preset, colors, stars, last):
|
|
rate = max(1, min(255, int(preset.n1) if int(preset.n1) > 0 else 14))
|
|
speed = max(1, int(preset.n2) if int(preset.n2) > 0 else 2)
|
|
tail = max(2, int(preset.n3) if int(preset.n3) > 0 else 10)
|
|
max_stars = 4
|
|
d = max(1, int(preset.d))
|
|
now = utime.ticks_ms()
|
|
if utime.ticks_diff(now, last) < d:
|
|
return stars, last, False
|
|
bg = self.driver.apply_brightness(preset.background_or(colors), preset.b)
|
|
for i in range(self.driver.num_leds):
|
|
self.driver.n[i] = bg
|
|
if len(stars) < max_stars and random.randint(0, 255) < rate:
|
|
top = self.driver.num_leds - 1 + random.randint(
|
|
0, min(8, self.driver.num_leds // 2)
|
|
)
|
|
stars.append({"h": float(top), "ci": random.randint(0, len(colors) - 1)})
|
|
ns = []
|
|
for s in stars:
|
|
h = s["h"]
|
|
ci = s["ci"]
|
|
ih = int(h)
|
|
for t in range(tail):
|
|
idx = ih + t
|
|
if 0 <= idx < self.driver.num_leds:
|
|
fade = 255 - (t * 255 // max(1, tail - 1))
|
|
base = colors[ci]
|
|
lit = (
|
|
(base[0] * fade) // 255,
|
|
(base[1] * fade) // 255,
|
|
(base[2] * fade) // 255,
|
|
)
|
|
lit = self.driver.apply_brightness(lit, preset.b)
|
|
o = self.driver.n[idx]
|
|
self.driver.n[idx] = (
|
|
max(o[0], lit[0]),
|
|
max(o[1], lit[1]),
|
|
max(o[2], lit[2]),
|
|
)
|
|
h -= speed
|
|
if h >= -tail:
|
|
s["h"] = h
|
|
ns.append(s)
|
|
stars = ns
|
|
self.driver.n.write()
|
|
return stars, utime.ticks_add(last, d), True
|
|
|
|
def run(self, preset):
|
|
"""Falling particles: n6 0 snowfall flakes, 1 starfall streaks."""
|
|
mode = style_mode(preset, 0, _LEGACY)
|
|
colors = preset.c if preset.c else [(255, 255, 255), (180, 220, 255)]
|
|
last = utime.ticks_ms()
|
|
|
|
if mode == 1:
|
|
colors = preset.c if preset.c else [
|
|
(255, 255, 255),
|
|
(200, 230, 255),
|
|
(255, 248, 220),
|
|
]
|
|
stars = []
|
|
while True:
|
|
stars, last, stepped = self._run_starfall(preset, colors, stars, last)
|
|
if stepped and not preset.a:
|
|
yield
|
|
return
|
|
yield
|
|
|
|
flakes = []
|
|
while True:
|
|
flakes, last, stepped = self._run_snowfall(preset, colors, flakes, last)
|
|
if stepped and not preset.a:
|
|
yield
|
|
return
|
|
yield
|