mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
`--width 3840 --height 2160` against a composition with `data-width="1920"` silently produces a 1080p output because the runtime lays out the page at the composition's authored dimensions — real footgun we hit during a cost-analysis sweep. Warn early and point at `--output-resolution` (the supersampling escape hatch) so the user doesn't burn a 30-minute render learning the override rule. Skipped when `--output-resolution` is set (the supported supersampling path — the user is opting in), when `--json` is set (machine consumers), or when `index.html` isn't on disk (typical with `--site-id`). Helper lives in a shared module so render + render-batch agree on the parse + message. Tests cover both attribute orders, single/double quotes, the silent paths, and the warning path. Best-effort regex over the canonical attr shape — malformed HTML falls through to no warning rather than blocking the render. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
37 lines
1.4 KiB
TypeScript
37 lines
1.4 KiB
TypeScript
import { ensureDOMParser } from "./dom.js";
|
||
|
||
const DEFAULT_VIEWPORT = { width: 1920, height: 1080 } as const;
|
||
const MAX_VIEWPORT_DIMENSION = 4096;
|
||
|
||
function parseViewportDimension(value: string | null): number | null {
|
||
if (!value) return null;
|
||
const parsed = Number.parseInt(value, 10);
|
||
if (!Number.isFinite(parsed) || parsed <= 0) return null;
|
||
return Math.min(parsed, MAX_VIEWPORT_DIMENSION);
|
||
}
|
||
|
||
/**
|
||
* Pull `data-width` + `data-height` from the document's first composition
|
||
* root (the element with `data-composition-id` plus both dimension attrs
|
||
* — the same selector the producer uses to lay out the page). Returns
|
||
* `null` when no such root exists or either attr is invalid, so callers
|
||
* can distinguish "no declared dimensions" from "declared 1920×1080".
|
||
*/
|
||
export function findCompositionDimensions(html: string): { width: number; height: number } | null {
|
||
ensureDOMParser();
|
||
const doc = new DOMParser().parseFromString(html, "text/html");
|
||
const root = doc.querySelector("[data-composition-id][data-width][data-height]");
|
||
if (!root) return null;
|
||
const width = parseViewportDimension(root.getAttribute("data-width"));
|
||
const height = parseViewportDimension(root.getAttribute("data-height"));
|
||
if (width === null || height === null) return null;
|
||
return { width, height };
|
||
}
|
||
|
||
export function resolveCompositionViewportFromHtml(html: string): {
|
||
width: number;
|
||
height: number;
|
||
} {
|
||
return findCompositionDimensions(html) ?? DEFAULT_VIEWPORT;
|
||
}
|