fix(football-scoreboard): give the possession ball room and let it scale - #337
Merged
Conversation
Contributor
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Up to standards ✅🟢 Issues
|
11 tasks
…dage The possession football was placed a fixed 3px from the down & distance text and guarded only by `ball_x_center > 0` -- a check that a number had not come out negative, not that the ball fit anywhere in particular. On a 64px-wide panel it landed on the timeout bars; the guard could not see the right-hand edge at all, so home possession pushed it off a narrow panel; and on the adaptive 256x128 card it was drawn at x 262-274 of a 256px card, entirely off the edge. The ball's size is unchanged -- a fixed 7x5 on the classic paths, px() radii on the adaptive card -- and so is the wording beside it. The ball is placed around the text now, never the other way round. Where a row genuinely cannot hold both (a 64x32 leaves ~30px between the timeout bars and the text alone wants 29) the down & distance wins and the ball is omitted rather than the wording shortened. Fixed on all three paths that draw it: football.py's classic scorebug, GameRenderer's classic card (scroll mode), and its adaptive card. Separately, the adaptive card drew the down & distance in PressStart2P, ~4x wider per character than the 4x6 face: on a 192x48 panel that rendered "3rd & 8 at KC 42" 128px wide against the classic layout's 65px, and on a 256x128 it reached the full 256px, clipping the line at both ends. That line alone now uses a dedicated ADAPTIVE_LADDER_DETAIL on the compact 4x6 face, both rungs verified crisp (measure_font_crispness == 0.0). The clock, status band, records and dates keep ADAPTIVE_LADDER_TEXT and the face they had -- every recent and upcoming golden is pixel-identical to main. With the narrower face the yardage also fits where it previously did not. The long form was gated on `display_width > 128`, a proxy for "is there room" that got a 128x64 wrong: the string is 65px in the 4x6 face and the free band there is wider. It is now preferred whenever it fits the space the timeout bars and records leave free, the same trade the classic layout already makes via _fit_text. ADAPTIVE_LADDER_TEXT and the possession helpers exist only in this plugin's game_renderer.py, so no lineage port is needed. test_possession_ball_has_room.py pins the two properties that matter: the ball is exactly the size it always was, and the down & distance drawn is identical whether possession is home, away or unknown -- so the ball can never be paid for out of the wording. 671 checks across three render paths x eight harness sizes. Harness 24/24. Plugin suite 26 passed with the same two pre-existing environment failures as main. Rebased onto main after #336, which bumped the version and touched the same renderer; football goes to 2.27.2 since #339 takes 2.27.1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ChuckBuilds
force-pushed
the
fix/football-possession-ball-room
branch
from
August 30, 2026 03:59
59b9664 to
ba0483f
Compare
Manifest resolved by splicing this branch's 2.27.2 release entry on top of #335's 2.27.1; plugins.json regenerated by the pre-commit hook. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YF7Q48EYCCkU1Vs932uDY1
ChuckBuilds
pushed a commit
that referenced
this pull request
Aug 30, 2026
Football's manifest resolved by renumbering this branch's release entry to 2.27.3, dated today, on top of main's 2.27.1 and 2.27.2 -- 2.27.1 was claimed here before #335 took it. plugins.json regenerated by the hook. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YF7Q48EYCCkU1Vs932uDY1
ChuckBuilds
added a commit
that referenced
this pull request
Aug 30, 2026
main landed four commits that touch the same files as this branch: 0855372 fix(scoreboards): import datetime, timezone and ZoneInfo in game_renderer (#339) 6e8b863 fix(football-scoreboard): give the possession ball room (#337) 85a5555 feat(football): favourites first, ranked others, and a rotation (#335) 93bd554 feat(sports): apply the matchup separator settings to every mode (#336) 17 conflicts: eight sports.py, eight manifest.json, and the generated plugins.json. sports.py -- every conflict was the same shape. #336 moved the upcoming card's centre (matchup separator, or the date and time stacked, or nothing) out of the inline scorebug code and into _draw_upcoming_center_switch, which is exactly where this branch had scaled the stacked date/time offsets. Those edits are dead weight now: SportsUpcoming sets _DRAWS_SCORE = False, so _time_font_size() returns the un-grown 8 and max(7, 8-1) / max(9, 8+1) are the original 7 and 9. Resolved to main's side throughout, then re-asserted _DRAWS_SCORE on the SportsUpcoming that main's restructure left behind (football's #335 moved that class's body, so the flag came away with the hunk). Audited rather than assumed: diffing each resolved file against origin/main leaves 200-300 added lines -- the helper block and its comments -- and 3 to 6 removed, each one a line this branch deliberately replaced (return fonts, the 1.5x max_width, score_y's -14 and -3, date_y's -7, football's two "00-00" probes and its centre-gap return). No upcoming-card line is removed, so #336's relocation is intact. manifest.json -- main released the very version numbers this branch had claimed and then some, so the branch entries could not be kept. Took main's manifest whole, including its full versions[] history, and re-stacked this branch's entry on top a minor above where main now sits: afl 1.16.0, baseball 1.34.0, basketball 1.23.0, football 2.28.0, hockey 1.19.0, lacrosse 1.18.0, nrl 1.15.0, soccer 2.18.0. CHANGELOG headings follow. plugins.json regenerated. Verified against the merged origin/main across ten sizes (64x32, 128x32, 256x32, 64x64, 96x48, 192x48, 128x64, 256x64, 256x128, 384x96): * 240 harness renders, all PASS, no overflow or fill warnings. * All 80 upcoming renders byte-identical to main -- the screen draws no score and this branch leaves it alone. * Live and recent byte-identical at 64x32, 128x32 and 256x32 for every plugin, and football also at 64x64. Taller panels take the larger score. * Adaptive layout: only 192x48 live and recent move; the "VS" separator and every other size are byte-identical. * Plugin self-test failures identical to origin/main (11 pre-existing on this machine), including main's new test_switch_upcoming_center, which covers the region resolved to its side. * check_module_collisions clean across 43 plugins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The possession football was placed a fixed 3px from the down & distance text and guarded only by
ball_x_center > 0— a check that a number had not come out negative, not that the ball fit anywhere in particular. On a 64px-wide panel it landed on the timeout bars; the guard could not see the right-hand edge at all, so home possession pushed it off a narrow panel; and on the adaptive 256×128 card it was drawn at x 262–274 of a 256px card, entirely off the edge.The ball is now placed around the text rather than the other way round.
Type of change
Plugin(s) affected
football-scoreboardWhat changed
The ball's size is unchanged — a fixed 7×5 on the classic paths,
px()-scaled radii on the adaptive card — and so is the wording beside it. Where it still fits, it lands on the same pixel it always did. Where a row genuinely cannot hold both (a 64×32 leaves ~30px between the timeout bars and the text alone wants 29) the down & distance wins and the ball is omitted, rather than the wording being shortened.Fixed on all three paths that draw it:
football.py's classic scorebug,GameRenderer's classic card (scroll mode), and its adaptive card.Separately, the adaptive card drew the down & distance in
PressStart2P, ~4× wider per character than the 4×6 face. On a 192×48 panel that rendered3rd & 8 at KC 42128px wide against the classic layout's 65px; on a 256×128 it reached the full 256px, clipping the line at both ends and leaving nowhere for the ball. That line alone now uses a dedicatedADAPTIVE_LADDER_DETAILon the compact 4×6 face, both rungs verified crisp (measure_font_crispness == 0.0).The clock, status band, records and dates are untouched — they keep
ADAPTIVE_LADDER_TEXTand the face they had. Every recent and upcoming golden is pixel-identical tomain; only the three live cards differ.With the narrower face the yardage also fits where it previously did not. The long form was gated on
display_width > 128— a proxy for "is there room" that gets a 128×64 wrong, since the string is 65px in the 4×6 face and the free band there is wider. It is now preferred whenever it fits the space the timeout bars and records leave free, the same trade the classic layout already makes via_fit_text.Shared-code note
ADAPTIVE_LADDER_TEXTand the possession helpers exist only in this plugin'sgame_renderer.py, so no lineage port is needed (docs/plugin-development/08-shared-sports-code.md). No shared-shape signature changed — that is why the down & distance is fitted inline rather than by adding a parameter to the shared_draw_bottom_center_adaptive.Test plan
main(test_football_plugin.pywants a tty;test_timezone_resolution.pyhits Windows cp1252 on a✓— both pass on CI).check_module_collisions.pyclean.origin/main.New regression test:
test_possession_ball_has_room.py671 checks over three render paths × the harness's eight sizes × possession side × four down & distance strings (including the kickoff case) × records on and off. Each case renders twice — once capturing the ball's box, once with it suppressed — asserting the ball is on-panel, is exactly the size it always was, and covers no other element. Team logos are blanked, since the scorebug draws over them deliberately.
It pins the two properties that matter: the ball's size is unchanged, and the down & distance drawn is identical whether possession is home, away or unknown — so the ball can never be paid for out of the wording. Reintroducing a text reservation fails it.
Required for plugin changes
version(2.27.0 → 2.27.2), new entry at the top ofversionsclass_name/entry_pointunchangedplugins.jsonregenerated withupdate_registry.pyChecklist
CONTRIBUTING.mdNotes for reviewer
Rebased onto
mainafter #336, which bumped the version and touched the same renderer.Version coordination with #339: that PR takes
football-scoreboardto 2.27.1, this one to 2.27.2, so they merge in either order without a re-bump. They touch different parts ofgame_renderer.py— imports there, the detail ladder here.Known trade-off worth a second opinion: 128×64 and 128×96 now show the yardage but drop the ball. The limiting factor is the records —
10-5in PressStart2P is 32px per corner, which eats the free band. Moving the records to the compact face would fit both, but that would change text this PR deliberately leaves alone, so I have not.