mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
* feat(engine): adaptive per-frame sample count for motion blur Measured against the accuracy bar set in #4010 (72.4dB mean PSNR vs the 960fps shutter integral), the fixed default of 16 samples misses it for hard-edge content while paying nothing extra for static/slow content is still important. This picks a sample count per frame from measured motion, floor 16 ceiling 64 (issue #4029). Two probe captures at the true shutter-window edges (never a sample that enters the average) measure motion magnitude, mapped through a monotone step table to a sample count. Frames confirmed to move only non-spatial properties (opacity, colour) skip the probe and use the floor directly, since a fade's shutter integral is a smooth blend that does not need many samples. MotionBlurPlan's window (from shutter angle/phase alone) is now independent of how many samples fill it, which is what lets the count vary per frame without moving the window; motionBlurWindowIsStatic is bounded by the widest sample inset any chosen K could produce so the static-dedup safety guarantee holds for every K in [16, 64]. * refactor(engine): simplify the adaptive motion-blur sample selection Two findings from an independent code-reuse/quality/efficiency review of the previous commit: - armStaticDedup ran the GSAP-timeline walk (computeStaticFrameSet) twice on the same page when adaptive motion blur and static dedup both apply, once for each purpose. Shares the one result instead. - The non-spatial floor path read the sample count from adaptiveSampleCount(0), which only worked because the step table happens to be sorted with the first bucket covering zero. Reads the now-exported DEFAULT_SAMPLES_PER_FRAME directly instead. * fix(engine): read raw options for the adaptive motion-blur gate Independent review caught it: every armStaticDedup call site runs before finalizeSessionInit resolves session.motionBlur, so the adaptive-classification gate's `session.motionBlur && session.motionBlur.fixedSamplesPerFrame === null` was always false at runtime. The non-spatial probe-skip described in the PR never engaged outside tests that hand-set motionBlurNonSpatialFrames directly, bypassing real init order. Reads session.options.motionBlur (set unconditionally at session creation) instead, which carries the same "adaptive requested" information the resolved plan would have. Adds a source-order lock test plus direct coverage of computeStaticFrameSet's nonSpatialOnlyFrameSet, mutation-proved against the exact regression. * fix(engine): add xPercent/yPercent to the spatial-property list Round 2 of the independent review: the spatial-property list deciding whether a frame's motion needs the adaptive probe omitted GSAP's percentage-based position properties (xPercent/yPercent) and two 3D transform properties (perspective/transformPerspective) that two other lists already in this repo (packages/parsers/src/gsapConstants.ts, packages/studio/.../gsapAnimatesProperty.ts) both carry. A composition positioned via xPercent/yPercent would have been silently floored to K=16 with no probe and no log line, the same failure shape as the round-1 bug through a data gap instead of a dead gate. Moves the list to an exported SPATIAL_TWEEN_PROPERTIES array in motionBlur.ts, passed into computeStaticFrameSet's page.evaluate as data rather than duplicated inline, so it stays a single list and is directly testable. Adds tests that execute the real page-side closure (the existing tests all mocked the whole result and never exercised the matching code), mutation-proved against the exact gap found. * fix(engine): add rotate to the spatial-property list Round 3 of the independent review, comparing SPATIAL_TWEEN_PROPERTIES side by side against the two sibling lists rather than trusting the prior commit's summary: GSAP's individual "rotate" transform property (distinct from "rotation", carried in packages/studio/.../gsapAnimatesProperty.ts's GSAP_TRANSFORM_PROPS) was still missing, same failure shape as the two prior rounds. The same pass also raised transformOrigin, which is deliberately NOT added: gsapConstants.ts's own classifyTweenPropertyGroup excludes it as a pivot-point modifier with no independent visual effect, and a test now locks that reasoning in rather than leaving it to be "fixed" again by a future pass that does not read that far.