hyperframes 0.8.45 → 0.8.47

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.
@@ -56326,37 +56326,80 @@ function finiteOr(value, fallback) {
56326
56326
  }
56327
56327
  function resolveMotionBlurPlan(options) {
56328
56328
  if (!options) return null;
56329
- const samplesPerFrame = Math.min(
56329
+ const fixedSamplesPerFrame = options.samplesPerFrame === void 0 ? null : Math.min(
56330
56330
  MAX_SAMPLES_PER_FRAME,
56331
56331
  Math.max(1, Math.round(finiteOr(options.samplesPerFrame, DEFAULT_SAMPLES_PER_FRAME)))
56332
56332
  );
56333
56333
  const shutterAngle = finiteOr(options.shutterAngle, DEFAULT_SHUTTER_ANGLE);
56334
56334
  const shutterPhase = finiteOr(options.shutterPhase, DEFAULT_SHUTTER_PHASE);
56335
56335
  const blend = options.blend === "linear" ? "linear" : "srgb";
56336
- const windowStartFrames = shutterPhase / 360;
56337
- const shutterFrames = shutterAngle / 360;
56338
- const sampleTickOffsets = [];
56336
+ return {
56337
+ blend,
56338
+ subFrameDivisions: SUB_FRAME_DIVISIONS,
56339
+ windowStartFrames: shutterPhase / 360,
56340
+ shutterFrames: shutterAngle / 360,
56341
+ fixedSamplesPerFrame
56342
+ };
56343
+ }
56344
+ function sampleTickOffsets(plan2, samplesPerFrame) {
56345
+ const offsets = [];
56339
56346
  for (let k = 0; k < samplesPerFrame; k++) {
56340
- const offsetFrames = windowStartFrames + (k + 0.5) / samplesPerFrame * shutterFrames;
56341
- sampleTickOffsets.push(Math.round(offsetFrames * SUB_FRAME_DIVISIONS));
56347
+ const offsetFrames = plan2.windowStartFrames + (k + 0.5) / samplesPerFrame * plan2.shutterFrames;
56348
+ offsets.push(Math.round(offsetFrames * plan2.subFrameDivisions));
56342
56349
  }
56343
- return { blend, subFrameDivisions: SUB_FRAME_DIVISIONS, sampleTickOffsets };
56350
+ return offsets;
56344
56351
  }
56345
- function motionBlurSampleTimes(plan2, frameIndex, fps) {
56352
+ function motionBlurSampleTimes(plan2, frameIndex, fps, samplesPerFrame) {
56346
56353
  const grid = fps * plan2.subFrameDivisions;
56347
56354
  const frameTicks = frameIndex * plan2.subFrameDivisions;
56348
- return plan2.sampleTickOffsets.map((offset2) => Math.max(0, frameTicks + offset2) / grid);
56355
+ return sampleTickOffsets(plan2, samplesPerFrame).map(
56356
+ (offset2) => Math.max(0, frameTicks + offset2) / grid
56357
+ );
56349
56358
  }
56350
- function motionBlurWindowIsStatic(plan2, frameIndex, staticFrames) {
56351
- const first = Math.floor(
56352
- frameIndex - 1 + Math.min(...plan2.sampleTickOffsets) / plan2.subFrameDivisions
56359
+ function motionBlurProbeTimes(plan2, frameIndex, fps) {
56360
+ const grid = fps * plan2.subFrameDivisions;
56361
+ const frameTicks = frameIndex * plan2.subFrameDivisions;
56362
+ const startTick = Math.round(plan2.windowStartFrames * plan2.subFrameDivisions);
56363
+ const endTick = Math.round(
56364
+ (plan2.windowStartFrames + plan2.shutterFrames) * plan2.subFrameDivisions
56353
56365
  );
56354
- const last = Math.floor(frameIndex + Math.max(...plan2.sampleTickOffsets) / plan2.subFrameDivisions) + 1;
56366
+ return {
56367
+ windowStart: Math.max(0, frameTicks + startTick) / grid,
56368
+ windowEnd: Math.max(0, frameTicks + endTick) / grid
56369
+ };
56370
+ }
56371
+ function motionBlurWindowIsStatic(plan2, frameIndex, staticFrames) {
56372
+ const worstCaseSamples = plan2.fixedSamplesPerFrame ?? MAX_SAMPLES_PER_FRAME;
56373
+ const inset = plan2.shutterFrames / (2 * worstCaseSamples);
56374
+ const minOffsetFrames = plan2.windowStartFrames + inset;
56375
+ const maxOffsetFrames = plan2.windowStartFrames + plan2.shutterFrames - inset;
56376
+ const first = Math.floor(frameIndex - 1 + Math.min(0, minOffsetFrames));
56377
+ const last = Math.floor(frameIndex + Math.max(0, maxOffsetFrames)) + 1;
56355
56378
  for (let frame = first; frame <= last; frame++) {
56356
56379
  if (!staticFrames.has(frame)) return false;
56357
56380
  }
56358
56381
  return true;
56359
56382
  }
56383
+ function adaptiveSampleCount(diff) {
56384
+ for (const step of ADAPTIVE_SAMPLE_STEPS) {
56385
+ if (diff <= step.maxDiff) return step.samples;
56386
+ }
56387
+ return MAX_SAMPLES_PER_FRAME;
56388
+ }
56389
+ function probeDiffMagnitude(a, b) {
56390
+ const decodedA = decodePng(a);
56391
+ const decodedB = decodePng(b);
56392
+ if (decodedA.width !== decodedB.width || decodedA.height !== decodedB.height) {
56393
+ throw new Error(
56394
+ `probeDiffMagnitude: sample geometry mismatch (${decodedA.width}x${decodedA.height} vs ${decodedB.width}x${decodedB.height})`
56395
+ );
56396
+ }
56397
+ let sum = 0;
56398
+ for (let i = 0; i < decodedA.data.length; i++) {
56399
+ sum += Math.abs(decodedA.data[i] - decodedB.data[i]);
56400
+ }
56401
+ return sum / decodedA.data.length;
56402
+ }
56360
56403
  function linearToByte(value) {
56361
56404
  const c = value <= 31308e-7 ? value * 12.92 : 1.055 * Math.pow(value, 1 / 2.4) - 0.055;
56362
56405
  return clampByte(c * 255);
@@ -56364,7 +56407,7 @@ function linearToByte(value) {
56364
56407
  function clampByte(value) {
56365
56408
  return Math.min(255, Math.max(0, Math.round(value)));
56366
56409
  }
56367
- var MAX_SAMPLES_PER_FRAME, DEFAULT_SAMPLES_PER_FRAME, DEFAULT_SHUTTER_ANGLE, DEFAULT_SHUTTER_PHASE, SUB_FRAME_DIVISIONS, SRGB_TO_LINEAR, SRGB_PASSTHROUGH, MotionBlurAccumulator;
56410
+ var MAX_SAMPLES_PER_FRAME, DEFAULT_SAMPLES_PER_FRAME, DEFAULT_SHUTTER_ANGLE, DEFAULT_SHUTTER_PHASE, SUB_FRAME_DIVISIONS, ADAPTIVE_SAMPLE_STEPS, SPATIAL_TWEEN_PROPERTIES, SRGB_TO_LINEAR, SRGB_PASSTHROUGH, MotionBlurAccumulator;
56368
56411
  var init_motionBlur = __esm({
56369
56412
  "../engine/src/services/motionBlur.ts"() {
56370
56413
  "use strict";
@@ -56374,6 +56417,42 @@ var init_motionBlur = __esm({
56374
56417
  DEFAULT_SHUTTER_ANGLE = 180;
56375
56418
  DEFAULT_SHUTTER_PHASE = -90;
56376
56419
  SUB_FRAME_DIVISIONS = 4096;
56420
+ ADAPTIVE_SAMPLE_STEPS = [
56421
+ { maxDiff: 3, samples: DEFAULT_SAMPLES_PER_FRAME },
56422
+ { maxDiff: 6, samples: 32 },
56423
+ { maxDiff: Infinity, samples: MAX_SAMPLES_PER_FRAME }
56424
+ ];
56425
+ SPATIAL_TWEEN_PROPERTIES = [
56426
+ "x",
56427
+ "y",
56428
+ "z",
56429
+ "xPercent",
56430
+ "yPercent",
56431
+ "rotation",
56432
+ "rotate",
56433
+ "rotationX",
56434
+ "rotationY",
56435
+ "rotationZ",
56436
+ "scale",
56437
+ "scaleX",
56438
+ "scaleY",
56439
+ "scaleZ",
56440
+ "skewX",
56441
+ "skewY",
56442
+ "perspective",
56443
+ "transformPerspective",
56444
+ "top",
56445
+ "left",
56446
+ "right",
56447
+ "bottom",
56448
+ "width",
56449
+ "height",
56450
+ "translate",
56451
+ "translateX",
56452
+ "translateY",
56453
+ "translateZ",
56454
+ "transform"
56455
+ ];
56377
56456
  SRGB_TO_LINEAR = (() => {
56378
56457
  const lut = new Float64Array(256);
56379
56458
  for (let i = 0; i < 256; i++) lut[i] = srgbByteToLinear(i);
@@ -59995,7 +60074,13 @@ function isStaticDedupFrameAnalysisSafe(totalFrames) {
59995
60074
  return Number.isFinite(totalFrames) && Number.isSafeInteger(totalFrames) && totalFrames > 0 && totalFrames <= MAX_STATIC_DEDUP_ANALYSIS_FRAMES;
59996
60075
  }
59997
60076
  async function computeStaticFrameSet(page, fps) {
59998
- const result = await page.evaluate(() => {
60077
+ const result = await page.evaluate((spatialProps) => {
60078
+ const SPATIAL_PROPS = new Set(spatialProps);
60079
+ function isSpatial(vars) {
60080
+ if (!vars) return false;
60081
+ for (const key2 of Object.keys(vars)) if (SPATIAL_PROPS.has(key2)) return true;
60082
+ return false;
60083
+ }
59999
60084
  const intervals2 = [];
60000
60085
  let tweenCount2 = 0;
60001
60086
  let hasTimelineCall2 = false;
@@ -60003,7 +60088,7 @@ async function computeStaticFrameSet(page, fps) {
60003
60088
  if (typeof tl.getChildren !== "function") return;
60004
60089
  if (typeof tl.vars?.onUpdate === "function") {
60005
60090
  const total = typeof tl.totalDuration === "function" ? tl.totalDuration() : 0;
60006
- if (total > 0) intervals2.push({ start: offset2, end: offset2 + total });
60091
+ if (total > 0) intervals2.push({ start: offset2, end: offset2 + total, spatial: true });
60007
60092
  }
60008
60093
  for (const child of tl.getChildren(false, true, true)) {
60009
60094
  const start = offset2 + (typeof child.startTime === "function" ? child.startTime() : 0);
@@ -60011,14 +60096,14 @@ async function computeStaticFrameSet(page, fps) {
60011
60096
  const total = typeof child.totalDuration === "function" ? child.totalDuration() : single;
60012
60097
  if (typeof child.getChildren === "function") {
60013
60098
  if (total > single + 1e-6) {
60014
- intervals2.push({ start, end: start + total });
60099
+ intervals2.push({ start, end: start + total, spatial: true });
60015
60100
  walk(child, start);
60016
60101
  } else {
60017
60102
  walk(child, start);
60018
60103
  }
60019
60104
  } else {
60020
60105
  tweenCount2++;
60021
- intervals2.push({ start, end: start + total });
60106
+ intervals2.push({ start, end: start + total, spatial: isSpatial(child.vars) });
60022
60107
  if (total <= 1e-6 && (typeof child.vars?.onComplete === "function" || typeof child.vars?.onReverseComplete === "function")) {
60023
60108
  hasTimelineCall2 = true;
60024
60109
  }
@@ -60059,7 +60144,7 @@ async function computeStaticFrameSet(page, fps) {
60059
60144
  hasUnresolvableClipStart: hasUnresolvableClipStart2,
60060
60145
  hasTimelineCall: hasTimelineCall2
60061
60146
  };
60062
- });
60147
+ }, SPATIAL_TWEEN_PROPERTIES);
60063
60148
  const {
60064
60149
  intervals,
60065
60150
  tweenCount,
@@ -60075,6 +60160,7 @@ async function computeStaticFrameSet(page, fps) {
60075
60160
  return {
60076
60161
  totalFrames,
60077
60162
  staticFrameSet: /* @__PURE__ */ new Set(),
60163
+ nonSpatialOnlyFrameSet: /* @__PURE__ */ new Set(),
60078
60164
  hasVideo,
60079
60165
  hasCanvas,
60080
60166
  hasNonGsapAnim,
@@ -60084,10 +60170,14 @@ async function computeStaticFrameSet(page, fps) {
60084
60170
  };
60085
60171
  }
60086
60172
  const animated = /* @__PURE__ */ new Set();
60087
- for (const { start, end } of intervals) {
60173
+ const spatialFrameSet = /* @__PURE__ */ new Set();
60174
+ for (const { start, end, spatial } of intervals) {
60088
60175
  const lo = Math.max(0, Math.floor(start * fps));
60089
60176
  const hi = Math.min(totalFrames - 1, Math.ceil(end * fps));
60090
- for (let f = lo; f <= hi; f++) animated.add(f);
60177
+ for (let f = lo; f <= hi; f++) {
60178
+ animated.add(f);
60179
+ if (spatial) spatialFrameSet.add(f);
60180
+ }
60091
60181
  }
60092
60182
  for (const f of await computeClipBoundaryFrames(page, fps)) animated.add(f);
60093
60183
  const reasons = [];
@@ -60105,9 +60195,14 @@ async function computeStaticFrameSet(page, fps) {
60105
60195
  if (!animated.has(f) && !animated.has(f - 1)) staticFrameSet.add(f);
60106
60196
  }
60107
60197
  }
60198
+ const nonSpatialOnlyFrameSet = /* @__PURE__ */ new Set();
60199
+ if (eligible) {
60200
+ for (const f of animated) if (!spatialFrameSet.has(f)) nonSpatialOnlyFrameSet.add(f);
60201
+ }
60108
60202
  return {
60109
60203
  totalFrames,
60110
60204
  staticFrameSet,
60205
+ nonSpatialOnlyFrameSet,
60111
60206
  hasVideo,
60112
60207
  hasCanvas,
60113
60208
  hasNonGsapAnim,
@@ -60317,6 +60412,11 @@ async function verifyStaticFramesSafe(session, page, staticFrames, fps, sampleCo
60317
60412
  }
60318
60413
  }
60319
60414
  async function armStaticDedup(session, page, logInitPhase) {
60415
+ let sharedStaticFrameStats;
60416
+ if (session.options.motionBlur && session.options.motionBlur.samplesPerFrame === void 0 && !session.motionBlurNonSpatialFrames) {
60417
+ sharedStaticFrameStats = await computeStaticFrameSet(page, fpsToNumber(session.options.fps));
60418
+ session.motionBlurNonSpatialFrames = sharedStaticFrameStats.nonSpatialOnlyFrameSet;
60419
+ }
60320
60420
  if (session.staticFrames || session.staticDedupSkipReason) return;
60321
60421
  session.staticDedupEnabled = session.config?.staticFrameDedup !== false;
60322
60422
  if (!session.staticDedupEnabled) return;
@@ -60341,7 +60441,7 @@ async function armStaticDedup(session, page, logInitPhase) {
60341
60441
  return;
60342
60442
  }
60343
60443
  const fps = fpsToNumber(session.options.fps);
60344
- const stats = await computeStaticFrameSet(page, fps);
60444
+ const stats = sharedStaticFrameStats ?? await computeStaticFrameSet(page, fps);
60345
60445
  if (!stats.eligible || stats.staticFrameSet.size === 0) {
60346
60446
  session.staticDedupSkipReason = "ineligible";
60347
60447
  logInitPhase(`static-frame dedup: disabled (${stats.reason})`);
@@ -60587,6 +60687,25 @@ function finalizeSessionInit(session) {
60587
60687
  session.motionBlur = resolveSessionMotionBlur(session);
60588
60688
  session.isInitialized = true;
60589
60689
  }
60690
+ async function resolveAdaptiveSampleCount(session, frameIndex, absFrameIndex, plan2, fps, sampleSeek) {
60691
+ if (session.motionBlurNonSpatialFrames?.has(absFrameIndex)) {
60692
+ return {
60693
+ samplesPerFrame: DEFAULT_SAMPLES_PER_FRAME,
60694
+ seekMs: 0,
60695
+ beforeCaptureMs: 0,
60696
+ screenshotMs: 0
60697
+ };
60698
+ }
60699
+ const { windowStart, windowEnd } = motionBlurProbeTimes(plan2, absFrameIndex, fps);
60700
+ const probeA = await captureFrameSurface(session, frameIndex, windowStart, sampleSeek);
60701
+ const probeB = await captureFrameSurface(session, frameIndex, windowEnd, sampleSeek);
60702
+ return {
60703
+ samplesPerFrame: adaptiveSampleCount(probeDiffMagnitude(probeA.buffer, probeB.buffer)),
60704
+ seekMs: probeA.seekMs + probeB.seekMs,
60705
+ beforeCaptureMs: probeA.beforeCaptureMs + probeB.beforeCaptureMs,
60706
+ screenshotMs: probeA.screenshotMs + probeB.screenshotMs
60707
+ };
60708
+ }
60590
60709
  async function captureAccumulatedFrame(session, frameIndex, absFrameIndex, plan2) {
60591
60710
  const fps = fpsToNumber(session.options.fps);
60592
60711
  const frameTime = quantizeSeekTime(absFrameIndex / fps, fps);
@@ -60597,8 +60716,23 @@ async function captureAccumulatedFrame(session, frameIndex, absFrameIndex, plan2
60597
60716
  suppressEvents: true,
60598
60717
  subFrameDivisions: plan2.subFrameDivisions
60599
60718
  };
60719
+ let samplesPerFrame = plan2.fixedSamplesPerFrame;
60720
+ if (samplesPerFrame === null) {
60721
+ const chosen = await resolveAdaptiveSampleCount(
60722
+ session,
60723
+ frameIndex,
60724
+ absFrameIndex,
60725
+ plan2,
60726
+ fps,
60727
+ sampleSeek
60728
+ );
60729
+ samplesPerFrame = chosen.samplesPerFrame;
60730
+ totals.seekMs += chosen.seekMs;
60731
+ totals.beforeCaptureMs += chosen.beforeCaptureMs;
60732
+ totals.screenshotMs += chosen.screenshotMs;
60733
+ }
60600
60734
  const accumulator = new MotionBlurAccumulator(plan2.blend);
60601
- for (const sampleTime of motionBlurSampleTimes(plan2, absFrameIndex, fps)) {
60735
+ for (const sampleTime of motionBlurSampleTimes(plan2, absFrameIndex, fps, samplesPerFrame)) {
60602
60736
  const sample = await captureFrameSurface(session, frameIndex, sampleTime, sampleSeek);
60603
60737
  totals.seekMs += sample.seekMs;
60604
60738
  totals.beforeCaptureMs += sample.beforeCaptureMs;
@@ -100520,8 +100654,8 @@ async function runFontLocalize(io, localize) {
100520
100654
  }
100521
100655
 
100522
100656
  // src/version.ts
100523
- var VERSION = true ? "0.8.45" : "0.0.0-dev";
100524
- var PRODUCER_VERSION = true ? "0.8.45" : "0.0.0-dev";
100657
+ var VERSION = true ? "0.8.47" : "0.0.0-dev";
100658
+ var PRODUCER_VERSION = true ? "0.8.47" : "0.0.0-dev";
100525
100659
 
100526
100660
  // src/fontLocalizeCli.ts
100527
100661
  async function readStdin() {