Repository navigation
examples: add a tennis scoreboard exercising dynamic steps and per-step action durations - #87
bensynapse wants to merge 3 commits into
Conversation
The existing scoreboard example is football-shaped: five fixed steps from pre-match to full-time, a minute capped at 90, and goal custom actions. Tennis needs parts of the specification that shape cannot reach, so this example covers them: - stepCount -1, because the step sequence is one per set plus the result and the set count comes from the bestOf data field; - actionDurations.steps, so the establishing transition onto set one can declare a different duration from the later set and result transitions; - a boolean serve indicator, and a tie-break flag that switches the points from 0/15/30/40/AD to a running count; - custom actions in both forms: two parameterless point actions and two that carry a GDD payload schema; - hidden: true on the technical properties, so a controller labels the Graphic with the event and the two players only. Points cascade as they do on court: a point can win the game, the game can win the set, 6-6 starts a tie-break whose serve rotates every two points, and the break-point badge is derived from the score rather than supplied, so it cannot contradict it. The Graphic reads only the data it is given. It has no fetch, no XMLHttpRequest, no WebSocket, no imports and no external font or image, so it renders complete from the manifest's schema defaults in an offline renderer. Registers the example in the demo catalogue with the generated file list, a carousel card driven by the existing generic controller, and a drawn court backdrop for the demo. The suite gains a cross-browser lifecycle test and a test that renders the Graphic with the network blocked; the expectations that enumerated six catalogue examples now cover seven, and the two demo navigation assertions that relied on Weather being the last card now point at the last card.
|
This looks like a great addition to the example collection, especially with the dynamic steps and parameterised custom actions.
One small thought on the website demo: since the card highlights “Dynamic steps”, it might be nice to let visitors explore the different set and result views, perhaps also with both match formats. Happy to help with the website integration if useful, just let me know. |
|
Thanks for the concrete cases. I reproduced all three and pushed fixes in 8f086bf:
I also added Previous/Next view controls and a best-of-three/five selector. Shortening the format while on a later view clamps it to the result; browser coverage exercises both formats. Verification used Node 24 and the pinned Chromium, Firefox and WebKit versions. Website validation passed. The full browser run passed 48 of 50 cases; the two accessibility scans exceeded their existing 45-second timeout. Both passed on a serial rerun ( These checks served the source tree; I have not exercised the Jekyll-built site or a broadcast renderer. |
|
Looks like a very good example to add, thanks for taking the time to add it! I also tested it just now, and I found a minor (potential) bug: When I send an |
|
The reset is not intended. I reproduced a remaining race in the website demo: click Point and then Update before the point animation finishes, and Update resends the old score from the form (30 becomes 15). The controller now sends only edited fields when the graphic has returned state. This preserves points awarded during an animation, while explicit score edits, including zero, still work. The new browser regression reproduces the reset before the fix and checks both the name update and an intentional score correction afterward. Pushed in 4bc7d42. Website validation and all 54 browser tests passed in the test container, including Chromium desktop/mobile, Firefox and WebKit ( |
|
I re-tested the latest changes locally and can no longer reproduce the issues. The new demo controls work well too, and CI now covers the Jekyll-built site. Looks good to me! |
I work on the Live Tennis API, a tennis data feed, which is how I came to read the specification closely. This is a specification example, not a product integration: the graphic contains no
fetch, noXMLHttpRequest, noWebSocket, no imports and no API key, and it renders complete from its manifest schema defaults. Our feed is mentioned once, in the example's README, as one of three ways an operator might drive the fields, alongside a manual rundown or another provider. AI tooling was used while writing it; the testing below is mine.v1/examples/scoreboardis football-shaped, with a fixed five-step sequence from pre-match to full-time, a minute capped at 90, and goal custom actions. So several parts of v1 currently have no worked example. Tennis reaches them naturally.Points cascade as they do on court: a point can win the game, a game can win the set at six with two clear, seven-five or seven-six, six-all starts a tiebreak whose serve changes after the first point and then every two, and the break-point badge is derived from the score rather than supplied, so it cannot contradict it. The rules are four exported pure functions.
Registration, and a footprint question for you
The example is registered in the demo catalogue using your own tooling rather than by hand-editing the generated file list. Your tests couple catalogue membership to the landing page, since every catalogue example must have a carousel slide, so this also adds a slide and a tab driven by your existing generic controller, and a drawn court backdrop at 21 KB with no third-party asset.
That makes the diff larger than a pure example would be. If you would rather it stayed out of the landing page, say so and I will cut it back to the example directory and the catalogue entry alone.
Two expectations in your suite enumerated six catalogue examples and assumed Weather was the last card. I retargeted them rather than weakening them: "End" still means the last tab, and the focus-rescue assertion still checks that focus lands on the tab when Next becomes disabled on the final slide.
One design note. Your generic controller always plays step 0. My first step model made step 0 a pre-match card, which showed a scoreboard with no score in the demo, so I restructured it to make step 0 the live set. That is better for any renderer that simply plays the graphic, and it keeps the dynamic-step justification intact.
Proof that it makes no network call
Three independent lines. Statically, the module has no network, storage or import statements at all. At runtime, a new test imports it with every route aborted and the browser context offline, drives play and a custom action, asserts the rendered shadow DOM matches the schema defaults and a laid-out board, and then asserts the abort handler recorded nothing. And driven through your own demo player, the complete request list is the player, its scripts, the catalogue, the manifest, the module and the site's own background image, with no console errors.
Verification
That is 36 of 36 across Chromium 151, Firefox 153 and WebKit 26.5, up from 32 of 32 before this change. The suite gains a cross-browser lifecycle test, which I tagged so it runs on all three engines rather than Chromium only, and the network-blocked render test. The thumbnail is 19 KB against the 500 KB limit, and the vendored-assets check stays clean.
What I could not verify
Your CI pins Node 24 and this machine has 22, so everything above ran on 22 and npm warned about the engine requirement. No Jekyll gem is installed either, so the browser tests ran against the repository root rather than the built site, meaning the one assertion that branches on that variable was not exercised in its CI form; it touches only pre-existing specification routes. And nothing has been verified against a real broadcast renderer, only against the specification, the schemas and your harness.
One observation for you, independent of this change: the accessibility test now scans one more carousel state and measured 39.4 seconds against its 45 second timeout on my machine, where a pristine main measured 41.1. The margin was already thin, so you may want to raise that timeout on its own merits.