@hyperframes/producer 0.9.22 → 0.9.25

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.
package/dist/index.js CHANGED
@@ -286,9 +286,24 @@ function parseRangeHeader(header, size, contentType = "application/octet-stream"
286
286
  const end = Math.min(requestedEnd, size - 1);
287
287
  return { kind: "satisfiable", start, end };
288
288
  }
289
- function buildVirtualTimeShim(options) {
290
- const seedRandomFromFrame = options.seedRandomFromFrame === true;
291
- const seededRandomBlock = seedRandomFromFrame ? String.raw`
289
+ var VIRTUAL_TIME_SHIM = String.raw`(function() {
290
+ if (window.__HF_VIRTUAL_TIME__) return;
291
+
292
+ var virtualNowMs = 0;
293
+ var rafId = 1;
294
+ var rafQueue = [];
295
+ var OriginalDate = Date;
296
+ var originalSetTimeout = window.setTimeout.bind(window);
297
+ var originalClearTimeout = window.clearTimeout.bind(window);
298
+ var originalSetInterval = window.setInterval.bind(window);
299
+ var originalClearInterval = window.clearInterval.bind(window);
300
+ var originalRequestAnimationFrame = window.requestAnimationFrame
301
+ ? window.requestAnimationFrame.bind(window)
302
+ : null;
303
+ var originalCancelAnimationFrame = window.cancelAnimationFrame
304
+ ? window.cancelAnimationFrame.bind(window)
305
+ : null;
306
+
292
307
  // Seeded Math.random / crypto.getRandomValues, keyed by virtual time.
293
308
  // Mulberry32: single uint32 state, deterministic, fast.
294
309
  var rngState = 0;
@@ -330,26 +345,7 @@ function buildVirtualTimeShim(options) {
330
345
  window.crypto.getRandomValues = __seededGetRandomValues;
331
346
  } catch (e) {}
332
347
  }
333
- ` : "";
334
- const seekToTimeReseedCall = seedRandomFromFrame ? "reseedRngFromTime(safeTimeMs);\n " : "";
335
- return String.raw`(function() {
336
- if (window.__HF_VIRTUAL_TIME__) return;
337
348
 
338
- var virtualNowMs = 0;
339
- var rafId = 1;
340
- var rafQueue = [];
341
- var OriginalDate = Date;
342
- var originalSetTimeout = window.setTimeout.bind(window);
343
- var originalClearTimeout = window.clearTimeout.bind(window);
344
- var originalSetInterval = window.setInterval.bind(window);
345
- var originalClearInterval = window.clearInterval.bind(window);
346
- var originalRequestAnimationFrame = window.requestAnimationFrame
347
- ? window.requestAnimationFrame.bind(window)
348
- : null;
349
- var originalCancelAnimationFrame = window.cancelAnimationFrame
350
- ? window.cancelAnimationFrame.bind(window)
351
- : null;
352
- ${seededRandomBlock}
353
349
  function flushAnimationFrame() {
354
350
  if (!rafQueue.length) return;
355
351
  var current = rafQueue.slice();
@@ -480,7 +476,8 @@ ${seededRandomBlock}
480
476
  // page starts there keep the schedule a one-worker render gives them.
481
477
  if (safeTimeMs > 0) seekToTime(0);
482
478
  }
483
- ${seekToTimeReseedCall}fireDueTimers(safeTimeMs);
479
+ reseedRngFromTime(safeTimeMs);
480
+ fireDueTimers(safeTimeMs);
484
481
  virtualNowMs = safeTimeMs;
485
482
  flushAnimationFrame();
486
483
  return virtualNowMs;
@@ -499,8 +496,6 @@ ${seededRandomBlock}
499
496
  },
500
497
  };
501
498
  })();`;
502
- }
503
- var VIRTUAL_TIME_SHIM = buildVirtualTimeShim({ seedRandomFromFrame: false });
504
499
  var RENDER_SEEK_MODE = process.env.PRODUCER_RUNTIME_RENDER_SEEK_MODE === "strict-boundary" ? "strict-boundary" : "preview-phase";
505
500
  var RENDER_SEEK_DIAGNOSTICS = process.env.PRODUCER_DEBUG_SEEK_DIAGNOSTICS === "true";
506
501
  var RENDER_SEEK_STEP = Math.max(
@@ -17060,7 +17055,7 @@ async function measurePlanSecondsPerFrame(input) {
17060
17055
  projectDir: compiledDir,
17061
17056
  compiledDir,
17062
17057
  port: 0,
17063
- preHeadScripts: [buildVirtualTimeShim({ seedRandomFromFrame: true })],
17058
+ preHeadScripts: [VIRTUAL_TIME_SHIM],
17064
17059
  fps: fpsRatio
17065
17060
  });
17066
17061
  let session = null;
@@ -19988,7 +19983,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19988
19983
  projectDir: compiledDir,
19989
19984
  compiledDir,
19990
19985
  port: 0,
19991
- preHeadScripts: [buildVirtualTimeShim({ seedRandomFromFrame: true })],
19986
+ preHeadScripts: [VIRTUAL_TIME_SHIM],
19992
19987
  // These dimensions are frozen by the controller from the render job, so
19993
19988
  // chunk runtime seek quantization stays on the same fps grid as capture.
19994
19989
  fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen }
@@ -303,9 +303,24 @@ function parseRangeHeader(header, size, contentType = "application/octet-stream"
303
303
  const end = Math.min(requestedEnd, size - 1);
304
304
  return { kind: "satisfiable", start, end };
305
305
  }
306
- function buildVirtualTimeShim(options) {
307
- const seedRandomFromFrame = options.seedRandomFromFrame === true;
308
- const seededRandomBlock = seedRandomFromFrame ? String.raw`
306
+ var VIRTUAL_TIME_SHIM = String.raw`(function() {
307
+ if (window.__HF_VIRTUAL_TIME__) return;
308
+
309
+ var virtualNowMs = 0;
310
+ var rafId = 1;
311
+ var rafQueue = [];
312
+ var OriginalDate = Date;
313
+ var originalSetTimeout = window.setTimeout.bind(window);
314
+ var originalClearTimeout = window.clearTimeout.bind(window);
315
+ var originalSetInterval = window.setInterval.bind(window);
316
+ var originalClearInterval = window.clearInterval.bind(window);
317
+ var originalRequestAnimationFrame = window.requestAnimationFrame
318
+ ? window.requestAnimationFrame.bind(window)
319
+ : null;
320
+ var originalCancelAnimationFrame = window.cancelAnimationFrame
321
+ ? window.cancelAnimationFrame.bind(window)
322
+ : null;
323
+
309
324
  // Seeded Math.random / crypto.getRandomValues, keyed by virtual time.
310
325
  // Mulberry32: single uint32 state, deterministic, fast.
311
326
  var rngState = 0;
@@ -347,26 +362,7 @@ function buildVirtualTimeShim(options) {
347
362
  window.crypto.getRandomValues = __seededGetRandomValues;
348
363
  } catch (e) {}
349
364
  }
350
- ` : "";
351
- const seekToTimeReseedCall = seedRandomFromFrame ? "reseedRngFromTime(safeTimeMs);\n " : "";
352
- return String.raw`(function() {
353
- if (window.__HF_VIRTUAL_TIME__) return;
354
365
 
355
- var virtualNowMs = 0;
356
- var rafId = 1;
357
- var rafQueue = [];
358
- var OriginalDate = Date;
359
- var originalSetTimeout = window.setTimeout.bind(window);
360
- var originalClearTimeout = window.clearTimeout.bind(window);
361
- var originalSetInterval = window.setInterval.bind(window);
362
- var originalClearInterval = window.clearInterval.bind(window);
363
- var originalRequestAnimationFrame = window.requestAnimationFrame
364
- ? window.requestAnimationFrame.bind(window)
365
- : null;
366
- var originalCancelAnimationFrame = window.cancelAnimationFrame
367
- ? window.cancelAnimationFrame.bind(window)
368
- : null;
369
- ${seededRandomBlock}
370
366
  function flushAnimationFrame() {
371
367
  if (!rafQueue.length) return;
372
368
  var current = rafQueue.slice();
@@ -497,7 +493,8 @@ ${seededRandomBlock}
497
493
  // page starts there keep the schedule a one-worker render gives them.
498
494
  if (safeTimeMs > 0) seekToTime(0);
499
495
  }
500
- ${seekToTimeReseedCall}fireDueTimers(safeTimeMs);
496
+ reseedRngFromTime(safeTimeMs);
497
+ fireDueTimers(safeTimeMs);
501
498
  virtualNowMs = safeTimeMs;
502
499
  flushAnimationFrame();
503
500
  return virtualNowMs;
@@ -516,8 +513,6 @@ ${seededRandomBlock}
516
513
  },
517
514
  };
518
515
  })();`;
