Conversation
APNG was leaving the first shard as an untimed fallback, and fcTL's 16-bit delay fraction truncated holds that did not reduce into a ushort. The shared interval is now 100–65535 ms so a multi-second hold is exact in both the HTML page and slideshow.apng. Co-authored-by: lfarrand <lfarrand@users.noreply.github.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The maximum interval is off by one because 65,536 ms remains exactly representable in APNG fields.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Extends slideshow holds beyond one second while keeping HTML and APNG timing consistent.
Changes:
- Adds APNG root-frame timing and reduced delay fractions.
- Validates and documents the new interval range.
- Adds boundary and round-trip tests.
| File | Description |
|---|---|
src/QrShard.Core/SlideshowWriter.cs |
Implements APNG timing and interval validation. |
src/QrShard/Cli.cs |
Validates intervals and safely calculates cycle duration. |
tests/QrShard.Tests/VideoDecodeTests.cs |
Tests timing and slow intervals. |
tests/QrShard.Tests/DecodeSafetyRoundTests.cs |
Tests CLI boundary rejection. |
README.md |
Documents longer slideshow holds. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
65536/1000 reduces to 8192/125, so both 16-bit fcTL fields fit. 65537 is the first millisecond that stays unreduced and overflows. Co-authored-by: lfarrand <lfarrand@users.noreply.github.com>
The HTML check now requires the exact interval assignment and both playback timers, the out-of-range test requires the interval message on a real frame, and the printed cycle length stays a 64-bit product at the 5,000,000-image ceiling. Co-authored-by: lfarrand <lfarrand@users.noreply.github.com>
This branch has not been deployed
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
--intervalis now 100–65536 ms (default stays 500). Values above 1000 ms are slower than one frame per second: each shard stays on screen for multiple seconds, so a receiver that was skipping frames can collect every image in one pass instead of waiting through several full cycles.Two things kept a long hold from actually playing:
AnimateRootFrameoff, so that frame had nofcTLdelay and was skipped at the start of the cycle. The root frame is now part of the timed sequence, and every frame uses the same hold.intervalMs/1000seconds). ImageSharp casts both parts toushort. 65536/1000 reduces to 8192/125, so both parts fit. 65537 is coprime to 1000 and does not reduce; the unreduced numerator truncates and the hold collapses to 1/1000 s. The CLI only required ≥ 100 ms, so those values were accepted and then shown for a fraction of a second. 100–65536 ms is the contiguous range that reduces into those fields exactly. Faster intervals in that range, including the 100 ms minimum and the 500 ms default, are unchanged.HTML
slideshow.htmlstill usessetTimeoutwith that millisecond value.slideshow.apnguses the same interval. This stays on the cross-platform HTML and ffmpegreceive --screenpath.The printed cycle length is
imageCount * (long)intervalMs / 1000.0. At the 5,000,000-image ceiling and a 65536 ms hold that product is 327,680,000,000, which is computed in 64 bits.Test plan
dotnet restore QrShard.slnx --locked-modedotnet build QrShard.slnx -c Release -warnaserror(SDK 10.0.400,rollForward: disable) — 0 warnings, 0 errorsdotnet test tests/QrShard.Tests/QrShard.Tests.csproj -c Release -- --filter-class QrShard.Tests.VideoDecodeTests— 26 passedconst interval = {ms};(a non-digit follows the number) and bothwindow.setTimeout(queueNext, interval)calls pluswindow.setTimeout(() => queueNext(0), interval)Slideshow interval must be an integer from 100 to 65536 ms.against a real frame, so the empty-list guard cannot satisfy the testSlideshowCycleSeconds(5_000_000, 65536)is 327,680,000 seconds, which the wrapped Int32 product is not--interval 5000prints5000 ms/image, ~5 s per cycleand writesconst interval = 5000;dotnet test tests/QrShard.Tests/QrShard.Tests.csproj -c Release -- --filter-class QrShard.Tests.DecodeSafetyRoundTests— 18 passed on the previous commit, including CLI rejection of50,65537, and non-integers before any images are written