@hyperframes/producer 0.8.145 → 0.8.146

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.
@@ -292,7 +292,7 @@ function buildVirtualTimeShim(options) {
292
292
  const seedRandomFromFrame = options.seedRandomFromFrame === true;
293
293
  const seededRandomBlock = seedRandomFromFrame ? String.raw`
294
294
  // Seeded Math.random / crypto.getRandomValues, keyed by virtual time.
295
- // Mulberry32 — single uint32 state, deterministic, fast.
295
+ // Mulberry32: single uint32 state, deterministic, fast.
296
296
  var rngState = 0;
297
297
  function mulberry32() {
298
298
  rngState |= 0; rngState = (rngState + 0x6D2B79F5) | 0;
@@ -303,7 +303,7 @@ function buildVirtualTimeShim(options) {
303
303
  }
304
304
  function reseedRngFromTime(ms) {
305
305
  var ms32 = Math.max(0, Math.floor(Number(ms) || 0)) | 0;
306
- // Knuth's multiplicative hash + golden-ratio offset — gives a well-
306
+ // Knuth's multiplicative hash + golden-ratio offset gives a well-
307
307
  // distributed seed even for frame 0 (otherwise rngState=0 degenerates
308
308
  // the PRNG's first few outputs).
309
309
  rngState = (Math.imul(ms32, -1640531527) + 0x9E3779B9) | 0;
@@ -545,7 +545,7 @@ function buildRenderModeScript(fps) {
545
545
  };
546
546
  window.__playerReady = true;
547
547
  // Media-fallback player has no timeline to bind, so render-ready is immediate.
548
- // init.ts defers __renderReady until the timeline is bound \u2014 different runtime.
548
+ // init.ts defers __renderReady until the timeline is bound (a different runtime).
549
549
  window.__renderReady = true;
550
550
  return true;
551
551
  }
@@ -2136,7 +2136,7 @@ function blitHdrVideoLayer(canvas, el, time, fps, hdrVideoFrameSources, hdrStart
2136
2136
  if (matrix && !isTranslationOnly) {
2137
2137
  if (clipped && log) {
2138
2138
  log.debug(
2139
- `HDR clip rect on affine-transformed element ${el.id} \u2014 clip not applied (affine scissor not yet supported)`
2139
+ `HDR clip rect on affine-transformed element ${el.id}: clip not applied (affine scissor not yet supported)`
2140
2140
  );
2141
2141
  }
2142
2142
  blitRgb48leAffine(
@@ -2193,7 +2193,7 @@ function blitHdrImageLayer(canvas, el, hdrImageBuffers, hdrImageTransferCache, w
2193
2193
  return;
2194
2194
  }
2195
2195
  if (el.clipRect && log) {
2196
- log.debug(`HDR clip rect on image element ${el.id} \u2014 clip not yet supported for images`);
2196
+ log.debug(`HDR clip rect on image element ${el.id}: clip not yet supported for images`);
2197
2197
  }
2198
2198
  try {
2199
2199
  if (hdrPerf) hdrPerf.hdrImageLayerBlits += 1;
@@ -4385,7 +4385,7 @@ import {
4385
4385
  function formatDowngradeWarning(outputFormat, forcedHdrWithoutSources) {
4386
4386
  const hdrSourceReason = forcedHdrWithoutSources ? "HDR was forced without detected HDR sources" : "HDR source detected";
4387
4387
  const formatReason = outputFormat === "hls" ? "HLS output is SDR-only (H.264 in MPEG-TS)" : "HDR + alpha is not supported";
4388
- return `[Render] ${hdrSourceReason}, but format is "${outputFormat}" \u2014 falling back to SDR. ${formatReason}. Use --format mp4 for HDR10 output.`;
4388
+ return `[Render] ${hdrSourceReason}, but format is "${outputFormat}", so falling back to SDR. ${formatReason}. Use --format mp4 for HDR10 output.`;
4389
4389
  }
4390
4390
  function findRenderHdrAutoPromotionTrigger(input) {
4391
4391
  for (const extracted of input.extractionResult?.extracted ?? []) {
@@ -4398,12 +4398,12 @@ function findRenderHdrAutoPromotionTrigger(input) {
4398
4398
  function logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources) {
4399
4399
  if (forcedHdrWithoutSources) {
4400
4400
  input.log.warn(
4401
- "[Render] HDR forced by --hdr flag, but no HDR sources were detected \u2014 defaulting to HLG. SDR-only compositions may look perceptually wrong on HDR displays."
4401
+ "[Render] HDR forced by --hdr flag, but no HDR sources were detected, defaulting to HLG. SDR-only compositions may look perceptually wrong on HDR displays."
4402
4402
  );
4403
4403
  }
4404
4404
  if (!effectiveHdr) {
4405
4405
  input.log.info(
4406
- hdrMode === "force-sdr" ? "[Render] SDR forced by --sdr flag" : "[Render] No HDR sources detected \u2014 rendering SDR"
4406
+ hdrMode === "force-sdr" ? "[Render] SDR forced by --sdr flag" : "[Render] No HDR sources detected, rendering SDR"
4407
4407
  );
4408
4408
  return;
4409
4409
  }
@@ -4418,9 +4418,9 @@ function logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources)
4418
4418
  );
4419
4419
  return;
4420
4420
  }
4421
- const reason = forcedHdrWithoutSources ? "forced by --hdr flag (no HDR sources detected \u2014 defaulting to HLG)" : "forced by --hdr flag";
4421
+ const reason = forcedHdrWithoutSources ? "forced by --hdr flag (no HDR sources detected, defaulting to HLG)" : "forced by --hdr flag";
4422
4422
  input.log.info(
4423
- `[Render] HDR ${reason} \u2014 output: ${effectiveHdr.transfer.toUpperCase()} (BT.2020, 10-bit H.265)`
4423
+ `[Render] HDR ${reason}, output: ${effectiveHdr.transfer.toUpperCase()} (BT.2020, 10-bit H.265)`
4424
4424
  );
4425
4425
  }
4426
4426
  function resolveEffectiveHdrMode(input) {
@@ -4516,14 +4516,14 @@ function resolveRenderWorkerCount(totalFrames, requestedWorkers, cfg, compiled,
4516
4516
  const reasonCodes = new Set(compiled.renderModeHints.reasons.map((r) => r.code));
4517
4517
  if (reasonCodes.has("htmlInCanvas")) {
4518
4518
  log.warn(
4519
- "[Render] html-in-canvas (drawElementImage) detected \u2014 pinning to 1 worker (Chrome concurrency limitation).",
4519
+ "[Render] html-in-canvas (drawElementImage) detected, pinning to 1 worker (Chrome concurrency limitation).",
4520
4520
  { requestedWorkers }
4521
4521
  );
4522
4522
  return 1;
4523
4523
  }
4524
4524
  if (cfg.lowMemoryMode && requestedWorkers === void 0) {
4525
4525
  log.info(
4526
- "[Render] Low-memory profile \u2014 pinning to 1 capture worker (auto-worker calibration skipped)."
4526
+ "[Render] Low-memory profile, pinning to 1 capture worker (auto-worker calibration skipped)."
4527
4527
  );
4528
4528
  return 1;
4529
4529
  }
@@ -5158,7 +5158,7 @@ function assertVideoFrameCoverage(reports, threshold) {
5158
5158
  const thresholdPct = (threshold * 100).toFixed(1);
5159
5159
  const suffix = sorted.length > 1 ? ` (+${sorted.length - 1} more clip(s) below threshold)` : "";
5160
5160
  throw new VideoFrameCoverageError(
5161
- `Video "${worst.videoId}" captured ${worst.capturedFrames} of expected ${worst.expectedFrames} frames (coverage ${pct}%, threshold ${thresholdPct}%). check/snapshot may pass while the encoded MP4 renders this clip blank \u2014 aborting render to prevent shipping a wrong MP4.${suffix} Set HF_VIDEO_COVERAGE_THRESHOLD=0 to disable this gate.`,
5161
+ `Video "${worst.videoId}" captured ${worst.capturedFrames} of expected ${worst.expectedFrames} frames (coverage ${pct}%, threshold ${thresholdPct}%). check/snapshot may pass while the encoded MP4 renders this clip blank, so the render is aborted to prevent shipping a wrong MP4.${suffix} Set HF_VIDEO_COVERAGE_THRESHOLD=0 to disable this gate.`,
5162
5162
  { threshold, worst, failedReports: sorted }
5163
5163
  );
5164
5164
  }
@@ -6054,7 +6054,7 @@ async function resolveMediaDuration(src, mediaStart, playbackRate, baseDir, down
6054
6054
  if (tagName !== "video") {
6055
6055
  if (error instanceof NotMediaPayloadError2) {
6056
6056
  log?.warn(
6057
- `[compile] Audio "${elementIdentity}" (${src}) is a text document, not a media file \u2014 the element is dropped from the render. Point it at a rendered media file.`
6057
+ `[compile] Audio "${elementIdentity}" (${src}) is a text document, not a media file, so the element is dropped from the render. Point it at a rendered media file.`
6058
6058
  );
6059
6059
  }
6060
6060
  return { duration: null, resolvedPath: filePath };
@@ -6143,7 +6143,7 @@ async function compileHtmlFile(html, baseDir, downloadDir, log) {
6143
6143
  if (r.maxDuration != null && shouldClampResolvedMediaDuration(r.tagName, r.duration, r.maxDuration)) {
6144
6144
  clampList.push({ id: r.id, duration: r.maxDuration });
6145
6145
  log?.warn(
6146
- `[compile] Audio "${r.id}" (${r.src}) is ${r.maxDuration.toFixed(2)}s but its data-duration is ${r.duration.toFixed(2)}s \u2014 the slot is shortened to the media length. Set data-duration to ~${r.maxDuration.toFixed(2)}s, trim data-media-start, or use a longer/looping source if that isn't intended.`
6146
+ `[compile] Audio "${r.id}" (${r.src}) is ${r.maxDuration.toFixed(2)}s but its data-duration is ${r.duration.toFixed(2)}s, so the slot is shortened to the media length. Set data-duration to ~${r.maxDuration.toFixed(2)}s, trim data-media-start, or use a longer/looping source if that isn't intended.`
6147
6147
  );
