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