mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-08-31 02:41:44 +00:00
fix(cli): respect timeline-free static compositions (#3533)
This commit is contained in:
@@ -145,6 +145,7 @@ function fakeDriver(overrides: Partial<CheckAuditDriver> = {}): CheckAuditDriver
|
||||
return {
|
||||
initialize: vi.fn(async (_contrast: boolean) => undefined),
|
||||
getDuration: vi.fn(async () => 9),
|
||||
hasNoTimelineDeclaration: vi.fn(async () => false),
|
||||
getTransitionBoundaries: vi.fn(async () => []),
|
||||
getCanvas: vi.fn(async () => ({ width: 1920, height: 1080 })),
|
||||
findAmbiguousSelectors: vi.fn(async (_selectors: string[]) => []),
|
||||
@@ -1222,6 +1223,18 @@ describe("check pipeline", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("does not flag intentional static content declared with data-no-timeline", async () => {
|
||||
const driver = fakeDriver({
|
||||
getDuration: vi.fn(async () => 6),
|
||||
hasNoTimelineDeclaration: vi.fn(async () => true),
|
||||
collectLayoutGeometry: vi.fn(async () => "frozen"),
|
||||
});
|
||||
|
||||
const { report } = await runScenario(driver);
|
||||
|
||||
expect(report.layout.findings.some((finding) => finding.code === "sweep_static")).toBe(false);
|
||||
});
|
||||
|
||||
it("does not flag a 1.5s static title card — too short for the guard to apply", async () => {
|
||||
const driver = fakeDriver({
|
||||
getDuration: vi.fn(async () => 1.5),
|
||||
|
||||
@@ -395,6 +395,7 @@ function createPageDriver(page: Page, setTime: (time: number) => void): CheckAud
|
||||
return {
|
||||
initialize: (contrast) => injectAuditScripts(page, contrast),
|
||||
getDuration: () => getCompositionDuration(page),
|
||||
hasNoTimelineDeclaration: () => hasNoTimelineDeclaration(page),
|
||||
getTransitionBoundaries: () => collectTweenBoundaries(page),
|
||||
getCanvas: () =>
|
||||
page.evaluate(() => ({ width: window.innerWidth, height: window.innerHeight })),
|
||||
@@ -420,6 +421,13 @@ function createPageDriver(page: Page, setTime: (time: number) => void): CheckAud
|
||||
};
|
||||
}
|
||||
|
||||
async function hasNoTimelineDeclaration(page: Page): Promise<boolean> {
|
||||
return page.evaluate(
|
||||
() =>
|
||||
document.querySelector("[data-composition-id]")?.hasAttribute("data-no-timeline") ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
async function injectAuditScripts(page: Page, contrast: boolean): Promise<void> {
|
||||
await page.addScriptTag({ content: loadBrowserScript("layout-audit.browser.js") });
|
||||
await page.addScriptTag({ content: loadBrowserScript("motion-sample.browser.js") });
|
||||
|
||||
@@ -492,7 +492,9 @@ function detectSweepStatic(
|
||||
duration: number,
|
||||
geometrySignatures: string[],
|
||||
motionIssues: AnchoredLayoutIssue[],
|
||||
hasNoTimelineDeclaration: boolean,
|
||||
): AnchoredLayoutIssue[] {
|
||||
if (hasNoTimelineDeclaration) return [];
|
||||
if (duration < SWEEP_STATIC_MIN_DURATION_SEC) return [];
|
||||
if (geometrySignatures.length < 2) return [];
|
||||
if (motionIssues.some((issue) => issue.code === "motion_frozen")) return [];
|
||||
@@ -1071,6 +1073,7 @@ export async function runAuditGrid(
|
||||
grid.duration,
|
||||
collected.geometrySignatures,
|
||||
motionIssues,
|
||||
await driver.hasNoTimelineDeclaration(),
|
||||
);
|
||||
const rotationFindings = detectRotationPivotDrift(
|
||||
collected.rotationSamples,
|
||||
|
||||
@@ -179,6 +179,8 @@ export type MotionSpecResolution =
|
||||
export interface CheckAuditDriver {
|
||||
initialize(contrast: boolean): Promise<void>;
|
||||
getDuration(): Promise<number>;
|
||||
/** True when the root composition explicitly declares that it is intentionally timeline-free. */
|
||||
hasNoTimelineDeclaration(): Promise<boolean>;
|
||||
getTransitionBoundaries(): Promise<number[]>;
|
||||
getCanvas(): Promise<Canvas>;
|
||||
findAmbiguousSelectors(selectors: string[]): Promise<AnchoredLayoutIssue[]>;
|
||||
|
||||
Reference in New Issue
Block a user