Files
hyperframes/packages/core/src/previewProxyBox.ts
Miguel Ángel b66e8a195e perf(studio): preview decodes hard-to-play videos at the size they are shown (#5184)
* perf(studio): preview decodes hard-to-play videos at the size they are shown

Studio's copy of an HEVC or ProRes clip was made at the source's full size, so a 4K clip was decoded at 4K inside a preview a few hundred pixels wide, and back-to-back 4K clips flashed the background at their cuts. The player now reports how large it shows the composition, the runtime asks for a copy sized to the shown video (on a ladder of sizes, never above the source), and Studio stops pre-warming source-size copies. CLI play, static serving, publish and renders keep the source-size copy.

* fix(studio): sized preview copies follow zoom, hover previews and the newest size

Studio reports the preview's on-screen scale when a zoom settles and for composition hover previews, which no player measures. The runtime loads only the newest size asked for, regrows a first copy made while the frame grew, and never replaces a copy with one smaller on either side. The player's scale is measured against the frame's own layout width.

* fix(studio): keep comment shares and file sizes within the repo ratchets

* test(studio-server): end the sizing test's ffprobe options before its input

* fix(studio): hover previews report their size once their runtime is ready
2026-10-08 00:26:08 +00:00

33 lines
1.3 KiB
TypeScript

/** Query parameter carrying the largest box, in device pixels, a preview shows a proxied video at. */
export const PREVIEW_PROXY_BOX_PARAM = "hf-proxy-box";
export type PreviewProxyBox = { width: number; height: number };
// 256 * 2^(k/2), even: nearby boxes share one cached copy, and a rung overshoots by at most ~41%.
const RUNGS = [256, 362, 512, 724, 1024, 1448, 2048, 2896, 4096, 5792, 8192];
function rungAtLeast(pixels: number): number | null {
if (!(pixels > 0)) return null;
return RUNGS.find((rung) => rung >= pixels) ?? null;
}
/** Rounds a shown box up to the size ladder; null when it is empty or larger than any rung. */
export function quantizePreviewProxyBox(width: number, height: number): PreviewProxyBox | null {
const w = rungAtLeast(width);
const h = rungAtLeast(height);
return w && h ? { width: w, height: h } : null;
}
export function formatPreviewProxyBox(box: PreviewProxyBox): string {
return `${box.width}x${box.height}`;
}
/** Accepts only ladder rungs, so a client cannot make one cached copy per pixel. */
export function parsePreviewProxyBox(raw: string): PreviewProxyBox | null {
const match = /^(\d{3,4})x(\d{3,4})$/.exec(raw);
if (!match) return null;
const width = Number(match[1]);
const height = Number(match[2]);
return RUNGS.includes(width) && RUNGS.includes(height) ? { width, height } : null;
}