@hyperframes/producer 0.4.10 → 0.4.11
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 +604 -132
- package/dist/index.js.map +3 -3
- package/dist/public-server.js +604 -132
- package/dist/public-server.js.map +3 -3
- package/dist/services/htmlCompiler.d.ts +2 -1
- package/dist/services/htmlCompiler.d.ts.map +1 -1
- package/dist/services/renderOrchestrator.d.ts +8 -1
- package/dist/services/renderOrchestrator.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -78348,16 +78348,16 @@ var require_buffer_crc32 = __commonJS({
|
|
|
78348
78348
|
}
|
|
78349
78349
|
return crc ^ -1;
|
|
78350
78350
|
}
|
|
78351
|
-
function
|
|
78351
|
+
function crc322() {
|
|
78352
78352
|
return bufferizeInt(_crc32.apply(null, arguments));
|
|
78353
78353
|
}
|
|
78354
|
-
|
|
78354
|
+
crc322.signed = function() {
|
|
78355
78355
|
return _crc32.apply(null, arguments);
|
|
78356
78356
|
};
|
|
78357
|
-
|
|
78357
|
+
crc322.unsigned = function() {
|
|
78358
78358
|
return _crc32.apply(null, arguments) >>> 0;
|
|
78359
78359
|
};
|
|
78360
|
-
module.exports =
|
|
78360
|
+
module.exports = crc322;
|
|
78361
78361
|
}
|
|
78362
78362
|
});
|
|
78363
78363
|
|
|
@@ -78367,7 +78367,7 @@ var require_yauzl = __commonJS({
|
|
|
78367
78367
|
var fs8 = __require("fs");
|
|
78368
78368
|
var zlib = __require("zlib");
|
|
78369
78369
|
var fd_slicer = require_fd_slicer();
|
|
78370
|
-
var
|
|
78370
|
+
var crc322 = require_buffer_crc32();
|
|
78371
78371
|
var util = __require("util");
|
|
78372
78372
|
var EventEmitter4 = __require("events").EventEmitter;
|
|
78373
78373
|
var Transform = __require("stream").Transform;
|
|
@@ -78653,7 +78653,7 @@ var require_yauzl = __commonJS({
|
|
|
78653
78653
|
continue;
|
|
78654
78654
|
}
|
|
78655
78655
|
var oldNameCrc32 = extraField.data.readUInt32LE(1);
|
|
78656
|
-
if (
|
|
78656
|
+
if (crc322.unsigned(buffer.slice(0, entry.fileNameLength)) !== oldNameCrc32) {
|
|
78657
78657
|
continue;
|
|
78658
78658
|
}
|
|
78659
78659
|
entry.fileName = decodeBuffer(extraField.data, 5, extraField.data.length, true);
|
|
@@ -89420,7 +89420,7 @@ import {
|
|
|
89420
89420
|
existsSync as existsSync15,
|
|
89421
89421
|
mkdirSync as mkdirSync10,
|
|
89422
89422
|
rmSync as rmSync3,
|
|
89423
|
-
readFileSync as
|
|
89423
|
+
readFileSync as readFileSync10,
|
|
89424
89424
|
readdirSync as readdirSync6,
|
|
89425
89425
|
writeFileSync as writeFileSync4,
|
|
89426
89426
|
copyFileSync as copyFileSync2,
|
|
@@ -99641,9 +99641,25 @@ var mediaRules = [
|
|
|
99641
99641
|
// video_nested_in_timed_element
|
|
99642
99642
|
({ source: source2, tags }) => {
|
|
99643
99643
|
const findings = [];
|
|
99644
|
+
const voidElements3 = /* @__PURE__ */ new Set([
|
|
99645
|
+
"area",
|
|
99646
|
+
"base",
|
|
99647
|
+
"br",
|
|
99648
|
+
"col",
|
|
99649
|
+
"embed",
|
|
99650
|
+
"hr",
|
|
99651
|
+
"img",
|
|
99652
|
+
"input",
|
|
99653
|
+
"link",
|
|
99654
|
+
"meta",
|
|
99655
|
+
"source",
|
|
99656
|
+
"track",
|
|
99657
|
+
"wbr"
|
|
99658
|
+
]);
|
|
99644
99659
|
const timedTagPositions = [];
|
|
99645
99660
|
for (const tag of tags) {
|
|
99646
99661
|
if (tag.name === "video" || tag.name === "audio") continue;
|
|
99662
|
+
if (voidElements3.has(tag.name)) continue;
|
|
99647
99663
|
if (readAttr(tag.raw, "data-composition-id")) continue;
|
|
99648
99664
|
if (readAttr(tag.raw, "data-start")) {
|
|
99649
99665
|
timedTagPositions.push({
|
|
@@ -99810,7 +99826,9 @@ function extractGsapWindows(script) {
|
|
|
99810
99826
|
let index = 0;
|
|
99811
99827
|
while ((match2 = methodPattern.exec(script)) !== null && index < parsed.animations.length) {
|
|
99812
99828
|
const raw2 = match2[0];
|
|
99813
|
-
const
|
|
99829
|
+
const args = match2[2] ?? "";
|
|
99830
|
+
if (!/^\s*["']/.test(args)) continue;
|
|
99831
|
+
const meta = parseGsapWindowMeta(match2[1] ?? "", args);
|
|
99814
99832
|
const animation = parsed.animations[index];
|
|
99815
99833
|
index += 1;
|
|
99816
99834
|
if (!animation) continue;
|
|
@@ -101104,6 +101122,12 @@ async function createCaptureSession(serverUrl, outputDir, options, onBeforeCaptu
|
|
|
101104
101122
|
);
|
|
101105
101123
|
const { browser, captureMode } = await acquireBrowser(chromeArgs, config2);
|
|
101106
101124
|
const page = await browser.newPage();
|
|
101125
|
+
await page.evaluateOnNewDocument(() => {
|
|
101126
|
+
const w = window;
|
|
101127
|
+
if (typeof w.__name !== "function") {
|
|
101128
|
+
w.__name = (fn, _name) => fn;
|
|
101129
|
+
}
|
|
101130
|
+
});
|
|
101107
101131
|
const browserVersion = await browser.version();
|
|
101108
101132
|
const expectedMajor = config2?.expectedChromiumMajor;
|
|
101109
101133
|
if (Number.isFinite(expectedMajor)) {
|
|
@@ -101208,9 +101232,10 @@ async function initializeSession(session) {
|
|
|
101208
101232
|
`[FrameCapture] window.__hf not ready after ${pageReadyTimeout2}ms. Page must expose window.__hf = { duration, seek }.`
|
|
101209
101233
|
);
|
|
101210
101234
|
}
|
|
101235
|
+
const skipIdsLiteral = JSON.stringify(session.options.skipReadinessVideoIds ?? []);
|
|
101211
101236
|
const videosReady = await pollPageExpression(
|
|
101212
101237
|
page,
|
|
101213
|
-
`
|
|
101238
|
+
`(() => { const skip = new Set(${skipIdsLiteral}); const vids = Array.from(document.querySelectorAll("video")).filter(v => !skip.has(v.id)); return vids.length === 0 || vids.every(v => v.readyState >= 1); })()`,
|
|
101214
101239
|
pageReadyTimeout2
|
|
101215
101240
|
);
|
|
101216
101241
|
if (!videosReady) {
|
|
@@ -101270,10 +101295,11 @@ async function initializeSession(session) {
|
|
|
101270
101295
|
`[FrameCapture] window.__hf not ready after ${pageReadyTimeout}ms. Page must expose window.__hf = { duration, seek }.`
|
|
101271
101296
|
);
|
|
101272
101297
|
}
|
|
101298
|
+
const beginframeSkipIdsLiteral = JSON.stringify(session.options.skipReadinessVideoIds ?? []);
|
|
101273
101299
|
const videoDeadline = Date.now() + (session.config?.playerReadyTimeout ?? DEFAULT_CONFIG.playerReadyTimeout);
|
|
101274
101300
|
while (Date.now() < videoDeadline) {
|
|
101275
101301
|
const videosReady = await page.evaluate(
|
|
101276
|
-
`
|
|
101302
|
+
`(() => { const skip = new Set(${beginframeSkipIdsLiteral}); const vids = Array.from(document.querySelectorAll("video")).filter(v => !skip.has(v.id)); return vids.length === 0 || vids.every(v => v.readyState >= 1); })()`
|
|
101277
101303
|
);
|
|
101278
101304
|
if (videosReady) break;
|
|
101279
101305
|
await new Promise((r) => setTimeout(r, 100));
|
|
@@ -102253,6 +102279,8 @@ import { join as join8 } from "path";
|
|
|
102253
102279
|
|
|
102254
102280
|
// ../engine/src/utils/ffprobe.ts
|
|
102255
102281
|
import { spawn as spawn7 } from "child_process";
|
|
102282
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
102283
|
+
import { extname as extname2 } from "path";
|
|
102256
102284
|
function runFfprobe(args) {
|
|
102257
102285
|
return new Promise((resolve13, reject) => {
|
|
102258
102286
|
const proc = spawn7("ffprobe", args);
|
|
@@ -102291,6 +102319,67 @@ function parseProbeJson(stdout) {
|
|
|
102291
102319
|
}
|
|
102292
102320
|
var videoMetadataCache = /* @__PURE__ */ new Map();
|
|
102293
102321
|
var audioMetadataCache = /* @__PURE__ */ new Map();
|
|
102322
|
+
function crc32(buf) {
|
|
102323
|
+
let crc = 4294967295;
|
|
102324
|
+
for (let i = 0; i < buf.length; i++) {
|
|
102325
|
+
crc ^= buf[i] ?? 0;
|
|
102326
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
102327
|
+
const mask = -(crc & 1);
|
|
102328
|
+
crc = crc >>> 1 ^ 3988292384 & mask;
|
|
102329
|
+
}
|
|
102330
|
+
}
|
|
102331
|
+
return (crc ^ 4294967295) >>> 0;
|
|
102332
|
+
}
|
|
102333
|
+
function extractPngMetadataFromBuffer(buf) {
|
|
102334
|
+
if (buf.length < 8 || buf[0] !== 137 || buf[1] !== 80 || buf[2] !== 78 || buf[3] !== 71 || buf[4] !== 13 || buf[5] !== 10 || buf[6] !== 26 || buf[7] !== 10) {
|
|
102335
|
+
return null;
|
|
102336
|
+
}
|
|
102337
|
+
let width = 0;
|
|
102338
|
+
let height = 0;
|
|
102339
|
+
let seenIdat = false;
|
|
102340
|
+
let pos = 8;
|
|
102341
|
+
while (pos + 12 <= buf.length) {
|
|
102342
|
+
const chunkLen = buf.readUInt32BE(pos);
|
|
102343
|
+
const chunkType = buf.toString("ascii", pos + 4, pos + 8);
|
|
102344
|
+
if (pos + 12 + chunkLen > buf.length) return null;
|
|
102345
|
+
const chunkData = buf.subarray(pos + 8, pos + 8 + chunkLen);
|
|
102346
|
+
const chunkCrc = buf.readUInt32BE(pos + 8 + chunkLen);
|
|
102347
|
+
const chunkBytes = Buffer.concat([Buffer.from(chunkType, "ascii"), chunkData]);
|
|
102348
|
+
if (crc32(chunkBytes) !== chunkCrc) return null;
|
|
102349
|
+
if (chunkType === "IHDR" && chunkLen >= 8) {
|
|
102350
|
+
width = buf.readUInt32BE(pos + 8);
|
|
102351
|
+
height = buf.readUInt32BE(pos + 12);
|
|
102352
|
+
}
|
|
102353
|
+
if (chunkType === "IDAT") {
|
|
102354
|
+
seenIdat = true;
|
|
102355
|
+
}
|
|
102356
|
+
if (chunkType === "cICP" && chunkLen === 4 && !seenIdat) {
|
|
102357
|
+
const primariesCode = chunkData[0] ?? 0;
|
|
102358
|
+
const transferCode = chunkData[1] ?? 0;
|
|
102359
|
+
const matrixCode = chunkData[2] ?? 0;
|
|
102360
|
+
return {
|
|
102361
|
+
width,
|
|
102362
|
+
height,
|
|
102363
|
+
colorSpace: {
|
|
102364
|
+
colorPrimaries: primariesCode === 9 ? "bt2020" : primariesCode === 1 ? "bt709" : `unknown-${primariesCode}`,
|
|
102365
|
+
colorTransfer: transferCode === 16 ? "smpte2084" : transferCode === 18 ? "arib-std-b67" : transferCode === 1 ? "bt709" : `unknown-${transferCode}`,
|
|
102366
|
+
colorSpace: matrixCode === 9 ? "bt2020nc" : matrixCode === 0 ? "gbr" : `unknown-${matrixCode}`
|
|
102367
|
+
}
|
|
102368
|
+
};
|
|
102369
|
+
}
|
|
102370
|
+
if (chunkType === "IEND") break;
|
|
102371
|
+
pos += 12 + chunkLen;
|
|
102372
|
+
}
|
|
102373
|
+
return width > 0 && height > 0 ? { width, height, colorSpace: null } : null;
|
|
102374
|
+
}
|
|
102375
|
+
function extractStillImageMetadata(filePath) {
|
|
102376
|
+
if (extname2(filePath).toLowerCase() !== ".png") return null;
|
|
102377
|
+
try {
|
|
102378
|
+
return extractPngMetadataFromBuffer(readFileSync5(filePath));
|
|
102379
|
+
} catch {
|
|
102380
|
+
return null;
|
|
102381
|
+
}
|
|
102382
|
+
}
|
|
102294
102383
|
function parseFrameRate(frameRateStr) {
|
|
102295
102384
|
if (!frameRateStr) return 0;
|
|
102296
102385
|
const parts = frameRateStr.split("/");
|
|
@@ -102305,18 +102394,38 @@ async function extractVideoMetadata(filePath) {
|
|
|
102305
102394
|
const cached = videoMetadataCache.get(filePath);
|
|
102306
102395
|
if (cached) return cached;
|
|
102307
102396
|
const probePromise = (async () => {
|
|
102308
|
-
const
|
|
102309
|
-
|
|
102310
|
-
|
|
102311
|
-
|
|
102312
|
-
|
|
102313
|
-
|
|
102314
|
-
|
|
102315
|
-
|
|
102316
|
-
|
|
102317
|
-
|
|
102318
|
-
|
|
102319
|
-
|
|
102397
|
+
const stillImageMeta = extractStillImageMetadata(filePath);
|
|
102398
|
+
let output2 = null;
|
|
102399
|
+
try {
|
|
102400
|
+
const stdout = await runFfprobe([
|
|
102401
|
+
"-v",
|
|
102402
|
+
"quiet",
|
|
102403
|
+
"-print_format",
|
|
102404
|
+
"json",
|
|
102405
|
+
"-show_format",
|
|
102406
|
+
"-show_streams",
|
|
102407
|
+
filePath
|
|
102408
|
+
]);
|
|
102409
|
+
output2 = parseProbeJson(stdout);
|
|
102410
|
+
} catch (error) {
|
|
102411
|
+
if (!stillImageMeta) throw error;
|
|
102412
|
+
}
|
|
102413
|
+
const videoStream = output2?.streams.find((s) => s.codec_type === "video");
|
|
102414
|
+
if (!videoStream) {
|
|
102415
|
+
if (stillImageMeta) {
|
|
102416
|
+
return {
|
|
102417
|
+
durationSeconds: 0,
|
|
102418
|
+
width: stillImageMeta.width,
|
|
102419
|
+
height: stillImageMeta.height,
|
|
102420
|
+
fps: 0,
|
|
102421
|
+
videoCodec: "png",
|
|
102422
|
+
hasAudio: false,
|
|
102423
|
+
isVFR: false,
|
|
102424
|
+
colorSpace: stillImageMeta.colorSpace
|
|
102425
|
+
};
|
|
102426
|
+
}
|
|
102427
|
+
throw new Error("[FFmpeg] No video stream found");
|
|
102428
|
+
}
|
|
102320
102429
|
const rFps = parseFrameRate(videoStream.r_frame_rate);
|
|
102321
102430
|
const avgFps = parseFrameRate(videoStream.avg_frame_rate);
|
|
102322
102431
|
const fps = avgFps || rFps;
|
|
@@ -102324,16 +102433,17 @@ async function extractVideoMetadata(filePath) {
|
|
|
102324
102433
|
const colorTransfer = videoStream.color_transfer || "";
|
|
102325
102434
|
const colorPrimaries = videoStream.color_primaries || "";
|
|
102326
102435
|
const colorSpaceVal = videoStream.color_space || "";
|
|
102327
|
-
const
|
|
102436
|
+
const ffprobeColorSpace = colorTransfer || colorPrimaries || colorSpaceVal ? { colorTransfer, colorPrimaries, colorSpace: colorSpaceVal } : null;
|
|
102437
|
+
const colorSpace = ffprobeColorSpace ?? stillImageMeta?.colorSpace ?? null;
|
|
102328
102438
|
return {
|
|
102329
|
-
durationSeconds: output2
|
|
102330
|
-
width: videoStream.width || 0,
|
|
102331
|
-
height: videoStream.height || 0,
|
|
102439
|
+
durationSeconds: output2?.format.duration ? parseFloat(output2.format.duration) : 0,
|
|
102440
|
+
width: videoStream.width || stillImageMeta?.width || 0,
|
|
102441
|
+
height: videoStream.height || stillImageMeta?.height || 0,
|
|
102332
102442
|
fps,
|
|
102333
102443
|
videoCodec: videoStream.codec_name || "unknown",
|
|
102334
|
-
hasAudio: output2
|
|
102444
|
+
hasAudio: output2?.streams.some((s) => s.codec_type === "audio") ?? false,
|
|
102335
102445
|
isVFR,
|
|
102336
|
-
colorSpace
|
|
102446
|
+
colorSpace
|
|
102337
102447
|
};
|
|
102338
102448
|
})();
|
|
102339
102449
|
videoMetadataCache.set(filePath, probePromise);
|
|
@@ -102432,7 +102542,7 @@ async function analyzeKeyframeIntervalsUncached(filePath) {
|
|
|
102432
102542
|
// ../engine/src/utils/urlDownloader.ts
|
|
102433
102543
|
import { createWriteStream as createWriteStream2, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
102434
102544
|
import { createHash } from "crypto";
|
|
102435
|
-
import { join as join7, extname as
|
|
102545
|
+
import { join as join7, extname as extname3 } from "path";
|
|
102436
102546
|
import { Readable } from "stream";
|
|
102437
102547
|
import { finished } from "stream/promises";
|
|
102438
102548
|
var downloadPathCache = /* @__PURE__ */ new Map();
|
|
@@ -102440,7 +102550,7 @@ var inFlightDownloads = /* @__PURE__ */ new Map();
|
|
|
102440
102550
|
function getFilenameFromUrl(url) {
|
|
102441
102551
|
const hash2 = createHash("md5").update(url).digest("hex").slice(0, 12);
|
|
102442
102552
|
const urlObj = new URL(url);
|
|
102443
|
-
const ext =
|
|
102553
|
+
const ext = extname3(urlObj.pathname) || ".mp4";
|
|
102444
102554
|
return `download_${hash2}${ext}`;
|
|
102445
102555
|
}
|
|
102446
102556
|
async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
|
|
@@ -102533,6 +102643,34 @@ function parseVideoElements(html) {
|
|
|
102533
102643
|
}
|
|
102534
102644
|
return videos;
|
|
102535
102645
|
}
|
|
102646
|
+
function parseImageElements(html) {
|
|
102647
|
+
const images = [];
|
|
102648
|
+
const { document: document2 } = parseHTML(html);
|
|
102649
|
+
const imgEls = document2.querySelectorAll("img[src]");
|
|
102650
|
+
let autoIdCounter = 0;
|
|
102651
|
+
for (const el of imgEls) {
|
|
102652
|
+
const src = el.getAttribute("src");
|
|
102653
|
+
if (!src) continue;
|
|
102654
|
+
const id = el.getAttribute("id") || `hf-img-${autoIdCounter++}`;
|
|
102655
|
+
if (!el.getAttribute("id")) {
|
|
102656
|
+
el.setAttribute("id", id);
|
|
102657
|
+
}
|
|
102658
|
+
const startAttr = el.getAttribute("data-start");
|
|
102659
|
+
const endAttr = el.getAttribute("data-end");
|
|
102660
|
+
const durationAttr = el.getAttribute("data-duration");
|
|
102661
|
+
const start = startAttr ? parseFloat(startAttr) : 0;
|
|
102662
|
+
let end = 0;
|
|
102663
|
+
if (endAttr) {
|
|
102664
|
+
end = parseFloat(endAttr);
|
|
102665
|
+
} else if (durationAttr) {
|
|
102666
|
+
end = start + parseFloat(durationAttr);
|
|
102667
|
+
} else {
|
|
102668
|
+
end = Infinity;
|
|
102669
|
+
}
|
|
102670
|
+
images.push({ id, src, start, end });
|
|
102671
|
+
}
|
|
102672
|
+
return images;
|
|
102673
|
+
}
|
|
102536
102674
|
async function extractVideoFramesRange(videoPath, videoId, startTime, duration, options, signal, config2) {
|
|
102537
102675
|
const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
|
|
102538
102676
|
const { fps, outputDir, quality = 95, format: format3 = "jpg" } = options;
|
|
@@ -102942,8 +103080,8 @@ function createVideoFrameInjector(frameLookup, config2) {
|
|
|
102942
103080
|
}
|
|
102943
103081
|
};
|
|
102944
103082
|
}
|
|
102945
|
-
async function queryElementStacking(page,
|
|
102946
|
-
const hdrIds = Array.from(
|
|
103083
|
+
async function queryElementStacking(page, nativeHdrIds) {
|
|
103084
|
+
const hdrIds = Array.from(nativeHdrIds);
|
|
102947
103085
|
return page.evaluate((hdrIdList) => {
|
|
102948
103086
|
const hdrSet = new Set(hdrIdList);
|
|
102949
103087
|
const elements = document.querySelectorAll("[data-start]");
|
|
@@ -103072,7 +103210,12 @@ async function queryElementStacking(page, nativeHdrVideoIds) {
|
|
|
103072
103210
|
// affine blit can apply rotation/scale/translate properly. For DOM
|
|
103073
103211
|
// elements, the element-level transform is sufficient for reference.
|
|
103074
103212
|
transform: isHdrEl ? getViewportMatrix(el) : style.transform || "none",
|
|
103075
|
-
borderRadius: isHdrEl ? getEffectiveBorderRadius(el) : [0, 0, 0, 0]
|
|
103213
|
+
borderRadius: isHdrEl ? getEffectiveBorderRadius(el) : [0, 0, 0, 0],
|
|
103214
|
+
// `getComputedStyle` returns "" when the property doesn't apply (e.g.
|
|
103215
|
+
// for non-replaced elements); normalize to the CSS defaults so callers
|
|
103216
|
+
// can rely on a populated value.
|
|
103217
|
+
objectFit: style.objectFit || "fill",
|
|
103218
|
+
objectPosition: style.objectPosition || "50% 50%"
|
|
103076
103219
|
});
|
|
103077
103220
|
}
|
|
103078
103221
|
return results;
|
|
@@ -106537,6 +106680,125 @@ function blitRgb48leAffine(canvas, source2, matrix, srcW, srcH, canvasW, canvasH
|
|
|
106537
106680
|
}
|
|
106538
106681
|
}
|
|
106539
106682
|
}
|
|
106683
|
+
function parseObjectPositionAxis(value, axis) {
|
|
106684
|
+
const lower = value.trim().toLowerCase();
|
|
106685
|
+
if (lower === "left" || lower === "top") return 0;
|
|
106686
|
+
if (lower === "right" || lower === "bottom") return 1;
|
|
106687
|
+
if (lower === "center" || lower === "") return 0.5;
|
|
106688
|
+
if (lower.endsWith("%")) {
|
|
106689
|
+
const pct = parseFloat(lower) / 100;
|
|
106690
|
+
return Number.isFinite(pct) ? Math.max(0, Math.min(1, pct)) : 0.5;
|
|
106691
|
+
}
|
|
106692
|
+
if (axis === "x" || axis === "y") return 0.5;
|
|
106693
|
+
return 0.5;
|
|
106694
|
+
}
|
|
106695
|
+
function parseObjectPosition(css) {
|
|
106696
|
+
if (!css || !css.trim()) return { x: 0.5, y: 0.5 };
|
|
106697
|
+
const tokens = css.trim().split(/\s+/);
|
|
106698
|
+
if (tokens.length === 1) {
|
|
106699
|
+
const single = tokens[0] ?? "";
|
|
106700
|
+
const v = parseObjectPositionAxis(single, "x");
|
|
106701
|
+
return { x: v, y: 0.5 };
|
|
106702
|
+
}
|
|
106703
|
+
return {
|
|
106704
|
+
x: parseObjectPositionAxis(tokens[0] ?? "", "x"),
|
|
106705
|
+
y: parseObjectPositionAxis(tokens[1] ?? "", "y")
|
|
106706
|
+
};
|
|
106707
|
+
}
|
|
106708
|
+
function computeObjectFitRect(srcW, srcH, dstW, dstH, fit, pos) {
|
|
106709
|
+
let renderedW = dstW;
|
|
106710
|
+
let renderedH = dstH;
|
|
106711
|
+
if (fit === "fill") {
|
|
106712
|
+
return { dx: 0, dy: 0, dw: dstW, dh: dstH };
|
|
106713
|
+
}
|
|
106714
|
+
if (fit === "none") {
|
|
106715
|
+
renderedW = srcW;
|
|
106716
|
+
renderedH = srcH;
|
|
106717
|
+
} else if (fit === "scale-down") {
|
|
106718
|
+
const scale = Math.min(dstW / srcW, dstH / srcH, 1);
|
|
106719
|
+
renderedW = srcW * scale;
|
|
106720
|
+
renderedH = srcH * scale;
|
|
106721
|
+
} else if (fit === "cover") {
|
|
106722
|
+
const scale = Math.max(dstW / srcW, dstH / srcH);
|
|
106723
|
+
renderedW = srcW * scale;
|
|
106724
|
+
renderedH = srcH * scale;
|
|
106725
|
+
} else {
|
|
106726
|
+
const scale = Math.min(dstW / srcW, dstH / srcH);
|
|
106727
|
+
renderedW = srcW * scale;
|
|
106728
|
+
renderedH = srcH * scale;
|
|
106729
|
+
}
|
|
106730
|
+
const dx = (dstW - renderedW) * pos.x;
|
|
106731
|
+
const dy = (dstH - renderedH) * pos.y;
|
|
106732
|
+
return { dx, dy, dw: renderedW, dh: renderedH };
|
|
106733
|
+
}
|
|
106734
|
+
function resampleRgb48leObjectFit(source2, srcW, srcH, dstW, dstH, fit = "fill", objectPosition) {
|
|
106735
|
+
if (srcW <= 0 || srcH <= 0 || dstW <= 0 || dstH <= 0) {
|
|
106736
|
+
return source2;
|
|
106737
|
+
}
|
|
106738
|
+
if (fit === "fill" && srcW === dstW && srcH === dstH) {
|
|
106739
|
+
return source2;
|
|
106740
|
+
}
|
|
106741
|
+
const pos = parseObjectPosition(objectPosition);
|
|
106742
|
+
const rect = computeObjectFitRect(srcW, srcH, dstW, dstH, fit, pos);
|
|
106743
|
+
const dst = Buffer.alloc(dstW * dstH * 6);
|
|
106744
|
+
const stride = dstW * 6;
|
|
106745
|
+
const xMin = Math.max(0, Math.floor(rect.dx));
|
|
106746
|
+
const yMin = Math.max(0, Math.floor(rect.dy));
|
|
106747
|
+
const xMax = Math.min(dstW, Math.ceil(rect.dx + rect.dw));
|
|
106748
|
+
const yMax = Math.min(dstH, Math.ceil(rect.dy + rect.dh));
|
|
106749
|
+
if (rect.dw <= 0 || rect.dh <= 0) {
|
|
106750
|
+
return dst;
|
|
106751
|
+
}
|
|
106752
|
+
const invScaleX = srcW / rect.dw;
|
|
106753
|
+
const invScaleY = srcH / rect.dh;
|
|
106754
|
+
for (let dy = yMin; dy < yMax; dy++) {
|
|
106755
|
+
const rowOff = dy * stride;
|
|
106756
|
+
const sy = (dy + 0.5 - rect.dy) * invScaleY - 0.5;
|
|
106757
|
+
const syc = Math.max(0, Math.min(srcH - 1, sy));
|
|
106758
|
+
const y0 = Math.floor(syc);
|
|
106759
|
+
const y1 = Math.min(y0 + 1, srcH - 1);
|
|
106760
|
+
const fy = syc - y0;
|
|
106761
|
+
const ify = 1 - fy;
|
|
106762
|
+
for (let dx = xMin; dx < xMax; dx++) {
|
|
106763
|
+
const sx = (dx + 0.5 - rect.dx) * invScaleX - 0.5;
|
|
106764
|
+
const sxc = Math.max(0, Math.min(srcW - 1, sx));
|
|
106765
|
+
const x0 = Math.floor(sxc);
|
|
106766
|
+
const x1 = Math.min(x0 + 1, srcW - 1);
|
|
106767
|
+
const fx = sxc - x0;
|
|
106768
|
+
const ifx = 1 - fx;
|
|
106769
|
+
const off00 = (y0 * srcW + x0) * 6;
|
|
106770
|
+
const off10 = (y0 * srcW + x1) * 6;
|
|
106771
|
+
const off01 = (y1 * srcW + x0) * 6;
|
|
106772
|
+
const off11 = (y1 * srcW + x1) * 6;
|
|
106773
|
+
const w00 = ifx * ify;
|
|
106774
|
+
const w10 = fx * ify;
|
|
106775
|
+
const w01 = ifx * fy;
|
|
106776
|
+
const w11 = fx * fy;
|
|
106777
|
+
const r = source2.readUInt16LE(off00) * w00 + source2.readUInt16LE(off10) * w10 + source2.readUInt16LE(off01) * w01 + source2.readUInt16LE(off11) * w11;
|
|
106778
|
+
const g = source2.readUInt16LE(off00 + 2) * w00 + source2.readUInt16LE(off10 + 2) * w10 + source2.readUInt16LE(off01 + 2) * w01 + source2.readUInt16LE(off11 + 2) * w11;
|
|
106779
|
+
const b = source2.readUInt16LE(off00 + 4) * w00 + source2.readUInt16LE(off10 + 4) * w10 + source2.readUInt16LE(off01 + 4) * w01 + source2.readUInt16LE(off11 + 4) * w11;
|
|
106780
|
+
const dstOff = rowOff + dx * 6;
|
|
106781
|
+
dst.writeUInt16LE(Math.round(r), dstOff);
|
|
106782
|
+
dst.writeUInt16LE(Math.round(g), dstOff + 2);
|
|
106783
|
+
dst.writeUInt16LE(Math.round(b), dstOff + 4);
|
|
106784
|
+
}
|
|
106785
|
+
}
|
|
106786
|
+
return dst;
|
|
106787
|
+
}
|
|
106788
|
+
function normalizeObjectFit(value) {
|
|
106789
|
+
switch ((value ?? "").trim().toLowerCase()) {
|
|
106790
|
+
case "cover":
|
|
106791
|
+
return "cover";
|
|
106792
|
+
case "contain":
|
|
106793
|
+
return "contain";
|
|
106794
|
+
case "none":
|
|
106795
|
+
return "none";
|
|
106796
|
+
case "scale-down":
|
|
106797
|
+
return "scale-down";
|
|
106798
|
+
default:
|
|
106799
|
+
return "fill";
|
|
106800
|
+
}
|
|
106801
|
+
}
|
|
106540
106802
|
function parseTransformMatrix(css) {
|
|
106541
106803
|
if (!css || css === "none") return null;
|
|
106542
106804
|
const match2 = css.match(
|
|
@@ -107205,12 +107467,12 @@ import { freemem as freemem2 } from "os";
|
|
|
107205
107467
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
107206
107468
|
|
|
107207
107469
|
// src/services/fileServer.ts
|
|
107208
|
-
import { readFileSync as
|
|
107209
|
-
import { join as join11, extname as
|
|
107470
|
+
import { readFileSync as readFileSync7, existsSync as existsSync12, statSync as statSync5 } from "node:fs";
|
|
107471
|
+
import { join as join11, extname as extname4 } from "node:path";
|
|
107210
107472
|
|
|
107211
107473
|
// src/services/hyperframeRuntimeLoader.ts
|
|
107212
107474
|
import { createHash as createHash2 } from "node:crypto";
|
|
107213
|
-
import { existsSync as existsSync11, readFileSync as
|
|
107475
|
+
import { existsSync as existsSync11, readFileSync as readFileSync6 } from "node:fs";
|
|
107214
107476
|
import { dirname as dirname8, resolve as resolve7 } from "node:path";
|
|
107215
107477
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
107216
107478
|
var PRODUCER_DIR = dirname8(fileURLToPath2(import.meta.url));
|
|
@@ -107253,7 +107515,7 @@ function resolveVerifiedHyperframeRuntime() {
|
|
|
107253
107515
|
`[HyperframeRuntimeLoader] Missing manifest at ${manifestPath}. Build core runtime artifacts before rendering.`
|
|
107254
107516
|
);
|
|
107255
107517
|
}
|
|
107256
|
-
const manifestRaw =
|
|
107518
|
+
const manifestRaw = readFileSync6(manifestPath, "utf8");
|
|
107257
107519
|
const manifest = JSON.parse(manifestRaw);
|
|
107258
107520
|
const runtimeFileName = manifest.artifacts?.iife;
|
|
107259
107521
|
if (!runtimeFileName || !manifest.sha256) {
|
|
@@ -107265,7 +107527,7 @@ function resolveVerifiedHyperframeRuntime() {
|
|
|
107265
107527
|
if (!existsSync11(runtimePath)) {
|
|
107266
107528
|
throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
|
|
107267
107529
|
}
|
|
107268
|
-
const runtimeSource =
|
|
107530
|
+
const runtimeSource = readFileSync6(runtimePath, "utf8");
|
|
107269
107531
|
const runtimeSha = createHash2("sha256").update(runtimeSource, "utf8").digest("hex");
|
|
107270
107532
|
if (runtimeSha !== manifest.sha256) {
|
|
107271
107533
|
throw new Error(
|
|
@@ -107685,10 +107947,10 @@ function createFileServer2(options) {
|
|
|
107685
107947
|
}
|
|
107686
107948
|
return c.text("Not found", 404);
|
|
107687
107949
|
}
|
|
107688
|
-
const ext =
|
|
107950
|
+
const ext = extname4(filePath).toLowerCase();
|
|
107689
107951
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
107690
107952
|
if (ext === ".html") {
|
|
107691
|
-
const rawHtml =
|
|
107953
|
+
const rawHtml = readFileSync7(filePath, "utf-8");
|
|
107692
107954
|
const isIndex = relativePath === "index.html";
|
|
107693
107955
|
let html = rawHtml;
|
|
107694
107956
|
if (preHeadScripts.length > 0) {
|
|
@@ -107697,7 +107959,7 @@ function createFileServer2(options) {
|
|
|
107697
107959
|
html = isIndex ? injectScriptsIntoHtml(html, headScripts, bodyScripts, stripEmbeddedRuntime) : html;
|
|
107698
107960
|
return c.text(html, 200, { "Content-Type": contentType });
|
|
107699
107961
|
}
|
|
107700
|
-
const content =
|
|
107962
|
+
const content = readFileSync7(filePath);
|
|
107701
107963
|
return new Response(content, {
|
|
107702
107964
|
status: 200,
|
|
107703
107965
|
headers: { "Content-Type": contentType }
|
|
@@ -107724,7 +107986,7 @@ function createFileServer2(options) {
|
|
|
107724
107986
|
}
|
|
107725
107987
|
|
|
107726
107988
|
// src/services/htmlCompiler.ts
|
|
107727
|
-
import { readFileSync as
|
|
107989
|
+
import { readFileSync as readFileSync9, existsSync as existsSync14, mkdirSync as mkdirSync9 } from "fs";
|
|
107728
107990
|
import { join as join14, dirname as dirname9, resolve as resolve9 } from "path";
|
|
107729
107991
|
import postcss from "postcss";
|
|
107730
107992
|
|
|
@@ -107757,7 +108019,7 @@ function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS
|
|
|
107757
108019
|
}
|
|
107758
108020
|
|
|
107759
108021
|
// src/services/deterministicFonts.ts
|
|
107760
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as
|
|
108022
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "node:fs";
|
|
107761
108023
|
import { homedir as homedir2 } from "node:os";
|
|
107762
108024
|
import { join as join13 } from "node:path";
|
|
107763
108025
|
|
|
@@ -108086,7 +108348,7 @@ async function fetchGoogleFont(familyName) {
|
|
|
108086
108348
|
continue;
|
|
108087
108349
|
}
|
|
108088
108350
|
}
|
|
108089
|
-
const fontBytes =
|
|
108351
|
+
const fontBytes = readFileSync8(cachePath);
|
|
108090
108352
|
const dataUri = `data:font/woff2;base64,${fontBytes.toString("base64")}`;
|
|
108091
108353
|
faces.push({ weight, style, dataUri });
|
|
108092
108354
|
}
|
|
@@ -108237,6 +108499,7 @@ async function compileHtmlFile(html, baseDir, downloadDir) {
|
|
|
108237
108499
|
async function parseSubCompositions(html, projectDir, downloadDir, parentOffset = 0, parentEnd = Infinity, visited = /* @__PURE__ */ new Set()) {
|
|
108238
108500
|
const videos = [];
|
|
108239
108501
|
const audios = [];
|
|
108502
|
+
const images = [];
|
|
108240
108503
|
const subCompositions = /* @__PURE__ */ new Map();
|
|
108241
108504
|
const { document: document2 } = parseHTML(html);
|
|
108242
108505
|
const compEls = document2.querySelectorAll("[data-composition-src]");
|
|
@@ -108256,7 +108519,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
108256
108519
|
if (!existsSync14(filePath)) {
|
|
108257
108520
|
continue;
|
|
108258
108521
|
}
|
|
108259
|
-
const rawSubHtml =
|
|
108522
|
+
const rawSubHtml = readFileSync9(filePath, "utf-8");
|
|
108260
108523
|
const nestedVisited = new Set(visited);
|
|
108261
108524
|
nestedVisited.add(filePath);
|
|
108262
108525
|
workItems.push({ srcPath, absoluteStart, absoluteEnd, filePath, rawSubHtml, nestedVisited });
|
|
@@ -108278,12 +108541,14 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
108278
108541
|
);
|
|
108279
108542
|
const subVideos = parseVideoElements(compiledSub);
|
|
108280
108543
|
const subAudios = parseAudioElements(compiledSub);
|
|
108544
|
+
const subImages = parseImageElements(compiledSub);
|
|
108281
108545
|
return {
|
|
108282
108546
|
srcPath: item.srcPath,
|
|
108283
108547
|
compiledSub,
|
|
108284
108548
|
nested,
|
|
108285
108549
|
subVideos,
|
|
108286
108550
|
subAudios,
|
|
108551
|
+
subImages,
|
|
108287
108552
|
absoluteStart: item.absoluteStart,
|
|
108288
108553
|
absoluteEnd: item.absoluteEnd
|
|
108289
108554
|
};
|
|
@@ -108296,6 +108561,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
108296
108561
|
}
|
|
108297
108562
|
videos.push(...r.nested.videos);
|
|
108298
108563
|
audios.push(...r.nested.audios);
|
|
108564
|
+
images.push(...r.nested.images);
|
|
108299
108565
|
for (const v of r.subVideos) {
|
|
108300
108566
|
v.start += r.absoluteStart;
|
|
108301
108567
|
v.end += r.absoluteStart;
|
|
@@ -108316,10 +108582,20 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
108316
108582
|
audios.push(a);
|
|
108317
108583
|
}
|
|
108318
108584
|
}
|
|
108319
|
-
|
|
108585
|
+
for (const img of r.subImages) {
|
|
108586
|
+
img.start += r.absoluteStart;
|
|
108587
|
+
img.end += r.absoluteStart;
|
|
108588
|
+
if (img.end > r.absoluteEnd) {
|
|
108589
|
+
img.end = r.absoluteEnd;
|
|
108590
|
+
}
|
|
108591
|
+
if (img.start < r.absoluteEnd) {
|
|
108592
|
+
images.push(img);
|
|
108593
|
+
}
|
|
108594
|
+
}
|
|
108595
|
+
if (r.subVideos.length > 0 || r.subAudios.length > 0 || r.subImages.length > 0 || r.nested.videos.length > 0 || r.nested.audios.length > 0 || r.nested.images.length > 0) {
|
|
108320
108596
|
}
|
|
108321
108597
|
}
|
|
108322
|
-
return { videos, audios, subCompositions };
|
|
108598
|
+
return { videos, audios, images, subCompositions };
|
|
108323
108599
|
}
|
|
108324
108600
|
function promoteCssImportsToLinkTags(html) {
|
|
108325
108601
|
const { document: document2 } = parseHTML(html);
|
|
@@ -108451,7 +108727,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
|
|
|
108451
108727
|
if (!compHtml) {
|
|
108452
108728
|
const filePath = resolve9(projectDir, srcPath);
|
|
108453
108729
|
if (existsSync14(filePath)) {
|
|
108454
|
-
compHtml =
|
|
108730
|
+
compHtml = readFileSync9(filePath, "utf-8");
|
|
108455
108731
|
}
|
|
108456
108732
|
}
|
|
108457
108733
|
if (!compHtml) {
|
|
@@ -108619,7 +108895,9 @@ ${html}
|
|
|
108619
108895
|
</html>`;
|
|
108620
108896
|
}
|
|
108621
108897
|
async function inlineExternalScripts(html) {
|
|
108622
|
-
const
|
|
108898
|
+
const fullHtml = ensureFullDocument(html);
|
|
108899
|
+
const wrappedFragment = fullHtml !== html;
|
|
108900
|
+
const { document: document2 } = parseHTML(fullHtml);
|
|
108623
108901
|
const scripts = document2.querySelectorAll("script[src]");
|
|
108624
108902
|
const externalScripts = [];
|
|
108625
108903
|
for (const el of scripts) {
|
|
@@ -108638,20 +108916,20 @@ async function inlineExternalScripts(html) {
|
|
|
108638
108916
|
return { src, text: await response.text() };
|
|
108639
108917
|
})
|
|
108640
108918
|
);
|
|
108641
|
-
let result = html;
|
|
108642
108919
|
for (let i = 0; i < downloads.length; i++) {
|
|
108643
108920
|
const download = downloads[i];
|
|
108644
|
-
const { src } = externalScripts[i];
|
|
108921
|
+
const { el, src } = externalScripts[i];
|
|
108645
108922
|
if (download.status === "fulfilled") {
|
|
108646
|
-
const escapedSrc = src.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
108647
|
-
const scriptTagRe = new RegExp(
|
|
108648
|
-
`<script\\b[^>]*\\bsrc=["']${escapedSrc}["'][^>]*>\\s*</script>`,
|
|
108649
|
-
"is"
|
|
108650
|
-
);
|
|
108651
108923
|
const safeText = download.value.text.replace(/<\/script/gi, "<\\/script");
|
|
108652
|
-
|
|
108924
|
+
const inlineScript = document2.createElement("script");
|
|
108925
|
+
for (const attr of Array.from(el.attributes)) {
|
|
108926
|
+
if (attr.name.toLowerCase() === "src") continue;
|
|
108927
|
+
inlineScript.setAttribute(attr.name, attr.value);
|
|
108928
|
+
}
|
|
108929
|
+
inlineScript.textContent = `/* inlined: ${src} */
|
|
108653
108930
|
${safeText}
|
|
108654
|
-
|
|
108931
|
+
`;
|
|
108932
|
+
el.replaceWith(inlineScript);
|
|
108655
108933
|
console.log(`[Compiler] Inlined CDN script: ${src}`);
|
|
108656
108934
|
} else {
|
|
108657
108935
|
console.warn(
|
|
@@ -108659,7 +108937,7 @@ ${safeText}
|
|
|
108659
108937
|
);
|
|
108660
108938
|
}
|
|
108661
108939
|
}
|
|
108662
|
-
return
|
|
108940
|
+
return wrappedFragment ? document2.body.innerHTML || "" : document2.toString();
|
|
108663
108941
|
}
|
|
108664
108942
|
function collectExternalAssets(html, projectDir) {
|
|
108665
108943
|
const absProjectDir = resolve9(projectDir);
|
|
@@ -108719,7 +108997,7 @@ function collectExternalAssets(html, projectDir) {
|
|
|
108719
108997
|
};
|
|
108720
108998
|
}
|
|
108721
108999
|
async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
108722
|
-
const rawHtml =
|
|
109000
|
+
const rawHtml = readFileSync9(htmlPath, "utf-8");
|
|
108723
109001
|
const { html: compiledHtml, unresolvedCompositions } = await compileHtmlFile(
|
|
108724
109002
|
rawHtml,
|
|
108725
109003
|
projectDir,
|
|
@@ -108728,6 +109006,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
108728
109006
|
const {
|
|
108729
109007
|
videos: subVideos,
|
|
108730
109008
|
audios: subAudios,
|
|
109009
|
+
images: subImages,
|
|
108731
109010
|
subCompositions
|
|
108732
109011
|
} = await parseSubCompositions(compiledHtml, projectDir, downloadDir);
|
|
108733
109012
|
const fullHtml = ensureFullDocument(compiledHtml);
|
|
@@ -108744,8 +109023,10 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
108744
109023
|
const { html, externalAssets } = collectExternalAssets(assembledHtml, projectDir);
|
|
108745
109024
|
const mainVideos = parseVideoElements(html);
|
|
108746
109025
|
const mainAudios = parseAudioElements(html);
|
|
109026
|
+
const mainImages = parseImageElements(html);
|
|
108747
109027
|
const videos = dedupeElementsById([...mainVideos, ...subVideos]);
|
|
108748
109028
|
const audios = dedupeElementsById([...mainAudios, ...subAudios]);
|
|
109029
|
+
const images = dedupeElementsById([...mainImages, ...subImages]);
|
|
108749
109030
|
for (const video of videos) {
|
|
108750
109031
|
if (isHttpUrl(video.src)) continue;
|
|
108751
109032
|
const videoPath = resolve9(projectDir, video.src);
|
|
@@ -108776,6 +109057,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
108776
109057
|
subCompositions,
|
|
108777
109058
|
videos,
|
|
108778
109059
|
audios,
|
|
109060
|
+
images,
|
|
108779
109061
|
unresolvedCompositions,
|
|
108780
109062
|
externalAssets,
|
|
108781
109063
|
width,
|
|
@@ -108860,12 +109142,15 @@ async function recompileWithResolutions(compiled, resolutions, projectDir, downl
|
|
|
108860
109142
|
const {
|
|
108861
109143
|
videos: subVideos,
|
|
108862
109144
|
audios: subAudios,
|
|
109145
|
+
images: subImages,
|
|
108863
109146
|
subCompositions
|
|
108864
109147
|
} = await parseSubCompositions(html, projectDir, downloadDir);
|
|
108865
109148
|
const mainVideos = parseVideoElements(html);
|
|
108866
109149
|
const mainAudios = parseAudioElements(html);
|
|
109150
|
+
const mainImages = parseImageElements(html);
|
|
108867
109151
|
const videos = dedupeElementsById([...mainVideos, ...subVideos]);
|
|
108868
109152
|
const audios = dedupeElementsById([...mainAudios, ...subAudios]);
|
|
109153
|
+
const images = dedupeElementsById([...mainImages, ...subImages]);
|
|
108869
109154
|
const remaining = compiled.unresolvedCompositions.filter(
|
|
108870
109155
|
(c) => !resolutions.some((r) => r.id === c.id)
|
|
108871
109156
|
);
|
|
@@ -108875,6 +109160,7 @@ async function recompileWithResolutions(compiled, resolutions, projectDir, downl
|
|
|
108875
109160
|
subCompositions,
|
|
108876
109161
|
videos,
|
|
108877
109162
|
audios,
|
|
109163
|
+
images,
|
|
108878
109164
|
unresolvedCompositions: remaining,
|
|
108879
109165
|
renderModeHints: compiled.renderModeHints
|
|
108880
109166
|
};
|
|
@@ -109060,7 +109346,7 @@ function blitHdrVideoLayer(canvas, el, time, fps, hdrFrameDirs, hdrStartTimes, w
|
|
|
109060
109346
|
return;
|
|
109061
109347
|
}
|
|
109062
109348
|
try {
|
|
109063
|
-
const { data: hdrRgb, width: srcW, height: srcH } = decodePngToRgb48le(
|
|
109349
|
+
const { data: hdrRgb, width: srcW, height: srcH } = decodePngToRgb48le(readFileSync10(framePath));
|
|
109064
109350
|
if (sourceTransfer && targetTransfer && sourceTransfer !== targetTransfer) {
|
|
109065
109351
|
convertTransfer(hdrRgb, sourceTransfer, targetTransfer);
|
|
109066
109352
|
}
|
|
@@ -109102,6 +109388,55 @@ function blitHdrVideoLayer(canvas, el, time, fps, hdrFrameDirs, hdrStartTimes, w
|
|
|
109102
109388
|
}
|
|
109103
109389
|
}
|
|
109104
109390
|
}
|
|
109391
|
+
function blitHdrImageLayer(canvas, el, hdrImageBuffers, width, height, log, sourceTransfer, targetTransfer) {
|
|
109392
|
+
const buf = hdrImageBuffers.get(el.id);
|
|
109393
|
+
if (!buf) {
|
|
109394
|
+
return;
|
|
109395
|
+
}
|
|
109396
|
+
try {
|
|
109397
|
+
let hdrRgb = buf.data;
|
|
109398
|
+
if (sourceTransfer && targetTransfer && sourceTransfer !== targetTransfer) {
|
|
109399
|
+
hdrRgb = Buffer.from(buf.data);
|
|
109400
|
+
convertTransfer(hdrRgb, sourceTransfer, targetTransfer);
|
|
109401
|
+
}
|
|
109402
|
+
const viewportMatrix = parseTransformMatrix(el.transform);
|
|
109403
|
+
const br = el.borderRadius;
|
|
109404
|
+
const hasBorderRadius = br[0] > 0 || br[1] > 0 || br[2] > 0 || br[3] > 0;
|
|
109405
|
+
const borderRadiusParam = hasBorderRadius ? br : void 0;
|
|
109406
|
+
if (viewportMatrix) {
|
|
109407
|
+
blitRgb48leAffine(
|
|
109408
|
+
canvas,
|
|
109409
|
+
hdrRgb,
|
|
109410
|
+
viewportMatrix,
|
|
109411
|
+
buf.width,
|
|
109412
|
+
buf.height,
|
|
109413
|
+
width,
|
|
109414
|
+
height,
|
|
109415
|
+
el.opacity < 0.999 ? el.opacity : void 0,
|
|
109416
|
+
borderRadiusParam
|
|
109417
|
+
);
|
|
109418
|
+
} else {
|
|
109419
|
+
blitRgb48leRegion(
|
|
109420
|
+
canvas,
|
|
109421
|
+
hdrRgb,
|
|
109422
|
+
el.x,
|
|
109423
|
+
el.y,
|
|
109424
|
+
buf.width,
|
|
109425
|
+
buf.height,
|
|
109426
|
+
width,
|
|
109427
|
+
height,
|
|
109428
|
+
el.opacity < 0.999 ? el.opacity : void 0,
|
|
109429
|
+
borderRadiusParam
|
|
109430
|
+
);
|
|
109431
|
+
}
|
|
109432
|
+
} catch (err) {
|
|
109433
|
+
if (log) {
|
|
109434
|
+
log.debug(`HDR image blit failed for ${el.id}`, {
|
|
109435
|
+
error: err instanceof Error ? err.message : String(err)
|
|
109436
|
+
});
|
|
109437
|
+
}
|
|
109438
|
+
}
|
|
109439
|
+
}
|
|
109105
109440
|
function createRenderJob(config2) {
|
|
109106
109441
|
return {
|
|
109107
109442
|
id: randomUUID(),
|
|
@@ -109153,6 +109488,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109153
109488
|
let lastBrowserConsole = [];
|
|
109154
109489
|
let restoreLogger = null;
|
|
109155
109490
|
const perfStages = {};
|
|
109491
|
+
const hdrDiagnostics = {
|
|
109492
|
+
videoExtractionFailures: 0,
|
|
109493
|
+
imageDecodeFailures: 0
|
|
109494
|
+
};
|
|
109156
109495
|
const perfOutputPath = join15(workDir, "perf-summary.json");
|
|
109157
109496
|
const cfg = { ...job.config.producerConfig ?? resolveConfig() };
|
|
109158
109497
|
const outputFormat = job.config.format ?? "mp4";
|
|
@@ -109184,7 +109523,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109184
109523
|
throw new Error(`Entry file not found: ${htmlPath}`);
|
|
109185
109524
|
}
|
|
109186
109525
|
assertNotAborted();
|
|
109187
|
-
const rawEntry =
|
|
109526
|
+
const rawEntry = readFileSync10(htmlPath, "utf-8");
|
|
109188
109527
|
if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
|
|
109189
109528
|
const wrapperPath = join15(workDir, "standalone-entry.html");
|
|
109190
109529
|
const projectIndexPath = join15(projectDir, "index.html");
|
|
@@ -109194,7 +109533,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109194
109533
|
);
|
|
109195
109534
|
}
|
|
109196
109535
|
const standaloneHtml = extractStandaloneEntryFromIndex(
|
|
109197
|
-
|
|
109536
|
+
readFileSync10(projectIndexPath, "utf-8"),
|
|
109198
109537
|
entryFile
|
|
109199
109538
|
);
|
|
109200
109539
|
if (!standaloneHtml) {
|
|
@@ -109229,6 +109568,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109229
109568
|
duration: compiled.staticDuration,
|
|
109230
109569
|
videos: compiled.videos,
|
|
109231
109570
|
audios: compiled.audios,
|
|
109571
|
+
images: compiled.images,
|
|
109232
109572
|
width: compiled.width,
|
|
109233
109573
|
height: compiled.height
|
|
109234
109574
|
};
|
|
@@ -109293,6 +109633,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109293
109633
|
assertNotAborted();
|
|
109294
109634
|
composition.videos = compiled.videos;
|
|
109295
109635
|
composition.audios = compiled.audios;
|
|
109636
|
+
composition.images = compiled.images;
|
|
109296
109637
|
writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
|
|
109297
109638
|
}
|
|
109298
109639
|
}
|
|
@@ -109448,6 +109789,30 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109448
109789
|
})
|
|
109449
109790
|
);
|
|
109450
109791
|
}
|
|
109792
|
+
const nativeHdrImageIds = /* @__PURE__ */ new Set();
|
|
109793
|
+
const imageTransfers = /* @__PURE__ */ new Map();
|
|
109794
|
+
const hdrImageSrcPaths = /* @__PURE__ */ new Map();
|
|
109795
|
+
const imageColorSpaces = [];
|
|
109796
|
+
if (job.config.hdr && composition.images.length > 0) {
|
|
109797
|
+
const probed = await Promise.all(
|
|
109798
|
+
composition.images.map(async (img) => {
|
|
109799
|
+
let imgPath = img.src;
|
|
109800
|
+
if (!imgPath.startsWith("/")) {
|
|
109801
|
+
const fromCompiled = existsSync15(join15(compiledDir, imgPath)) ? join15(compiledDir, imgPath) : join15(projectDir, imgPath);
|
|
109802
|
+
imgPath = fromCompiled;
|
|
109803
|
+
}
|
|
109804
|
+
if (!existsSync15(imgPath)) return null;
|
|
109805
|
+
const meta = await extractVideoMetadata(imgPath);
|
|
109806
|
+
if (isHdrColorSpace(meta.colorSpace)) {
|
|
109807
|
+
nativeHdrImageIds.add(img.id);
|
|
109808
|
+
imageTransfers.set(img.id, detectTransfer(meta.colorSpace));
|
|
109809
|
+
hdrImageSrcPaths.set(img.id, imgPath);
|
|
109810
|
+
}
|
|
109811
|
+
return meta.colorSpace;
|
|
109812
|
+
})
|
|
109813
|
+
);
|
|
109814
|
+
imageColorSpaces.push(...probed);
|
|
109815
|
+
}
|
|
109451
109816
|
if (composition.videos.length > 0) {
|
|
109452
109817
|
extractionResult = await extractAllVideoFrames(
|
|
109453
109818
|
composition.videos,
|
|
@@ -109485,21 +109850,22 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109485
109850
|
perfStages.videoExtractMs = Date.now() - stage2Start;
|
|
109486
109851
|
}
|
|
109487
109852
|
let effectiveHdr;
|
|
109488
|
-
if (job.config.hdr
|
|
109489
|
-
const
|
|
109490
|
-
|
|
109491
|
-
|
|
109492
|
-
|
|
109493
|
-
|
|
109494
|
-
|
|
109495
|
-
|
|
109496
|
-
|
|
109497
|
-
|
|
109498
|
-
effectiveHdr = { transfer: firstTransfer };
|
|
109853
|
+
if (job.config.hdr) {
|
|
109854
|
+
const videoColorSpaces = (extractionResult?.extracted ?? []).map(
|
|
109855
|
+
(ext) => ext.metadata.colorSpace
|
|
109856
|
+
);
|
|
109857
|
+
const allColorSpaces = [...videoColorSpaces, ...imageColorSpaces];
|
|
109858
|
+
if (allColorSpaces.length > 0) {
|
|
109859
|
+
const info = analyzeCompositionHdr(allColorSpaces);
|
|
109860
|
+
if (info.hasHdr && info.dominantTransfer) {
|
|
109861
|
+
effectiveHdr = { transfer: info.dominantTransfer };
|
|
109862
|
+
}
|
|
109499
109863
|
}
|
|
109500
109864
|
}
|
|
109501
109865
|
if (effectiveHdr && outputFormat !== "mp4") {
|
|
109502
|
-
log.
|
|
109866
|
+
log.warn(
|
|
109867
|
+
`[Render] HDR source detected but format is ${outputFormat} \u2014 falling back to SDR. Use --format mp4 for HDR10 output.`
|
|
109868
|
+
);
|
|
109503
109869
|
effectiveHdr = void 0;
|
|
109504
109870
|
}
|
|
109505
109871
|
if (effectiveHdr) {
|
|
@@ -109552,12 +109918,14 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109552
109918
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
109553
109919
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
109554
109920
|
const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
|
|
109555
|
-
const
|
|
109921
|
+
const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
|
|
109922
|
+
const hasHdrContent = effectiveHdr && nativeHdrIds.size > 0;
|
|
109556
109923
|
const encoderHdr = hasHdrContent ? effectiveHdr : void 0;
|
|
109557
109924
|
const preset = getEncoderPreset(job.config.quality, outputFormat, encoderHdr);
|
|
109558
109925
|
job.framesRendered = 0;
|
|
109559
109926
|
if (hasHdrContent) {
|
|
109560
109927
|
log.info("[Render] HDR layered composite: z-ordered DOM + native HLG video layers");
|
|
109928
|
+
cfg.forceScreenshot = true;
|
|
109561
109929
|
const hdrVideoIds = composition.videos.filter((v) => nativeHdrVideoIds.has(v.id)).map((v) => v.id);
|
|
109562
109930
|
const hdrVideoSrcPaths = /* @__PURE__ */ new Map();
|
|
109563
109931
|
for (const v of composition.videos) {
|
|
@@ -109573,7 +109941,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109573
109941
|
const domSession = await createCaptureSession(
|
|
109574
109942
|
fileServer.url,
|
|
109575
109943
|
framesDir,
|
|
109576
|
-
captureOptions,
|
|
109944
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
109577
109945
|
createVideoFrameInjector(frameLookup),
|
|
109578
109946
|
cfg
|
|
109579
109947
|
);
|
|
@@ -109627,13 +109995,22 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109627
109995
|
);
|
|
109628
109996
|
assertNotAborted();
|
|
109629
109997
|
const hdrExtractionDims = /* @__PURE__ */ new Map();
|
|
109998
|
+
const hdrImageFitInfo = /* @__PURE__ */ new Map();
|
|
109630
109999
|
const hdrVideoStartTimes = /* @__PURE__ */ new Map();
|
|
109631
110000
|
for (const v of composition.videos) {
|
|
109632
110001
|
if (hdrVideoIds.includes(v.id)) {
|
|
109633
110002
|
hdrVideoStartTimes.set(v.id, v.start);
|
|
109634
110003
|
}
|
|
109635
110004
|
}
|
|
109636
|
-
const
|
|
110005
|
+
const hdrImageStartTimes = /* @__PURE__ */ new Map();
|
|
110006
|
+
for (const img of composition.images) {
|
|
110007
|
+
if (nativeHdrImageIds.has(img.id)) {
|
|
110008
|
+
hdrImageStartTimes.set(img.id, img.start);
|
|
110009
|
+
}
|
|
110010
|
+
}
|
|
110011
|
+
const uniqueStartTimes = [
|
|
110012
|
+
.../* @__PURE__ */ new Set([...hdrVideoStartTimes.values(), ...hdrImageStartTimes.values()])
|
|
110013
|
+
].sort((a, b) => a - b);
|
|
109637
110014
|
for (const seekTime of uniqueStartTimes) {
|
|
109638
110015
|
await domSession.page.evaluate((t) => {
|
|
109639
110016
|
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
@@ -109641,11 +110018,17 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109641
110018
|
if (domSession.onBeforeCapture) {
|
|
109642
110019
|
await domSession.onBeforeCapture(domSession.page, seekTime);
|
|
109643
110020
|
}
|
|
109644
|
-
const stacking = await queryElementStacking(domSession.page,
|
|
110021
|
+
const stacking = await queryElementStacking(domSession.page, nativeHdrIds);
|
|
109645
110022
|
for (const el of stacking) {
|
|
109646
110023
|
if (el.isHdr && el.layoutWidth > 0 && el.layoutHeight > 0 && !hdrExtractionDims.has(el.id)) {
|
|
109647
110024
|
hdrExtractionDims.set(el.id, { width: el.layoutWidth, height: el.layoutHeight });
|
|
109648
110025
|
}
|
|
110026
|
+
if (el.isHdr && nativeHdrImageIds.has(el.id) && !hdrImageFitInfo.has(el.id)) {
|
|
110027
|
+
hdrImageFitInfo.set(el.id, {
|
|
110028
|
+
fit: el.objectFit,
|
|
110029
|
+
position: el.objectPosition
|
|
110030
|
+
});
|
|
110031
|
+
}
|
|
109649
110032
|
}
|
|
109650
110033
|
}
|
|
109651
110034
|
const hdrFrameDirs = /* @__PURE__ */ new Map();
|
|
@@ -109676,14 +110059,59 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109676
110059
|
];
|
|
109677
110060
|
const result = await runFfmpeg(ffmpegArgs, { signal: abortSignal });
|
|
109678
110061
|
if (!result.success) {
|
|
109679
|
-
|
|
110062
|
+
hdrDiagnostics.videoExtractionFailures += 1;
|
|
110063
|
+
log.error("HDR frame pre-extraction failed; aborting render", {
|
|
109680
110064
|
videoId,
|
|
109681
110065
|
srcPath,
|
|
109682
110066
|
stderr: result.stderr.slice(-400)
|
|
109683
110067
|
});
|
|
110068
|
+
throw new Error(
|
|
110069
|
+
`HDR frame extraction failed for video "${videoId}". Aborting render to avoid shipping black HDR layers.`
|
|
110070
|
+
);
|
|
109684
110071
|
}
|
|
109685
110072
|
hdrFrameDirs.set(videoId, frameDir);
|
|
109686
110073
|
}
|
|
110074
|
+
const hdrImageBuffers = /* @__PURE__ */ new Map();
|
|
110075
|
+
for (const [imageId, srcPath] of hdrImageSrcPaths) {
|
|
110076
|
+
try {
|
|
110077
|
+
const decoded = decodePngToRgb48le(readFileSync10(srcPath));
|
|
110078
|
+
const layout2 = hdrExtractionDims.get(imageId);
|
|
110079
|
+
const fitInfo = hdrImageFitInfo.get(imageId);
|
|
110080
|
+
if (layout2 && (layout2.width !== decoded.width || layout2.height !== decoded.height)) {
|
|
110081
|
+
const fit = normalizeObjectFit(fitInfo?.fit);
|
|
110082
|
+
const resampled = resampleRgb48leObjectFit(
|
|
110083
|
+
decoded.data,
|
|
110084
|
+
decoded.width,
|
|
110085
|
+
decoded.height,
|
|
110086
|
+
layout2.width,
|
|
110087
|
+
layout2.height,
|
|
110088
|
+
fit,
|
|
110089
|
+
fitInfo?.position
|
|
110090
|
+
);
|
|
110091
|
+
hdrImageBuffers.set(imageId, {
|
|
110092
|
+
data: resampled,
|
|
110093
|
+
width: layout2.width,
|
|
110094
|
+
height: layout2.height
|
|
110095
|
+
});
|
|
110096
|
+
} else {
|
|
110097
|
+
hdrImageBuffers.set(imageId, {
|
|
110098
|
+
data: Buffer.from(decoded.data),
|
|
110099
|
+
width: decoded.width,
|
|
110100
|
+
height: decoded.height
|
|
110101
|
+
});
|
|
110102
|
+
}
|
|
110103
|
+
} catch (err) {
|
|
110104
|
+
hdrDiagnostics.imageDecodeFailures += 1;
|
|
110105
|
+
log.error("HDR image decode failed; aborting render", {
|
|
110106
|
+
imageId,
|
|
110107
|
+
srcPath,
|
|
110108
|
+
error: err instanceof Error ? err.message : String(err)
|
|
110109
|
+
});
|
|
110110
|
+
throw new Error(
|
|
110111
|
+
`HDR image decode failed for image "${imageId}". Aborting render to avoid shipping missing HDR image layers.`
|
|
110112
|
+
);
|
|
110113
|
+
}
|
|
110114
|
+
}
|
|
109687
110115
|
assertNotAborted();
|
|
109688
110116
|
try {
|
|
109689
110117
|
let countNonZeroAlpha2 = function(rgba) {
|
|
@@ -109741,38 +110169,67 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109741
110169
|
const layer = layers[layerIdx];
|
|
109742
110170
|
if (layer.type === "hdr") {
|
|
109743
110171
|
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
109744
|
-
|
|
109745
|
-
|
|
109746
|
-
|
|
109747
|
-
|
|
109748
|
-
|
|
109749
|
-
|
|
109750
|
-
|
|
109751
|
-
|
|
109752
|
-
|
|
109753
|
-
|
|
109754
|
-
|
|
109755
|
-
|
|
109756
|
-
|
|
110172
|
+
const isHdrImage = nativeHdrImageIds.has(layer.element.id);
|
|
110173
|
+
if (isHdrImage) {
|
|
110174
|
+
blitHdrImageLayer(
|
|
110175
|
+
canvas,
|
|
110176
|
+
layer.element,
|
|
110177
|
+
hdrImageBuffers,
|
|
110178
|
+
width,
|
|
110179
|
+
height,
|
|
110180
|
+
log,
|
|
110181
|
+
imageTransfers.get(layer.element.id),
|
|
110182
|
+
effectiveHdr?.transfer
|
|
110183
|
+
);
|
|
110184
|
+
} else {
|
|
110185
|
+
blitHdrVideoLayer(
|
|
110186
|
+
canvas,
|
|
110187
|
+
layer.element,
|
|
110188
|
+
time,
|
|
110189
|
+
job.config.fps,
|
|
110190
|
+
hdrFrameDirs,
|
|
110191
|
+
hdrVideoStartTimes,
|
|
110192
|
+
width,
|
|
110193
|
+
height,
|
|
110194
|
+
log,
|
|
110195
|
+
videoTransfers.get(layer.element.id),
|
|
110196
|
+
effectiveHdr?.transfer
|
|
110197
|
+
);
|
|
110198
|
+
}
|
|
109757
110199
|
if (shouldLog) {
|
|
109758
110200
|
const after2 = countNonZeroRgb482(canvas);
|
|
109759
|
-
|
|
109760
|
-
|
|
109761
|
-
|
|
109762
|
-
|
|
109763
|
-
|
|
109764
|
-
|
|
109765
|
-
|
|
109766
|
-
|
|
109767
|
-
|
|
109768
|
-
|
|
109769
|
-
|
|
109770
|
-
|
|
109771
|
-
|
|
109772
|
-
|
|
109773
|
-
|
|
109774
|
-
|
|
109775
|
-
|
|
110201
|
+
if (isHdrImage) {
|
|
110202
|
+
const buf = hdrImageBuffers.get(layer.element.id);
|
|
110203
|
+
log.info("[diag] hdr layer blit", {
|
|
110204
|
+
frame: debugFrameIndex,
|
|
110205
|
+
layerIdx,
|
|
110206
|
+
id: layer.element.id,
|
|
110207
|
+
kind: "image",
|
|
110208
|
+
pixelsAdded: after2 - before2,
|
|
110209
|
+
totalNonZero: after2,
|
|
110210
|
+
bufferDecoded: !!buf,
|
|
110211
|
+
bufferDims: buf ? `${buf.width}x${buf.height}` : null
|
|
110212
|
+
});
|
|
110213
|
+
} else {
|
|
110214
|
+
const frameDir = hdrFrameDirs.get(layer.element.id);
|
|
110215
|
+
const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
|
|
110216
|
+
const localTime = time - startTime;
|
|
110217
|
+
const frameNum = Math.floor(localTime * job.config.fps) + 1;
|
|
110218
|
+
const expectedFrame = frameDir ? join15(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
|
|
110219
|
+
log.info("[diag] hdr layer blit", {
|
|
110220
|
+
frame: debugFrameIndex,
|
|
110221
|
+
layerIdx,
|
|
110222
|
+
id: layer.element.id,
|
|
110223
|
+
kind: "video",
|
|
110224
|
+
pixelsAdded: after2 - before2,
|
|
110225
|
+
totalNonZero: after2,
|
|
110226
|
+
startTime,
|
|
110227
|
+
localTime: localTime.toFixed(3),
|
|
110228
|
+
hdrFrameNum: frameNum,
|
|
110229
|
+
expectedFrame,
|
|
110230
|
+
expectedFrameExists: expectedFrame ? existsSync15(expectedFrame) : false
|
|
110231
|
+
});
|
|
110232
|
+
}
|
|
109776
110233
|
}
|
|
109777
110234
|
} else {
|
|
109778
110235
|
const allElementIds = fullStacking.map((e) => e.id);
|
|
@@ -109847,7 +110304,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109847
110304
|
if (beforeCaptureHook) {
|
|
109848
110305
|
await beforeCaptureHook(domSession.page, time);
|
|
109849
110306
|
}
|
|
109850
|
-
const stackingInfo = await queryElementStacking(domSession.page,
|
|
110307
|
+
const stackingInfo = await queryElementStacking(domSession.page, nativeHdrIds);
|
|
109851
110308
|
const activeTransition = transitionRanges.find(
|
|
109852
110309
|
(t) => i >= t.startFrame && i <= t.endFrame
|
|
109853
110310
|
);
|
|
@@ -109879,22 +110336,35 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109879
110336
|
}
|
|
109880
110337
|
for (const el of stackingInfo) {
|
|
109881
110338
|
if (!el.isHdr || !sceneIds.has(el.id)) continue;
|
|
109882
|
-
|
|
109883
|
-
|
|
109884
|
-
|
|
109885
|
-
|
|
109886
|
-
|
|
109887
|
-
|
|
109888
|
-
|
|
109889
|
-
|
|
109890
|
-
|
|
109891
|
-
|
|
109892
|
-
|
|
109893
|
-
|
|
109894
|
-
|
|
110339
|
+
if (nativeHdrImageIds.has(el.id)) {
|
|
110340
|
+
blitHdrImageLayer(
|
|
110341
|
+
sceneBuf,
|
|
110342
|
+
el,
|
|
110343
|
+
hdrImageBuffers,
|
|
110344
|
+
width,
|
|
110345
|
+
height,
|
|
110346
|
+
log,
|
|
110347
|
+
imageTransfers.get(el.id),
|
|
110348
|
+
effectiveHdr?.transfer
|
|
110349
|
+
);
|
|
110350
|
+
} else {
|
|
110351
|
+
blitHdrVideoLayer(
|
|
110352
|
+
sceneBuf,
|
|
110353
|
+
el,
|
|
110354
|
+
time,
|
|
110355
|
+
job.config.fps,
|
|
110356
|
+
hdrFrameDirs,
|
|
110357
|
+
hdrVideoStartTimes,
|
|
110358
|
+
width,
|
|
110359
|
+
height,
|
|
110360
|
+
log,
|
|
110361
|
+
videoTransfers.get(el.id),
|
|
110362
|
+
effectiveHdr?.transfer
|
|
110363
|
+
);
|
|
110364
|
+
}
|
|
109895
110365
|
}
|
|
109896
110366
|
const showIds = Array.from(sceneIds);
|
|
109897
|
-
const hideIds = stackingInfo.map((e) => e.id).filter((id) => !sceneIds.has(id) ||
|
|
110367
|
+
const hideIds = stackingInfo.map((e) => e.id).filter((id) => !sceneIds.has(id) || nativeHdrIds.has(id));
|
|
109898
110368
|
await applyDomLayerMask(domSession.page, showIds, hideIds);
|
|
109899
110369
|
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
109900
110370
|
await removeDomLayerMask(domSession.page, hideIds);
|
|
@@ -110015,7 +110485,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110015
110485
|
fileServer.url,
|
|
110016
110486
|
workDir,
|
|
110017
110487
|
tasks,
|
|
110018
|
-
captureOptions,
|
|
110488
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
110019
110489
|
() => createVideoFrameInjector(frameLookup),
|
|
110020
110490
|
abortSignal,
|
|
110021
110491
|
(progress) => {
|
|
@@ -110045,7 +110515,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110045
110515
|
const session = probeSession ?? await createCaptureSession(
|
|
110046
110516
|
fileServer.url,
|
|
110047
110517
|
framesDir,
|
|
110048
|
-
captureOptions,
|
|
110518
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
110049
110519
|
videoInjector,
|
|
110050
110520
|
cfg
|
|
110051
110521
|
);
|
|
@@ -110096,7 +110566,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110096
110566
|
fileServer.url,
|
|
110097
110567
|
workDir,
|
|
110098
110568
|
tasks,
|
|
110099
|
-
captureOptions,
|
|
110569
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
110100
110570
|
() => createVideoFrameInjector(frameLookup),
|
|
110101
110571
|
abortSignal,
|
|
110102
110572
|
(progress) => {
|
|
@@ -110127,7 +110597,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110127
110597
|
const session = probeSession ?? await createCaptureSession(
|
|
110128
110598
|
fileServer.url,
|
|
110129
110599
|
framesDir,
|
|
110130
|
-
captureOptions,
|
|
110600
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
110131
110601
|
videoInjector,
|
|
110132
110602
|
cfg
|
|
110133
110603
|
);
|
|
@@ -110245,6 +110715,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110245
110715
|
videoCount: composition.videos.length,
|
|
110246
110716
|
audioCount: composition.audios.length,
|
|
110247
110717
|
stages: perfStages,
|
|
110718
|
+
hdrDiagnostics: hdrDiagnostics.videoExtractionFailures > 0 || hdrDiagnostics.imageDecodeFailures > 0 ? { ...hdrDiagnostics } : void 0,
|
|
110248
110719
|
captureAvgMs: totalFrames > 0 ? Math.round((perfStages.captureMs ?? 0) / totalFrames) : void 0
|
|
110249
110720
|
};
|
|
110250
110721
|
job.perfSummary = perfSummary;
|
|
@@ -110325,7 +110796,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110325
110796
|
elapsedMs: elapsed,
|
|
110326
110797
|
freeMemoryMB: freeMemMB,
|
|
110327
110798
|
browserConsoleTail: lastBrowserConsole.length > 0 ? lastBrowserConsole.slice(-30) : void 0,
|
|
110328
|
-
perfStages: Object.keys(perfStages).length > 0 ? { ...perfStages } : void 0
|
|
110799
|
+
perfStages: Object.keys(perfStages).length > 0 ? { ...perfStages } : void 0,
|
|
110800
|
+
hdrDiagnostics: hdrDiagnostics.videoExtractionFailures > 0 || hdrDiagnostics.imageDecodeFailures > 0 ? { ...hdrDiagnostics } : void 0
|
|
110329
110801
|
};
|
|
110330
110802
|
if (fileServer) {
|
|
110331
110803
|
const fs8 = fileServer;
|
|
@@ -110520,7 +110992,7 @@ var streamSSE = (c, cb, onError) => {
|
|
|
110520
110992
|
};
|
|
110521
110993
|
|
|
110522
110994
|
// src/services/hyperframeLint.ts
|
|
110523
|
-
import { existsSync as existsSync16, readFileSync as
|
|
110995
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11, statSync as statSync6 } from "node:fs";
|
|
110524
110996
|
import { resolve as resolve11, join as join16 } from "node:path";
|
|
110525
110997
|
function isStringRecord(value) {
|
|
110526
110998
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -110563,7 +111035,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
110563
111035
|
if (existsSync16(absoluteEntryPath) && statSync6(absoluteEntryPath).isFile()) {
|
|
110564
111036
|
return {
|
|
110565
111037
|
entryFile,
|
|
110566
|
-
html:
|
|
111038
|
+
html: readFileSync11(absoluteEntryPath, "utf-8"),
|
|
110567
111039
|
source: "projectDir"
|
|
110568
111040
|
};
|
|
110569
111041
|
}
|