@hyperframes/producer 0.8.150 → 0.8.151

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
@@ -4304,7 +4304,8 @@ function computeSegmentPlanHash(input) {
4304
4304
  input.imageFormat,
4305
4305
  input.useGpu ? "gpu" : "cpu",
4306
4306
  `${input.outputWidth}x${input.outputHeight}`,
4307
- input.motionBlur
4307
+ input.motionBlur,
4308
+ input.captureQuality === void 0 ? "" : String(input.captureQuality)
4308
4309
  ].join(" ");
4309
4310
  return createHash2("sha256").update(ordered).digest("hex").slice(0, 16);
4310
4311
  }
@@ -7617,6 +7618,9 @@ function isActionableProbeFailure(line) {
7617
7618
  function resolveCaptureImageFormat(input) {
7618
7619
  return input.needsAlpha || input.motionBlur ? "png" : "jpeg";
7619
7620
  }
7621
+ function resolveCaptureJpegQuality(quality) {
7622
+ return quality === "draft" ? 80 : 100;
7623
+ }
7620
7624
 
7621
7625
  // src/services/render/stages/probeStage.ts
7622
7626
  var FRAME_BOUNDARY_EPSILON = 1e-3;
@@ -7772,7 +7776,7 @@ async function runProbeStage(input) {
7772
7776
  height,
7773
7777
  fps: job.config.fps,
7774
7778
  format: captureFormat,
7775
- quality: captureFormat === "png" ? void 0 : 80,
7779
+ quality: captureFormat === "png" ? void 0 : resolveCaptureJpegQuality(job.config.quality),
7776
7780
  variables: job.config.variables,
7777
7781
  deviceScaleFactor,
7778
7782
  motionBlur,
@@ -8756,13 +8760,16 @@ function shouldAllowAdaptiveCaptureRetry(workerCount, _explicitlyConfigured) {
8756
8760
  return workerCount > 1;
8757
8761
  }
8758
8762
  var JPEG_RAW_RGBA_DIVISOR = 8;
8763
+ var HIGH_QUALITY_JPEG_RAW_RGBA_DIVISOR = 4;
8759
8764
  var DISK_PROJECTION_SAMPLE_FRAMES = 10;
8760
8765
  function estimateDiskCaptureBytes(totalFrames, captureOptions) {
8761
8766
  const scale = captureOptions.deviceScaleFactor ?? 1;
8762
8767
  const outputWidth = Math.ceil(captureOptions.width * scale);
8763
8768
  const outputHeight = Math.ceil(captureOptions.height * scale);
8764
8769
  const rawBytes = Math.ceil(totalFrames) * outputWidth * outputHeight * 4;
8765
- return frameFileExtension(captureOptions.format) === "jpg" ? Math.ceil(rawBytes / JPEG_RAW_RGBA_DIVISOR) : rawBytes;
8770
+ return frameFileExtension(captureOptions.format) === "jpg" ? Math.ceil(
8771
+ rawBytes / ((captureOptions.quality ?? 80) > 80 ? HIGH_QUALITY_JPEG_RAW_RGBA_DIVISOR : JPEG_RAW_RGBA_DIVISOR)
8772
+ ) : rawBytes;
8766
8773
  }
8767
8774
  function freeDiskBytesAt(path) {
8768
8775
  try {
@@ -12224,7 +12231,7 @@ async function executeRenderPipeline(input) {
12224
12231
  height,
12225
12232
  fps: job.config.fps,
12226
12233
  format: captureImageFormat,
12227
- quality: captureImageFormat === "png" ? void 0 : job.config.quality === "draft" ? 80 : 95,
12234
+ quality: captureImageFormat === "png" ? void 0 : resolveCaptureJpegQuality(job.config.quality),
12228
12235
  variables: job.config.variables,
12229
12236
  deviceScaleFactor,
12230
12237
  motionBlur: job.config.motionBlur,
@@ -12852,7 +12859,8 @@ async function executeRenderPipeline(input) {
12852
12859
  // Device-scaled: the capture buffer, not the CSS composition size.
12853
12860
  outputWidth: captureCompositionWidth ?? width,
12854
12861
  outputHeight: captureCompositionHeight ?? height,
12855
- motionBlur: job.config.motionBlur ? JSON.stringify(job.config.motionBlur) : ""
12862
+ motionBlur: job.config.motionBlur ? JSON.stringify(job.config.motionBlur) : "",
12863
+ captureQuality: captureOptions.quality
12856
12864
  });
12857
12865
  const segmentDir = segmentDirFor(join26(projectDir, "renders"), segmentPlanHash);
12858
12866
  let completedSegments = /* @__PURE__ */ new Set();
@@ -17724,7 +17732,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
17724
17732
  height: plan2.dimensions.height,
17725
17733
  fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
17726
17734
  format: plan2.dimensions.format === "mp4" ? "jpeg" : "png",
17727
- quality: plan2.dimensions.format === "mp4" ? 80 : void 0,
17735
+ quality: plan2.dimensions.format === "mp4" ? resolveCaptureJpegQuality(job.config.quality) : void 0,
17728
17736
  deviceScaleFactor: encoder.deviceScaleFactor,
17729
17737
  // Re-inject the controller's snapshotted variables so the chunk's
17730
17738
  // first capture sees the same `window.__hfVariables` the in-process
@@ -4323,7 +4323,8 @@ function computeSegmentPlanHash(input) {
4323
4323
  input.imageFormat,
4324
4324
  input.useGpu ? "gpu" : "cpu",
4325
4325
  `${input.outputWidth}x${input.outputHeight}`,
4326
- input.motionBlur
4326
+ input.motionBlur,
4327
+ input.captureQuality === void 0 ? "" : String(input.captureQuality)
4327
4328
  ].join(" ");
4328
4329
  return createHash2("sha256").update(ordered).digest("hex").slice(0, 16);
4329
4330
  }
@@ -7636,6 +7637,9 @@ function isActionableProbeFailure(line) {
7636
7637
  function resolveCaptureImageFormat(input) {
7637
7638
  return input.needsAlpha || input.motionBlur ? "png" : "jpeg";
7638
7639
  }
7640
+ function resolveCaptureJpegQuality(quality) {
7641
+ return quality === "draft" ? 80 : 100;
7642
+ }
7639
7643
 
7640
7644
  // src/services/render/stages/probeStage.ts
7641
7645
  var FRAME_BOUNDARY_EPSILON = 1e-3;
@@ -7791,7 +7795,7 @@ async function runProbeStage(input) {
7791
7795
  height,
7792
7796
  fps: job.config.fps,
7793
7797
  format: captureFormat,
7794
- quality: captureFormat === "png" ? void 0 : 80,
7798
+ quality: captureFormat === "png" ? void 0 : resolveCaptureJpegQuality(job.config.quality),
7795
7799
  variables: job.config.variables,
7796
7800
  deviceScaleFactor,
7797
7801
  motionBlur,
@@ -8739,13 +8743,16 @@ function shouldAllowAdaptiveCaptureRetry(workerCount, _explicitlyConfigured) {
8739
8743
  return workerCount > 1;
8740
8744
  }
8741
8745
  var JPEG_RAW_RGBA_DIVISOR = 8;
8746
+ var HIGH_QUALITY_JPEG_RAW_RGBA_DIVISOR = 4;
8742
8747
  var DISK_PROJECTION_SAMPLE_FRAMES = 10;
8743
8748
  function estimateDiskCaptureBytes(totalFrames, captureOptions) {
8744
8749
  const scale = captureOptions.deviceScaleFactor ?? 1;
8745
8750
  const outputWidth = Math.ceil(captureOptions.width * scale);
8746
8751
  const outputHeight = Math.ceil(captureOptions.height * scale);
8747
8752
  const rawBytes = Math.ceil(totalFrames) * outputWidth * outputHeight * 4;
8748
- return frameFileExtension(captureOptions.format) === "jpg" ? Math.ceil(rawBytes / JPEG_RAW_RGBA_DIVISOR) : rawBytes;
8753
+ return frameFileExtension(captureOptions.format) === "jpg" ? Math.ceil(
8754
+ rawBytes / ((captureOptions.quality ?? 80) > 80 ? HIGH_QUALITY_JPEG_RAW_RGBA_DIVISOR : JPEG_RAW_RGBA_DIVISOR)
8755
+ ) : rawBytes;
8749
8756
  }
8750
8757
  function freeDiskBytesAt(path) {
8751
8758
  try {
@@ -12207,7 +12214,7 @@ async function executeRenderPipeline(input) {
12207
12214
  height,
12208
12215
  fps: job.config.fps,
12209
12216
  format: captureImageFormat,
12210
- quality: captureImageFormat === "png" ? void 0 : job.config.quality === "draft" ? 80 : 95,
12217
+ quality: captureImageFormat === "png" ? void 0 : resolveCaptureJpegQuality(job.config.quality),
12211
12218
  variables: job.config.variables,
12212
12219
  deviceScaleFactor,
12213
12220
  motionBlur: job.config.motionBlur,
@@ -12835,7 +12842,8 @@ async function executeRenderPipeline(input) {
12835
12842
  // Device-scaled: the capture buffer, not the CSS composition size.
12836
12843
  outputWidth: captureCompositionWidth ?? width,
12837
12844
  outputHeight: captureCompositionHeight ?? height,
12838
- motionBlur: job.config.motionBlur ? JSON.stringify(job.config.motionBlur) : ""
12845
+ motionBlur: job.config.motionBlur ? JSON.stringify(job.config.motionBlur) : "",
12846
+ captureQuality: captureOptions.quality
12839
12847
  });
12840
12848
  const segmentDir = segmentDirFor(join26(projectDir, "renders"), segmentPlanHash);
12841
12849
  let completedSegments = /* @__PURE__ */ new Set();
@@ -1,4 +1,4 @@
1
- import type { MotionBlurOptions } from "@hyperframes/engine";
1
+ import type { EngineConfig, MotionBlurOptions } from "@hyperframes/engine";
2
2
  /**
3
3
  * The format a render captures its frames in.
4
4
  *
@@ -16,3 +16,8 @@ export declare function resolveCaptureImageFormat(input: {
16
16
  needsAlpha: boolean;
17
17
  motionBlur: MotionBlurOptions | undefined;
18
18
  }): "jpeg" | "png";
19
+ /**
20
+ * Below 100, Chrome's JPEG turns graded colour and grain into 8x8 chroma blotches that survive
21
+ * the final encode. Draft keeps the smaller, faster frames.
22
+ */
23
+ export declare function resolveCaptureJpegQuality(quality: EngineConfig["quality"]): number;
@@ -37,6 +37,7 @@ export interface SegmentPlanHashInput {
37
37
  outputHeight: number;
38
38
  /** Serialised motion-blur options, or "" when off; sample count and shutter change every pixel. */
39
39
  motionBlur: string;
40
+ captureQuality: number | undefined;
40
41
  }
41
42
  /** Everything that determines segment bytes. Key order is fixed by construction. */
42
43
  export declare function computeSegmentPlanHash(input: SegmentPlanHashInput): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/producer",
3
- "version": "0.8.150",
3
+ "version": "0.8.151",
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/lint": "0.8.150",
39
- "@hyperframes/engine": "0.8.150",
40
- "@hyperframes/core": "0.8.150",
41
- "@hyperframes/studio-server": "0.8.150",
42
- "@hyperframes/parsers": "0.8.150"
38
+ "@hyperframes/lint": "0.8.151",
39
+ "@hyperframes/engine": "0.8.151",
40
+ "@hyperframes/studio-server": "0.8.151",
41
+ "@hyperframes/parsers": "0.8.151",
42
+ "@hyperframes/core": "0.8.151"
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.150"
51
+ "@hyperframes/aws-lambda": "0.8.151"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"