pixdial 0.1.0__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 (238) hide show
  1. pixdial-0.1.0/.gitignore +11 -0
  2. pixdial-0.1.0/.python-version +1 -0
  3. pixdial-0.1.0/CHANGELOG.md +27 -0
  4. pixdial-0.1.0/CONTRIBUTING.md +121 -0
  5. pixdial-0.1.0/LICENSE +675 -0
  6. pixdial-0.1.0/PKG-INFO +268 -0
  7. pixdial-0.1.0/README.md +239 -0
  8. pixdial-0.1.0/SECURITY.md +44 -0
  9. pixdial-0.1.0/docs/architecture.md +52 -0
  10. pixdial-0.1.0/docs/config.md +203 -0
  11. pixdial-0.1.0/docs/plugins.md +163 -0
  12. pixdial-0.1.0/examples/plugin/pixdial_example.py +67 -0
  13. pixdial-0.1.0/examples/plugin/pyproject.toml +18 -0
  14. pixdial-0.1.0/pyproject.toml +95 -0
  15. pixdial-0.1.0/src/pixdial/__init__.py +4 -0
  16. pixdial-0.1.0/src/pixdial/__main__.py +3 -0
  17. pixdial-0.1.0/src/pixdial/cli.py +146 -0
  18. pixdial-0.1.0/src/pixdial/config.py +229 -0
  19. pixdial-0.1.0/src/pixdial/data/60-pixdial.rules +5 -0
  20. pixdial-0.1.0/src/pixdial/data/pixdial.service +16 -0
  21. pixdial-0.1.0/src/pixdial/demo.py +69 -0
  22. pixdial-0.1.0/src/pixdial/designs/__init__.py +57 -0
  23. pixdial-0.1.0/src/pixdial/designs/agents.py +83 -0
  24. pixdial-0.1.0/src/pixdial/designs/base.py +144 -0
  25. pixdial-0.1.0/src/pixdial/designs/clock.py +55 -0
  26. pixdial-0.1.0/src/pixdial/designs/colour.py +114 -0
  27. pixdial-0.1.0/src/pixdial/designs/cpu.py +229 -0
  28. pixdial-0.1.0/src/pixdial/designs/frame.py +208 -0
  29. pixdial-0.1.0/src/pixdial/designs/geometry.py +126 -0
  30. pixdial-0.1.0/src/pixdial/designs/gpu.py +156 -0
  31. pixdial-0.1.0/src/pixdial/designs/motion.py +38 -0
  32. pixdial-0.1.0/src/pixdial/designs/power.py +199 -0
  33. pixdial-0.1.0/src/pixdial/designs/thermals.py +51 -0
  34. pixdial-0.1.0/src/pixdial/devices/__init__.py +9 -0
  35. pixdial-0.1.0/src/pixdial/devices/base.py +50 -0
  36. pixdial-0.1.0/src/pixdial/devices/png.py +39 -0
  37. pixdial-0.1.0/src/pixdial/devices/slv3.py +169 -0
  38. pixdial-0.1.0/src/pixdial/devices/usbfs.py +95 -0
  39. pixdial-0.1.0/src/pixdial/doctor.py +105 -0
  40. pixdial-0.1.0/src/pixdial/fonts/LICENSE-Lato.txt +108 -0
  41. pixdial-0.1.0/src/pixdial/fonts/Lato-Black.ttf +0 -0
  42. pixdial-0.1.0/src/pixdial/fonts/Lato-Bold.ttf +0 -0
  43. pixdial-0.1.0/src/pixdial/fonts/Lato-Regular.ttf +0 -0
  44. pixdial-0.1.0/src/pixdial/gallery.py +143 -0
  45. pixdial-0.1.0/src/pixdial/plugins.py +55 -0
  46. pixdial-0.1.0/src/pixdial/py.typed +0 -0
  47. pixdial-0.1.0/src/pixdial/readings.py +106 -0
  48. pixdial-0.1.0/src/pixdial/runtime/__init__.py +10 -0
  49. pixdial-0.1.0/src/pixdial/runtime/feed.py +22 -0
  50. pixdial-0.1.0/src/pixdial/runtime/layout.py +85 -0
  51. pixdial-0.1.0/src/pixdial/runtime/report.py +22 -0
  52. pixdial-0.1.0/src/pixdial/runtime/runner.py +92 -0
  53. pixdial-0.1.0/src/pixdial/runtime/sampler.py +70 -0
  54. pixdial-0.1.0/src/pixdial/runtime/screen.py +136 -0
  55. pixdial-0.1.0/src/pixdial/sources/__init__.py +13 -0
  56. pixdial-0.1.0/src/pixdial/sources/base.py +29 -0
  57. pixdial-0.1.0/src/pixdial/sources/command.py +50 -0
  58. pixdial-0.1.0/src/pixdial/sources/cpu.py +47 -0
  59. pixdial-0.1.0/src/pixdial/sources/hwmon.py +86 -0
  60. pixdial-0.1.0/src/pixdial/sources/nvml.py +74 -0
  61. pixdial-0.1.0/tests/__init__.py +0 -0
  62. pixdial-0.1.0/tests/data/slv3-headers.txt +7 -0
  63. pixdial-0.1.0/tests/golden/clock-ember-busy.png +0 -0
  64. pixdial-0.1.0/tests/golden/clock-ember-full.png +0 -0
  65. pixdial-0.1.0/tests/golden/clock-ember-idle.png +0 -0
  66. pixdial-0.1.0/tests/golden/clock-ember-missing.png +0 -0
  67. pixdial-0.1.0/tests/golden/clock-ice-busy.png +0 -0
  68. pixdial-0.1.0/tests/golden/clock-ice-full.png +0 -0
  69. pixdial-0.1.0/tests/golden/clock-ice-idle.png +0 -0
  70. pixdial-0.1.0/tests/golden/clock-ice-missing.png +0 -0
  71. pixdial-0.1.0/tests/golden/clock-warm-busy.png +0 -0
  72. pixdial-0.1.0/tests/golden/clock-warm-full.png +0 -0
  73. pixdial-0.1.0/tests/golden/clock-warm-idle.png +0 -0
  74. pixdial-0.1.0/tests/golden/clock-warm-missing.png +0 -0
  75. pixdial-0.1.0/tests/golden/crown-ember-busy.png +0 -0
  76. pixdial-0.1.0/tests/golden/crown-ember-full.png +0 -0
  77. pixdial-0.1.0/tests/golden/crown-ember-idle.png +0 -0
  78. pixdial-0.1.0/tests/golden/crown-ember-missing.png +0 -0
  79. pixdial-0.1.0/tests/golden/crown-ice-busy.png +0 -0
  80. pixdial-0.1.0/tests/golden/crown-ice-full.png +0 -0
  81. pixdial-0.1.0/tests/golden/crown-ice-idle.png +0 -0
  82. pixdial-0.1.0/tests/golden/crown-ice-missing.png +0 -0
  83. pixdial-0.1.0/tests/golden/crown-warm-busy.png +0 -0
  84. pixdial-0.1.0/tests/golden/crown-warm-full.png +0 -0
  85. pixdial-0.1.0/tests/golden/crown-warm-idle.png +0 -0
  86. pixdial-0.1.0/tests/golden/crown-warm-missing.png +0 -0
  87. pixdial-0.1.0/tests/golden/flow-ember-busy.png +0 -0
  88. pixdial-0.1.0/tests/golden/flow-ember-full.png +0 -0
  89. pixdial-0.1.0/tests/golden/flow-ember-idle.png +0 -0
  90. pixdial-0.1.0/tests/golden/flow-ember-missing.png +0 -0
  91. pixdial-0.1.0/tests/golden/flow-ice-busy.png +0 -0
  92. pixdial-0.1.0/tests/golden/flow-ice-full.png +0 -0
  93. pixdial-0.1.0/tests/golden/flow-ice-idle.png +0 -0
  94. pixdial-0.1.0/tests/golden/flow-ice-missing.png +0 -0
  95. pixdial-0.1.0/tests/golden/flow-warm-busy.png +0 -0
  96. pixdial-0.1.0/tests/golden/flow-warm-full.png +0 -0
  97. pixdial-0.1.0/tests/golden/flow-warm-idle.png +0 -0
  98. pixdial-0.1.0/tests/golden/flow-warm-missing.png +0 -0
  99. pixdial-0.1.0/tests/golden/gpu-ember-busy.png +0 -0
  100. pixdial-0.1.0/tests/golden/gpu-ember-full.png +0 -0
  101. pixdial-0.1.0/tests/golden/gpu-ember-idle.png +0 -0
  102. pixdial-0.1.0/tests/golden/gpu-ember-missing.png +0 -0
  103. pixdial-0.1.0/tests/golden/gpu-ice-busy.png +0 -0
  104. pixdial-0.1.0/tests/golden/gpu-ice-full.png +0 -0
  105. pixdial-0.1.0/tests/golden/gpu-ice-idle.png +0 -0
  106. pixdial-0.1.0/tests/golden/gpu-ice-missing.png +0 -0
  107. pixdial-0.1.0/tests/golden/gpu-warm-busy.png +0 -0
  108. pixdial-0.1.0/tests/golden/gpu-warm-full.png +0 -0
  109. pixdial-0.1.0/tests/golden/gpu-warm-idle.png +0 -0
  110. pixdial-0.1.0/tests/golden/gpu-warm-missing.png +0 -0
  111. pixdial-0.1.0/tests/golden/grid-ember-busy.png +0 -0
  112. pixdial-0.1.0/tests/golden/grid-ember-full.png +0 -0
  113. pixdial-0.1.0/tests/golden/grid-ember-idle.png +0 -0
  114. pixdial-0.1.0/tests/golden/grid-ember-missing.png +0 -0
  115. pixdial-0.1.0/tests/golden/grid-ice-busy.png +0 -0
  116. pixdial-0.1.0/tests/golden/grid-ice-full.png +0 -0
  117. pixdial-0.1.0/tests/golden/grid-ice-idle.png +0 -0
  118. pixdial-0.1.0/tests/golden/grid-ice-missing.png +0 -0
  119. pixdial-0.1.0/tests/golden/grid-warm-busy.png +0 -0
  120. pixdial-0.1.0/tests/golden/grid-warm-full.png +0 -0
  121. pixdial-0.1.0/tests/golden/grid-warm-idle.png +0 -0
  122. pixdial-0.1.0/tests/golden/grid-warm-missing.png +0 -0
  123. pixdial-0.1.0/tests/golden/history-ember-busy.png +0 -0
  124. pixdial-0.1.0/tests/golden/history-ember-full.png +0 -0
  125. pixdial-0.1.0/tests/golden/history-ember-idle.png +0 -0
  126. pixdial-0.1.0/tests/golden/history-ember-missing.png +0 -0
  127. pixdial-0.1.0/tests/golden/history-ice-busy.png +0 -0
  128. pixdial-0.1.0/tests/golden/history-ice-full.png +0 -0
  129. pixdial-0.1.0/tests/golden/history-ice-idle.png +0 -0
  130. pixdial-0.1.0/tests/golden/history-ice-missing.png +0 -0
  131. pixdial-0.1.0/tests/golden/history-warm-busy.png +0 -0
  132. pixdial-0.1.0/tests/golden/history-warm-full.png +0 -0
  133. pixdial-0.1.0/tests/golden/history-warm-idle.png +0 -0
  134. pixdial-0.1.0/tests/golden/history-warm-missing.png +0 -0
  135. pixdial-0.1.0/tests/golden/minimal-ember-busy.png +0 -0
  136. pixdial-0.1.0/tests/golden/minimal-ember-full.png +0 -0
  137. pixdial-0.1.0/tests/golden/minimal-ember-idle.png +0 -0
  138. pixdial-0.1.0/tests/golden/minimal-ember-missing.png +0 -0
  139. pixdial-0.1.0/tests/golden/minimal-ice-busy.png +0 -0
  140. pixdial-0.1.0/tests/golden/minimal-ice-full.png +0 -0
  141. pixdial-0.1.0/tests/golden/minimal-ice-idle.png +0 -0
  142. pixdial-0.1.0/tests/golden/minimal-ice-missing.png +0 -0
  143. pixdial-0.1.0/tests/golden/minimal-warm-busy.png +0 -0
  144. pixdial-0.1.0/tests/golden/minimal-warm-full.png +0 -0
  145. pixdial-0.1.0/tests/golden/minimal-warm-idle.png +0 -0
  146. pixdial-0.1.0/tests/golden/minimal-warm-missing.png +0 -0
  147. pixdial-0.1.0/tests/golden/orb-ember-busy.png +0 -0
  148. pixdial-0.1.0/tests/golden/orb-ember-full.png +0 -0
  149. pixdial-0.1.0/tests/golden/orb-ember-idle.png +0 -0
  150. pixdial-0.1.0/tests/golden/orb-ember-missing.png +0 -0
  151. pixdial-0.1.0/tests/golden/orb-ice-busy.png +0 -0
  152. pixdial-0.1.0/tests/golden/orb-ice-full.png +0 -0
  153. pixdial-0.1.0/tests/golden/orb-ice-idle.png +0 -0
  154. pixdial-0.1.0/tests/golden/orb-ice-missing.png +0 -0
  155. pixdial-0.1.0/tests/golden/orb-warm-busy.png +0 -0
  156. pixdial-0.1.0/tests/golden/orb-warm-full.png +0 -0
  157. pixdial-0.1.0/tests/golden/orb-warm-idle.png +0 -0
  158. pixdial-0.1.0/tests/golden/orb-warm-missing.png +0 -0
  159. pixdial-0.1.0/tests/golden/pins-ember-busy.png +0 -0
  160. pixdial-0.1.0/tests/golden/pins-ember-full.png +0 -0
  161. pixdial-0.1.0/tests/golden/pins-ember-idle.png +0 -0
  162. pixdial-0.1.0/tests/golden/pins-ember-missing.png +0 -0
  163. pixdial-0.1.0/tests/golden/pins-ice-busy.png +0 -0
  164. pixdial-0.1.0/tests/golden/pins-ice-full.png +0 -0
  165. pixdial-0.1.0/tests/golden/pins-ice-idle.png +0 -0
  166. pixdial-0.1.0/tests/golden/pins-ice-missing.png +0 -0
  167. pixdial-0.1.0/tests/golden/pins-warm-busy.png +0 -0
  168. pixdial-0.1.0/tests/golden/pins-warm-full.png +0 -0
  169. pixdial-0.1.0/tests/golden/pins-warm-idle.png +0 -0
  170. pixdial-0.1.0/tests/golden/pins-warm-missing.png +0 -0
  171. pixdial-0.1.0/tests/golden/psu-ember-busy.png +0 -0
  172. pixdial-0.1.0/tests/golden/psu-ember-full.png +0 -0
  173. pixdial-0.1.0/tests/golden/psu-ember-idle.png +0 -0
  174. pixdial-0.1.0/tests/golden/psu-ember-missing.png +0 -0
  175. pixdial-0.1.0/tests/golden/psu-ice-busy.png +0 -0
  176. pixdial-0.1.0/tests/golden/psu-ice-full.png +0 -0
  177. pixdial-0.1.0/tests/golden/psu-ice-idle.png +0 -0
  178. pixdial-0.1.0/tests/golden/psu-ice-missing.png +0 -0
  179. pixdial-0.1.0/tests/golden/psu-warm-busy.png +0 -0
  180. pixdial-0.1.0/tests/golden/psu-warm-full.png +0 -0
  181. pixdial-0.1.0/tests/golden/psu-warm-idle.png +0 -0
  182. pixdial-0.1.0/tests/golden/psu-warm-missing.png +0 -0
  183. pixdial-0.1.0/tests/golden/quota-ember-busy.png +0 -0
  184. pixdial-0.1.0/tests/golden/quota-ember-full.png +0 -0
  185. pixdial-0.1.0/tests/golden/quota-ember-idle.png +0 -0
  186. pixdial-0.1.0/tests/golden/quota-ember-missing.png +0 -0
  187. pixdial-0.1.0/tests/golden/quota-ice-busy.png +0 -0
  188. pixdial-0.1.0/tests/golden/quota-ice-full.png +0 -0
  189. pixdial-0.1.0/tests/golden/quota-ice-idle.png +0 -0
  190. pixdial-0.1.0/tests/golden/quota-ice-missing.png +0 -0
  191. pixdial-0.1.0/tests/golden/quota-warm-busy.png +0 -0
  192. pixdial-0.1.0/tests/golden/quota-warm-full.png +0 -0
  193. pixdial-0.1.0/tests/golden/quota-warm-idle.png +0 -0
  194. pixdial-0.1.0/tests/golden/quota-warm-missing.png +0 -0
  195. pixdial-0.1.0/tests/golden/radar-ember-busy.png +0 -0
  196. pixdial-0.1.0/tests/golden/radar-ember-full.png +0 -0
  197. pixdial-0.1.0/tests/golden/radar-ember-idle.png +0 -0
  198. pixdial-0.1.0/tests/golden/radar-ember-missing.png +0 -0
  199. pixdial-0.1.0/tests/golden/radar-ice-busy.png +0 -0
  200. pixdial-0.1.0/tests/golden/radar-ice-full.png +0 -0
  201. pixdial-0.1.0/tests/golden/radar-ice-idle.png +0 -0
  202. pixdial-0.1.0/tests/golden/radar-ice-missing.png +0 -0
  203. pixdial-0.1.0/tests/golden/radar-warm-busy.png +0 -0
  204. pixdial-0.1.0/tests/golden/radar-warm-full.png +0 -0
  205. pixdial-0.1.0/tests/golden/radar-warm-idle.png +0 -0
  206. pixdial-0.1.0/tests/golden/radar-warm-missing.png +0 -0
  207. pixdial-0.1.0/tests/golden/thermals-ember-busy.png +0 -0
  208. pixdial-0.1.0/tests/golden/thermals-ember-full.png +0 -0
  209. pixdial-0.1.0/tests/golden/thermals-ember-idle.png +0 -0
  210. pixdial-0.1.0/tests/golden/thermals-ember-missing.png +0 -0
  211. pixdial-0.1.0/tests/golden/thermals-ice-busy.png +0 -0
  212. pixdial-0.1.0/tests/golden/thermals-ice-full.png +0 -0
  213. pixdial-0.1.0/tests/golden/thermals-ice-idle.png +0 -0
  214. pixdial-0.1.0/tests/golden/thermals-ice-missing.png +0 -0
  215. pixdial-0.1.0/tests/golden/thermals-warm-busy.png +0 -0
  216. pixdial-0.1.0/tests/golden/thermals-warm-full.png +0 -0
  217. pixdial-0.1.0/tests/golden/thermals-warm-idle.png +0 -0
  218. pixdial-0.1.0/tests/golden/thermals-warm-missing.png +0 -0
  219. pixdial-0.1.0/tests/golden/twin-ember-busy.png +0 -0
  220. pixdial-0.1.0/tests/golden/twin-ember-full.png +0 -0
  221. pixdial-0.1.0/tests/golden/twin-ember-idle.png +0 -0
  222. pixdial-0.1.0/tests/golden/twin-ember-missing.png +0 -0
  223. pixdial-0.1.0/tests/golden/twin-ice-busy.png +0 -0
  224. pixdial-0.1.0/tests/golden/twin-ice-full.png +0 -0
  225. pixdial-0.1.0/tests/golden/twin-ice-idle.png +0 -0
  226. pixdial-0.1.0/tests/golden/twin-ice-missing.png +0 -0
  227. pixdial-0.1.0/tests/golden/twin-warm-busy.png +0 -0
  228. pixdial-0.1.0/tests/golden/twin-warm-full.png +0 -0
  229. pixdial-0.1.0/tests/golden/twin-warm-idle.png +0 -0
  230. pixdial-0.1.0/tests/golden/twin-warm-missing.png +0 -0
  231. pixdial-0.1.0/tests/test_cli.py +60 -0
  232. pixdial-0.1.0/tests/test_config.py +123 -0
  233. pixdial-0.1.0/tests/test_golden.py +34 -0
  234. pixdial-0.1.0/tests/test_plugins.py +61 -0
  235. pixdial-0.1.0/tests/test_runtime.py +254 -0
  236. pixdial-0.1.0/tests/test_slv3.py +205 -0
  237. pixdial-0.1.0/tests/test_sources.py +190 -0
  238. pixdial-0.1.0/uv.lock +676 -0
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.egg-info/
4
+ .mypy_cache/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ dist/
8
+ build/
9
+ tests/golden/*.actual.png
10
+ .agents/
11
+ .product-marketing.md
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ All notable changes are recorded here, following [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
4
+ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.1.0] - 2026-11-06
9
+
10
+ ### Added
11
+
12
+ - Initial 0.1.0 implementation: a Python SDK and CLI for hardware screens on Linux.
13
+ - Fourteen designs, warm/ember/ice themes, animated designs, history trails and transitions.
14
+ - Linux USB support for Lian Li UNI FAN SL V3 Wireless LCD panels (`1cbe:0005`), plus a PNG device for previews.
15
+ - CPU, RAPL, NVML, hwmon and command sources, with hardware-reported limits, config overrides and stale readings.
16
+ - `run`, `show`, `list`, `devices`, `render` and `doctor` commands, with TOML configuration and Python entry points
17
+ for designs, sources and devices.
18
+
19
+ ### Changed
20
+
21
+ - Expanded the README with a render gallery, theme samples and animation, with a reproducible image script.
22
+ - Moved detailed configuration and API documentation into guides; added contribution and security policies.
23
+ - Prepared GPL-3.0-or-later package metadata and licence; bundled Lato fonts retain their SIL Open Font License.
24
+ - Added CI for Ruff, mypy and pytest on Ubuntu with Python 3.12 and 3.13.
25
+
26
+ [Unreleased]: https://github.com/YordiLorenzo/pixdial/compare/v0.1.0...HEAD
27
+ [0.1.0]: https://github.com/YordiLorenzo/pixdial/releases/tag/v0.1.0
@@ -0,0 +1,121 @@
1
+ # Contributing
2
+
3
+ Designs, data sources, support for more screens and reproducible bug reports are welcome.
4
+ Read [the architecture](docs/architecture.md) and [plugin guide](docs/plugins.md) before adding an extension.
5
+
6
+ ## Development setup
7
+
8
+ Use Python 3.12 or newer and [uv](https://docs.astral.sh/uv/). Linux is required for the physical USB driver
9
+ and built-in system sensors; rendering and the test suite also run on macOS without hardware.
10
+
11
+ ```sh
12
+ git clone https://github.com/YordiLorenzo/pixdial.git
13
+ cd pixdial
14
+ uv sync --locked
15
+ ```
16
+
17
+ Run the same checks as CI:
18
+
19
+ ```sh
20
+ uv run ruff check
21
+ uv run mypy
22
+ uv run pytest -q
23
+ ```
24
+
25
+ CI runs on Ubuntu with Python 3.12 and 3.13. `mypy` uses the strict settings and file list in `pyproject.toml`.
26
+ Tests use fake hardware and synthetic readings; no attached panel is needed.
27
+ Format files you change with `uv run ruff format PATH`, then rerun the checks.
28
+
29
+ ## Golden images
30
+
31
+ `tests/test_golden.py` compares every built-in design in three themes and four states against committed images.
32
+ A mismatch writes a neighbouring `.actual.png` for inspection. Small FreeType edge differences are tolerated;
33
+ changes in layout or colour should fail.
34
+
35
+ For an intentional visual change, inspect the difference first, then regenerate only the affected design.
36
+ For example, after changing `crown`:
37
+
38
+ ```sh
39
+ UPDATE_GOLDEN=1 uv run pytest -q tests/test_golden.py -k crown
40
+ uv run pytest -q tests/test_golden.py
41
+ ```
42
+
43
+ Review the resulting image diff before committing. Do not regenerate goldens to silence an unexplained failure.
44
+ Use `uv run pixdial render --gallery build/gallery` to inspect the full built-in gallery in
45
+ `build/gallery/gallery.html`.
46
+
47
+ ## Add an extension
48
+
49
+ | Kind | Start here | What to verify |
50
+ | --- | --- | --- |
51
+ | Design | Subclass `Design`; see [Build a design](README.md#build-a-design) | Every theme, missing readings, full scale and text inside the round edge. Add it to `BUILTIN` for a built-in design, or register an entry point for a plugin. |
52
+ | Source | Subclass `Source`; see [Sources](docs/plugins.md#sources) | Units, reported limits, unavailable sensors, stale readings and reset after resume. Use fixtures or fake readers in tests. |
53
+ | Device | Subclass `Device`; see [Devices](docs/plugins.md#devices) | Exact command bytes, frame size, permissions, disconnect/reconnect and normal shutdown. Record protocol references and real hardware tested. |
54
+
55
+ [examples/plugin](examples/plugin/) has an installable package covering all three kinds. Source and device
56
+ constructor arguments become config options. Keep defaults safe and errors specific to the option or device.
57
+ Do not require real hardware or network services in the normal test suite.
58
+
59
+ For a new built-in design, `test_golden.py` picks it up from `BUILTIN`; generate and review its golden images
60
+ with the same filtered command as above. For new hardware, separate tested support from protocol similarities.
61
+
62
+ ## Rebuild README graphics
63
+
64
+ ```sh
65
+ uv run python docs/images/build.py
66
+ ```
67
+
68
+ The script invokes `pixdial render` for the 14 designs, the three theme samples and the animated gallery output.
69
+ It composes `docs/images/designs.png`, `themes.png` and `demo.webp` on the brand's coffee-night background.
70
+ Intermediate renders stay in ignored `build/readme/`; each final image must be under 1.5 MB.
71
+ Open all three outputs and check labels and circular crops. The existing banner and logos are separate brand assets.
72
+
73
+ ## Website
74
+
75
+ `site/` is the static GitHub Pages site: HTML, CSS and vanilla JavaScript, with no analytics or external font
76
+ requests. Edit the page directly; there is no framework build. Keep claims aligned with the README and code.
77
+
78
+ Rebuild the images and check local links:
79
+
80
+ ```sh
81
+ uv run python site/build.py
82
+ uv run python site/check.py
83
+ uv run ruff check
84
+ uv run mypy
85
+ ```
86
+
87
+ The image script uses `pixdial render --state busy --scale 4` with an isolated config and no sources. It creates
88
+ real 1600 × 1600 renders for all 14 designs and three crown themes in ignored `build/site/renders/`. It encodes
89
+ 400/640/960/1280-pixel WebP variants, plus the 1600-pixel crown hero, without upscaling. The logo, SVG favicon and
90
+ social preview come from `docs/images/`. The fitted ICO/32px/Apple icons and Space Grotesk Latin variable WOFF2
91
+ are committed brand assets; the font's OFL is in `site/fonts/OFL.txt`. Rebuilding images needs no brand-kit path.
92
+ Keep all published files below 4 MB and the initial browser load below 1 MB. Below-fold images should lazy-load.
93
+
94
+ To preview with the same `/pixdial/` prefix as Pages, create a local server root (once) and serve it:
95
+
96
+ ```sh
97
+ mkdir -p build/pages
98
+ ln -s ../../site build/pages/pixdial
99
+ python3 -m http.server 8765 --bind 127.0.0.1 --directory build/pages
100
+ ```
101
+
102
+ Open `http://127.0.0.1:8765/pixdial/`. Check 390, 768, 1024 and 1440-pixel widths, keyboard focus, copy buttons,
103
+ all 14 preview designs, pause/resume and reduced motion. Reduced motion stops automatic rotation and fades;
104
+ previous/next still work. With JavaScript disabled, the first preview, full gallery, commands and FAQ remain usable.
105
+
106
+ `.github/workflows/pages.yml` deploys committed `site/` files on matching pushes to `main` or manual dispatch.
107
+ The deploy job skips private repositories. When the repository is public, enable **Settings → Pages → GitHub
108
+ Actions** and run **Actions → Pages → Run workflow**. The production URL is
109
+ `https://yordilorenzo.github.io/pixdial/`; publishing is separate from building or previewing locally.
110
+ GitHub Pages project sites share the origin's `/robots.txt`; `site/robots.txt` records the intended policy and
111
+ sitemap, but does not override that origin-wide file.
112
+
113
+ ## Send a change
114
+
115
+ 1. Keep the change focused and explain what now works, with a reproduction for a fix.
116
+ 2. Run the lint, type and test commands above; include results and any checks you could not run.
117
+ 3. Include render images for a visual change and update docs when config or behaviour changes.
118
+ 4. Describe hardware testing separately from mocked tests. Remove serials, private paths and credentials from logs.
119
+ 5. Open a pull request. Contributions must be compatible with GPL-3.0-or-later; retain third-party notices.
120
+
121
+ Report vulnerabilities privately as described in [SECURITY.md](SECURITY.md).