Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,18 @@ specific plugin later.
Per-plugin tests live in the LEDMatrix repo at `test/plugins/`. If
you're adding a test for your plugin, open a corresponding PR in
LEDMatrix. The dev preview server (`scripts/dev_server.py` in
LEDMatrix) is the fastest way to iterate visually.
LEDMatrix) is the fastest way to iterate visually — its **All Sizes**
button renders your plugin at every harness panel size side by side.

Plugins should **scale up, not just avoid overflow**: content that stays
tiny in the corner of a panel twice its design size passes the bounds
check but fails users. Use the adaptive layout system
(`docs/ADAPTIVE_LAYOUT.md` in LEDMatrix: `self.layout`, `draw_fit`,
`draw_image`, `scoreboard_regions`) and check the harness's
`fill warn` output in `check_plugin.py` reports. Declare your layout's
design size in the manifest (`"display": {"design_size": ...}`) and, once
your plugin is adaptive, opt into strict checking via
`test/harness.json`: `{"fill_check": "strict"}`.

## Code of Conduct

Expand Down
4 changes: 2 additions & 2 deletions plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,10 @@
"plugin_path": "plugins/football-scoreboard",
"stars": 0,
"downloads": 0,
"last_updated": "2026-07-08",
"last_updated": "2026-07-10",
"verified": true,
"screenshot": "",
"latest_version": "2.7.0"
"latest_version": "2.8.2"
},
{
"id": "geochron",
Expand Down
44 changes: 44 additions & 0 deletions plugins/football-scoreboard/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
# Changelog

## [2.8.1] - 2026-07-10

### Fixed
- **Adaptive layout (beta): blurry text on small panels.** Two of the ladder rungs
used for score/status/detail text rendered with visible antialiasing:
`press_start@10px`/`@12px` (PressStart2P only rasterizes crisply at exact
multiples of its 8px design grid) and `5by7.regular` (never crisp at any
size tested, in this or any other font's PIL rendering). Both dropped;
`4x6-font` corrected from 6px (33% antialiased) to 7px (its actual crisp
size). Every rung is now verified with `measure_font_crispness()` at 0%
antialiasing, with a regression test guarding it.
- **Adaptive layout (beta): score text could overlap the team logos on
larger panels.** Score/status/detail text was sized to the largest crisp
font that fit its own region — on a big panel that region has generous
room, so the score could balloon large enough to visually overlap/obscure
the logos next to it (which scale by a fixed geometry factor instead).
Text now sizes proportionally to the panel's scale factor relative to the
classic fixed size for that element (score=10px, status=8px, detail=6px)
via the new core `LayoutContext.fit_text_proportional()`, matching
classic's visual balance at every size while still being crisp and
larger than classic's fixed size.

## [2.8.0] - 2026-07-10

### Added
- **Adaptive layout (beta, opt-in)**: set `"layout_mode": "adaptive"` to scale
fonts, logos, and element regions to the panel size — score/status/detail
text grows on large panels (e.g. 32px score on a 256x128) instead of staying
at the fixed classic sizes, and layouts degrade gracefully on small panels.
Built on the LEDMatrix core adaptive layout system (`src/adaptive_layout.py`);
on older cores the plugin silently keeps the classic layout.
- **Default is `"classic"`** — rendering is byte-identical to 2.7.0 unless
you opt in (verified by the committed golden images).
- **Your customization still applies in adaptive mode**: explicitly
configured `customization.<element>.font`/`font_size` win over the
adaptive sizing, and `customization.layout.<element>` x/y offsets
translate elements from their computed positions. Note: adaptive mode
applies layout offsets in scroll mode too (classic scroll never did).
- **To revert**: set `"layout_mode": "classic"` in the plugin config — no
reinstall needed. (Or roll back to 2.7.0 in the plugin store.)
- Manifest now declares `display.design_size` (128x32), enabling the harness
scale-up fill check. Adaptive-mode golden images live in
`test/golden-adaptive/` (`test_adaptive_layout_mode.py`).

## [2.4.0] - 2026-06-15

### Added
Expand Down
21 changes: 21 additions & 0 deletions plugins/football-scoreboard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,27 @@ If you have dynamic duration caps configured (e.g., `max_duration_seconds: 120`)
- **Customizable Layout**: Adjust positioning of all elements via X/Y offsets
- **Customizable Fonts**: Configure font family and size for each text element

### Adaptive Layout (beta)

Set `"layout_mode": "adaptive"` to scale fonts, logos, and element regions
to your panel size — the score renders at up to 32px on a 256x128 instead of
the fixed 10px, and layouts degrade gracefully on small panels.

```json
{
"layout_mode": "adaptive"
}
```

- The default is `"classic"`: rendering is completely unchanged unless you
opt in. **To revert at any time, set it back to `"classic"`** — no
reinstall needed.
- Your font and X/Y offset customizations still apply in adaptive mode:
an explicitly configured font wins over the adaptive sizing, and offsets
shift elements from their computed positions.
- Requires a LEDMatrix core with the adaptive layout system
(`docs/ADAPTIVE_LAYOUT.md`); older cores silently keep the classic layout.

### Layout Customization

The plugin supports fine-tuning element positioning for custom display sizes. All offsets are relative to the default calculated positions, allowing you to adjust elements without breaking the layout.
Expand Down
6 changes: 6 additions & 0 deletions plugins/football-scoreboard/config_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,12 @@
}
}
},
"layout_mode": {
"type": "string",
"enum": ["classic", "adaptive"],
"default": "classic",
"description": "Layout engine. 'classic' is the original fixed layout (unchanged). 'adaptive' (beta) scales fonts, logos, and element regions to the panel size — content grows on large panels and degrades gracefully on small ones. Your customization fonts and x/y offsets still apply in adaptive mode. Requires LEDMatrix core with the adaptive layout system; falls back to classic on older cores. Switch back to 'classic' at any time to restore the original rendering."
},
"customization": {
"type": "object",
"title": "Display Customization",
Expand Down
5 changes: 5 additions & 0 deletions plugins/football-scoreboard/football.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ def _test_mode_update(self):
def _draw_scorebug_layout(self, game: Dict, force_clear: bool = False) -> None:
"""Draw the detailed scorebug layout for a live NCAA FB game.""" # Updated docstring
try:
# Adaptive layout (beta, opt-in via layout_mode: "adaptive") —
# classic layout below is untouched when it declines.
if self._adaptive_scorebug(game, "live", force_clear):
return

# Clear the display first to ensure full coverage (like weather plugin does)
if force_clear:
self.display_manager.clear()
Expand Down
Loading
Loading