mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
refactor(runtime): trim color grading helpers
This commit is contained in:
@@ -119,10 +119,7 @@ describe("installRuntimeControlBridge", () => {
|
||||
const grading = { preset: "warm-clean", intensity: 0.7 };
|
||||
const target = { id: "hero-video", selectorIndex: 0 };
|
||||
handler(makeControlMessage("set-color-grading", { target, grading }));
|
||||
expect(deps.onSetColorGrading).toHaveBeenCalledWith(
|
||||
{ id: "hero-video", hfId: null, selector: null, selectorIndex: 0 },
|
||||
grading,
|
||||
);
|
||||
expect(deps.onSetColorGrading).toHaveBeenCalledWith(target, grading);
|
||||
});
|
||||
|
||||
it("dispatches set-color-grading-compare command with target and compare payload", () => {
|
||||
@@ -131,10 +128,7 @@ describe("installRuntimeControlBridge", () => {
|
||||
const compare = { enabled: true, position: 0.42 };
|
||||
const target = { id: "hero-video", selectorIndex: 0 };
|
||||
handler(makeControlMessage("set-color-grading-compare", { target, compare }));
|
||||
expect(deps.onSetColorGradingCompare).toHaveBeenCalledWith(
|
||||
{ id: "hero-video", hfId: null, selector: null, selectorIndex: 0 },
|
||||
compare,
|
||||
);
|
||||
expect(deps.onSetColorGradingCompare).toHaveBeenCalledWith(target, compare);
|
||||
});
|
||||
|
||||
it("dispatches tick command", () => {
|
||||
|
||||
@@ -20,30 +20,6 @@ type BridgeDeps = {
|
||||
onDisablePickMode: () => void;
|
||||
};
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function readOptionalString(value: unknown): string | null {
|
||||
return typeof value === "string" && value.trim() ? value : null;
|
||||
}
|
||||
|
||||
function readOptionalIndex(value: unknown): number | null {
|
||||
const parsed = Number(value);
|
||||
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : null;
|
||||
}
|
||||
|
||||
function readColorGradingTarget(value: unknown): HfColorGradingTarget | string | null {
|
||||
if (typeof value === "string") return value;
|
||||
if (!isRecord(value)) return null;
|
||||
return {
|
||||
id: readOptionalString(value.id),
|
||||
hfId: readOptionalString(value.hfId),
|
||||
selector: readOptionalString(value.selector),
|
||||
selectorIndex: readOptionalIndex(value.selectorIndex),
|
||||
};
|
||||
}
|
||||
|
||||
export function postRuntimeMessage(payload: RuntimeOutboundMessage): void {
|
||||
try {
|
||||
window.parent.postMessage(payload, "*");
|
||||
@@ -91,16 +67,11 @@ export function installRuntimeControlBridge(deps: BridgeDeps): (event: MessageEv
|
||||
return;
|
||||
}
|
||||
if (action === "set-color-grading") {
|
||||
const payload = isRecord(data) ? data : {};
|
||||
deps.onSetColorGrading(readColorGradingTarget(payload.target), payload.grading ?? null);
|
||||
deps.onSetColorGrading(data.target ?? null, data.grading ?? null);
|
||||
return;
|
||||
}
|
||||
if (action === "set-color-grading-compare") {
|
||||
const payload = isRecord(data) ? data : {};
|
||||
deps.onSetColorGradingCompare(
|
||||
readColorGradingTarget(payload.target),
|
||||
payload.compare ?? null,
|
||||
);
|
||||
deps.onSetColorGradingCompare(data.target ?? null, data.compare ?? null);
|
||||
return;
|
||||
}
|
||||
if (action === "enable-pick-mode") {
|
||||
|
||||
@@ -121,12 +121,10 @@ export type RuntimeColorGradingStatus =
|
||||
| { state: "active"; message: string }
|
||||
| { state: "unavailable"; message: string };
|
||||
|
||||
interface HfGlobalWithColorGrading {
|
||||
colorGrading?: RuntimeColorGradingApi;
|
||||
}
|
||||
|
||||
type WindowWithColorGrading = Window & {
|
||||
__hf?: HfGlobalWithColorGrading;
|
||||
__hf?: {
|
||||
colorGrading?: RuntimeColorGradingApi;
|
||||
};
|
||||
__hyperframes?: {
|
||||
getVariables?: () => Partial<Record<string, unknown>>;
|
||||
};
|
||||
@@ -161,10 +159,6 @@ const DEFAULT_COMPARE: RuntimeColorGradingCompareState = {
|
||||
lineWidth: 2,
|
||||
};
|
||||
|
||||
function readColorGradingRawAttribute(element: Element): string | null {
|
||||
return element.getAttribute(HF_COLOR_GRADING_ATTR);
|
||||
}
|
||||
|
||||
function readVariablesForElement(element: Element): HfColorGradingVariableMap {
|
||||
const win = window as WindowWithColorGrading;
|
||||
const scope = element.closest("[data-composition-id]");
|
||||
@@ -180,7 +174,7 @@ function readVariablesForElement(element: Element): HfColorGradingVariableMap {
|
||||
}
|
||||
|
||||
function readColorGradingAttribute(element: Element): NormalizedHfColorGrading | null {
|
||||
const raw = readColorGradingRawAttribute(element);
|
||||
const raw = element.getAttribute(HF_COLOR_GRADING_ATTR);
|
||||
if (raw == null) return null;
|
||||
return normalizeHfColorGradingWithVariables(raw, readVariablesForElement(element));
|
||||
}
|
||||
@@ -680,21 +674,24 @@ function parseObjectPosition(value: string): { x: number; y: number } {
|
||||
const tokens = value.trim().split(/\s+/).filter(Boolean);
|
||||
let x = 0.5;
|
||||
let y = 0.5;
|
||||
for (const token of tokens) {
|
||||
for (let index = 0; index < tokens.length; index++) {
|
||||
const token = tokens[index] ?? "";
|
||||
const xValue = parseObjectPositionPart(token, "x");
|
||||
const yValue = parseObjectPositionPart(token, "y");
|
||||
if (xValue !== null && (token === "left" || token === "right" || token.endsWith("%"))) {
|
||||
if (
|
||||
xValue !== null &&
|
||||
(token === "left" || token === "right" || (token.endsWith("%") && index === 0))
|
||||
) {
|
||||
x = xValue;
|
||||
continue;
|
||||
}
|
||||
if (yValue !== null && (token === "top" || token === "bottom")) {
|
||||
if (
|
||||
yValue !== null &&
|
||||
(token === "top" || token === "bottom" || (token.endsWith("%") && index > 0))
|
||||
) {
|
||||
y = yValue;
|
||||
continue;
|
||||
}
|
||||
if (token === "center") {
|
||||
if (x === 0.5) x = 0.5;
|
||||
else y = 0.5;
|
||||
}
|
||||
}
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
@@ -272,11 +272,10 @@ describe("createVideoFrameInjector cache hygiene against page-side skips", () =>
|
||||
injectVideoFramesBatchMock.mockResolvedValueOnce(["facet"]);
|
||||
await hook!(page, 1.5);
|
||||
|
||||
expect(evaluate).toHaveBeenCalledTimes(1);
|
||||
// Re-render is requested at the same time as the seek.
|
||||
expect(evaluate.mock.calls[0]![1]).toBe(1.5);
|
||||
const reseekCall = evaluate.mock.calls.find((call) => call[1] === 1.5);
|
||||
expect(reseekCall).toBeDefined();
|
||||
// The evaluated page function invokes window.__hfReseekGpu(time).
|
||||
const pageFn = evaluate.mock.calls[0]![0] as (t: number) => void;
|
||||
const pageFn = reseekCall![0] as (t: number) => void;
|
||||
const reseek = vi.fn();
|
||||
(globalThis as unknown as { window?: unknown }).window = { __hfReseekGpu: reseek };
|
||||
pageFn(1.5);
|
||||
@@ -296,6 +295,6 @@ describe("createVideoFrameInjector cache hygiene against page-side skips", () =>
|
||||
injectVideoFramesBatchMock.mockResolvedValueOnce([]);
|
||||
await hook!(page, 1.5);
|
||||
|
||||
expect(evaluate).not.toHaveBeenCalled();
|
||||
expect(evaluate.mock.calls.some((call) => call[1] === 1.5)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -147,7 +147,7 @@ function createFrameSourceCache(
|
||||
export const __testing = { createFrameSourceCache };
|
||||
|
||||
async function redrawRuntimeColorGrading(page: Page): Promise<void> {
|
||||
await page.evaluate(async () => {
|
||||
await page.evaluate(() => {
|
||||
const hf = (
|
||||
window as Window & {
|
||||
__hf?: {
|
||||
@@ -158,7 +158,7 @@ async function redrawRuntimeColorGrading(page: Page): Promise<void> {
|
||||
const redraw = hf?.colorGrading?.redraw;
|
||||
if (typeof redraw !== "function") return;
|
||||
try {
|
||||
await Promise.resolve(redraw());
|
||||
redraw();
|
||||
} catch {
|
||||
// Optional page-side shader layer.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user