scrollkit 0.8.3__tar.gz → 0.8.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. {scrollkit-0.8.3 → scrollkit-0.8.4}/LICENSE +17 -5
  2. {scrollkit-0.8.3/src/scrollkit.egg-info → scrollkit-0.8.4}/PKG-INFO +9 -2
  3. {scrollkit-0.8.3 → scrollkit-0.8.4}/README.md +7 -0
  4. {scrollkit-0.8.3 → scrollkit-0.8.4}/pyproject.toml +2 -2
  5. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/__init__.py +2 -2
  6. scrollkit-0.8.4/src/scrollkit/app/__init__.py +6 -0
  7. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/app/base.py +1 -1
  8. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/app/memory.py +1 -1
  9. scrollkit-0.8.4/src/scrollkit/config/__init__.py +1 -0
  10. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/config/settings_manager.py +1 -1
  11. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/config/transition_names.py +1 -1
  12. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/dev/__init__.py +1 -1
  13. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/dev/capabilities.py +36 -4
  14. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/dev/harness.py +1 -1
  15. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/dev/metrics.py +1 -1
  16. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/dev/performance.py +1 -1
  17. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/dev/validation.py +1 -1
  18. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/__init__.py +1 -1
  19. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/_graphics.py +1 -1
  20. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/_recording.py +1 -1
  21. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/_sim_backend.py +1 -1
  22. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/bitmap_text.py +1 -1
  23. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/boards.py +1 -1
  24. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/colors.py +1 -1
  25. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/content.py +1 -1
  26. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/gradient_text.py +1 -1
  27. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/interface.py +1 -1
  28. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/simulator.py +1 -1
  29. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/text_fill.py +1 -1
  30. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/text_pixels.py +1 -1
  31. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/display/unified.py +1 -1
  32. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/__init__.py +5 -1
  33. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/drip_splash.py +1 -1
  34. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/easing.py +1 -1
  35. scrollkit-0.8.4/src/scrollkit/effects/image_animators.py +1239 -0
  36. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/overlay.py +1 -1
  37. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/particles.py +1 -1
  38. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/reveal_splash.py +1 -1
  39. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/scrolling.py +1 -1
  40. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/swarm_reveal.py +1 -1
  41. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/text_render.py +1 -1
  42. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/effects/transitions.py +1 -1
  43. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/exceptions.py +1 -1
  44. scrollkit-0.8.4/src/scrollkit/network/__init__.py +1 -0
  45. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/network/http_client.py +1 -1
  46. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/network/mdns.py +1 -1
  47. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/network/wifi_manager.py +1 -1
  48. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/ota/__init__.py +1 -1
  49. scrollkit-0.8.4/src/scrollkit/ota/client.py +922 -0
  50. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/ota/display_progress.py +27 -3
  51. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/ota/manifest.py +24 -5
  52. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/ota/publish.py +1 -1
  53. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/__init__.py +1 -1
  54. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/bitmaptools.py +1 -1
  55. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/core/__init__.py +1 -1
  56. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/core/color_utils.py +1 -1
  57. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/core/feasibility.py +1 -1
  58. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/core/hardware_profile.py +1 -1
  59. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/core/led_matrix.py +1 -1
  60. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/core/performance_manager.py +1 -1
  61. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/core/pixel_buffer.py +1 -1
  62. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/devices/__init__.py +1 -1
  63. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/devices/base_device.py +1 -1
  64. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/devices/matrixportal_s3.py +1 -1
  65. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/displayio/__init__.py +1 -1
  66. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/displayio/bitmap.py +1 -1
  67. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/displayio/display.py +1 -1
  68. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/displayio/fourwire.py +1 -1
  69. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/displayio/group.py +1 -1
  70. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/displayio/ondiskbitmap.py +1 -1
  71. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/displayio/palette.py +1 -1
  72. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/displayio/tilegrid.py +1 -1
  73. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/terminalio/__init__.py +1 -1
  74. scrollkit-0.8.4/src/scrollkit/utils/__init__.py +1 -0
  75. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/utils/color_utils.py +1 -1
  76. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/utils/diagnostics.py +1 -1
  77. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/utils/error_handler.py +1 -1
  78. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/utils/system_utils.py +1 -1
  79. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/utils/url_utils.py +1 -1
  80. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/web/__init__.py +1 -1
  81. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/web/settings_server.py +1 -1
  82. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/web/wifi_setup.py +10 -2
  83. {scrollkit-0.8.3 → scrollkit-0.8.4/src/scrollkit.egg-info}/PKG-INFO +9 -2
  84. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit.egg-info/SOURCES.txt +1 -0
  85. scrollkit-0.8.3/src/scrollkit/app/__init__.py +0 -6
  86. scrollkit-0.8.3/src/scrollkit/config/__init__.py +0 -1
  87. scrollkit-0.8.3/src/scrollkit/network/__init__.py +0 -1
  88. scrollkit-0.8.3/src/scrollkit/ota/client.py +0 -528
  89. scrollkit-0.8.3/src/scrollkit/utils/__init__.py +0 -1
  90. {scrollkit-0.8.3 → scrollkit-0.8.4}/setup.cfg +0 -0
  91. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/ATTRIBUTION.md +0 -0
  92. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/CIRCUITPYTHON_COMPATIBILITY.md +0 -0
  93. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/LICENSE +0 -0
  94. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/README.md +0 -0
  95. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/adafruit_bitmap_font/__init__.py +0 -0
  96. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/adafruit_bitmap_font/bitmap_font.py +0 -0
  97. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/adafruit_bitmap_font/glyph_cache.py +0 -0
  98. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/adafruit_display_text/__init__.py +0 -0
  99. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/adafruit_display_text/label.py +0 -0
  100. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/core/device_benchmarks.json +0 -0
  101. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/core/matrixportal_s3_baseline.json +0 -0
  102. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/3x5.bdf +0 -0
  103. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/Arial_16.bdf +0 -0
  104. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/Arial_16.bdf.license +0 -0
  105. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/Arial_Bold_12.bdf +0 -0
  106. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/Arial_Bold_12.bdf.license +0 -0
  107. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/Arial_Bold_18.bdf +0 -0
  108. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/Arial_Bold_18.bdf.license +0 -0
  109. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/Junction_regular_24.bdf +0 -0
  110. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/Junction_regular_24.bdf.license +0 -0
  111. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/LeagueSpartan-Bold-16.bdf +0 -0
  112. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/LeagueSpartan-Bold-16.bdf.license +0 -0
  113. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/LeagueSpartan_Bold_16.bdf +0 -0
  114. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/LeagueSpartan_Bold_16.bdf.license +0 -0
  115. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/LibreBodoniv2002-Bold-27.bdf +0 -0
  116. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/LibreBodoniv2002-Bold-27.bdf.license +0 -0
  117. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/tom-thumb.bdf +0 -0
  118. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/viii-bold.bdf +0 -0
  119. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit/simulator/fonts/viii.bdf +0 -0
  120. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit.egg-info/dependency_links.txt +0 -0
  121. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit.egg-info/requires.txt +0 -0
  122. {scrollkit-0.8.3 → scrollkit-0.8.4}/src/scrollkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024-2026 Michael Winslow Czeiszperger
