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>
148 lines
5.6 KiB
Python
148 lines
5.6 KiB
Python
import random
|
|
import utime
|
|
|
|
from patterns.pattern_modes import style_mode
|
|
|
|
_LEGACY = {"sparkle_trail": 0, "ice_sparkle": 1, "fireflies": 2}
|
|
|
|
|
|
class Sparkle:
|
|
def __init__(self, driver):
|
|
self.driver = driver
|
|
|
|
def _run_trail(self, preset, colors, last):
|
|
density = max(1, int(preset.n1) if int(preset.n1) > 0 else 24)
|
|
decay = max(1, min(255, int(preset.n2) if int(preset.n2) > 0 else 210))
|
|
d = max(1, int(preset.d))
|
|
now = utime.ticks_ms()
|
|
if utime.ticks_diff(now, last) < d:
|
|
return last, False
|
|
for i in range(self.driver.num_leds):
|
|
r, g, b = self.driver.n[i]
|
|
self.driver.n[i] = ((r * decay) // 255, (g * decay) // 255, (b * decay) // 255)
|
|
sparks = max(1, self.driver.num_leds * density // 255)
|
|
for _ in range(sparks):
|
|
idx = random.randint(0, max(0, self.driver.num_leds - 1))
|
|
c = self.driver.apply_brightness(
|
|
colors[random.randint(0, len(colors) - 1)], preset.b
|
|
)
|
|
self.driver.n[idx] = c
|
|
self.driver.n.write()
|
|
return utime.ticks_add(last, d), True
|
|
|
|
def _run_ice(self, preset, colors, sparks, last):
|
|
rate = max(1, min(255, int(preset.n1) if int(preset.n1) > 0 else 55))
|
|
decay = max(1, min(255, int(preset.n2) if int(preset.n2) > 0 else 140))
|
|
halo = max(0, min(3, int(preset.n3)))
|
|
cap = 28
|
|
d = max(1, int(preset.d))
|
|
now = utime.ticks_ms()
|
|
if utime.ticks_diff(now, last) < d:
|
|
return sparks, 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
|
|
ns = []
|
|
for s in sparks:
|
|
lv = s["lv"] - decay
|
|
if lv > 0:
|
|
s["lv"] = lv
|
|
ns.append(s)
|
|
sparks = ns
|
|
if len(sparks) < cap and random.randint(0, 255) < rate:
|
|
sparks.append(
|
|
{
|
|
"p": random.randint(0, max(0, self.driver.num_leds - 1)),
|
|
"lv": 255,
|
|
"ci": random.randint(0, len(colors) - 1),
|
|
}
|
|
)
|
|
for s in sparks:
|
|
p = s["p"]
|
|
lv = s["lv"]
|
|
ci = s["ci"]
|
|
base = colors[ci]
|
|
for off in range(-halo, halo + 1):
|
|
idx = p + off
|
|
if 0 <= idx < self.driver.num_leds:
|
|
dist = abs(off)
|
|
fac = lv if dist == 0 else (lv * (halo - dist + 1)) // (halo + 1)
|
|
lit = self.driver.apply_brightness(
|
|
(
|
|
(base[0] * fac) // 255,
|
|
(base[1] * fac) // 255,
|
|
(base[2] * fac) // 255,
|
|
),
|
|
preset.b,
|
|
)
|
|
o = self.driver.n[idx]
|
|
self.driver.n[idx] = (
|
|
min(255, o[0] + lit[0]),
|
|
min(255, o[1] + lit[1]),
|
|
min(255, o[2] + lit[2]),
|
|
)
|
|
self.driver.n.write()
|
|
return sparks, utime.ticks_add(last, d), True
|
|
|
|
def _run_fireflies(self, preset, colors, bugs, last):
|
|
count = max(1, int(preset.n1) if int(preset.n1) > 0 else 6)
|
|
speed = max(1, int(preset.n2) if int(preset.n2) > 0 else 8)
|
|
d = max(1, int(preset.d))
|
|
now = utime.ticks_ms()
|
|
if utime.ticks_diff(now, last) < d:
|
|
return bugs, last, False
|
|
bg_color = self.driver.apply_brightness(preset.background_or(colors), preset.b)
|
|
for i in range(self.driver.num_leds):
|
|
self.driver.n[i] = bg_color
|
|
for b in bugs:
|
|
idx, ph = b
|
|
tri = 255 - abs(128 - ph) * 2
|
|
c = self.driver.apply_brightness(colors[idx % len(colors)], preset.b)
|
|
self.driver.n[idx] = ((c[0] * tri) // 255, (c[1] * tri) // 255, (c[2] * tri) // 255)
|
|
b[1] = (ph + speed) & 255
|
|
if random.randint(0, 31) == 0:
|
|
b[0] = random.randint(0, max(0, self.driver.num_leds - 1))
|
|
self.driver.n.write()
|
|
return bugs, utime.ticks_add(last, d), True
|
|
|
|
def run(self, preset):
|
|
"""Sparkles: n6 0 trail decay, 1 ice burst+halo, 2 fireflies."""
|
|
mode = style_mode(preset, 0, _LEGACY)
|
|
colors = preset.c if preset.c else [(120, 120, 255)]
|
|
last = utime.ticks_ms()
|
|
|
|
if mode == 2:
|
|
colors = preset.c if preset.c else [(255, 210, 80), (120, 255, 120)]
|
|
count = max(1, int(preset.n1) if int(preset.n1) > 0 else 6)
|
|
bugs = [
|
|
[random.randint(0, max(0, self.driver.num_leds - 1)), random.randint(0, 255)]
|
|
for _ in range(count)
|
|
]
|
|
while True:
|
|
bugs, last, stepped = self._run_fireflies(preset, colors, bugs, last)
|
|
if stepped and not preset.a:
|
|
yield
|
|
return
|
|
yield
|
|
|
|
if mode == 1:
|
|
colors = preset.c if preset.c else [
|
|
(240, 248, 255),
|
|
(200, 235, 255),
|
|
(255, 255, 255),
|
|
]
|
|
sparks = []
|
|
while True:
|
|
sparks, last, stepped = self._run_ice(preset, colors, sparks, last)
|
|
if stepped and not preset.a:
|
|
yield
|
|
return
|
|
yield
|
|
|
|
while True:
|
|
last, stepped = self._run_trail(preset, colors, last)
|
|
if stepped and not preset.a:
|
|
yield
|
|
return
|
|
yield
|