chore: prepare the 3.8.1 release (#756)

* chore: prepare the 3.8.1 release

Bumps src.__version__ to 3.8.1 and moves the Unreleased CHANGELOG entries
under a 3.8.1 heading, with an empty Unreleased above it.

The reason for the release is smooth scrolling at held-frame speeds. On
3.8.0 the default 50 px/s snapped to a stepped 48 px/s on a 120 Hz panel,
and any scroll slower than one pixel per refresh showed a half-pixel step
across the middle of the panel. Both are fixed on main (#710, #711) but
were in no release, so every stable-channel device still had them.

- #710's CHANGELOG entry had been filed under 3.8.0 although it merged
  after the v3.8.0 tag; it moves to 3.8.1.
- #711 had no CHANGELOG entry; it gets one.

scripts/check_release_version.py v3.8.1 passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: sports_game_over and draw_text_outlined ship in 3.8.1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-10-05 10:11:17 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent c20c0beac2
commit a669d781f5
4 changed files with 41 additions and 17 deletions
+37 -13
View File
@@ -19,6 +19,42 @@ accepts both, but the store flags the old spelling as deprecated
## Unreleased ## Unreleased
## 3.8.1
Smooth scrolling at the slower speeds, and the fixes and performance work
since 3.8.0. Highlights: the default 50 px/s and every other held-frame speed
now scroll cleanly (below), Raspberry Pi OS Bookworm is supported alongside
Trixie, updates refresh the systemd units, the display control socket gains
stages 2 and 3, the shared fetch service lands (stages 1 and 2), and a run of
web UI and Plugin Manager fixes. One new module is for plugins:
`src.common.sports_game_over` (sports family 5), which the scoreboards adopt
by flooring on 3.8.1; the other new modules are core-internal and set no
`ledmatrix_min_version` floor.
### Scroll speed
These two entries were the reason for this release: on 3.8.0 a slow scroll
either stepped or showed a half-pixel tear across the middle of the panel,
so only speeds of one pixel per refresh looked right.
- The Vegas Scroll Speed slider now says what the panel will do with the speed
it is on, and offers the nearest smooth ones to click. Only speeds that advance
a whole number of pixels per refresh look smooth, and which those are depends
on the panel (`GET /api/v3/config/scroll-speed-advice`, built on
`scroll_config.speed_advice()`; it uses the refresh the display measured, not
the `limit_refresh_rate_hz` cap). The slider steps by 1 px/s instead of 5.
- The default 50 px/s no longer snaps to a stepped 48 px/s (2 px every 5
refreshes, 24 fps) on a 120 Hz panel: `solve_crisp()` now prefers 60 or 40 px/s,
which move one pixel at a time. 100 Hz panels are unaffected. (#710)
- A held-frame scroll (one pixel every two or more refreshes, such as 50 or
60 px/s on a 100-120 Hz panel) no longer shows a half-pixel step across the
middle of the panel. Scan-order compensation ran only at one frame per
refresh; a held frame is now presented as a sequence of swaps
(`scan_order.refresh_plan()`), so the half of the panel that scans later
steps one refresh after the rest. It is skipped when a blit takes more than
half a refresh, since the second blit has to land before the next vsync.
(#711)
### Web UI: the Display tab is an ES-module page, with a page-visibility service (stage 4) ### Web UI: the Display tab is an ES-module page, with a page-visibility service (stage 4)
- New `static/v3/js/core/visibility.js`: each page module gets - New `static/v3/js/core/visibility.js`: each page module gets
@@ -719,7 +755,7 @@ policies are unchanged.
class attribute, `None` by default (the clock never ends a game); the class attribute, `None` by default (the clock never ends a game); the
scoreboards declare 3 (hockey), 4 (basketball, football, lacrosse) or scoreboards declare 3 (hockey), 4 (basketball, football, lacrosse) or
`None`. List the mixin before `SportsLiveSharedMixin`. A plugin may import `None`. List the mixin before `SportsLiveSharedMixin`. A plugin may import
it once it floors on the release that ships it, and deletes its copy then. it once it floors on 3.8.1, and deletes its copy then. (#770)
### Tooling ### Tooling
@@ -1373,18 +1409,6 @@ guard the import, since the loader's version check is advisory).
processes, or turns the socket off with `off`. A non-root dev run uses a processes, or turns the socket off with `off`. A non-root dev run uses a
private per-user path under the temp directory. private per-user path under the temp directory.
### Scroll speed
- The Vegas Scroll Speed slider now says what the panel will do with the speed
it is on, and offers the nearest smooth ones to click. Only speeds that advance
a whole number of pixels per refresh look smooth, and which those are depends
on the panel (`GET /api/v3/config/scroll-speed-advice`, built on
`scroll_config.speed_advice()`; it uses the refresh the display measured, not
the `limit_refresh_rate_hz` cap). The slider steps by 1 px/s instead of 5.
- The default 50 px/s no longer snaps to a stepped 48 px/s (2 px every 5
refreshes, 24 fps) on a 120 Hz panel: `solve_crisp()` now prefers 60 or 40 px/s,
which move one pixel at a time. 100 Hz panels are unaffected.
### Update channels ### Update channels
- Devices no longer pick up every merge to `main`. A new setting, - Devices no longer pick up every merge to `main`. A new setting,
+1 -1
View File
@@ -91,7 +91,7 @@ more. Shared sports code lives in `src/common`:
| `sports_live_scroll.py` | next release | `SportsLiveScrollMixin` — rebuild a live scroll strip mid-cycle, keeping the marquee's place | | `sports_live_scroll.py` | next release | `SportsLiveScrollMixin` — rebuild a live scroll strip mid-cycle, keeping the marquee's place |
| `sports_display_rules.py` | next release | `SportsCardOptionsMixin`, `SportsGameRulesMixin` — scorebug date options, the no-favourites filter, non-favourite live dwell | | `sports_display_rules.py` | next release | `SportsCardOptionsMixin`, `SportsGameRulesMixin` — scorebug date options, the no-favourites filter, non-favourite live dwell |
| `sports_font_path.py` | next release | `resolve_font_path` — what the plugins' `_resolve_font_path` copies return | | `sports_font_path.py` | next release | `resolve_font_path` — what the plugins' `_resolve_font_path` copies return |
| `sports_game_over.py` | next release | `SportsGameOverMixin` — `_is_game_really_over`, with the `FINAL_PERIOD` seam (family 5) | | `sports_game_over.py` | 3.8.1 | `SportsGameOverMixin` — `_is_game_really_over`, with the `FINAL_PERIOD` seam (family 5) |
Each is described in [src/common/README.md](../src/common/README.md). Each is described in [src/common/README.md](../src/common/README.md).
+1 -1
View File
@@ -4,5 +4,5 @@ LEDMatrix Display System
Core source package for the LED Matrix Display project. Core source package for the LED Matrix Display project.
""" """
__version__ = "3.8.0" __version__ = "3.8.1"
+2 -2
View File
@@ -46,7 +46,7 @@ Rules for the package:
| [`sports_display_rules`](#sports_display_rules) | Which games a scoreboard shows, for how long, and its scorebug date line | Yes (scoreboards) | 3.8.0 | | [`sports_display_rules`](#sports_display_rules) | Which games a scoreboard shows, for how long, and its scorebug date line | Yes (scoreboards) | 3.8.0 |
| [`sports_fetch`](#sports_fetch) | Scoreboard season fetch, lookback and live-odds decisions | Yes (scoreboards) | 3.7.0 | | [`sports_fetch`](#sports_fetch) | Scoreboard season fetch, lookback and live-odds decisions | Yes (scoreboards) | 3.7.0 |
| [`sports_font_path`](#sports_font_path) | Find a scoreboard's bundled font whatever the cwd | Yes (scoreboards) | 3.8.0 | | [`sports_font_path`](#sports_font_path) | Find a scoreboard's bundled font whatever the cwd | Yes (scoreboards) | 3.8.0 |
| [`sports_game_over`](#sports_game_over) | Whether a game ESPN still lists as live has ended | Yes (scoreboards) | next release | | [`sports_game_over`](#sports_game_over) | Whether a game ESPN still lists as live has ended | Yes (scoreboards) | 3.8.1 |
| [`sports_game_renderer`](#sports_game_renderer) | Scoreboard scroll/Vegas card geometry | Yes (scoreboards) | 3.3.0 | | [`sports_game_renderer`](#sports_game_renderer) | Scoreboard scroll/Vegas card geometry | Yes (scoreboards) | 3.3.0 |
| [`sports_helpers`](#sports_helpers) | Small helpers every scoreboard `sports.py` copies | Yes (scoreboards) | 3.5.0 | | [`sports_helpers`](#sports_helpers) | Small helpers every scoreboard `sports.py` copies | Yes (scoreboards) | 3.5.0 |
| [`sports_live_scroll`](#sports_live_scroll) | Rebuild a live scroll strip mid-cycle without moving it | Yes (scoreboards) | 3.8.0 | | [`sports_live_scroll`](#sports_live_scroll) | Rebuild a live scroll strip mid-cycle without moving it | Yes (scoreboards) | 3.8.0 |
@@ -402,7 +402,7 @@ Created by `DisplayController`; works with any plugin.
`draw_multiline_text()`, `create_text_image()`. `draw_multiline_text()`, `create_text_image()`.
`draw_text_outlined(draw, xy, text, font, fill, outline_color=(0, 0, 0), `draw_text_outlined(draw, xy, text, font, fill, outline_color=(0, 0, 0),
offsets=OUTLINE_SQUARE)` (Unreleased) draws the text in `outline_color` at offsets=OUTLINE_SQUARE)` (3.8.1) draws the text in `outline_color` at
each offset, then in `fill` on top: the same pixels as one `draw.text` per each offset, then in `fill` on top: the same pixels as one `draw.text` per
offset, but the string is rasterized once. `OUTLINE_SQUARE` is the offset, but the string is rasterized once. `OUTLINE_SQUARE` is the
eight-sided one-pixel outline the scoreboards draw, `OUTLINE_CROSS` the eight-sided one-pixel outline the scoreboards draw, `OUTLINE_CROSS` the