@hyperframes/producer 0.9.20 → 0.9.21

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.
@@ -430,6 +430,68 @@ ${seededRandomBlock}
430
430
  }
431
431
  };
432
432
 
433
+ // Timers set once rendering has started run on film time: each seek fires every timer due by then, in
434
+ // due order. Until a seek after the page reports ready, timers keep the wall clock: setup code waits on
435
+ // them while the renderer may already be seeking.
436
+ var rendering = false;
437
+ var timerQueue = [];
438
+ var nextTimerId = 1000000000;
439
+ var firingDepth = 0;
440
+ function addTimer(callback, delay, args, repeats) {
441
+ // A timer set from a firing timer waits at least 1 ms, so a zero-delay chain cannot stall a seek.
442
+ var ms = Math.max(firingDepth > 0 ? 1 : 0, Number(delay) || 0);
443
+ var entry = { id: nextTimerId++, callback: callback, args: args, due: virtualNowMs + ms, every: repeats ? Math.max(1, ms) : 0, cancelled: false };
444
+ timerQueue.push(entry);
445
+ return entry.id;
446
+ }
447
+ function cancelTimer(id) {
448
+ for (var i = 0; i < timerQueue.length; i++) {
449
+ if (timerQueue[i].id === id) {
450
+ timerQueue[i].cancelled = true;
451
+ return true;
452
+ }
453
+ }
454
+ return false;
455
+ }
456
+ function fireDueTimers(untilMs) {
457
+ // Frame times are fractional, so a timer due on a frame lands a rounding error past it; it still fires on it.
458
+ untilMs += 0.000001;
459
+ while (true) {
460
+ var next = null;
461
+ for (var i = 0; i < timerQueue.length; i++) {
462
+ var candidate = timerQueue[i];
463
+ if (!candidate.cancelled && candidate.due <= untilMs && (next === null || candidate.due < next.due)) next = candidate;
464
+ }
465
+ if (next === null) break;
466
+ var dueMs = next.due;
467
+ if (next.every) next.due += next.every;
468
+ else next.cancelled = true;
469
+ virtualNowMs = dueMs;
470
+ firingDepth++;
471
+ try {
472
+ next.callback.apply(window, next.args);
473
+ } catch (err) {
474
+ originalSetTimeout(function() { throw err; }, 0);
475
+ }
476
+ firingDepth--;
477
+ }
478
+ timerQueue = timerQueue.filter(function(entry) { return !entry.cancelled; });
479
+ }
480
+ window.setTimeout = function(callback, delay) {
481
+ if (!rendering || typeof callback !== "function") return originalSetTimeout.apply(null, arguments);
482
+ return addTimer(callback, delay, Array.prototype.slice.call(arguments, 2), false);
483
+ };
484
+ window.setInterval = function(callback, delay) {
485
+ if (!rendering || typeof callback !== "function") return originalSetInterval.apply(null, arguments);
486
+ return addTimer(callback, delay, Array.prototype.slice.call(arguments, 2), true);
487
+ };
488
+ window.clearTimeout = function(id) {
489
+ if (!cancelTimer(id)) originalClearTimeout(id);
490
+ };
491
+ window.clearInterval = function(id) {
492
+ if (!cancelTimer(id)) originalClearInterval(id);
493
+ };
494
+
433
495
  window.__HF_VIRTUAL_TIME__ = {
434
496
  originalSetTimeout: originalSetTimeout,
435
497
  originalClearTimeout: originalClearTimeout,
@@ -439,8 +501,10 @@ ${seededRandomBlock}
439
501
  originalCancelAnimationFrame: originalCancelAnimationFrame,
440
502
  seekToTime: function(nextTimeMs) {
441
503
  var safeTimeMs = Math.max(0, Number(nextTimeMs) || 0);
504
+ if (window.__renderReady === true) rendering = true;
505
+ ${seekToTimeReseedCall}fireDueTimers(safeTimeMs);
442
506
  virtualNowMs = safeTimeMs;
443
- ${seekToTimeReseedCall}flushAnimationFrame();
507
+ flushAnimationFrame();
444
508
  return virtualNowMs;
445
509
  },
446
510
  getTime: function() {
@@ -9939,7 +10003,7 @@ function assertPlanSizeWithinLimit(input) {
9939
10003
  });
9940
10004
  throw new PlanTooLargeError(breakdown.totalBytes, input.limitBytes, breakdown, input.observedAt);
9941
10005
  }
