import utime class Icicles: """Icicles hanging from anchor points; tips brighten toward max length then shrink.""" def __init__(self, driver): self.driver = driver def run(self, preset): colors = preset.c if preset.c else [(240, 248, 255), (160, 210, 255), (255, 255, 255)] spacing = max(1, int(preset.n1) if int(preset.n1) > 0 else 12) nled = self.driver.num_leds max_len = max( 2, min( int(preset.n2) if int(preset.n2) > 0 else min(14, max(3, nled // 4)), max(2, nled), ), ) span = max_len * 2 phase_step = max(1, int(preset.n3) if int(preset.n3) > 0 else 1) phase = 0 last = utime.ticks_ms() while True: d_ms = max(1, int(preset.d)) now = utime.ticks_ms() if utime.ticks_diff(now, last) >= d_ms: bg_rgb = preset.background_or(colors) bg = self.driver.apply_brightness(bg_rgb, preset.b) for i in range(nled): self.driver.n[i] = bg aidx = 0 for anchor in range(0, nled, spacing): tri_i = (phase + aidx * 5) % span ic_len = tri_i if tri_i <= max_len else span - tri_i tip_c = colors[aidx % len(colors)] tip = self.driver.apply_brightness(tip_c, preset.b) for k in range(ic_len): idx = anchor + k if idx >= nled: break br = ((k + 1) * 255) // max(1, ic_len) self.driver.n[self.driver.led_i(preset, idx)] = ( (tip[0] * br + bg[0] * (255 - br)) // 255, (tip[1] * br + bg[1] * (255 - br)) // 255, (tip[2] * br + bg[2] * (255 - br)) // 255, ) aidx += 1 self.driver.n.write() phase = (phase + self.driver.signed(preset, phase_step)) % span last = utime.ticks_add(last, d_ms) if not preset.a: yield return yield