6148
6148
  }
6149
6149
  }
@@ -6532,7 +6532,7 @@ ${safeText}
6532
6532
  } else {
6533
6533
  if (download.reason instanceof ScriptIntegrityError) throw download.reason;
6534
6534
  defaultLogger.warn(
6535
- `[Compiler] WARNING: Failed to download CDN script: ${src} \u2014 ${download.reason}. The render may fail if this script is required (e.g. GSAP). Consider bundling it locally in your project.`
6535
+ `[Compiler] WARNING: Failed to download CDN script: ${src} (${download.reason}). The render may fail if this script is required (e.g. GSAP). Consider bundling it locally in your project.`
6536
6536
  );
6537
6537
  }
6538
6538
  }
@@ -6584,7 +6584,7 @@ function collectExternalAssets(html, projectDir) {
6584
6584
  }
6585
6585
  if (externalAssets.size > 0) {
6586
6586
  defaultLogger.info(
6587
- `[Compiler] Found ${externalAssets.size} asset(s) outside project directory \u2014 will copy to render output`
6587
+ `[Compiler] Found ${externalAssets.size} asset(s) outside project directory, will copy to render output`
6588
6588
  );
6589
6589
  }
6590
6590
  return {
@@ -6609,7 +6609,7 @@ async function downloadAndRewriteUrls(urlSet, html, remoteDir, warnLabel, logLab
6609
6609
  urlToLocal.set(url, localPath);
6610
6610
  } catch (err) {
6611
6611
  const identity = safeDownloadUrlIdentity(url);
6612
- defaultLogger.warn(`[Compiler] ${warnLabel} \u2014 using original URL as fallback.`, {
6612
+ defaultLogger.warn(`[Compiler] ${warnLabel}, using original URL as fallback.`, {
6613
6613
  urlFingerprint: identity.urlFingerprint,
6614
6614
  host: identity.host,
6615
6615
  error: err instanceof Error ? err.message : String(err)
@@ -6702,7 +6702,7 @@ async function fetchExternalStylesheetCss(href) {
6702
6702
  timeoutMs: 15e3
6703
6703
  });
6704
6704
  } catch (err) {
6705
- defaultLogger.warn("[Compiler] External stylesheet fetch failed \u2014 preserving link tag.", {
6705
+ defaultLogger.warn("[Compiler] External stylesheet fetch failed, preserving link tag.", {
6706
6706
  urlFingerprint: identity.urlFingerprint,
6707
6707
  host: identity.host,
6708
6708
  error: err instanceof Error ? err.message : String(err)
@@ -7346,12 +7346,15 @@ async function resolveCompositionDurations(page, unresolved) {
7346
7346
  const resolved = [];
7347
7347
  for (const id of compIds) {
7348
7348
  const tl = timelines[id];
7349
- if (tl && typeof tl.duration === "function") {
7350
- const dur = tl.duration();
7351
- if (dur > 0) {
7352
- resolved.push({ id, duration: dur, source: "__timelines" });
7353
- continue;
7354
- }
7349
+ let dur = 0;
7350
+ try {
7351
+ dur = typeof tl?.duration === "function" ? Number(tl.duration()) : 0;
7352
+ } catch {
7353
+ dur = 0;
7354
+ }
7355
+ if (dur > 0) {
7356
+ resolved.push({ id, duration: dur, source: "__timelines" });
7357
+ continue;
7355
7358
  }
7356
7359
  const el = document.getElementById(id);
7357
7360
  if (el) {
@@ -7447,28 +7450,28 @@ async function runCompileStage(input) {
7447
7450
  cfg.useDrawElement = false;
7448
7451
  deCompileGate = "3d";
7449
7452
  log.info(
7450
- "[Render] Fast capture: composition uses a CSS 3D rendering context (perspective / preserve-3d / backface-visibility) \u2014 disabling drawElementImage for this render. Capture uses the platform's baseline route."
7453
+ "[Render] Fast capture: composition uses a CSS 3D rendering context (perspective / preserve-3d / backface-visibility), so disabling drawElementImage for this render. Capture uses the platform's baseline route."
7451
7454
  );
7452
7455
  }
7453
7456
  if (cfg.useDrawElement && process.env.HF_FAST_CAPTURE_BLEND !== "true" && compiled.usesMixBlendMode) {
7454
7457
  cfg.useDrawElement = false;
7455
7458
  deCompileGate = "mix_blend_mode";
7456
7459
  log.info(
7457
- "[Render] Fast capture: composition uses mix-blend-mode \u2014 disabling drawElementImage for this render. Capture uses the platform's baseline route."
7460
+ "[Render] Fast capture: composition uses mix-blend-mode, so disabling drawElementImage for this render. Capture uses the platform's baseline route."
7458
7461
  );
7459
7462
  }
7460
7463
  if (cfg.useDrawElement && process.env.HF_FAST_CAPTURE_ANCESTOR_BG !== "true" && compiled.hasAncestorBackgroundImage) {
7461
7464
  cfg.useDrawElement = false;
7462
7465
  deCompileGate = "ancestor_background_image";
7463
7466
  log.info(
7464
- "[Render] Fast capture: composition root's ancestors (body/html/wrapper) carry a background-image \u2014 disabling drawElementImage for this render. Capture uses the platform's baseline route."
7467
+ "[Render] Fast capture: composition root's ancestors (body/html/wrapper) carry a background-image, so disabling drawElementImage for this render. Capture uses the platform's baseline route."
7465
7468
  );
7466
7469
  }
7467
7470
  if (cfg.useDrawElement && process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE !== "true" && compiled.hasShaderTransitions) {
7468
7471
  cfg.useDrawElement = false;
7469
7472
  deCompileGate = "shader_transitions";
7470
7473
  log.info(
7471
- "[Render] Fast capture: composition uses shader transitions \u2014 disabling drawElementImage so page-side compositing stays available."
7474
+ "[Render] Fast capture: composition uses shader transitions, so disabling drawElementImage so page-side compositing stays available."
7472
7475
  );
7473
7476
  }
7474
7477
  if (!cfg.useDrawElement && cfg.pageSideCompositingAutoDisabled) {
@@ -7796,7 +7799,7 @@ async function runProbeStage(input) {
7796
7799
  } else {
7797
7800
  beginFrameStalled = true;
7798
7801
  log.warn(
7799
- "[Render] BeginFrame liveness probe timed out \u2014 this composition stalls BeginFrame on this host (SwiftShader heavy-layer pattern). Relaunching the probe browser in screenshot capture mode; the render will use screenshot capture throughout.",
7802
+ "[Render] BeginFrame liveness probe timed out: this composition stalls BeginFrame on this host (SwiftShader heavy-layer pattern). Relaunching the probe browser in screenshot capture mode; the render will use screenshot capture throughout.",
7800
7803
  { probeTimeoutMs }
7801
7804
  );
7802
7805
  lastBrowserConsole = probeSession.browserConsoleBuffer;
@@ -8010,7 +8013,7 @@ async function runProbeStage(input) {
8010
8013
  video.start = win.visibleStart;
8011
8014
  video.end = win.visibleEnd;
8012
8015
  log.info(
8013
- `[Probe] Runtime video discovery: ${video.id} visible ${win.visibleStart.toFixed(2)}s\u2013${win.visibleEnd.toFixed(2)}s`
8016
+ `[Probe] Runtime video discovery: ${video.id} visible ${win.visibleStart.toFixed(2)}s to ${win.visibleEnd.toFixed(2)}s`
8014
8017
  );
8015
8018
  }
8016
8019
  }
@@ -8058,7 +8061,7 @@ async function runProbeStage(input) {
8058
8061
  });
8059
8062
  if (!timelinesInfo.gsapLoaded) {
8060
8063
  diagnostics.push(
8061
- "GSAP is not loaded \u2014 CDN script may have failed to download. Bundle GSAP locally in your project instead of using a CDN <script src>."
8064
+ "GSAP is not loaded. The CDN script may have failed to download. Bundle GSAP locally in your project instead of using a CDN <script src>."
8062
8065
  );
8063
8066
  } else if (timelinesInfo.timelineKeys.length === 0) {
8064
8067
  diagnostics.push(
@@ -8075,10 +8078,10 @@ async function runProbeStage(input) {
8075
8078
  log.warn("Failed to gather browser diagnostics for zero-duration composition", {
8076
8079
  error: err instanceof Error ? err.message : String(err)
8077
8080
  });
8078
- diagnostics.push("(Could not gather browser diagnostics \u2014 page may have crashed)");
8081
+ diagnostics.push("(Could not gather browser diagnostics. The page may have crashed.)");
8079
8082
  }
8080
8083
  const hint = diagnostics.length > 0 ? "\n\nDiagnostics:\n - " + diagnostics.join("\n - ") : "\n\nCheck that GSAP timelines are registered on window.__timelines.";
8081
- throw new Error("Composition duration is 0 \u2014 this would produce a black video." + hint);
8084
+ throw new Error("Composition duration is 0, so this would produce a black video." + hint);
8082
8085
  }
8083
8086
  if (probeSession) {
8084
8087
  const failedRequests = probeSession.browserConsoleBuffer.filter(isActionableProbeFailure);
@@ -8159,6 +8162,7 @@ import {
8159
8162
  detectTransfer,
8160
8163
  extractAllVideoFrames,
8161
8164
  extractMediaMetadata as extractMediaMetadata3,
8165
+ isVideoPastTimelineEnd,
8162
8166
  isHdrColorSpace as isHdrColorSpace2,
8163
8167
  resolveProjectRelativeSrc as resolveProjectRelativeSrc3,
8164
8168
  runVideoExtractionWithRetry,
@@ -8373,6 +8377,9 @@ async function runExtractVideosStage(input) {
8373
8377
  } = input;
8374
8378
  const stage2Start = Date.now();
8375
8379
  const extractionPolicy = resolveVideoExtractionPolicy();
8380
+ composition.videos = composition.videos.filter(
8381
+ (video) => !isVideoPastTimelineEnd(video, composition.duration)
8382
+ );
8376
8383
  let frameLookup = null;
8377
8384
  let extractionResult = null;
8378
8385
  let failureToEnforce = null;
@@ -8459,7 +8466,8 @@ async function runExtractVideosStage(input) {
8459
8466
  timelineEnd: composition.duration,
8460
8467
  maxTransientRetries: extractionPolicy.maxTransientRetries,
8461
8468
  collectProbeFailures: extractionPolicy.failureMode === "enforce",
8462
- deferRangeExtraction
8469
+ deferRangeExtraction,
8470
+ contentKeyedDirs: [join16(compiledDir, REMOTE_MEDIA_SUBDIR)]
8463
8471
  },
8464
8472
  abortSignal,
8465
8473
  cfg,
@@ -11085,7 +11093,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
11085
11093
  const madeProgress = captureAttemptMadeProgress(frameCount, remainingCount);
11086
11094
  if (!madeProgress) {
11087
11095
  options.log.warn(
11088
- "[Render] Capture attempt made no forward progress; composition is likely structurally broken \u2014 not retrying.",
11096
+ "[Render] Capture attempt made no forward progress; composition is likely structurally broken, not retrying.",
11089
11097
  { attempt, frameCount, remainingCount, workers: currentWorkers }
11090
11098
  );
11091
11099
  }
@@ -11154,7 +11162,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
11154
11162
  }
11155
11163
  if (!madeProgress) {
11156
11164
  options.log.warn(
11157
- "[Render] Capture attempt made no forward progress; composition is likely structurally broken \u2014 not retrying.",
11165
+ "[Render] Capture attempt made no forward progress; composition is likely structurally broken, not retrying.",
11158
11166
  { attempt, frameCount, remainingCount, workers: currentWorkers }
11159
11167
  );
11160
11168
  }
@@ -11617,7 +11625,7 @@ async function executeRenderJob(job, projectDir, outputPath, progressSink, abort
11617
11625
  execution.defer("remove workDir", () => {
11618
11626
  if (job.config.debug) return;
11619
11627
  if (job.status === "complete" && process.env.KEEP_TEMP === "1") {
11620
- log.info("KEEP_TEMP=1 \u2014 leaving workDir on disk for inspection", { workDir });
11628
+ log.info("KEEP_TEMP=1, leaving workDir on disk for inspection", { workDir });
11621
11629
  return;
11622
11630
  }
11623
11631
  rmSync9(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
@@ -11854,7 +11862,7 @@ async function executeRenderPipeline(input) {
11854
11862
  captureForceScreenshot = true;
11855
11863
  updateCaptureObservability({ forceScreenshot: captureForceScreenshot });
11856
11864
  log.info(
11857
- "[Render] Low-memory render profile active \u2014 screenshot capture, auto-worker calibration skipped" + (job.config.workers === void 0 ? ", pinned to 1 worker" : "") + ". Override with --no-low-memory-mode or PRODUCER_LOW_MEMORY_MODE=false.",
11865
+ "[Render] Low-memory render profile active: screenshot capture, auto-worker calibration skipped" + (job.config.workers === void 0 ? ", pinned to 1 worker" : "") + ". Override with --no-low-memory-mode or PRODUCER_LOW_MEMORY_MODE=false.",
11858
11866
  { totalMemMb: getSystemTotalMb(), thresholdMb: LOW_MEMORY_TOTAL_MB_THRESHOLD }
11859
11867
  );
11860
11868
  }
@@ -12422,7 +12430,7 @@ async function executeRenderPipeline(input) {
12422
12430
  cfg.useDrawElement = false;
12423
12431
  deClampReason = workerCount > 1 ? "parallel" : "disk_path";
12424
12432
  log.info(
12425
- "[Render] Fast capture: default-on drawElement disabled for this render \u2014 " + (workerCount > 1 ? "parallel capture" : "the disk capture path") + " has no runtime self-verification. Set PRODUCER_EXPERIMENTAL_FAST_CAPTURE=true to override."
12433
+ "[Render] Fast capture: default-on drawElement disabled for this render: " + (workerCount > 1 ? "parallel capture" : "the disk capture path") + " has no runtime self-verification. Set PRODUCER_EXPERIMENTAL_FAST_CAPTURE=true to override."
12426
12434
  );
12427
12435
  if (probeSession && probeSession.captureMode === "drawelement") {
12428
12436
  lastBrowserConsole = probeSession.browserConsoleBuffer;
@@ -12518,7 +12526,7 @@ async function executeRenderPipeline(input) {
12518
12526
  });
12519
12527
  updateCaptureObservability({ forceScreenshot: captureForceScreenshot });
12520
12528
  log.info(
12521
- `[Render] Page-side compositing enabled \u2014 bypassing Node-side layered shader-blend path. Engine will capture one ${needsAlpha ? "RGBA PNG" : "opaque RGB"} screenshot per output frame.`
12529
+ `[Render] Page-side compositing enabled, bypassing Node-side layered shader-blend path. Engine will capture one ${needsAlpha ? "RGBA PNG" : "opaque RGB"} screenshot per output frame.`
12522
12530
  );
12523
12531
  }
12524
12532
  const useLayeredComposite = !usePageSideCompositingForTransitions && shouldUseLayeredComposite({
@@ -13015,7 +13023,7 @@ async function executeRenderPipeline(input) {
13015
13023
  cfg.useDrawElement = false;
13016
13024
  deClampReason = deClampReason ?? "disk_path";
13017
13025
  log.info(
13018
- "[Render] Fast capture: drawElement disabled for the disk fallback \u2014 streaming encoder spawn failed and the disk path has no runtime self-verification."
13026
+ "[Render] Fast capture: drawElement disabled for the disk fallback: streaming encoder spawn failed and the disk path has no runtime self-verification."
13019
13027
  );
13020
13028
  if (probeSession && probeSession.captureMode === "drawelement") {
13021
13029
  lastBrowserConsole = probeSession.browserConsoleBuffer;
@@ -13633,10 +13641,10 @@ function validateJsonSafeValue(value, field) {
13633
13641
  walkVariables(value, field, /* @__PURE__ */ new WeakSet());
13634
13642
  }
13635
13643
  var LEAF_REJECTIONS = {
13636
- undefined: "undefined leaves are silently dropped by JSON.stringify \u2014 use null if you mean an absent value",
13644
+ undefined: "undefined leaves are silently dropped by JSON.stringify. Use null if you mean an absent value",
13637
13645
  function: "functions are not JSON-serializable",
13638
13646
  symbol: "Symbols are not JSON-serializable",
13639
- bigint: "BigInt values throw at JSON.stringify \u2014 encode as a string if you need 64-bit integers"
13647
+ bigint: "BigInt values throw at JSON.stringify. Encode as a string if you need 64-bit integers"
13640
13648
  };
13641
13649
  function walkVariables(value, path, seen) {
13642
13650
  const t = typeof value;
@@ -13657,7 +13665,7 @@ function walkVariables(value, path, seen) {
13657
13665
  if (seen.has(value)) {
13658
13666
  throw new InvalidConfigError(
13659
13667
  path,
13660
- "circular reference detected \u2014 JSON.stringify cannot serialize cycles"
13668
+ "circular reference detected: JSON.stringify cannot serialize cycles"
13661
13669
  );
13662
13670
  }
13663
13671
  seen.add(value);
@@ -13997,7 +14005,7 @@ function validateOutputResolutionOverride(body) {
13997
14005
  return `Invalid outputResolution "${body.outputResolution}". Must be one of: landscape, portrait, landscape-4k, portrait-4k, square, square-4k (aliases: 1080p, 4k, \u2026).`;
13998
14006
  }
13999
14007
  if (normalized !== void 0 && (body.format === "webm" || body.format === "mov")) {
14000
- return `outputResolution is not supported with format "${body.format}" \u2014 the alpha (webm/mov) capture path can't supersample. Use format "mp4", or omit outputResolution to render at the composition's native dimensions.`;
14008
+ return `outputResolution is not supported with format "${body.format}": the alpha (webm/mov) capture path can't supersample. Use format "mp4", or omit outputResolution to render at the composition's native dimensions.`;
14001
14009
  }
14002
14010
  return void 0;
14003
14011
  }
@@ -67,6 +67,7 @@ export declare function collectExternalAssets(html: string, projectDir: string):
67
67
  html: string;
68
68
  externalAssets: Map<string, string>;
69
69
  };
70
+ export declare const REMOTE_MEDIA_SUBDIR = "_remote_media";
70
71
  /**
71
72
  * Download any remote `src` URLs on `<video>` / `<audio>` elements and their
72
73
  * `<source>` children into a local subdirectory of `downloadDir`, rewrite the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/producer",
3
- "version": "0.8.145",
3
+ "version": "0.8.146",
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.2.1",
37
37
  "puppeteer-core": "^25.2.1",
38
- "@hyperframes/core": "0.8.145",
39
- "@hyperframes/engine": "0.8.145",
40
- "@hyperframes/lint": "0.8.145",
41
- "@hyperframes/parsers": "0.8.145",
42
- "@hyperframes/studio-server": "0.8.145"
38
+ "@hyperframes/lint": "0.8.146",
39
+ "@hyperframes/studio-server": "0.8.146",
40
+ "@hyperframes/core": "0.8.146",
41
+ "@hyperframes/parsers": "0.8.146",
42
+ "@hyperframes/engine": "0.8.146"
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.8.145"
51
+ "@hyperframes/aws-lambda": "0.8.146"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"