519
- }
520
- var VIRTUAL_TIME_SHIM = buildVirtualTimeShim({ seedRandomFromFrame: false });
521
516
  var RENDER_SEEK_MODE = process.env.PRODUCER_RUNTIME_RENDER_SEEK_MODE === "strict-boundary" ? "strict-boundary" : "preview-phase";
522
517
  var RENDER_SEEK_DIAGNOSTICS = process.env.PRODUCER_DEBUG_SEEK_DIAGNOSTICS === "true";
523
518
  var RENDER_SEEK_STEP = Math.max(
@@ -21,8 +21,7 @@
21
21
  * - Browser is launched with `browserGpuMode: "software"` and verified
22
22
  * against `chrome://gpu` via `assertSwiftShader` — a non-SwiftShader
23
23
  * backend trips a non-retryable `BROWSER_GPU_NOT_SOFTWARE`.
24
- * - The file server serves with the seeded-random shim
25
- * (`buildVirtualTimeShim({ seedRandomFromFrame: true })`) so any
24
+ * - The file server serves `VIRTUAL_TIME_SHIM`, as every render path does, so any
26
25
  * composition that uses `Math.random` / `crypto.getRandomValues`
27
26
  * produces byte-identical pixels per `(planDir, chunkIndex)`.
28
27
  * - No `lastFrameCache` priming: every frame seeks fresh DOM so the
@@ -30,7 +29,7 @@
30
29
  * - The chunk's encode runs with `lockGopForChunkConcat: true` and
31
30
  * `gopSize === framesInChunk` so concat-copy at assemble time is safe.
32
31
  *
33
- * Every determinism toggle above is opt-in — only this primitive enables them.
32
+ * Every other determinism toggle above is opt-in — only this primitive enables them.
34
33
  * In-process renders (`executeRenderJob`) leave them off.
35
34
  */
36
35
  import { assertSwiftShader, type CaptureOptions, type CaptureMode, type CapturePerfSummary, type CaptureSession, closeCaptureSession, createCaptureSession, type EngineConfig, initializeSession, probeBeginFrameLiveness, readWebGlVendorInfoFromCanvas } from "@hyperframes/engine";
@@ -76,42 +76,10 @@ export type RangeRequest = {
76
76
  */
77
77
  export declare function parseRangeHeader(header: string | null | undefined, size: number, contentType?: string): RangeRequest;
78
78
  /**
79
- * Options for {@link buildVirtualTimeShim}.
80
- */
81
- export interface VirtualTimeShimOptions {
82
- /**
83
- * When `true`, the shim additionally replaces `Math.random` and
84
- * `crypto.getRandomValues` with a Mulberry32-seeded PRNG keyed by the
85
- * current frame's virtual time. Compositions that call `Math.random()`
86
- * during render then produce byte-identical pixels across machines and
87
- * across replays of the same `(planDir, chunkIndex)` pair.
88
- *
89
- * Default `false`: leaves `Math.random` / `crypto.getRandomValues` native,
90
- * preserving the in-process renderer's non-deterministic behavior for
91
- * compositions that rely on it.
92
- */
93
- seedRandomFromFrame: boolean;
94
- }
95
- /**
96
- * Build the page-side virtual-time shim script.
97
- *
98
- * The shim freezes `Date.now`, `performance.now`, rAF, and the timers set
99
- * after the first seek, so a render seek can deterministically advance the
100
- * page's notion of "now". The renderer issues `__HF_VIRTUAL_TIME__.seekToTime(ms)`
101
- * before every frame capture; everything timing-related on the page sees
102
- * exactly `ms` until the next seek.
103
- *
104
- * When `options.seedRandomFromFrame` is `true`, the returned script also
105
- * installs a seeded `Math.random` / `crypto.getRandomValues` keyed by the
106
- * current virtual time — so compositions with stochastic visuals retry
107
- * identically. When `false`, the shim emits no random-override code; the
108
- * page's native `Math.random` is left alone (the in-process default).
109
- */
110
- export declare function buildVirtualTimeShim(options: VirtualTimeShimOptions): string;
111
- /**
112
- * Default in-process virtual-time shim — `seedRandomFromFrame: false`.
113
- * Existing call sites (`renderOrchestrator`, `probeStage`) import this
114
- * constant. Distributed callers build their own with seeding enabled.
79
+ * Page-side virtual-time shim, installed before page scripts on every render path.
80
+ * Holds Date.now, performance.now, rAF and later timers at the seek time, and seeds Math.random and
81
+ * crypto.getRandomValues from it, so a re-render repeats. Draws at page load or inside a frame also match
82
+ * across worker counts; a value resolved on a tween's first render depends on the frame a worker reaches first.
115
83
  */
116
84
  declare const VIRTUAL_TIME_SHIM: string;
117
85
  export declare function resolveRenderFpsConfig(fps: Fps | undefined): {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/producer",
3
- "version": "0.9.22",
3
+ "version": "0.9.25",
4
4
  "description": "HTML-to-video rendering engine using Chrome's BeginFrame API",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,11 +35,11 @@
35
35
  "postcss": "^8.4.0",
36
36
  "puppeteer": "~25.11.0",
37
37
  "puppeteer-core": "^25.11.0",
38
- "@hyperframes/core": "0.9.22",
39
- "@hyperframes/parsers": "0.9.22",
40
- "@hyperframes/lint": "0.9.22",
41
- "@hyperframes/engine": "0.9.22",
42
- "@hyperframes/studio-server": "0.9.22"
38
+ "@hyperframes/lint": "0.9.25",
39
+ "@hyperframes/engine": "0.9.25",
40
+ "@hyperframes/studio-server": "0.9.25",
41
+ "@hyperframes/core": "0.9.25",
42
+ "@hyperframes/parsers": "0.9.25"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^25.0.10",
@@ -48,7 +48,7 @@
48
48
  "tsx": "^4.21.0",
49
49
  "typescript": "^5.7.2",
50
50
  "vitest": "^4.1.11",
51
- "@hyperframes/aws-lambda": "0.9.22"
51
+ "@hyperframes/aws-lambda": "0.9.25"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"