3
+ Copyright (c) 2024-2026 Michael Czeiszperger
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,19 @@ SOFTWARE.
25
25
  This repository vendors third-party components that retain their own licenses
26
26
  and copyright notices; this MIT license does not supersede them:
27
27
 
28
- - src/scrollkit/simulator/adafruit_display_text/ and adafruit_bitmap_font/
29
- Adafruit Industries (MIT). See the SPDX headers in those files.
30
- - Bundled fonts under src/scrollkit/simulator/ — various foundries under the
31
- SIL Open Font License (OFL). See src/scrollkit/simulator/ATTRIBUTION.md.
28
+ - Bundled fonts under src/scrollkit/simulator/fonts/ various foundries under
29
+ the SIL Open Font License (OFL). Each font ships with its own .license file;
30
+ see src/scrollkit/simulator/ATTRIBUTION.md.
31
+
32
+ The desktop simulator provides API-compatible, clean-room reimplementations
33
+ under Adafruit-matching names (e.g. src/scrollkit/simulator/adafruit_display_text/
34
+ and adafruit_bitmap_font/) so that unmodified device code — which imports those
35
+ module names — also runs on the desktop. These directories contain ScrollKit's
36
+ own code, not Adafruit's, and are covered by the MIT license above. The
37
+ corresponding Adafruit CircuitPython libraries are not redistributed here; they
38
+ are installed separately onto the device.
39
+
40
+ Acknowledgement: ScrollKit's over-the-air update feature was inspired by Ronald
41
+ Dehuysser's micropython-ota-updater
42
+ (https://github.com/rdehuyss/micropython-ota-updater). ScrollKit's OTA subsystem
43
+ is its own manifest-based design and contains none of that project's code.
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scrollkit
3
- Version: 0.8.3
3
+ Version: 0.8.4
4
4
  Summary: LED Matrix Display Framework for CircuitPython and Desktop
5
- Author-email: Michael Winslow Czeiszperger <michael@czei.org>
5
+ Author-email: Michael Czeiszperger <michael@czei.org>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://github.com/czei/scrollkit
8
8
  Project-URL: Repository, https://github.com/czei/scrollkit
@@ -243,6 +243,13 @@ voice, with my own screenshots. Yes, AI has touched a lot of this code. It was
243
243
  also directed by an engineer who has shipped production software for a living,
244
244
  including time on one of Sun Microsystems' API teams. Both are true.
245
245
 
246
+ ## Acknowledgements
247
+
248
+ ScrollKit's over-the-air update feature was inspired by
249
+ [Ronald Dehuysser's micropython-ota-updater](https://github.com/rdehuyss/micropython-ota-updater).
250
+ The current implementation is ScrollKit's own manifest-based design and uses none
251
+ of his code — but the idea came from his project, and it deserves the shout-out.
252
+
246
253
  ## License
247
254
 
248
255
  MIT
@@ -199,6 +199,13 @@ voice, with my own screenshots. Yes, AI has touched a lot of this code. It was
199
199
  also directed by an engineer who has shipped production software for a living,
200
200
  including time on one of Sun Microsystems' API teams. Both are true.
201
201
 
202
+ ## Acknowledgements
203
+
204
+ ScrollKit's over-the-air update feature was inspired by
205
+ [Ronald Dehuysser's micropython-ota-updater](https://github.com/rdehuyss/micropython-ota-updater).
206
+ The current implementation is ScrollKit's own manifest-based design and uses none
207
+ of his code — but the idea came from his project, and it deserves the shout-out.
208
+
202
209
  ## License
203
210
 
204
211
  MIT
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "scrollkit"
7
- version = "0.8.3"
7
+ version = "0.8.4"
8
8
  description = "LED Matrix Display Framework for CircuitPython and Desktop"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
11
11
  license = {text = "MIT"}
12
12
  authors = [
13
- {name = "Michael Winslow Czeiszperger", email = "michael@czei.org"}
13
+ {name = "Michael Czeiszperger", email = "michael@czei.org"}
14
14
  ]
15
15
  keywords = ["circuitpython", "led-matrix", "display", "matrixportal", "simulator"]
16
16
  classifiers = [
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """ScrollKit - LED Matrix Display Framework for CircuitPython and Desktop.
3
3
 
4
4
  A framework for building scrolling LED matrix applications that run unchanged on
@@ -13,4 +13,4 @@ need from submodules, e.g.::
13
13
  from scrollkit.display.unified import UnifiedDisplay
14
14
  """
15
15
 
16
- __version__ = "0.8.3"
16
+ __version__ = "0.8.4"
@@ -0,0 +1,6 @@
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
+ """ScrollKit Application framework."""
3
+
4
+ from .base import SLDKApp, ScrollKitApp
5
+
6
+ __all__ = ['SLDKApp', 'ScrollKitApp']
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Base application class for SLDK.
3
3
 
4
4
  Provides the three-process architecture with graceful degradation for ESP32.
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Realistic free-RAM estimate shared by the run loop and the dev harness.
3
3
 
4
4
  The run loop gates optional processes on free RAM (data updates need ~20-30 KB,
@@ -0,0 +1 @@
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
@@ -1,6 +1,6 @@
1
1
  """
2
2
  Settings manager for handling user configuration.
3
- Copyright (c) 2024-2026 Michael Winslow Czeiszperger
3
+ Copyright (c) 2024-2026 Michael Czeiszperger
4
4
  """
5
5
  import json
6
6
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Canonical list of built-in transition names — the single source of truth.
3
3
 
4
4
  This module is **literal-only**: it imports nothing, so it is safe to import on
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Desktop-only developer / AI-agent affordances for ScrollKit.
3
3
 
4
4
  Everything here exists to help a human or an AI agent build and *verify* a
@@ -1,11 +1,13 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Machine-readable catalog of what a ScrollKit app can use — for AI authoring.
3
3
 
4
4
  ``capabilities()`` returns a JSON-able dict describing the building blocks an
5
5
  agent should reach for when writing an app: the panel geometry, the content
6
- types and their constructor parameters, priority levels, available effects,
7
- named colors, and the display drawing API — plus a pointer at the headless
8
- verification loop.
6
+ types and their constructor parameters, priority levels, the effect categories
7
+ (standalone splash/particle ``effects``, content-swap ``transitions``,
8
+ ``scrolling`` presentations, BitmapText ``palette_effects``, and the
9
+ ``image_animators`` that decorate a static image), named colors, and the display
10
+ drawing API — plus a pointer at the headless verification loop.
9
11
 
10
12
  Everything is **introspected from live code** (the real ``Priority`` class, the
11
13
  ``effects`` package's ``__all__``, ``NAMED_COLORS``, the
@@ -147,6 +149,27 @@ def _effects():
147
149
  return out
148
150
 
149
151
 
152
+ def _image_animators():
153
+ """``[{name, doc, feasibility}]`` for the per-frame image-layer animators.
154
+
155
+ Its OWN category — these decorate a *static image already on screen* via the
156
+ start/step/detach contract, distinct from the content-swap ``transitions`` and from
157
+ the standalone splash/particle ``effects``. Enumerated via the module's explicit
158
+ ``ANIMATOR_CLASSES`` catalog (not ``__subclasses__``) so the order is stable and the
159
+ base ``IntroAnimator`` scaffolding is excluded. No ``pairs_with`` — they attach to an
160
+ image, not to text presentations; ``feasibility`` is each class's FEASIBILITY budget.
161
+ """
162
+ out = []
163
+ try:
164
+ from ..effects.image_animators import ANIMATOR_CLASSES
165
+ except ImportError:
166
+ return out
167
+ for cls in ANIMATOR_CLASSES:
168
+ out.append({"name": cls.__name__, "doc": _first_line(cls),
169
+ "feasibility": getattr(cls, "FEASIBILITY", None)})
170
+ return out
171
+
172
+
150
173
  def _transitions():
151
174
  """``[{name, doc, feasibility, pairs_with}]`` for the built-in content-swap transitions.
152
175
 
@@ -299,6 +322,7 @@ def capabilities():
299
322
  for key, fn in (("content_types", _content_types), ("priorities", _priorities),
300
323
  ("effects", _effects), ("transitions", _transitions),
301
324
  ("scrolling", _scrolling), ("palette_effects", _palette_effects),
325
+ ("image_animators", _image_animators),
302
326
  ("text_fills", _text_fills), ("color_utilities", _color_utilities),
303
327
  ("named_colors", _named_colors),
304
328
  ("display_api", _display_api), ("hardware", _hardware),
@@ -356,6 +380,14 @@ def as_text(cat=None):
356
380
  lines.append("Palette effects (on BitmapText):")
357
381
  for e in pe:
358
382
  lines.append(" - %s%s — %s" % (e["name"], _pairs(e), e["doc"]))
383
+ ia = cat.get("image_animators")
384
+ if isinstance(ia, list) and ia:
385
+ lines.append("Image animators (decorate a static image on screen):")
386
+ for e in ia:
387
+ feas = e.get("feasibility") or {}
388
+ ms = feas.get("modeled_frame_ms")
389
+ budget = " (~%sms/frame)" % ms if ms is not None else ""
390
+ lines.append(" - %s%s — %s" % (e["name"], budget, e["doc"]))
359
391
  tf = cat.get("text_fills")
360
392
  if isinstance(tf, dict) and isinstance(tf.get("gradient"), dict):
361
393
  g = tf["gradient"]
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Headless verification harness — the AI agent's primary tool.
3
3
 
4
4
  ``run_headless(app, frames=N)`` drives a ``ScrollKitApp``'s display loop
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Pixel-level metrics for headless verification (desktop-only, numpy).
3
3
 
4
4
  Reads the simulator's true-color RGB888 buffer
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Measured performance trade-offs for the MatrixPortal S3 — for AI authoring.
3
3
 
4
4
  Turns the raw microbenchmark table (``simulator/core/device_benchmarks.json``,
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Pre-flight validation for a ScrollKit app — structured issues with fixes.
3
3
 
4
4
  ``validate(app)`` runs the app headless once and combines *static* checks on its
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """ScrollKit Display module.
3
3
 
4
4
  Kept lean on purpose: importing this package pulls in only the core content
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Shared display-graphics primitives (mixed into Simulator + Unified displays).
3
3
 
4
4
  One code path, both platforms. Provides:
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Desktop-only frame capture + encoding for the display recording API.
3
3
 
4
4
  The user-facing methods (``start_recording`` / ``save_gif`` / ``save_video`` /
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Shared desktop-simulator backend setup for the two display classes.
3
3
 
4
4
  ``UnifiedDisplay`` (the production entry point, which auto-selects hardware vs
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Palette-animated bitmap text (Class 3 — the proving spike for the foundation).
3
3
 
4
4
  A ScrollKit-native fixed-cell 5x7 font is rendered ONCE into an indexed Bitmap
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Board registry: how ScrollKit builds a panel on each supported board.
3
3
 
4
4
  ScrollKit runs the *same* app on more than one HUB75 driver board. The boards
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Continuous 24-bit colour generators (device-safe, pure-integer math).
3
3
 
4
4
  These expose the **full** colour space as functions an app or effect samples at any
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Display content classes for SLDK.
3
3
 
4
4
  Provides base classes and implementations for displayable content.
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Static directional gradient / palette text fill (indexed-bitmap renderer).
3
3
 
4
4
  When ``StaticText`` / ``ScrollingText`` are given a ``palette``, their glyphs are
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Display interface for SLDK.
3
3
 
4
4
  This provides the abstract interface that all display implementations must follow.
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Simulator display for SLDK — the interactive desktop entry point.
3
3
 
4
4
  ``SimulatorDisplay`` IS ``UnifiedDisplay`` (one per-frame pipeline: the same
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Shared vocabulary for gradient text fills (the live source of truth).
3
3
 
4
4
  Kept deliberately tiny and dependency-free (pure constants + functions, no
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Font/scale-aware text → lit-pixel composition (single source of truth).
3
3
 
4
4
  ``pixels_from_font_text`` renders a string with *any* loaded font at an integer
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Unified display implementation for SLDK.
3
3
 
4
4
  Provides a unified interface that works on both CircuitPython hardware
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """ScrollKit Effects package.
3
3
 
4
4
  Kept deliberately empty of imports: importing ``scrollkit.effects`` must not
@@ -18,6 +18,10 @@ into RAM. Import each submodule directly instead:
18
18
  ``from scrollkit.effects.swarm_reveal import show_swarm_splash, SwarmReveal``
19
19
  - **Particles** —
20
20
  ``from scrollkit.effects.particles import ParticleEngine, Sparkle, Snow``
21
+ - **Image animators** (per-frame motion layered onto a static image already on
22
+ screen — start/step/detach, not the ``Transition`` contract) —
23
+ ``from scrollkit.effects.image_animators import TwinkleAnimator, MotionAnimator,
24
+ ComboAnimator``
21
25
  - **Text-rendering helpers** —
22
26
  ``from scrollkit.effects.text_render import pixels_from_font_text, font_text_width``
23
27
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Drip-splash animation — LEDs drip in from an edge (default the top) into place.
3
3
 
4
4
  The inverse of :func:`scrollkit.effects.show_reveal_splash`. The screen starts
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024-2026 Michael Winslow Czeiszperger
1
+ # Copyright (c) 2024-2026 Michael Czeiszperger
2
2
  """Integer easing/tween lookup tables (CircuitPython-safe).
3
3
 
4
4
  Each named curve is a length-256 ``bytes`` table mapping a 0..255 progress to a