Files
hyperframes/packages/core/src/runtime/protocol.ts
T
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

108 lines
3.5 KiB
TypeScript

export const RUNTIME_PROTOCOL_VERSION = 1 as const;
export const RUNTIME_FILLER = "hf-runtime-filler";
export const RUNTIME_PROTOCOL_CAPABILITIES = [
"seconds-time",
"rational-fps",
"seek-keep-playing",
"composition-manifest-v1",
"runtime-data",
"play-range",
] as const;
export type RuntimeProtocolFps = {
numerator: number;
denominator: number;
};
export type RuntimeProtocolV1 = {
protocolVersion: typeof RUNTIME_PROTOCOL_VERSION;
capabilities: readonly string[];
fps: RuntimeProtocolFps;
};
export type RuntimeProtocolInspection =
| { status: "legacy"; fps: number }
| { status: "supported"; fps: number; metadata: RuntimeProtocolV1 }
| {
status: "unsupported";
code: "unsupported_protocol_version" | "invalid_protocol_metadata";
receivedVersion: unknown;
};
function greatestCommonDivisor(a: number, b: number): number {
let left = Math.abs(a);
let right = Math.abs(b);
while (right !== 0) {
const remainder = left % right;
left = right;
right = remainder;
}
return left || 1;
}
export function runtimeProtocolFpsFromNumber(value: number): RuntimeProtocolFps {
const safe = Number.isFinite(value) && value > 0 ? value : 30;
const denominator = Number.isInteger(safe) ? 1 : 1_000_000;
const numerator = Math.round(safe * denominator);
const divisor = greatestCommonDivisor(numerator, denominator);
return { numerator: numerator / divisor, denominator: denominator / divisor };
}
export function playRangeHoldTime(start: number, end: number, fps: number): number {
return Math.max(start, (Math.ceil(end * fps - 1e-6) - 1) / fps);
}
export function runtimeProtocolFpsToNumber(value: unknown): number | null {
if (typeof value !== "object" || value === null) return null;
const fps = value as Partial<RuntimeProtocolFps>;
if (!Number.isFinite(fps.numerator) || !Number.isFinite(fps.denominator)) return null;
if ((fps.numerator ?? 0) <= 0 || (fps.denominator ?? 0) <= 0) return null;
return Number(fps.numerator) / Number(fps.denominator);
}
export function runtimeProtocolMetadata(fps: number): RuntimeProtocolV1 {
return {
protocolVersion: RUNTIME_PROTOCOL_VERSION,
capabilities: RUNTIME_PROTOCOL_CAPABILITIES,
fps: runtimeProtocolFpsFromNumber(fps),
};
}
export function frameDisplayScale(frame: HTMLElement): number | null {
const layoutWidth = frame.offsetWidth;
const shownWidth = frame.getBoundingClientRect().width;
return layoutWidth > 0 && shownWidth > 0 ? shownWidth / layoutWidth : null;
}
function hasDeclaredCapabilities(value: unknown): boolean {
return Array.isArray(value) && value.every((capability) => typeof capability === "string");
}
export function inspectRuntimeProtocol(value: unknown, legacyFps = 30): RuntimeProtocolInspection {
if (typeof value !== "object" || value === null) return { status: "legacy", fps: legacyFps };
const message = value as Record<string, unknown>;
if (message.protocolVersion === undefined) return { status: "legacy", fps: legacyFps };
if (message.protocolVersion !== RUNTIME_PROTOCOL_VERSION) {
return {
status: "unsupported",
code: "unsupported_protocol_version",
receivedVersion: message.protocolVersion,
};
}
const fps = runtimeProtocolFpsToNumber(message.fps);
if (fps === null || !hasDeclaredCapabilities(message.capabilities)) {
return {
status: "unsupported",
code: "invalid_protocol_metadata",
receivedVersion: message.protocolVersion,
};
}
return {
status: "supported",
fps,
metadata: message as RuntimeProtocolV1,
};
}