Skip to content

feat(studio): preview copy progress, retry and a remembered quality - #6366

Merged
miguel-heygen merged 25 commits into
mainfrom
checklong/preview-quality-progress
Oct 26, 2026
Merged

miguel-heygen merged 25 commits into
mainfrom
checklong/preview-quality-progress

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

What

  • Shows how far each lighter copy has got: the server reports progress on the wait reply, and the runtime relays a short summary of the copies wanted, ready, waiting and failed (about once a second).
  • A failed copy can be retried; retrying clears that copy's remembered failure.
  • The chosen quality is saved per computer and restored on load (unknown value falls back to full quality). A pick made by a person is never overridden by an automatic change.
  • Reports how playback is going: over a rolling 3 s window of playing, the share of frames due but not drawn, or of time a playing video waited for data, whichever is larger. choppy is true at 25% or more. Only play is measured (not paused or scrubbing), the first second after play starts or after a seek is ignored, and the window restarts on a level change, a copy swap, a scene mount, a window or zoom change, a rate change, a hidden page, and a project reload. Renders never measure. All numbers sit in one constant block (PLAYBACK_HEALTH).
  • On request, reports what the preview holds as counts and classes only: scene count, mounted element count, duration, videos grouped by codec, size and bit depth, and whether the lighter copies are ready.

Why

A wait of tens of seconds on a big file looked like a hang. People need to see progress, retry a failure, and keep their choice between sessions, and the host needs to know when a level is too heavy for the machine.

Tests

Server tests for progress and retry; runtime tests for reporting, retry, the health window and the video grouping; store, router, forwarding hook and preference tests in studio. Health tests fail when the threshold or the warm-up is removed.

Before

The Studio player store on main, driven by the real preview: playing, and nothing else to read. The panel is a dev-only readout of the store (the dev handle), added to the page by the capture script.

Before: player store on main, only isPlaying

After

The same project and playback with this PR, quality set to 1/2: the store holds the chosen quality and who chose it, a playback health reading from 3 s of play, and the preview facts. This is a store and runtime change; the controls that use it ship in the host app.

After: player store with quality 1/2, playback health and preview facts

@miguel-heygen
miguel-heygen force-pushed the checklong/preview-quality-progress branch 3 times, most recently from 0ff271c to f414d18 Compare October 25, 2026 23:52

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 2 blockers · 0 important · 0 nits

Both blockers are inline: the studio build breaks, and a retry of a file that keeps failing re-transcodes forever. The Comments ratchet is also red: core/src/previewProxyBox.ts goes from 14.9% to 16.5% (+2 lines, the new param/header docs).

Scope

Reviewed the stack delta 6fb77f5e..f414d182: previewCopies reporting and throttling, proxyWait progress, the retry path from client to server, the studio slice, forwarding, preferences and the message router. Failure evidence for the build comes from the Player Safari perf run on this head (Run bun run build). preview-regression, regression and Player perf were still running when I posted this.