9942
- function resolveChunkPlan(totalFrames, configChunkSize, maxParallelChunks, targetChunkFrames) {
10006
+ function resolveChunkPlan(totalFrames, configChunkSize, maxParallelChunks, targetChunkFrames, minParallelChunks = 1) {
9943
10007
  assertPositiveInteger("totalFrames", totalFrames);
9944
10008
  assertPositiveInteger("maxParallelChunks", maxParallelChunks);
9945
10009
  if (configChunkSize !== void 0) {
@@ -9948,7 +10012,11 @@ function resolveChunkPlan(totalFrames, configChunkSize, maxParallelChunks, targe
9948
10012
  if (targetChunkFrames !== void 0) {
9949
10013
  assertPositiveInteger("targetChunkFrames", targetChunkFrames);
9950
10014
  }
9951
- const autoSizeParallel = targetChunkFrames === void 0 ? maxParallelChunks : Math.min(maxParallelChunks, Math.max(1, Math.ceil(totalFrames / targetChunkFrames)));
10015
+ assertPositiveInteger("minParallelChunks", minParallelChunks);
10016
+ const autoSizeParallel = targetChunkFrames === void 0 ? maxParallelChunks : Math.min(
10017
+ maxParallelChunks,
10018
+ Math.max(minParallelChunks, Math.ceil(totalFrames / targetChunkFrames))
10019
+ );
9952
10020
  const resolvedChunkSize = configChunkSize ?? Math.max(MIN_CHUNK_SIZE, Math.ceil(totalFrames / autoSizeParallel));
9953
10021
  const naiveCount = Math.ceil(totalFrames / resolvedChunkSize);
9954
10022
  const chunkCount = Math.min(maxParallelChunks, Math.max(1, naiveCount));
@@ -10527,7 +10595,8 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
10527
10595
  totalFrames,
10528
10596
  config.chunkSize,
10529
10597
  maxParallel,
10530
- config.targetChunkFrames
10598
+ config.targetChunkFrames,
10599
+ config.minParallelChunks
10531
10600
  );
10532
10601
  const chunks = buildPlanChunkSlices(
10533
10602
  frameWeights,
@@ -12803,6 +12872,20 @@ function validateDistributedRenderConfig(config) {
12803
12872
  );
12804
12873
  }
12805
12874
  }
12875
+ if (config.minParallelChunks !== void 0) {
12876
+ if (!Number.isInteger(config.minParallelChunks) || config.minParallelChunks < 1) {
12877
+ throw new InvalidConfigError(
12878
+ "config.minParallelChunks",
12879
+ `must be a positive integer; got ${config.minParallelChunks}`
12880
+ );
12881
+ }
12882
+ if (config.minParallelChunks > MAX_PARALLEL_CHUNKS_CEILING) {
12883
+ throw new InvalidConfigError(
12884
+ "config.minParallelChunks",
12885
+ `must be <= ${MAX_PARALLEL_CHUNKS_CEILING}; got ${config.minParallelChunks}`
12886
+ );
12887
+ }
12888
+ }
12806
12889
  for (const field of ["workerTimeoutSeconds", "workerConcurrency"]) {
12807
12890
  const value = config[field];
12808
12891
  if (value !== void 0 && (!Number.isInteger(value) || value < 1)) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "0.1.0",
3
3
  "buildId": "dev",
4
- "sha256": "347118bef63abc711d082cef8209cc65a539e5e87be2b0ce55474b0240a601c7",
4
+ "sha256": "e72564d48551e0bec028dc4b7708ec94a0efdfcb49e1d236d98a773464cb8087",
5
5
  "artifacts": {
6
6
  "iife": "hyperframe.runtime.iife.js",
7
7
  "esm": "hyperframe.runtime.mjs"