feat: add video frame format render option (#1481)

* feat: add video frame format render option

* refactor: single source of truth for video-frame-format allow-list

Addresses PR review (Via) on #1481: the ["auto","jpg","png"] set was
declared three times — render.ts (VIDEO_FRAME_FORMATS), server.ts
(inline includes), and renderConfigValidation.ts
(ALLOWED_VIDEO_FRAME_FORMATS) — three boundaries to update when a new
extraction format lands.

Hoist the constant + a reusable `isVideoFrameFormat` type guard into
@hyperframes/engine (where VideoFrameFormat is defined) and route all
three call sites through them. Behavior unchanged; also drops two
`as RenderConfig[...]` casts in favor of the guard (narrowing over
assertion, per repo TS conventions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Xuelong Mu <xuelongmu@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
James Russo
2026-06-15 22:05:20 -07:00
committed by GitHub
co-authored by Claude Opus 4.8 Xuelong Mu
parent e812fc8895
commit 36b24acf20
18 changed files with 392 additions and 17 deletions
+9 -1
View File
@@ -33,8 +33,10 @@ import {
RenderCancelledError,
createRenderJob,
executeRenderJob,
type RenderConfig,
} from "./services/renderOrchestrator.js";
import { prepareHyperframeLintBody, runHyperframeLint } from "./services/hyperframeLint.js";
import { isVideoFrameFormat } from "@hyperframes/engine";
import { resolveRenderPaths } from "./utils/paths.js";
import { defaultLogger, type ProducerLogger } from "./logger.js";
import { Semaphore } from "./utils/semaphore.js";
@@ -72,6 +74,7 @@ interface RenderInput {
fps: import("@hyperframes/core").Fps;
quality: "draft" | "standard" | "high";
format?: "mp4" | "webm" | "mov";
videoFrameFormat?: RenderConfig["videoFrameFormat"];
workers?: number;
useGpu: boolean;
debug: boolean;
@@ -125,7 +128,10 @@ export function parseRenderOptions(body: Record<string, unknown>): Omit<RenderIn
const format = (
["mp4", "webm", "mov"].includes(body.format as string) ? body.format : undefined
) as "mp4" | "webm" | "mov" | undefined;
) as RenderInput["format"];
const videoFrameFormat = isVideoFrameFormat(body.videoFrameFormat)
? body.videoFrameFormat
: undefined;
const { variables, outputResolution } = parseRenderOverrides(body);
@@ -140,6 +146,7 @@ export function parseRenderOptions(body: Record<string, unknown>): Omit<RenderIn
format,
variables,
outputResolution,
videoFrameFormat,
};
}
@@ -183,6 +190,7 @@ function buildRenderJobConfig(input: RenderInput, log: ProducerLogger) {
entryFile: input.entryFile,
variables: input.variables,
outputResolution: input.outputResolution,
videoFrameFormat: input.videoFrameFormat,
logger: log,
};
}