mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(engine): detect onUpdate callbacks and enable verification events (#3794)
The static-frame dedup predictor walked tween intervals from window.__timelines but was blind to onUpdate callbacks — motion driven from a timeline's onUpdate in a tween-free window was predicted static. The verifier compounded the gap by seeking with suppressEvents: true, so the onUpdate never fired and the frozen frame passed verification. Two changes: 1. Predictor: when a timeline carries vars.onUpdate, mark its full span as animated so those frames are never predicted static. 2. Verifier: seek with suppressEvents: false so the verification page behaves identically to the capture page. The verification page is already isolated (separate Page instance), so out-of-order event side effects cannot corrupt sequential capture. Fixes #3793
This commit is contained in:
@@ -70,7 +70,7 @@ describe("verifyStaticFramesSafe catches drift the old fixed-point density would
|
||||
expect(result.badFrame).toBe(changeAt);
|
||||
});
|
||||
|
||||
it("uses silent verification seeks and restores the playhead to frame zero", async () => {
|
||||
it("uses event-enabled verification seeks and restores the playhead to frame zero", async () => {
|
||||
const seekCalls: Array<{ t: number; options?: { suppressEvents?: boolean } }> = [];
|
||||
const page = {
|
||||
evaluate: vi.fn(async (fn: (tt: number) => void, t: number) => {
|
||||
@@ -103,7 +103,7 @@ describe("verifyStaticFramesSafe catches drift the old fixed-point density would
|
||||
|
||||
expect(result.outcome).toBe("verified");
|
||||
expect(seekCalls.map((call) => Math.round(call.t * fps))).toEqual([0, 3, 0]);
|
||||
expect(seekCalls.every((call) => call.options?.suppressEvents === true)).toBe(true);
|
||||
expect(seekCalls.every((call) => call.options?.suppressEvents === false)).toBe(true);
|
||||
});
|
||||
|
||||
it("disarms within a wall-clock budget instead of spending minutes verifying a long static run", async () => {
|
||||
|
||||
@@ -2736,6 +2736,13 @@ export async function computeStaticFrameSet(
|
||||
let hasTimelineCall = false;
|
||||
function walk(tl: AnyTween, offset: number): void {
|
||||
if (typeof tl.getChildren !== "function") return;
|
||||
// A timeline with an onUpdate callback can drive motion without any
|
||||
// visible tween (e.g. setting x/y from Math.random inside onUpdate).
|
||||
// Mark its entire span as animated so those frames are never deduped.
|
||||
if (typeof tl.vars?.onUpdate === "function") {
|
||||
const total = typeof tl.totalDuration === "function" ? tl.totalDuration() : 0;
|
||||
if (total > 0) intervals.push({ start: offset, end: offset + total });
|
||||
}
|
||||
for (const child of tl.getChildren(false, true, true)) {
|
||||
const start = offset + (typeof child.startTime === "function" ? child.startTime() : 0);
|
||||
const single = typeof child.duration === "function" ? child.duration() : 0;
|
||||
@@ -3054,8 +3061,9 @@ interface StaticVerificationDependencies {
|
||||
|
||||
/**
|
||||
* Prepare an isolated page for static-frame verification. Verification seeks
|
||||
* intentionally visit frames out of capture order, so they must never mutate
|
||||
* the page that will later be captured sequentially.
|
||||
* intentionally visit frames out of capture order on a SEPARATE page that is
|
||||
* never used for the real capture — out-of-order event-callback side effects
|
||||
* are contained to this disposable page and cannot corrupt sequential capture.
|
||||
*/
|
||||
export async function createStaticVerificationPage(session: CaptureSession): Promise<Page> {
|
||||
const page = await session.browser.newPage();
|
||||
@@ -3167,7 +3175,7 @@ export async function verifyStaticFramesSafe(
|
||||
__hf?: { seek?: (t: number, options?: { suppressEvents?: boolean }) => void };
|
||||
}
|
||||
).__hf;
|
||||
if (hf && typeof hf.seek === "function") hf.seek(tt, { suppressEvents: true });
|
||||
if (hf && typeof hf.seek === "function") hf.seek(tt, { suppressEvents: false });
|
||||
}, t);
|
||||
};
|
||||
const hardCap = Math.max(
|
||||
|
||||
Reference in New Issue
Block a user