try {
// A cached copy settles before any timer; a transcode never holds one of
// the browser's few connections to this host. 202 until the copy lands.
if (c.req.query(PREVIEW_PROXY_RETRY_PARAM) !== undefined) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[blocker] Retrying a copy that keeps failing re-transcodes forever and never reports failed. retryNext.delete(el) adds hf-proxy-retry=1 to href once, but waitForServedProxy polls that same href on every ask. Each poll lands here and clears failedTranscodes, so resolveProxy starts a fresh ffmpeg job and the reply is 202 again. A non-OK reply never comes back, so failed never reaches MAX_FAILED_ASKS.

How to trigger it: a corrupt source fails, then the user clicks retry. The copy stays at "making" and ffmpeg reruns every Retry-After seconds. The URL that finally loads also keeps the flag on every range request.

Fix: send the retry only on the first ask. One option is to give waitForServedProxy a first-ask-only href, or strip the param after one fetch. A server-side guard that clears only when no job is in flight does not help, because the failed job has already left inFlight. A test where the transcode fails twice and the stub expects one restart would pin this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Fixed in 1eae0d1 (723e5c4: retry flag on the first ask only).

@@ -1,3 +1,4 @@
import { isPreviewQuality, type PreviewQuality } from "@hyperframes/core";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[blocker] The studio build fails. These are the studio's first value imports from the @hyperframes/core root; the existing root imports are all import type. The same goes for PREVIEW_QUALITY_LEVELS in studio/src/index.ts:37. The root index pulls safePath, hyperframesRuntime.engine and parsers' assetPaths into the browser bundle. Player Safari perf at this head fails in bun run build with ../parsers/src/assetPaths.ts (8:31): "resolve" is not exported by "__vite-browser-external".

Fix: export previewProxyBox through a browser-safe subpath, for example @hyperframes/core/preview-proxy-box next to ./studio-preview-mark, and import from that in both places.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Fixed in d8f546b (@hyperframes/core/preview-quality).

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 0 resolved, 2 open, 0 new · f414d182 → 3453b93d

Neither earlier blocker is fixed at this head. studioUiPreferences.ts:1 and studio/src/index.ts:37 still import values from the @hyperframes/core root. routes/preview.ts:759 still honours hf-proxy-retry on every poll, while proxyWait keeps re-fetching the same href. The new playbackHealth and preview-facts code adds no new finding.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 resolved, 1 open, 0 new · 3453b93d → d8f546b1

The build fix holds: the new ./preview-quality entry is pinned by lightEntries.test.ts. The retry loop is still open, because routes/preview.ts:759 honours hf-proxy-retry on every poll of the same href. The Comments ratchet is still red on previewProxyBox.ts (14.9% → 15.2%, +1 line).

@miguel-heygen
miguel-heygen force-pushed the checklong/preview-quality-copies branch from 2655700 to 2d5faf8 Compare October 26, 2026 02:38
@miguel-heygen
miguel-heygen force-pushed the checklong/preview-quality-progress branch from d8f546b to 5318ef2 Compare October 26, 2026 02:45

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 0 resolved, 1 open, 0 new · d8f546b1 → a027e9c5

The retry loop is still open. routes/preview.ts:759 still honours hf-proxy-retry on every poll of the same href, and proxyWait.ts is unchanged. This head sits on #6365 2d5faf88, which is not fixed yet: it still fails typecheck there (CopyJob.level: number, mediaProxy.ts:391). The CI workflow does not run on this stacked PR, so nothing here catches that.

@miguel-heygen
miguel-heygen force-pushed the checklong/preview-quality-progress branch from a027e9c to 723e5c4 Compare October 26, 2026 03:29

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 resolved, 0 open, 1 new · a027e9c5 → 1eae0d17

The retry loop is fixed: proxyWait sends the flag on the first ask only, and the new test pins it. Typecheck passes locally for core, studio and studio-server. [blocker] The Comments check fails at this head against b3dc2150:

  • previewProxyBox.ts +1 comment line
  • proxyTranscoder.ts +2 comment lines
  • useTimelinePlayer.ts +1, from the new fallow-ignore-next-line complexity directive

The other workflows pass.

Base automatically changed from checklong/preview-quality-copies to main October 26, 2026 04:13
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 134 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

Unstable (1)

  • seqplainkeys-none-pct-r0-root-z100: tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo false, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true

@miguel-heygen
miguel-heygen force-pushed the checklong/preview-quality-progress branch from 1eae0d1 to 60471b0 Compare October 26, 2026 04:55

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 resolved, 0 open, 1 new · 1eae0d17 → b5d0681d

The rebase onto main (after #6365) carries the reviewed commits through unchanged. The comment cuts, the playerStore line cap and the producer unpacked budget (raised to 3015439 with the reason in the body) are fine. CI, regression and Windows pass on this head. I re-ran a regression shard that failed on a docker layer fetch, and the first CI run's edit-accuracy miss passed on the second run (271/271).

[blocker] The required Studio and player captures check fails. The body has no ## Before / ## After sections, and this PR changes packages/studio. Add the captures, or use ## No visible change if the gate's size rule allows it, then re-run the check.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 resolved, 0 open, 1 new · b5d0681d → 7897e457

The captures are in the body, and the check passes. The health-window fixes are sound: noteDisplayScale restarts only on a changed scale, and a scene mount no longer clears the window. CI, regression, captures and both perf runs pass on this head. One of the two Windows runs passed. The other failed in gsapValueAtPlayhead.browser.test.ts, which this PR does not touch, so it looks flaky.

[blocker] The PR no longer merges: mergeStateStatus is DIRTY. main raised the producer unpacked budget to 2897429 in scripts/package-size-budgets.json, which conflicts with this PR's 3015439. Rebase onto main, then re-measure the producer size on top of main before choosing the budget.

@miguel-heygen
miguel-heygen force-pushed the checklong/preview-quality-progress branch from 7897e45 to 16f11bb Compare October 26, 2026 07:23

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 1 resolved, 0 open, 0 new · 7897e457 → 16f11bb7

The rebase onto main carries every reviewed commit through unchanged and drops only the budget commit. scripts/package-size-budgets.json is no longer touched, and the PR merges cleanly. Every workflow passes on this head: CI including packed sizes, regression, Windows, captures, both perf runs, preview-regression, Comments and CodeQL. The CodeQL note on previewMessageRouter.ts:142 is a false positive: the lookup only reaches three fixed handlers, and any other message type matches none of them, so no unexpected method runs.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 0 resolved, 0 open, 0 new · 16f11bb7 → e9d22a65

The one change is applyStoreReport, which replaces the Map lookup with a switch over the three report types. Behaviour is unchanged: any other type returns false and falls through as before. Every workflow passes on this head, including CodeQL.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 26, 2026
Merged via the queue into main with commit 84fd701 Oct 26, 2026
81 checks passed
@miguel-heygen
miguel-heygen deleted the checklong/preview-quality-progress branch October 26, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants