@hyperframes/engine 0.8.198 → 0.8.199
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -761,6 +761,8 @@ export declare function getCompositionDuration(session: CaptureSession): Promise
|
|
|
761
761
|
* timeline passed verification while the drained output bottomed at 30.9 dB.
|
|
762
762
|
*/
|
|
763
763
|
export declare function computeDeVerifySampleFractions(k: number): number[];
|
|
764
|
+
/** Seeks the page the truth is read from; callbacks run unless suppressed (suppressed, a count-up's text is stale). */
|
|
765
|
+
export declare function seekDeVerifyTruth(page: Page, t: number, suppressEvents: boolean): Promise<void>;
|
|
764
766
|
/**
|
|
765
767
|
* Percentile of a positive-real sample set (nearest-rank; matches how the
|
|
766
768
|
* existing {@link medianOf} p50 helper picks the middle index). `p` is a
|
|
@@ -3774,6 +3774,14 @@ export function computeDeVerifySampleFractions(k) {
|
|
|
3774
3774
|
return [0.95];
|
|
3775
3775
|
return [...Array.from({ length: k - 1 }, (_, i) => (i + 1) / k), 0.95];
|
|
3776
3776
|
}
|
|
3777
|
+
/** Seeks the page the truth is read from; callbacks run unless suppressed (suppressed, a count-up's text is stale). */
|
|
3778
|
+
export async function seekDeVerifyTruth(page, t, suppressEvents) {
|
|
3779
|
+
await page.evaluate((tt, suppress) => {
|
|
3780
|
+
const hf = window.__hf;
|
|
3781
|
+
if (hf && typeof hf.seek === "function")
|
|
3782
|
+
hf.seek(tt, { suppressEvents: suppress });
|
|
3783
|
+
}, t, suppressEvents);
|
|
3784
|
+
}
|
|
3777
3785
|
async function captureDeVerificationFrames(session, page, logInitPhase) {
|
|
3778
3786
|
// Explicit HF_DE_VERIFY wins; otherwise the session's own sample count
|
|
3779
3787
|
// (raised by the parallel coordinator for multi-worker DE), then default 4.
|
|
@@ -3819,48 +3827,54 @@ async function captureDeVerificationFrames(session, page, logInitPhase) {
|
|
|
3819
3827
|
// would share the corruption, PSNR would pass on the damaged output.
|
|
3820
3828
|
// Seeking 0 → ascending reproduces the render's own seek order.
|
|
3821
3829
|
const fractions = computeDeVerifySampleFractions(k);
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3830
|
+
// A video-free comp reads its truth on a disposable page: callbacks that run there
|
|
3831
|
+
// cannot leave the render's own page changed. The video injector is tied to the render page.
|
|
3832
|
+
const disposable = session.onBeforeCapture
|
|
3833
|
+
? null
|
|
3834
|
+
: await createStaticVerificationPage(session).catch(() => {
|
|
3835
|
+
logInitPhase("self-verify truth page unavailable; reading it on the render page");
|
|
3836
|
+
return null;
|
|
3837
|
+
});
|
|
3838
|
+
const isolated = disposable !== null;
|
|
3839
|
+
const truthPage = disposable ?? page;
|
|
3840
|
+
const seekTo = (t) => seekDeVerifyTruth(truthPage, t, !isolated);
|
|
3832
3841
|
const frames = new Map();
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
//
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3842
|
+
try {
|
|
3843
|
+
await seekTo(quantizeTimeToFrame(0, fps));
|
|
3844
|
+
// Force one frame so lazy tween initialization paints at t=0 state.
|
|
3845
|
+
await pageScreenshotCapture(truthPage, session.options);
|
|
3846
|
+
for (const f of fractions) {
|
|
3847
|
+
let idx = Math.min(totalFrames - 1, Math.max(1, Math.round(totalFrames * f)));
|
|
3848
|
+
// Nudge off clip-cut boundaries (±1-frame desync is legitimate there);
|
|
3849
|
+
// if the nudge saturates on a boundary index, skip the sample entirely.
|
|
3850
|
+
let guard = 0;
|
|
3851
|
+
while (boundary.has(idx) && guard++ < 6)
|
|
3852
|
+
idx = Math.min(totalFrames - 1, idx + 2);
|
|
3853
|
+
if (boundary.has(idx))
|
|
3854
|
+
continue;
|
|
3855
|
+
if (frames.has(idx))
|
|
3856
|
+
continue;
|
|
3857
|
+
const t = quantizeTimeToFrame(idx / fps, fps);
|
|
3858
|
+
await seekTo(t);
|
|
3859
|
+
// Video frame injection (same hook the real capture paths run) — without
|
|
3860
|
+
// it, <video> elements screenshot black and every video comp would
|
|
3861
|
+
// false-positive into the screenshot fallback.
|
|
3862
|
+
if (session.onBeforeCapture)
|
|
3863
|
+
await session.onBeforeCapture(truthPage, t);
|
|
3864
|
+
// The first screenshot forces a frame, which runs rAF-driven callbacks (a count-up lands
|
|
3865
|
+
// a tick after seek()); waiting on rAF via evaluate deadlocks, headless fires it only
|
|
3866
|
+
// when a frame is produced.
|
|
3867
|
+
await pageScreenshotCapture(truthPage, session.options);
|
|
3868
|
+
frames.set(idx, await pageScreenshotCapture(truthPage, session.options));
|
|
3869
|
+
}
|
|
3870
|
+
// The render's own page goes back to frame 0 so its first seek starts like an unverified render.
|
|
3871
|
+
if (!isolated)
|
|
3872
|
+
await seekTo(quantizeTimeToFrame(0, fps));
|
|
3873
|
+
}
|
|
3874
|
+
finally {
|
|
3875
|
+
if (isolated)
|
|
3876
|
+
await truthPage.close().catch(() => { });
|
|
3877
|
+
}
|
|
3864
3878
|
session.deVerifyFrames = frames;
|
|
3865
3879
|
logInitPhase(`drawElement self-verify armed: ${frames.size} ground-truth frame(s) @ [${[...frames.keys()].join(", ")}] of ${totalFrames}`);
|
|
3866
3880
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/engine",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.199",
|
|
4
4
|
"description": "Seekable web page to video rendering engine (Puppeteer + FFmpeg)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"linkedom": "^0.18.12",
|
|
51
51
|
"puppeteer": "^25.8.0",
|
|
52
52
|
"puppeteer-core": "^25.8.0",
|
|
53
|
-
"@hyperframes/
|
|
54
|
-
"@hyperframes/
|
|
53
|
+
"@hyperframes/core": "^0.8.199",
|
|
54
|
+
"@hyperframes/parsers": "^0.8.199"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/node": "^25.0.10",
|