MCPcopy Create free account
hub / github.com/heygen-com/hyperframes / keepsMoving

Function keepsMoving

packages/cli/src/utils/motionAudit.ts:164–208  ·  view source on GitHub ↗
(
  frames: MotionFrame[],
  within: string | undefined,
  maxStaticSec: number,
)

Source from the content-addressed store, hash-verified

162}
163
164function keepsMoving(
165 frames: MotionFrame[],
166 within: string | undefined,
167 maxStaticSec: number,
168): LayoutIssue[] {
169 // "*" is reserved for whole-canvas scope; motionSpec.ts rejects it as a user-supplied withinSelector.
170 const scope = within ?? "*";
171 if (within && frames.every((frame) => !frame.liveness[scope])) {
172 return [missingIssue(within, 0)];
173 }
174
175 const issues: LayoutIssue[] = [];
176 const first = frames[0];
177 if (!first) return issues;
178 let runStart = first.time;
179 let runSig = first.liveness[scope] ?? "";
180 const flush = (endTime: number) => {
181 const span = endTime - runStart;
182 if (span > maxStaticSec) {
183 issues.push({
184 code: "motion_frozen",
185 severity: "error",
186 time: runStart,
187 selector: within ?? "composition",
188 message: `nothing moves${within ? ` within ${within}` : ""} between ${round(runStart)}s and ${round(endTime)}s (${round(span)}s static) — should keep moving`,
189 rect: ZERO_RECT,
190 fixHint:
191 "Add or extend motion so no shot freezes for this long, or shorten the static hold.",
192 });
193 }
194 };
195
196 let lastTime = runStart;
197 for (const frame of frames.slice(1)) {
198 lastTime = frame.time;
199 const sig = frame.liveness[scope] ?? "";
200 if (sig !== runSig) {
201 flush(frame.time);
202 runStart = frame.time;
203 runSig = sig;
204 }
205 }
206 flush(lastTime);
207 return issues;
208}
209
210/**
211 * Evaluate motion assertions against the dense `element × time` matrix.

Callers 1

evaluateMotionFunction · 0.85

Calls 2

missingIssueFunction · 0.85
flushFunction · 0.70

Tested by

no test coverage detected