1.9 KiB
1.9 KiB
Pattern Contract (Important)
Pattern classes are loaded dynamically by Presets._load_dynamic_patterns().
Patterns must follow this contract exactly.
Required class shape
- File name is the pattern id (for example
blink.py-> pattern nameblink). - Module exports a class with:
__init__(self, driver)wheredriveris thePresetsinstance.run(self, preset)that returns a generator.
Presets binds patterns like this:
pattern_class(self).run- then calls
self.patterns[preset.p](preset)and stores that generator. - every frame,
Presets.tick()doesnext(self.generator).
run() generator rules
run()mustyieldfrequently (normally once per tick loop).- Do not block inside
run():- no
sleep()/sleep_ms()/ long loops withoutyield. - no network or file I/O.
- no
- Use time checks (
utime.ticks_ms()+utime.ticks_diff(...)) to schedule updates. - Keep pattern state inside local variables in
run()(or object fields if needed).
Drawing and brightness
- Use
self.driver.apply_brightness(color, preset.b)for per-preset brightness. - Write pixels through
self.driver.n[...]/self.driver.n.fill(...). - Flush frame with
self.driver.n.write(). - If a pattern needs to clear, use black
(0, 0, 0).
Step semantics
self.driver.stepis shared pattern state managed byPresets.select(...)and patterns.- Patterns that use step-based progression should update
self.driver.stepthemselves. select(..., step=...)may set an explicit starting step.
Error handling
- Let unexpected errors raise inside the generator.
Presets.tick()catches exceptions, logs, and stops the active generator.- Pattern code should not swallow broad exceptions unless there is a clear recovery path.
Built-ins
offandonare built-in methods onPresets, not loaded from this folder.__init__.pyis ignored by dynamic loader.