From ab066b1bf6a6422b8927b1f35e28e33d8ac72aea Mon Sep 17 00:00:00 2001 From: Kresna Date: Sat, 1 Aug 2026 22:04:32 +0700 Subject: [PATCH] fix(optical-transfer): honest progress by frames collected, not solved blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported: progress stayed 0% while many frames were captured. LT fountain codes solve almost nothing until they avalanche near the end, so 'solved blocks ÷ total' reads ~0% the whole time you collect frames — looks stuck. Report progress by unique frames collected ÷ the ~k×1.15 typically needed (LtDecoder.progress() + new framesSeen), capped below 100% until actually done. The bar now climbs smoothly as frames come in, then completes on the avalanche. 592 tests · lint clean · build green. --- src/islands/network/OpticalTransfer.tsx | 9 ++------- src/tools/optical/fountain.lib.ts | 14 +++++++++++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/islands/network/OpticalTransfer.tsx b/src/islands/network/OpticalTransfer.tsx index 8644ff6..7fa2edc 100644 --- a/src/islands/network/OpticalTransfer.tsx +++ b/src/islands/network/OpticalTransfer.tsx @@ -128,7 +128,6 @@ function Receiver({ onBack }: { onBack: () => void }) { useEffect(() => { if (!stream) return; if (!captureRef.current) captureRef.current = document.createElement('canvas'); - let collected = 0; const scan = () => { const video = videoRef.current; @@ -149,13 +148,9 @@ function Receiver({ onBack }: { onBack: () => void }) { decoderRef.current = new LtDecoder(frame.k, BLOCK_SIZE); } if (frame.session === metaRef.current.session && decoderRef.current) { - const before = decoderRef.current.solvedCount; const done = decoderRef.current.addFrame(frame.seq, frame.payload); - if (decoderRef.current.solvedCount !== before || decoderRef.current.progress() > 0) { - collected++; - setFrames(collected); - setProgress(decoderRef.current.progress()); - } + setFrames(decoderRef.current.framesSeen); + setProgress(decoderRef.current.progress()); if (done) finish(); } } diff --git a/src/tools/optical/fountain.lib.ts b/src/tools/optical/fountain.lib.ts index 364b759..1c45bf7 100644 --- a/src/tools/optical/fountain.lib.ts +++ b/src/tools/optical/fountain.lib.ts @@ -127,8 +127,20 @@ export class LtDecoder { return this.solvedCount >= this.k; } + /** Unique frames received so far. */ + get framesSeen(): number { + return this.seenSeq.size; + } + + /** + * Collection progress 0..1. LT codes solve almost nothing until they avalanche + * near the end, so reporting solved-blocks looks stuck at 0%. Report frames + * collected vs. the ~k×1.15 typically needed instead (capped below 1 until done). + */ progress(): number { - return this.k === 0 ? 1 : this.solvedCount / this.k; + if (this.done) return 1; + if (this.k === 0) return 1; + return Math.min(0.99, this.framesSeen / (this.k * 1.15)); } /** Feed one frame. Returns true once the whole file is solved. */