@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/public-server.js
CHANGED
|
@@ -78349,16 +78349,16 @@ var require_buffer_crc32 = __commonJS({
|
|
|
78349
78349
|
}
|
|
78350
78350
|
return crc ^ -1;
|
|
78351
78351
|
}
|
|
78352
|
-
function
|
|
78352
|
+
function crc322() {
|
|
78353
78353
|
return bufferizeInt(_crc32.apply(null, arguments));
|
|
78354
78354
|
}
|
|
78355
|
-
|
|
78355
|
+
crc322.signed = function() {
|
|
78356
78356
|
return _crc32.apply(null, arguments);
|
|
78357
78357
|
};
|
|
78358
|
-
|
|
78358
|
+
crc322.unsigned = function() {
|
|
78359
78359
|
return _crc32.apply(null, arguments) >>> 0;
|
|
78360
78360
|
};
|
|
78361
|
-
module.exports =
|
|
78361
|
+
module.exports = crc322;
|
|
78362
78362
|
}
|
|
78363
78363
|
});
|
|
78364
78364
|
|
|
@@ -78368,7 +78368,7 @@ var require_yauzl = __commonJS({
|
|
|
78368
78368
|
var fs8 = __require("fs");
|
|
78369
78369
|
var zlib = __require("zlib");
|
|
78370
78370
|
var fd_slicer = require_fd_slicer();
|
|
78371
|
-
var
|
|
78371
|
+
var crc322 = require_buffer_crc32();
|
|
78372
78372
|
var util = __require("util");
|
|
78373
78373
|
var EventEmitter4 = __require("events").EventEmitter;
|
|
78374
78374
|
var Transform = __require("stream").Transform;
|
|
@@ -78654,7 +78654,7 @@ var require_yauzl = __commonJS({
|
|
|
78654
78654
|
continue;
|
|
78655
78655
|
}
|
|
78656
78656
|
var oldNameCrc32 = extraField.data.readUInt32LE(1);
|
|
78657
|
-
if (
|
|
78657
|
+
if (crc322.unsigned(buffer.slice(0, entry.fileNameLength)) !== oldNameCrc32) {
|
|
78658
78658
|
continue;
|
|
78659
78659
|
}
|
|
78660
78660
|
entry.fileName = decodeBuffer(extraField.data, 5, extraField.data.length, true);
|
|
@@ -92209,7 +92209,7 @@ import {
|
|
|
92209
92209
|
existsSync as existsSync15,
|
|
92210
92210
|
mkdirSync as mkdirSync10,
|
|
92211
92211
|
rmSync as rmSync3,
|
|
92212
|
-
readFileSync as
|
|
92212
|
+
readFileSync as readFileSync10,
|
|
92213
92213
|
readdirSync as readdirSync6,
|
|
92214
92214
|
writeFileSync as writeFileSync4,
|
|
92215
92215
|
copyFileSync as copyFileSync2,
|
|
@@ -102430,9 +102430,25 @@ var mediaRules = [
|
|
|
102430
102430
|
// video_nested_in_timed_element
|
|
102431
102431
|
({ source: source2, tags }) => {
|
|
102432
102432
|
const findings = [];
|
|
102433
|
+
const voidElements3 = /* @__PURE__ */ new Set([
|
|
102434
|
+
"area",
|
|
102435
|
+
"base",
|
|
102436
|
+
"br",
|
|
102437
|
+
"col",
|
|
102438
|
+
"embed",
|
|
102439
|
+
"hr",
|
|
102440
|
+
"img",
|
|
102441
|
+
"input",
|
|
102442
|
+
"link",
|
|
102443
|
+
"meta",
|
|
102444
|
+
"source",
|
|
102445
|
+
"track",
|
|
102446
|
+
"wbr"
|
|
102447
|
+
]);
|
|
102433
102448
|
const timedTagPositions = [];
|
|
102434
102449
|
for (const tag of tags) {
|
|
102435
102450
|
if (tag.name === "video" || tag.name === "audio") continue;
|
|
102451
|
+
if (voidElements3.has(tag.name)) continue;
|
|
102436
102452
|
if (readAttr(tag.raw, "data-composition-id")) continue;
|
|
102437
102453
|
if (readAttr(tag.raw, "data-start")) {
|
|
102438
102454
|
timedTagPositions.push({
|
|
@@ -102599,7 +102615,9 @@ function extractGsapWindows(script) {
|
|
|
102599
102615
|
let index = 0;
|
|
102600
102616
|
while ((match2 = methodPattern.exec(script)) !== null && index < parsed.animations.length) {
|
|
102601
102617
|
const raw2 = match2[0];
|
|
102602
|
-
const
|
|
102618
|
+
const args = match2[2] ?? "";
|
|
102619
|
+
if (!/^\s*["']/.test(args)) continue;
|
|
102620
|
+
const meta = parseGsapWindowMeta(match2[1] ?? "", args);
|
|
102603
102621
|
const animation = parsed.animations[index];
|
|
102604
102622
|
index += 1;
|
|
102605
102623
|
if (!animation) continue;
|
|
@@ -103893,6 +103911,12 @@ async function createCaptureSession(serverUrl, outputDir, options, onBeforeCaptu
|
|
|
103893
103911
|
);
|
|
103894
103912
|
const { browser, captureMode } = await acquireBrowser(chromeArgs, config2);
|
|
103895
103913
|
const page = await browser.newPage();
|
|
103914
|
+
await page.evaluateOnNewDocument(() => {
|
|
103915
|
+
const w = window;
|
|
103916
|
+
if (typeof w.__name !== "function") {
|
|
103917
|
+
w.__name = (fn, _name) => fn;
|
|
103918
|
+
}
|
|
103919
|
+
});
|
|
103896
103920
|
const browserVersion = await browser.version();
|
|
103897
103921
|
const expectedMajor = config2?.expectedChromiumMajor;
|
|
103898
103922
|
if (Number.isFinite(expectedMajor)) {
|
|
@@ -103997,9 +104021,10 @@ async function initializeSession(session) {
|
|
|
103997
104021
|
`[FrameCapture] window.__hf not ready after ${pageReadyTimeout2}ms. Page must expose window.__hf = { duration, seek }.`
|
|
103998
104022
|
);
|
|
103999
104023
|
}
|
|
104024
|
+
const skipIdsLiteral = JSON.stringify(session.options.skipReadinessVideoIds ?? []);
|
|
104000
104025
|
const videosReady = await pollPageExpression(
|
|
104001
104026
|
page,
|
|
104002
|
-
`
|
|
104027
|
+
`(() => { 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); })()`,
|
|
104003
104028
|
pageReadyTimeout2
|
|
104004
104029
|
);
|
|
104005
104030
|
if (!videosReady) {
|
|
@@ -104059,10 +104084,11 @@ async function initializeSession(session) {
|
|
|
104059
104084
|
`[FrameCapture] window.__hf not ready after ${pageReadyTimeout}ms. Page must expose window.__hf = { duration, seek }.`
|
|
104060
104085
|
);
|
|
104061
104086
|
}
|
|
104087
|
+
const beginframeSkipIdsLiteral = JSON.stringify(session.options.skipReadinessVideoIds ?? []);
|
|
104062
104088
|
const videoDeadline = Date.now() + (session.config?.playerReadyTimeout ?? DEFAULT_CONFIG.playerReadyTimeout);
|
|
104063
104089
|
while (Date.now() < videoDeadline) {
|
|
104064
104090
|
const videosReady = await page.evaluate(
|
|
104065
|
-
`
|
|
104091
|
+
`(() => { 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); })()`
|
|
104066
104092
|
);
|
|
104067
104093
|
if (videosReady) break;
|
|
104068
104094
|
await new Promise((r) => setTimeout(r, 100));
|
|
@@ -105042,6 +105068,8 @@ import { join as join8 } from "path";
|
|
|
105042
105068
|
|
|
105043
105069
|
// ../engine/src/utils/ffprobe.ts
|
|
105044
105070
|
import { spawn as spawn7 } from "child_process";
|
|
105071
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
105072
|
+
import { extname as extname2 } from "path";
|
|
105045
105073
|
function runFfprobe(args) {
|
|
105046
105074
|
return new Promise((resolve13, reject) => {
|
|
105047
105075
|
const proc = spawn7("ffprobe", args);
|
|
@@ -105080,6 +105108,67 @@ function parseProbeJson(stdout) {
|
|
|
105080
105108
|
}
|
|
105081
105109
|
var videoMetadataCache = /* @__PURE__ */ new Map();
|
|
105082
105110
|
var audioMetadataCache = /* @__PURE__ */ new Map();
|
|
105111
|
+
function crc32(buf) {
|
|
105112
|
+
let crc = 4294967295;
|
|
105113
|
+
for (let i = 0; i < buf.length; i++) {
|
|
105114
|
+
crc ^= buf[i] ?? 0;
|
|
105115
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
105116
|
+
const mask = -(crc & 1);
|
|
105117
|
+
crc = crc >>> 1 ^ 3988292384 & mask;
|
|
105118
|
+
}
|
|
105119
|
+
}
|
|
105120
|
+
return (crc ^ 4294967295) >>> 0;
|
|
105121
|
+
}
|
|
105122
|
+
function extractPngMetadataFromBuffer(buf) {
|
|
105123
|
+
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) {
|
|
105124
|
+
return null;
|
|
105125
|
+
}
|
|
105126
|
+
let width = 0;
|
|
105127
|
+
let height = 0;
|
|
105128
|
+
let seenIdat = false;
|
|
105129
|
+
let pos = 8;
|
|
105130
|
+
while (pos + 12 <= buf.length) {
|
|
105131
|
+
const chunkLen = buf.readUInt32BE(pos);
|
|
105132
|
+
const chunkType = buf.toString("ascii", pos + 4, pos + 8);
|
|
105133
|
+
if (pos + 12 + chunkLen > buf.length) return null;
|
|
105134
|
+
const chunkData = buf.subarray(pos + 8, pos + 8 + chunkLen);
|
|
105135
|
+
const chunkCrc = buf.readUInt32BE(pos + 8 + chunkLen);
|
|
105136
|
+
const chunkBytes = Buffer.concat([Buffer.from(chunkType, "ascii"), chunkData]);
|
|
105137
|
+
if (crc32(chunkBytes) !== chunkCrc) return null;
|
|
105138
|
+
if (chunkType === "IHDR" && chunkLen >= 8) {
|
|
105139
|
+
width = buf.readUInt32BE(pos + 8);
|
|
105140
|
+
height = buf.readUInt32BE(pos + 12);
|
|
105141
|
+
}
|
|
105142
|
+
if (chunkType === "IDAT") {
|
|
105143
|
+
seenIdat = true;
|
|
105144
|
+
}
|
|
105145
|
+
if (chunkType === "cICP" && chunkLen === 4 && !seenIdat) {
|
|
105146
|
+
const primariesCode = chunkData[0] ?? 0;
|
|
105147
|
+
const transferCode = chunkData[1] ?? 0;
|
|
105148
|
+
const matrixCode = chunkData[2] ?? 0;
|
|
105149
|
+
return {
|
|
105150
|
+
width,
|
|
105151
|
+
height,
|
|
105152
|
+
colorSpace: {
|
|
105153
|
+
colorPrimaries: primariesCode === 9 ? "bt2020" : primariesCode === 1 ? "bt709" : `unknown-${primariesCode}`,
|
|
105154
|
+
colorTransfer: transferCode === 16 ? "smpte2084" : transferCode === 18 ? "arib-std-b67" : transferCode === 1 ? "bt709" : `unknown-${transferCode}`,
|
|
105155
|
+
colorSpace: matrixCode === 9 ? "bt2020nc" : matrixCode === 0 ? "gbr" : `unknown-${matrixCode}`
|
|
105156
|
+
}
|
|
105157
|
+
};
|
|
105158
|
+
}
|
|
105159
|
+
if (chunkType === "IEND") break;
|
|
105160
|
+
pos += 12 + chunkLen;
|
|
105161
|
+
}
|
|
105162
|
+
return width > 0 && height > 0 ? { width, height, colorSpace: null } : null;
|
|
105163
|
+
}
|
|
105164
|
+
function extractStillImageMetadata(filePath) {
|
|
105165
|
+
if (extname2(filePath).toLowerCase() !== ".png") return null;
|
|
105166
|
+
try {
|
|
105167
|
+
return extractPngMetadataFromBuffer(readFileSync5(filePath));
|
|
105168
|
+
} catch {
|
|
105169
|
+
return null;
|
|
105170
|
+
}
|
|
105171
|
+
}
|
|
105083
105172
|
function parseFrameRate(frameRateStr) {
|
|
105084
105173
|
if (!frameRateStr) return 0;
|
|
105085
105174
|
const parts = frameRateStr.split("/");
|
|
@@ -105094,18 +105183,38 @@ async function extractVideoMetadata(filePath) {
|
|
|
105094
105183
|
const cached = videoMetadataCache.get(filePath);
|
|
105095
105184
|
if (cached) return cached;
|
|
105096
105185
|
const probePromise = (async () => {
|
|
105097
|
-
const
|
|
105098
|
-
|
|
105099
|
-
|
|
105100
|
-
|
|
105101
|
-
|
|
105102
|
-
|
|
105103
|
-
|
|
105104
|
-
|
|
105105
|
-
|
|
105106
|
-
|
|
105107
|
-
|
|
105108
|
-
|
|
105186
|
+
const stillImageMeta = extractStillImageMetadata(filePath);
|
|
105187
|
+
let output2 = null;
|
|
105188
|
+
try {
|
|
105189
|
+
const stdout = await runFfprobe([
|
|
105190
|
+
"-v",
|
|
105191
|
+
"quiet",
|
|
105192
|
+
"-print_format",
|
|
105193
|
+
"json",
|
|
105194
|
+
"-show_format",
|
|
105195
|
+
"-show_streams",
|
|
105196
|
+
filePath
|
|
105197
|
+
]);
|
|
105198
|
+
output2 = parseProbeJson(stdout);
|
|
105199
|
+
} catch (error) {
|
|
105200
|
+
if (!stillImageMeta) throw error;
|
|
105201
|
+
}
|
|
105202
|
+
const videoStream = output2?.streams.find((s) => s.codec_type === "video");
|
|
105203
|
+
if (!videoStream) {
|
|
105204
|
+
if (stillImageMeta) {
|
|
105205
|
+
return {
|
|
105206
|
+
durationSeconds: 0,
|
|
105207
|
+
width: stillImageMeta.width,
|
|
105208
|
+
height: stillImageMeta.height,
|
|
105209
|
+
fps: 0,
|
|
105210
|
+
videoCodec: "png",
|
|
105211
|
+
hasAudio: false,
|
|
105212
|
+
isVFR: false,
|
|
105213
|
+
colorSpace: stillImageMeta.colorSpace
|
|
105214
|
+
};
|
|
105215
|
+
}
|
|
105216
|
+
throw new Error("[FFmpeg] No video stream found");
|
|
105217
|
+
}
|
|
105109
105218
|
const rFps = parseFrameRate(videoStream.r_frame_rate);
|
|
105110
105219
|
const avgFps = parseFrameRate(videoStream.avg_frame_rate);
|
|
105111
105220
|
const fps = avgFps || rFps;
|
|
@@ -105113,16 +105222,17 @@ async function extractVideoMetadata(filePath) {
|
|
|
105113
105222
|
const colorTransfer = videoStream.color_transfer || "";
|
|
105114
105223
|
const colorPrimaries = videoStream.color_primaries || "";
|
|
105115
105224
|
const colorSpaceVal = videoStream.color_space || "";
|
|
105116
|
-
const
|
|
105225
|
+
const ffprobeColorSpace = colorTransfer || colorPrimaries || colorSpaceVal ? { colorTransfer, colorPrimaries, colorSpace: colorSpaceVal } : null;
|
|
105226
|
+
const colorSpace = ffprobeColorSpace ?? stillImageMeta?.colorSpace ?? null;
|
|
105117
105227
|
return {
|
|
105118
|
-
durationSeconds: output2
|
|
105119
|
-
width: videoStream.width || 0,
|
|
105120
|
-
height: videoStream.height || 0,
|
|
105228
|
+
durationSeconds: output2?.format.duration ? parseFloat(output2.format.duration) : 0,
|
|
105229
|
+
width: videoStream.width || stillImageMeta?.width || 0,
|
|
105230
|
+
height: videoStream.height || stillImageMeta?.height || 0,
|
|
105121
105231
|
fps,
|
|
105122
105232
|
videoCodec: videoStream.codec_name || "unknown",
|
|
105123
|
-
hasAudio: output2
|
|
105233
|
+
hasAudio: output2?.streams.some((s) => s.codec_type === "audio") ?? false,
|
|
105124
105234
|
isVFR,
|
|
105125
|
-
colorSpace
|
|
105235
|
+
colorSpace
|
|
105126
105236
|
};
|
|
105127
105237
|
})();
|
|
105128
105238
|
videoMetadataCache.set(filePath, probePromise);
|
|
@@ -105221,7 +105331,7 @@ async function analyzeKeyframeIntervalsUncached(filePath) {
|
|
|
105221
105331
|
// ../engine/src/utils/urlDownloader.ts
|
|
105222
105332
|
import { createWriteStream as createWriteStream2, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
105223
105333
|
import { createHash } from "crypto";
|
|
105224
|
-
import { join as join7, extname as
|
|
105334
|
+
import { join as join7, extname as extname3 } from "path";
|
|
105225
105335
|
import { Readable as Readable2 } from "stream";
|
|
105226
105336
|
import { finished } from "stream/promises";
|
|
105227
105337
|
var downloadPathCache = /* @__PURE__ */ new Map();
|
|
@@ -105229,7 +105339,7 @@ var inFlightDownloads = /* @__PURE__ */ new Map();
|
|
|
105229
105339
|
function getFilenameFromUrl(url) {
|
|
105230
105340
|
const hash2 = createHash("md5").update(url).digest("hex").slice(0, 12);
|
|
105231
105341
|
const urlObj = new URL(url);
|
|
105232
|
-
const ext =
|
|
105342
|
+
const ext = extname3(urlObj.pathname) || ".mp4";
|
|
105233
105343
|
return `download_${hash2}${ext}`;
|
|
105234
105344
|
}
|
|
105235
105345
|
async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
|
|
@@ -105322,6 +105432,34 @@ function parseVideoElements(html) {
|
|
|
105322
105432
|
}
|
|
105323
105433
|
return videos;
|
|
105324
105434
|
}
|
|
105435
|
+
function parseImageElements(html) {
|
|
105436
|
+
const images = [];
|
|
105437
|
+
const { document: document2 } = parseHTML(html);
|
|
105438
|
+
const imgEls = document2.querySelectorAll("img[src]");
|
|
105439
|
+
let autoIdCounter = 0;
|
|
105440
|
+
for (const el of imgEls) {
|
|
105441
|
+
const src = el.getAttribute("src");
|
|
105442
|
+
if (!src) continue;
|
|
105443
|
+
const id = el.getAttribute("id") || `hf-img-${autoIdCounter++}`;
|
|
105444
|
+
if (!el.getAttribute("id")) {
|
|
105445
|
+
el.setAttribute("id", id);
|
|
105446
|
+
}
|
|
105447
|
+
const startAttr = el.getAttribute("data-start");
|
|
105448
|
+
const endAttr = el.getAttribute("data-end");
|
|
105449
|
+
const durationAttr = el.getAttribute("data-duration");
|
|
105450
|
+
const start = startAttr ? parseFloat(startAttr) : 0;
|
|
105451
|
+
let end = 0;
|
|
105452
|
+
if (endAttr) {
|
|
105453
|
+
end = parseFloat(endAttr);
|
|
105454
|
+
} else if (durationAttr) {
|
|
105455
|
+
end = start + parseFloat(durationAttr);
|
|
105456
|
+
} else {
|
|
105457
|
+
end = Infinity;
|
|
105458
|
+
}
|
|
105459
|
+
images.push({ id, src, start, end });
|
|
105460
|
+
}
|
|
105461
|
+
return images;
|
|
105462
|
+
}
|
|
105325
105463
|
async function extractVideoFramesRange(videoPath, videoId, startTime, duration, options, signal, config2) {
|
|
105326
105464
|
const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
|
|
105327
105465
|
const { fps, outputDir, quality = 95, format: format3 = "jpg" } = options;
|
|
@@ -105731,8 +105869,8 @@ function createVideoFrameInjector(frameLookup, config2) {
|
|
|
105731
105869
|
}
|
|
105732
105870
|
};
|
|
105733
105871
|
}
|
|
105734
|
-
async function queryElementStacking(page,
|
|
105735
|
-
const hdrIds = Array.from(
|
|
105872
|
+
async function queryElementStacking(page, nativeHdrIds) {
|
|
105873
|
+
const hdrIds = Array.from(nativeHdrIds);
|
|
105736
105874
|
return page.evaluate((hdrIdList) => {
|
|
105737
105875
|
const hdrSet = new Set(hdrIdList);
|
|
105738
105876
|
const elements = document.querySelectorAll("[data-start]");
|
|
@@ -105861,7 +105999,12 @@ async function queryElementStacking(page, nativeHdrVideoIds) {
|
|
|
105861
105999
|
// affine blit can apply rotation/scale/translate properly. For DOM
|
|
105862
106000
|
// elements, the element-level transform is sufficient for reference.
|
|
105863
106001
|
transform: isHdrEl ? getViewportMatrix(el) : style.transform || "none",
|
|
105864
|
-
borderRadius: isHdrEl ? getEffectiveBorderRadius(el) : [0, 0, 0, 0]
|
|
106002
|
+
borderRadius: isHdrEl ? getEffectiveBorderRadius(el) : [0, 0, 0, 0],
|
|
106003
|
+
// `getComputedStyle` returns "" when the property doesn't apply (e.g.
|
|
106004
|
+
// for non-replaced elements); normalize to the CSS defaults so callers
|
|
106005
|
+
// can rely on a populated value.
|
|
106006
|
+
objectFit: style.objectFit || "fill",
|
|
106007
|
+
objectPosition: style.objectPosition || "50% 50%"
|
|
105865
106008
|
});
|
|
105866
106009
|
}
|
|
105867
106010
|
return results;
|
|
@@ -106702,6 +106845,125 @@ function blitRgb48leAffine(canvas, source2, matrix, srcW, srcH, canvasW, canvasH
|
|
|
106702
106845
|
}
|
|
106703
106846
|
}
|
|
106704
106847
|
}
|
|
106848
|
+
function parseObjectPositionAxis(value, axis) {
|
|
106849
|
+
const lower = value.trim().toLowerCase();
|
|
106850
|
+
if (lower === "left" || lower === "top") return 0;
|
|
106851
|
+
if (lower === "right" || lower === "bottom") return 1;
|
|
106852
|
+
if (lower === "center" || lower === "") return 0.5;
|
|
106853
|
+
if (lower.endsWith("%")) {
|
|
106854
|
+
const pct = parseFloat(lower) / 100;
|
|
106855
|
+
return Number.isFinite(pct) ? Math.max(0, Math.min(1, pct)) : 0.5;
|
|
106856
|
+
}
|
|
106857
|
+
if (axis === "x" || axis === "y") return 0.5;
|
|
106858
|
+
return 0.5;
|
|
106859
|
+
}
|
|
106860
|
+
function parseObjectPosition(css) {
|
|
106861
|
+
if (!css || !css.trim()) return { x: 0.5, y: 0.5 };
|
|
106862
|
+
const tokens = css.trim().split(/\s+/);
|
|
106863
|
+
if (tokens.length === 1) {
|
|
106864
|
+
const single = tokens[0] ?? "";
|
|
106865
|
+
const v = parseObjectPositionAxis(single, "x");
|
|
106866
|
+
return { x: v, y: 0.5 };
|
|
106867
|
+
}
|
|
106868
|
+
return {
|
|
106869
|
+
x: parseObjectPositionAxis(tokens[0] ?? "", "x"),
|
|
106870
|
+
y: parseObjectPositionAxis(tokens[1] ?? "", "y")
|
|
106871
|
+
};
|
|
106872
|
+
}
|
|
106873
|
+
function computeObjectFitRect(srcW, srcH, dstW, dstH, fit, pos) {
|
|
106874
|
+
let renderedW = dstW;
|
|
106875
|
+
let renderedH = dstH;
|
|
106876
|
+
if (fit === "fill") {
|
|
106877
|
+
return { dx: 0, dy: 0, dw: dstW, dh: dstH };
|
|
106878
|
+
}
|
|
106879
|
+
if (fit === "none") {
|
|
106880
|
+
renderedW = srcW;
|
|
106881
|
+
renderedH = srcH;
|
|
106882
|
+
} else if (fit === "scale-down") {
|
|
106883
|
+
const scale = Math.min(dstW / srcW, dstH / srcH, 1);
|
|
106884
|
+
renderedW = srcW * scale;
|
|
106885
|
+
renderedH = srcH * scale;
|
|
106886
|
+
} else if (fit === "cover") {
|
|
106887
|
+
const scale = Math.max(dstW / srcW, dstH / srcH);
|
|
106888
|
+
renderedW = srcW * scale;
|
|
106889
|
+
renderedH = srcH * scale;
|
|
106890
|
+
} else {
|
|
106891
|
+
const scale = Math.min(dstW / srcW, dstH / srcH);
|
|
106892
|
+
renderedW = srcW * scale;
|
|
106893
|
+
renderedH = srcH * scale;
|
|
106894
|
+
}
|
|
106895
|
+
const dx = (dstW - renderedW) * pos.x;
|
|
106896
|
+
const dy = (dstH - renderedH) * pos.y;
|
|
106897
|
+
return { dx, dy, dw: renderedW, dh: renderedH };
|
|
106898
|
+
}
|
|
106899
|
+
function resampleRgb48leObjectFit(source2, srcW, srcH, dstW, dstH, fit = "fill", objectPosition) {
|
|
106900
|
+
if (srcW <= 0 || srcH <= 0 || dstW <= 0 || dstH <= 0) {
|
|
106901
|
+
return source2;
|
|
106902
|
+
}
|
|
106903
|
+
if (fit === "fill" && srcW === dstW && srcH === dstH) {
|
|
106904
|
+
return source2;
|
|
106905
|
+
}
|
|
106906
|
+
const pos = parseObjectPosition(objectPosition);
|
|
106907
|
+
const rect = computeObjectFitRect(srcW, srcH, dstW, dstH, fit, pos);
|
|
106908
|
+
const dst = Buffer.alloc(dstW * dstH * 6);
|
|
106909
|
+
const stride = dstW * 6;
|
|
106910
|
+
const xMin = Math.max(0, Math.floor(rect.dx));
|
|
106911
|
+
const yMin = Math.max(0, Math.floor(rect.dy));
|
|
106912
|
+
const xMax = Math.min(dstW, Math.ceil(rect.dx + rect.dw));
|
|
106913
|
+
const yMax = Math.min(dstH, Math.ceil(rect.dy + rect.dh));
|
|
106914
|
+
if (rect.dw <= 0 || rect.dh <= 0) {
|
|
106915
|
+
return dst;
|
|
106916
|
+
}
|
|
106917
|
+
const invScaleX = srcW / rect.dw;
|
|
106918
|
+
const invScaleY = srcH / rect.dh;
|
|
106919
|
+
for (let dy = yMin; dy < yMax; dy++) {
|
|
106920
|
+
const rowOff = dy * stride;
|
|
106921
|
+
const sy = (dy + 0.5 - rect.dy) * invScaleY - 0.5;
|
|
106922
|
+
const syc = Math.max(0, Math.min(srcH - 1, sy));
|
|
106923
|
+
const y0 = Math.floor(syc);
|
|
106924
|
+
const y1 = Math.min(y0 + 1, srcH - 1);
|
|
106925
|
+
const fy = syc - y0;
|
|
106926
|
+
const ify = 1 - fy;
|
|
106927
|
+
for (let dx = xMin; dx < xMax; dx++) {
|
|
106928
|
+
const sx = (dx + 0.5 - rect.dx) * invScaleX - 0.5;
|
|
106929
|
+
const sxc = Math.max(0, Math.min(srcW - 1, sx));
|
|
106930
|
+
const x0 = Math.floor(sxc);
|
|
106931
|
+
const x1 = Math.min(x0 + 1, srcW - 1);
|
|
106932
|
+
const fx = sxc - x0;
|
|
106933
|
+
const ifx = 1 - fx;
|
|
106934
|
+
const off00 = (y0 * srcW + x0) * 6;
|
|
106935
|
+
const off10 = (y0 * srcW + x1) * 6;
|
|
106936
|
+
const off01 = (y1 * srcW + x0) * 6;
|
|
106937
|
+
const off11 = (y1 * srcW + x1) * 6;
|
|
106938
|
+
const w00 = ifx * ify;
|
|
106939
|
+
const w10 = fx * ify;
|
|
106940
|
+
const w01 = ifx * fy;
|
|
106941
|
+
const w11 = fx * fy;
|
|
106942
|
+
const r = source2.readUInt16LE(off00) * w00 + source2.readUInt16LE(off10) * w10 + source2.readUInt16LE(off01) * w01 + source2.readUInt16LE(off11) * w11;
|
|
106943
|
+
const g = source2.readUInt16LE(off00 + 2) * w00 + source2.readUInt16LE(off10 + 2) * w10 + source2.readUInt16LE(off01 + 2) * w01 + source2.readUInt16LE(off11 + 2) * w11;
|
|
106944
|
+
const b = source2.readUInt16LE(off00 + 4) * w00 + source2.readUInt16LE(off10 + 4) * w10 + source2.readUInt16LE(off01 + 4) * w01 + source2.readUInt16LE(off11 + 4) * w11;
|
|
106945
|
+
const dstOff = rowOff + dx * 6;
|
|
106946
|
+
dst.writeUInt16LE(Math.round(r), dstOff);
|
|
106947
|
+
dst.writeUInt16LE(Math.round(g), dstOff + 2);
|
|
106948
|
+
dst.writeUInt16LE(Math.round(b), dstOff + 4);
|
|
106949
|
+
}
|
|
106950
|
+
}
|
|
106951
|
+
return dst;
|
|
106952
|
+
}
|
|
106953
|
+
function normalizeObjectFit(value) {
|
|
106954
|
+
switch ((value ?? "").trim().toLowerCase()) {
|
|
106955
|
+
case "cover":
|
|
106956
|
+
return "cover";
|
|
106957
|
+
case "contain":
|
|
106958
|
+
return "contain";
|
|
106959
|
+
case "none":
|
|
106960
|
+
return "none";
|
|
106961
|
+
case "scale-down":
|
|
106962
|
+
return "scale-down";
|
|
106963
|
+
default:
|
|
106964
|
+
return "fill";
|
|
106965
|
+
}
|
|
106966
|
+
}
|
|
106705
106967
|
function parseTransformMatrix(css) {
|
|
106706
106968
|
if (!css || css === "none") return null;
|
|
106707
106969
|
const match2 = css.match(
|
|
@@ -107370,12 +107632,12 @@ import { freemem as freemem2 } from "os";
|
|
|
107370
107632
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
107371
107633
|
|
|
107372
107634
|
// src/services/fileServer.ts
|
|
107373
|
-
import { readFileSync as
|
|
107374
|
-
import { join as join11, extname as
|
|
107635
|
+
import { readFileSync as readFileSync7, existsSync as existsSync12, statSync as statSync5 } from "node:fs";
|
|
107636
|
+
import { join as join11, extname as extname4 } from "node:path";
|
|
107375
107637
|
|
|
107376
107638
|
// src/services/hyperframeRuntimeLoader.ts
|
|
107377
107639
|
import { createHash as createHash2 } from "node:crypto";
|
|
107378
|
-
import { existsSync as existsSync11, readFileSync as
|
|
107640
|
+
import { existsSync as existsSync11, readFileSync as readFileSync6 } from "node:fs";
|
|
107379
107641
|
import { dirname as dirname8, resolve as resolve7 } from "node:path";
|
|
107380
107642
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
107381
107643
|
var PRODUCER_DIR = dirname8(fileURLToPath2(import.meta.url));
|
|
@@ -107418,7 +107680,7 @@ function resolveVerifiedHyperframeRuntime() {
|
|
|
107418
107680
|
`[HyperframeRuntimeLoader] Missing manifest at ${manifestPath}. Build core runtime artifacts before rendering.`
|
|
107419
107681
|
);
|
|
107420
107682
|
}
|
|
107421
|
-
const manifestRaw =
|
|
107683
|
+
const manifestRaw = readFileSync6(manifestPath, "utf8");
|
|
107422
107684
|
const manifest = JSON.parse(manifestRaw);
|
|
107423
107685
|
const runtimeFileName = manifest.artifacts?.iife;
|
|
107424
107686
|
if (!runtimeFileName || !manifest.sha256) {
|
|
@@ -107430,7 +107692,7 @@ function resolveVerifiedHyperframeRuntime() {
|
|
|
107430
107692
|
if (!existsSync11(runtimePath)) {
|
|
107431
107693
|
throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
|
|
107432
107694
|
}
|
|
107433
|
-
const runtimeSource =
|
|
107695
|
+
const runtimeSource = readFileSync6(runtimePath, "utf8");
|
|
107434
107696
|
const runtimeSha = createHash2("sha256").update(runtimeSource, "utf8").digest("hex");
|
|
107435
107697
|
if (runtimeSha !== manifest.sha256) {
|
|
107436
107698
|
throw new Error(
|
|
@@ -107850,10 +108112,10 @@ function createFileServer2(options) {
|
|
|
107850
108112
|
}
|
|
107851
108113
|
return c.text("Not found", 404);
|
|
107852
108114
|
}
|
|
107853
|
-
const ext =
|
|
108115
|
+
const ext = extname4(filePath).toLowerCase();
|
|
107854
108116
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
107855
108117
|
if (ext === ".html") {
|
|
107856
|
-
const rawHtml =
|
|
108118
|
+
const rawHtml = readFileSync7(filePath, "utf-8");
|
|
107857
108119
|
const isIndex = relativePath === "index.html";
|
|
107858
108120
|
let html = rawHtml;
|
|
107859
108121
|
if (preHeadScripts.length > 0) {
|
|
@@ -107862,7 +108124,7 @@ function createFileServer2(options) {
|
|
|
107862
108124
|
html = isIndex ? injectScriptsIntoHtml(html, headScripts, bodyScripts, stripEmbeddedRuntime) : html;
|
|
107863
108125
|
return c.text(html, 200, { "Content-Type": contentType });
|
|
107864
108126
|
}
|
|
107865
|
-
const content =
|
|
108127
|
+
const content = readFileSync7(filePath);
|
|
107866
108128
|
return new Response(content, {
|
|
107867
108129
|
status: 200,
|
|
107868
108130
|
headers: { "Content-Type": contentType }
|
|
@@ -107889,7 +108151,7 @@ function createFileServer2(options) {
|
|
|
107889
108151
|
}
|
|
107890
108152
|
|
|
107891
108153
|
// src/services/htmlCompiler.ts
|
|
107892
|
-
import { readFileSync as
|
|
108154
|
+
import { readFileSync as readFileSync9, existsSync as existsSync14, mkdirSync as mkdirSync9 } from "fs";
|
|
107893
108155
|
import { join as join14, dirname as dirname9, resolve as resolve9 } from "path";
|
|
107894
108156
|
import postcss from "postcss";
|
|
107895
108157
|
|
|
@@ -107922,7 +108184,7 @@ function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS
|
|
|
107922
108184
|
}
|
|
107923
108185
|
|
|
107924
108186
|
// src/services/deterministicFonts.ts
|
|
107925
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as
|
|
108187
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "node:fs";
|
|
107926
108188
|
import { homedir as homedir2 } from "node:os";
|
|
107927
108189
|
import { join as join13 } from "node:path";
|
|
107928
108190
|
|
|
@@ -108251,7 +108513,7 @@ async function fetchGoogleFont(familyName) {
|
|
|
108251
108513
|
continue;
|
|
108252
108514
|
}
|
|
108253
108515
|
}
|
|
108254
|
-
const fontBytes =
|
|
108516
|
+
const fontBytes = readFileSync8(cachePath);
|
|
108255
108517
|
const dataUri = `data:font/woff2;base64,${fontBytes.toString("base64")}`;
|
|
108256
108518
|
faces.push({ weight, style, dataUri });
|
|
108257
108519
|
}
|
|
@@ -108402,6 +108664,7 @@ async function compileHtmlFile(html, baseDir, downloadDir) {
|
|
|
108402
108664
|
async function parseSubCompositions(html, projectDir, downloadDir, parentOffset = 0, parentEnd = Infinity, visited = /* @__PURE__ */ new Set()) {
|
|
108403
108665
|
const videos = [];
|
|
108404
108666
|
const audios = [];
|
|
108667
|
+
const images = [];
|
|
108405
108668
|
const subCompositions = /* @__PURE__ */ new Map();
|
|
108406
108669
|
const { document: document2 } = parseHTML(html);
|
|
108407
108670
|
const compEls = document2.querySelectorAll("[data-composition-src]");
|
|
@@ -108421,7 +108684,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
108421
108684
|
if (!existsSync14(filePath)) {
|
|
108422
108685
|
continue;
|
|
108423
108686
|
}
|
|
108424
|
-
const rawSubHtml =
|
|
108687
|
+
const rawSubHtml = readFileSync9(filePath, "utf-8");
|
|
108425
108688
|
const nestedVisited = new Set(visited);
|
|
108426
108689
|
nestedVisited.add(filePath);
|
|
108427
108690
|
workItems.push({ srcPath, absoluteStart, absoluteEnd, filePath, rawSubHtml, nestedVisited });
|
|
@@ -108443,12 +108706,14 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
108443
108706
|
);
|
|
108444
108707
|
const subVideos = parseVideoElements(compiledSub);
|
|
108445
108708
|
const subAudios = parseAudioElements(compiledSub);
|
|
108709
|
+
const subImages = parseImageElements(compiledSub);
|
|
108446
108710
|
return {
|
|
108447
108711
|
srcPath: item.srcPath,
|
|
108448
108712
|
compiledSub,
|
|
108449
108713
|
nested,
|
|
108450
108714
|
subVideos,
|
|
108451
108715
|
subAudios,
|
|
108716
|
+
subImages,
|
|
108452
108717
|
absoluteStart: item.absoluteStart,
|
|
108453
108718
|
absoluteEnd: item.absoluteEnd
|
|
108454
108719
|
};
|
|
@@ -108461,6 +108726,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
108461
108726
|
}
|
|
108462
108727
|
videos.push(...r.nested.videos);
|
|
108463
108728
|
audios.push(...r.nested.audios);
|
|
108729
|
+
images.push(...r.nested.images);
|
|
108464
108730
|
for (const v of r.subVideos) {
|
|
108465
108731
|
v.start += r.absoluteStart;
|
|
108466
108732
|
v.end += r.absoluteStart;
|
|
@@ -108481,10 +108747,20 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
108481
108747
|
audios.push(a);
|
|
108482
108748
|
}
|
|
108483
108749
|
}
|
|
108484
|
-
|
|
108750
|
+
for (const img of r.subImages) {
|
|
108751
|
+
img.start += r.absoluteStart;
|
|
108752
|
+
img.end += r.absoluteStart;
|
|
108753
|
+
if (img.end > r.absoluteEnd) {
|
|
108754
|
+
img.end = r.absoluteEnd;
|
|
108755
|
+
}
|
|
108756
|
+
if (img.start < r.absoluteEnd) {
|
|
108757
|
+
images.push(img);
|
|
108758
|
+
}
|
|
108759
|
+
}
|
|
108760
|
+
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) {
|
|
108485
108761
|
}
|
|
108486
108762
|
}
|
|
108487
|
-
return { videos, audios, subCompositions };
|
|
108763
|
+
return { videos, audios, images, subCompositions };
|
|
108488
108764
|
}
|
|
108489
108765
|
function promoteCssImportsToLinkTags(html) {
|
|
108490
108766
|
const { document: document2 } = parseHTML(html);
|
|
@@ -108616,7 +108892,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
|
|
|
108616
108892
|
if (!compHtml) {
|
|
108617
108893
|
const filePath = resolve9(projectDir, srcPath);
|
|
108618
108894
|
if (existsSync14(filePath)) {
|
|
108619
|
-
compHtml =
|
|
108895
|
+
compHtml = readFileSync9(filePath, "utf-8");
|
|
108620
108896
|
}
|
|
108621
108897
|
}
|
|
108622
108898
|
if (!compHtml) {
|
|
@@ -108784,7 +109060,9 @@ ${html}
|
|
|
108784
109060
|
</html>`;
|
|
108785
109061
|
}
|
|
108786
109062
|
async function inlineExternalScripts(html) {
|
|
108787
|
-
const
|
|
109063
|
+
const fullHtml = ensureFullDocument(html);
|
|
109064
|
+
const wrappedFragment = fullHtml !== html;
|
|
109065
|
+
const { document: document2 } = parseHTML(fullHtml);
|
|
108788
109066
|
const scripts = document2.querySelectorAll("script[src]");
|
|
108789
109067
|
const externalScripts = [];
|
|
108790
109068
|
for (const el of scripts) {
|
|
@@ -108803,20 +109081,20 @@ async function inlineExternalScripts(html) {
|
|
|
108803
109081
|
return { src, text: await response.text() };
|
|
108804
109082
|
})
|
|
108805
109083
|
);
|
|
108806
|
-
let result = html;
|
|
108807
109084
|
for (let i = 0; i < downloads.length; i++) {
|
|
108808
109085
|
const download = downloads[i];
|
|
108809
|
-
const { src } = externalScripts[i];
|
|
109086
|
+
const { el, src } = externalScripts[i];
|
|
108810
109087
|
if (download.status === "fulfilled") {
|
|
108811
|
-
const escapedSrc = src.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
108812
|
-
const scriptTagRe = new RegExp(
|
|
108813
|
-
`<script\\b[^>]*\\bsrc=["']${escapedSrc}["'][^>]*>\\s*</script>`,
|
|
108814
|
-
"is"
|
|
108815
|
-
);
|
|
108816
109088
|
const safeText = download.value.text.replace(/<\/script/gi, "<\\/script");
|
|
108817
|
-
|
|
109089
|
+
const inlineScript = document2.createElement("script");
|
|
109090
|
+
for (const attr of Array.from(el.attributes)) {
|
|
109091
|
+
if (attr.name.toLowerCase() === "src") continue;
|
|
109092
|
+
inlineScript.setAttribute(attr.name, attr.value);
|
|
109093
|
+
}
|
|
109094
|
+
inlineScript.textContent = `/* inlined: ${src} */
|
|
108818
109095
|
${safeText}
|
|
108819
|
-
|
|
109096
|
+
`;
|
|
109097
|
+
el.replaceWith(inlineScript);
|
|
108820
109098
|
console.log(`[Compiler] Inlined CDN script: ${src}`);
|
|
108821
109099
|
} else {
|
|
108822
109100
|
console.warn(
|
|
@@ -108824,7 +109102,7 @@ ${safeText}
|
|
|
108824
109102
|
);
|
|
108825
109103
|
}
|
|
108826
109104
|
}
|
|
108827
|
-
return
|
|
109105
|
+
return wrappedFragment ? document2.body.innerHTML || "" : document2.toString();
|
|
108828
109106
|
}
|
|
108829
109107
|
function collectExternalAssets(html, projectDir) {
|
|
108830
109108
|
const absProjectDir = resolve9(projectDir);
|
|
@@ -108884,7 +109162,7 @@ function collectExternalAssets(html, projectDir) {
|
|
|
108884
109162
|
};
|
|
108885
109163
|
}
|
|
108886
109164
|
async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
108887
|
-
const rawHtml =
|
|
109165
|
+
const rawHtml = readFileSync9(htmlPath, "utf-8");
|
|
108888
109166
|
const { html: compiledHtml, unresolvedCompositions } = await compileHtmlFile(
|
|
108889
109167
|
rawHtml,
|
|
108890
109168
|
projectDir,
|
|
@@ -108893,6 +109171,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
108893
109171
|
const {
|
|
108894
109172
|
videos: subVideos,
|
|
108895
109173
|
audios: subAudios,
|
|
109174
|
+
images: subImages,
|
|
108896
109175
|
subCompositions
|
|
108897
109176
|
} = await parseSubCompositions(compiledHtml, projectDir, downloadDir);
|
|
108898
109177
|
const fullHtml = ensureFullDocument(compiledHtml);
|
|
@@ -108909,8 +109188,10 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
108909
109188
|
const { html, externalAssets } = collectExternalAssets(assembledHtml, projectDir);
|
|
108910
109189
|
const mainVideos = parseVideoElements(html);
|
|
108911
109190
|
const mainAudios = parseAudioElements(html);
|
|
109191
|
+
const mainImages = parseImageElements(html);
|
|
108912
109192
|
const videos = dedupeElementsById([...mainVideos, ...subVideos]);
|
|
108913
109193
|
const audios = dedupeElementsById([...mainAudios, ...subAudios]);
|
|
109194
|
+
const images = dedupeElementsById([...mainImages, ...subImages]);
|
|
108914
109195
|
for (const video of videos) {
|
|
108915
109196
|
if (isHttpUrl(video.src)) continue;
|
|
108916
109197
|
const videoPath = resolve9(projectDir, video.src);
|
|
@@ -108941,6 +109222,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
108941
109222
|
subCompositions,
|
|
108942
109223
|
videos,
|
|
108943
109224
|
audios,
|
|
109225
|
+
images,
|
|
108944
109226
|
unresolvedCompositions,
|
|
108945
109227
|
externalAssets,
|
|
108946
109228
|
width,
|
|
@@ -109025,12 +109307,15 @@ async function recompileWithResolutions(compiled, resolutions, projectDir, downl
|
|
|
109025
109307
|
const {
|
|
109026
109308
|
videos: subVideos,
|
|
109027
109309
|
audios: subAudios,
|
|
109310
|
+
images: subImages,
|
|
109028
109311
|
subCompositions
|
|
109029
109312
|
} = await parseSubCompositions(html, projectDir, downloadDir);
|
|
109030
109313
|
const mainVideos = parseVideoElements(html);
|
|
109031
109314
|
const mainAudios = parseAudioElements(html);
|
|
109315
|
+
const mainImages = parseImageElements(html);
|
|
109032
109316
|
const videos = dedupeElementsById([...mainVideos, ...subVideos]);
|
|
109033
109317
|
const audios = dedupeElementsById([...mainAudios, ...subAudios]);
|
|
109318
|
+
const images = dedupeElementsById([...mainImages, ...subImages]);
|
|
109034
109319
|
const remaining = compiled.unresolvedCompositions.filter(
|
|
109035
109320
|
(c) => !resolutions.some((r) => r.id === c.id)
|
|
109036
109321
|
);
|
|
@@ -109040,6 +109325,7 @@ async function recompileWithResolutions(compiled, resolutions, projectDir, downl
|
|
|
109040
109325
|
subCompositions,
|
|
109041
109326
|
videos,
|
|
109042
109327
|
audios,
|
|
109328
|
+
images,
|
|
109043
109329
|
unresolvedCompositions: remaining,
|
|
109044
109330
|
renderModeHints: compiled.renderModeHints
|
|
109045
109331
|
};
|
|
@@ -109225,7 +109511,7 @@ function blitHdrVideoLayer(canvas, el, time, fps, hdrFrameDirs, hdrStartTimes, w
|
|
|
109225
109511
|
return;
|
|
109226
109512
|
}
|
|
109227
109513
|
try {
|
|
109228
|
-
const { data: hdrRgb, width: srcW, height: srcH } = decodePngToRgb48le(
|
|
109514
|
+
const { data: hdrRgb, width: srcW, height: srcH } = decodePngToRgb48le(readFileSync10(framePath));
|
|
109229
109515
|
if (sourceTransfer && targetTransfer && sourceTransfer !== targetTransfer) {
|
|
109230
109516
|
convertTransfer(hdrRgb, sourceTransfer, targetTransfer);
|
|
109231
109517
|
}
|
|
@@ -109267,6 +109553,55 @@ function blitHdrVideoLayer(canvas, el, time, fps, hdrFrameDirs, hdrStartTimes, w
|
|
|
109267
109553
|
}
|
|
109268
109554
|
}
|
|
109269
109555
|
}
|
|
109556
|
+
function blitHdrImageLayer(canvas, el, hdrImageBuffers, width, height, log, sourceTransfer, targetTransfer) {
|
|
109557
|
+
const buf = hdrImageBuffers.get(el.id);
|
|
109558
|
+
if (!buf) {
|
|
109559
|
+
return;
|
|
109560
|
+
}
|
|
109561
|
+
try {
|
|
109562
|
+
let hdrRgb = buf.data;
|
|
109563
|
+
if (sourceTransfer && targetTransfer && sourceTransfer !== targetTransfer) {
|
|
109564
|
+
hdrRgb = Buffer.from(buf.data);
|
|
109565
|
+
convertTransfer(hdrRgb, sourceTransfer, targetTransfer);
|
|
109566
|
+
}
|
|
109567
|
+
const viewportMatrix = parseTransformMatrix(el.transform);
|
|
109568
|
+
const br = el.borderRadius;
|
|
109569
|
+
const hasBorderRadius = br[0] > 0 || br[1] > 0 || br[2] > 0 || br[3] > 0;
|
|
109570
|
+
const borderRadiusParam = hasBorderRadius ? br : void 0;
|
|
109571
|
+
if (viewportMatrix) {
|
|
109572
|
+
blitRgb48leAffine(
|
|
109573
|
+
canvas,
|
|
109574
|
+
hdrRgb,
|
|
109575
|
+
viewportMatrix,
|
|
109576
|
+
buf.width,
|
|
109577
|
+
buf.height,
|
|
109578
|
+
width,
|
|
109579
|
+
height,
|
|
109580
|
+
el.opacity < 0.999 ? el.opacity : void 0,
|
|
109581
|
+
borderRadiusParam
|
|
109582
|
+
);
|
|
109583
|
+
} else {
|
|
109584
|
+
blitRgb48leRegion(
|
|
109585
|
+
canvas,
|
|
109586
|
+
hdrRgb,
|
|
109587
|
+
el.x,
|
|
109588
|
+
el.y,
|
|
109589
|
+
buf.width,
|
|
109590
|
+
buf.height,
|
|
109591
|
+
width,
|
|
109592
|
+
height,
|
|
109593
|
+
el.opacity < 0.999 ? el.opacity : void 0,
|
|
109594
|
+
borderRadiusParam
|
|
109595
|
+
);
|
|
109596
|
+
}
|
|
109597
|
+
} catch (err) {
|
|
109598
|
+
if (log) {
|
|
109599
|
+
log.debug(`HDR image blit failed for ${el.id}`, {
|
|
109600
|
+
error: err instanceof Error ? err.message : String(err)
|
|
109601
|
+
});
|
|
109602
|
+
}
|
|
109603
|
+
}
|
|
109604
|
+
}
|
|
109270
109605
|
function createRenderJob(config2) {
|
|
109271
109606
|
return {
|
|
109272
109607
|
id: randomUUID(),
|
|
@@ -109318,6 +109653,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109318
109653
|
let lastBrowserConsole = [];
|
|
109319
109654
|
let restoreLogger = null;
|
|
109320
109655
|
const perfStages = {};
|
|
109656
|
+
const hdrDiagnostics = {
|
|
109657
|
+
videoExtractionFailures: 0,
|
|
109658
|
+
imageDecodeFailures: 0
|
|
109659
|
+
};
|
|
109321
109660
|
const perfOutputPath = join15(workDir, "perf-summary.json");
|
|
109322
109661
|
const cfg = { ...job.config.producerConfig ?? resolveConfig() };
|
|
109323
109662
|
const outputFormat = job.config.format ?? "mp4";
|
|
@@ -109349,7 +109688,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109349
109688
|
throw new Error(`Entry file not found: ${htmlPath}`);
|
|
109350
109689
|
}
|
|
109351
109690
|
assertNotAborted();
|
|
109352
|
-
const rawEntry =
|
|
109691
|
+
const rawEntry = readFileSync10(htmlPath, "utf-8");
|
|
109353
109692
|
if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
|
|
109354
109693
|
const wrapperPath = join15(workDir, "standalone-entry.html");
|
|
109355
109694
|
const projectIndexPath = join15(projectDir, "index.html");
|
|
@@ -109359,7 +109698,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109359
109698
|
);
|
|
109360
109699
|
}
|
|
109361
109700
|
const standaloneHtml = extractStandaloneEntryFromIndex(
|
|
109362
|
-
|
|
109701
|
+
readFileSync10(projectIndexPath, "utf-8"),
|
|
109363
109702
|
entryFile
|
|
109364
109703
|
);
|
|
109365
109704
|
if (!standaloneHtml) {
|
|
@@ -109394,6 +109733,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109394
109733
|
duration: compiled.staticDuration,
|
|
109395
109734
|
videos: compiled.videos,
|
|
109396
109735
|
audios: compiled.audios,
|
|
109736
|
+
images: compiled.images,
|
|
109397
109737
|
width: compiled.width,
|
|
109398
109738
|
height: compiled.height
|
|
109399
109739
|
};
|
|
@@ -109458,6 +109798,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109458
109798
|
assertNotAborted();
|
|
109459
109799
|
composition.videos = compiled.videos;
|
|
109460
109800
|
composition.audios = compiled.audios;
|
|
109801
|
+
composition.images = compiled.images;
|
|
109461
109802
|
writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
|
|
109462
109803
|
}
|
|
109463
109804
|
}
|
|
@@ -109613,6 +109954,30 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109613
109954
|
})
|
|
109614
109955
|
);
|
|
109615
109956
|
}
|
|
109957
|
+
const nativeHdrImageIds = /* @__PURE__ */ new Set();
|
|
109958
|
+
const imageTransfers = /* @__PURE__ */ new Map();
|
|
109959
|
+
const hdrImageSrcPaths = /* @__PURE__ */ new Map();
|
|
109960
|
+
const imageColorSpaces = [];
|
|
109961
|
+
if (job.config.hdr && composition.images.length > 0) {
|
|
109962
|
+
const probed = await Promise.all(
|
|
109963
|
+
composition.images.map(async (img) => {
|
|
109964
|
+
let imgPath = img.src;
|
|
109965
|
+
if (!imgPath.startsWith("/")) {
|
|
109966
|
+
const fromCompiled = existsSync15(join15(compiledDir, imgPath)) ? join15(compiledDir, imgPath) : join15(projectDir, imgPath);
|
|
109967
|
+
imgPath = fromCompiled;
|
|
109968
|
+
}
|
|
109969
|
+
if (!existsSync15(imgPath)) return null;
|
|
109970
|
+
const meta = await extractVideoMetadata(imgPath);
|
|
109971
|
+
if (isHdrColorSpace(meta.colorSpace)) {
|
|
109972
|
+
nativeHdrImageIds.add(img.id);
|
|
109973
|
+
imageTransfers.set(img.id, detectTransfer(meta.colorSpace));
|
|
109974
|
+
hdrImageSrcPaths.set(img.id, imgPath);
|
|
109975
|
+
}
|
|
109976
|
+
return meta.colorSpace;
|
|
109977
|
+
})
|
|
109978
|
+
);
|
|
109979
|
+
imageColorSpaces.push(...probed);
|
|
109980
|
+
}
|
|
109616
109981
|
if (composition.videos.length > 0) {
|
|
109617
109982
|
extractionResult = await extractAllVideoFrames(
|
|
109618
109983
|
composition.videos,
|
|
@@ -109650,21 +110015,22 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109650
110015
|
perfStages.videoExtractMs = Date.now() - stage2Start;
|
|
109651
110016
|
}
|
|
109652
110017
|
let effectiveHdr;
|
|
109653
|
-
if (job.config.hdr
|
|
109654
|
-
const
|
|
109655
|
-
|
|
109656
|
-
|
|
109657
|
-
|
|
109658
|
-
|
|
109659
|
-
|
|
109660
|
-
|
|
109661
|
-
|
|
109662
|
-
|
|
109663
|
-
effectiveHdr = { transfer: firstTransfer };
|
|
110018
|
+
if (job.config.hdr) {
|
|
110019
|
+
const videoColorSpaces = (extractionResult?.extracted ?? []).map(
|
|
110020
|
+
(ext) => ext.metadata.colorSpace
|
|
110021
|
+
);
|
|
110022
|
+
const allColorSpaces = [...videoColorSpaces, ...imageColorSpaces];
|
|
110023
|
+
if (allColorSpaces.length > 0) {
|
|
110024
|
+
const info = analyzeCompositionHdr(allColorSpaces);
|
|
110025
|
+
if (info.hasHdr && info.dominantTransfer) {
|
|
110026
|
+
effectiveHdr = { transfer: info.dominantTransfer };
|
|
110027
|
+
}
|
|
109664
110028
|
}
|
|
109665
110029
|
}
|
|
109666
110030
|
if (effectiveHdr && outputFormat !== "mp4") {
|
|
109667
|
-
log.
|
|
110031
|
+
log.warn(
|
|
110032
|
+
`[Render] HDR source detected but format is ${outputFormat} \u2014 falling back to SDR. Use --format mp4 for HDR10 output.`
|
|
110033
|
+
);
|
|
109668
110034
|
effectiveHdr = void 0;
|
|
109669
110035
|
}
|
|
109670
110036
|
if (effectiveHdr) {
|
|
@@ -109717,12 +110083,14 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109717
110083
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
109718
110084
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
109719
110085
|
const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
|
|
109720
|
-
const
|
|
110086
|
+
const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
|
|
110087
|
+
const hasHdrContent = effectiveHdr && nativeHdrIds.size > 0;
|
|
109721
110088
|
const encoderHdr = hasHdrContent ? effectiveHdr : void 0;
|
|
109722
110089
|
const preset = getEncoderPreset(job.config.quality, outputFormat, encoderHdr);
|
|
109723
110090
|
job.framesRendered = 0;
|
|
109724
110091
|
if (hasHdrContent) {
|
|
109725
110092
|
log.info("[Render] HDR layered composite: z-ordered DOM + native HLG video layers");
|
|
110093
|
+
cfg.forceScreenshot = true;
|
|
109726
110094
|
const hdrVideoIds = composition.videos.filter((v) => nativeHdrVideoIds.has(v.id)).map((v) => v.id);
|
|
109727
110095
|
const hdrVideoSrcPaths = /* @__PURE__ */ new Map();
|
|
109728
110096
|
for (const v of composition.videos) {
|
|
@@ -109738,7 +110106,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109738
110106
|
const domSession = await createCaptureSession(
|
|
109739
110107
|
fileServer.url,
|
|
109740
110108
|
framesDir,
|
|
109741
|
-
captureOptions,
|
|
110109
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
109742
110110
|
createVideoFrameInjector(frameLookup),
|
|
109743
110111
|
cfg
|
|
109744
110112
|
);
|
|
@@ -109792,13 +110160,22 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109792
110160
|
);
|
|
109793
110161
|
assertNotAborted();
|
|
109794
110162
|
const hdrExtractionDims = /* @__PURE__ */ new Map();
|
|
110163
|
+
const hdrImageFitInfo = /* @__PURE__ */ new Map();
|
|
109795
110164
|
const hdrVideoStartTimes = /* @__PURE__ */ new Map();
|
|
109796
110165
|
for (const v of composition.videos) {
|
|
109797
110166
|
if (hdrVideoIds.includes(v.id)) {
|
|
109798
110167
|
hdrVideoStartTimes.set(v.id, v.start);
|
|
109799
110168
|
}
|
|
109800
110169
|
}
|
|
109801
|
-
const
|
|
110170
|
+
const hdrImageStartTimes = /* @__PURE__ */ new Map();
|
|
110171
|
+
for (const img of composition.images) {
|
|
110172
|
+
if (nativeHdrImageIds.has(img.id)) {
|
|
110173
|
+
hdrImageStartTimes.set(img.id, img.start);
|
|
110174
|
+
}
|
|
110175
|
+
}
|
|
110176
|
+
const uniqueStartTimes = [
|
|
110177
|
+
.../* @__PURE__ */ new Set([...hdrVideoStartTimes.values(), ...hdrImageStartTimes.values()])
|
|
110178
|
+
].sort((a, b) => a - b);
|
|
109802
110179
|
for (const seekTime of uniqueStartTimes) {
|
|
109803
110180
|
await domSession.page.evaluate((t) => {
|
|
109804
110181
|
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
@@ -109806,11 +110183,17 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109806
110183
|
if (domSession.onBeforeCapture) {
|
|
109807
110184
|
await domSession.onBeforeCapture(domSession.page, seekTime);
|
|
109808
110185
|
}
|
|
109809
|
-
const stacking = await queryElementStacking(domSession.page,
|
|
110186
|
+
const stacking = await queryElementStacking(domSession.page, nativeHdrIds);
|
|
109810
110187
|
for (const el of stacking) {
|
|
109811
110188
|
if (el.isHdr && el.layoutWidth > 0 && el.layoutHeight > 0 && !hdrExtractionDims.has(el.id)) {
|
|
109812
110189
|
hdrExtractionDims.set(el.id, { width: el.layoutWidth, height: el.layoutHeight });
|
|
109813
110190
|
}
|
|
110191
|
+
if (el.isHdr && nativeHdrImageIds.has(el.id) && !hdrImageFitInfo.has(el.id)) {
|
|
110192
|
+
hdrImageFitInfo.set(el.id, {
|
|
110193
|
+
fit: el.objectFit,
|
|
110194
|
+
position: el.objectPosition
|
|
110195
|
+
});
|
|
110196
|
+
}
|
|
109814
110197
|
}
|
|
109815
110198
|
}
|
|
109816
110199
|
const hdrFrameDirs = /* @__PURE__ */ new Map();
|
|
@@ -109841,14 +110224,59 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109841
110224
|
];
|
|
109842
110225
|
const result = await runFfmpeg(ffmpegArgs, { signal: abortSignal });
|
|
109843
110226
|
if (!result.success) {
|
|
109844
|
-
|
|
110227
|
+
hdrDiagnostics.videoExtractionFailures += 1;
|
|
110228
|
+
log.error("HDR frame pre-extraction failed; aborting render", {
|
|
109845
110229
|
videoId,
|
|
109846
110230
|
srcPath,
|
|
109847
110231
|
stderr: result.stderr.slice(-400)
|
|
109848
110232
|
});
|
|
110233
|
+
throw new Error(
|
|
110234
|
+
`HDR frame extraction failed for video "${videoId}". Aborting render to avoid shipping black HDR layers.`
|
|
110235
|
+
);
|
|
109849
110236
|
}
|
|
109850
110237
|
hdrFrameDirs.set(videoId, frameDir);
|
|
109851
110238
|
}
|
|
110239
|
+
const hdrImageBuffers = /* @__PURE__ */ new Map();
|
|
110240
|
+
for (const [imageId, srcPath] of hdrImageSrcPaths) {
|
|
110241
|
+
try {
|
|
110242
|
+
const decoded = decodePngToRgb48le(readFileSync10(srcPath));
|
|
110243
|
+
const layout2 = hdrExtractionDims.get(imageId);
|
|
110244
|
+
const fitInfo = hdrImageFitInfo.get(imageId);
|
|
110245
|
+
if (layout2 && (layout2.width !== decoded.width || layout2.height !== decoded.height)) {
|
|
110246
|
+
const fit = normalizeObjectFit(fitInfo?.fit);
|
|
110247
|
+
const resampled = resampleRgb48leObjectFit(
|
|
110248
|
+
decoded.data,
|
|
110249
|
+
decoded.width,
|
|
110250
|
+
decoded.height,
|
|
110251
|
+
layout2.width,
|
|
110252
|
+
layout2.height,
|
|
110253
|
+
fit,
|
|
110254
|
+
fitInfo?.position
|
|
110255
|
+
);
|
|
110256
|
+
hdrImageBuffers.set(imageId, {
|
|
110257
|
+
data: resampled,
|
|
110258
|
+
width: layout2.width,
|
|
110259
|
+
height: layout2.height
|
|
110260
|
+
});
|
|
110261
|
+
} else {
|
|
110262
|
+
hdrImageBuffers.set(imageId, {
|
|
110263
|
+
data: Buffer.from(decoded.data),
|
|
110264
|
+
width: decoded.width,
|
|
110265
|
+
height: decoded.height
|
|
110266
|
+
});
|
|
110267
|
+
}
|
|
110268
|
+
} catch (err) {
|
|
110269
|
+
hdrDiagnostics.imageDecodeFailures += 1;
|
|
110270
|
+
log.error("HDR image decode failed; aborting render", {
|
|
110271
|
+
imageId,
|
|
110272
|
+
srcPath,
|
|
110273
|
+
error: err instanceof Error ? err.message : String(err)
|
|
110274
|
+
});
|
|
110275
|
+
throw new Error(
|
|
110276
|
+
`HDR image decode failed for image "${imageId}". Aborting render to avoid shipping missing HDR image layers.`
|
|
110277
|
+
);
|
|
110278
|
+
}
|
|
110279
|
+
}
|
|
109852
110280
|
assertNotAborted();
|
|
109853
110281
|
try {
|
|
109854
110282
|
let countNonZeroAlpha2 = function(rgba) {
|
|
@@ -109906,38 +110334,67 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109906
110334
|
const layer = layers[layerIdx];
|
|
109907
110335
|
if (layer.type === "hdr") {
|
|
109908
110336
|
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
109909
|
-
|
|
109910
|
-
|
|
109911
|
-
|
|
109912
|
-
|
|
109913
|
-
|
|
109914
|
-
|
|
109915
|
-
|
|
109916
|
-
|
|
109917
|
-
|
|
109918
|
-
|
|
109919
|
-
|
|
109920
|
-
|
|
109921
|
-
|
|
110337
|
+
const isHdrImage = nativeHdrImageIds.has(layer.element.id);
|
|
110338
|
+
if (isHdrImage) {
|
|
110339
|
+
blitHdrImageLayer(
|
|
110340
|
+
canvas,
|
|
110341
|
+
layer.element,
|
|
110342
|
+
hdrImageBuffers,
|
|
110343
|
+
width,
|
|
110344
|
+
height,
|
|
110345
|
+
log,
|
|
110346
|
+
imageTransfers.get(layer.element.id),
|
|
110347
|
+
effectiveHdr?.transfer
|
|
110348
|
+
);
|
|
110349
|
+
} else {
|
|
110350
|
+
blitHdrVideoLayer(
|
|
110351
|
+
canvas,
|
|
110352
|
+
layer.element,
|
|
110353
|
+
time,
|
|
110354
|
+
job.config.fps,
|
|
110355
|
+
hdrFrameDirs,
|
|
110356
|
+
hdrVideoStartTimes,
|
|
110357
|
+
width,
|
|
110358
|
+
height,
|
|
110359
|
+
log,
|
|
110360
|
+
videoTransfers.get(layer.element.id),
|
|
110361
|
+
effectiveHdr?.transfer
|
|
110362
|
+
);
|
|
110363
|
+
}
|
|
109922
110364
|
if (shouldLog) {
|
|
109923
110365
|
const after2 = countNonZeroRgb482(canvas);
|
|
109924
|
-
|
|
109925
|
-
|
|
109926
|
-
|
|
109927
|
-
|
|
109928
|
-
|
|
109929
|
-
|
|
109930
|
-
|
|
109931
|
-
|
|
109932
|
-
|
|
109933
|
-
|
|
109934
|
-
|
|
109935
|
-
|
|
109936
|
-
|
|
109937
|
-
|
|
109938
|
-
|
|
109939
|
-
|
|
109940
|
-
|
|
110366
|
+
if (isHdrImage) {
|
|
110367
|
+
const buf = hdrImageBuffers.get(layer.element.id);
|
|
110368
|
+
log.info("[diag] hdr layer blit", {
|
|
110369
|
+
frame: debugFrameIndex,
|
|
110370
|
+
layerIdx,
|
|
110371
|
+
id: layer.element.id,
|
|
110372
|
+
kind: "image",
|
|
110373
|
+
pixelsAdded: after2 - before2,
|
|
110374
|
+
totalNonZero: after2,
|
|
110375
|
+
bufferDecoded: !!buf,
|
|
110376
|
+
bufferDims: buf ? `${buf.width}x${buf.height}` : null
|
|
110377
|
+
});
|
|
110378
|
+
} else {
|
|
110379
|
+
const frameDir = hdrFrameDirs.get(layer.element.id);
|
|
110380
|
+
const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
|
|
110381
|
+
const localTime = time - startTime;
|
|
110382
|
+
const frameNum = Math.floor(localTime * job.config.fps) + 1;
|
|
110383
|
+
const expectedFrame = frameDir ? join15(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
|
|
110384
|
+
log.info("[diag] hdr layer blit", {
|
|
110385
|
+
frame: debugFrameIndex,
|
|
110386
|
+
layerIdx,
|
|
110387
|
+
id: layer.element.id,
|
|
110388
|
+
kind: "video",
|
|
110389
|
+
pixelsAdded: after2 - before2,
|
|
110390
|
+
totalNonZero: after2,
|
|
110391
|
+
startTime,
|
|
110392
|
+
localTime: localTime.toFixed(3),
|
|
110393
|
+
hdrFrameNum: frameNum,
|
|
110394
|
+
expectedFrame,
|
|
110395
|
+
expectedFrameExists: expectedFrame ? existsSync15(expectedFrame) : false
|
|
110396
|
+
});
|
|
110397
|
+
}
|
|
109941
110398
|
}
|
|
109942
110399
|
} else {
|
|
109943
110400
|
const allElementIds = fullStacking.map((e) => e.id);
|
|
@@ -110012,7 +110469,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110012
110469
|
if (beforeCaptureHook) {
|
|
110013
110470
|
await beforeCaptureHook(domSession.page, time);
|
|
110014
110471
|
}
|
|
110015
|
-
const stackingInfo = await queryElementStacking(domSession.page,
|
|
110472
|
+
const stackingInfo = await queryElementStacking(domSession.page, nativeHdrIds);
|
|
110016
110473
|
const activeTransition = transitionRanges.find(
|
|
110017
110474
|
(t) => i >= t.startFrame && i <= t.endFrame
|
|
110018
110475
|
);
|
|
@@ -110044,22 +110501,35 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110044
110501
|
}
|
|
110045
110502
|
for (const el of stackingInfo) {
|
|
110046
110503
|
if (!el.isHdr || !sceneIds.has(el.id)) continue;
|
|
110047
|
-
|
|
110048
|
-
|
|
110049
|
-
|
|
110050
|
-
|
|
110051
|
-
|
|
110052
|
-
|
|
110053
|
-
|
|
110054
|
-
|
|
110055
|
-
|
|
110056
|
-
|
|
110057
|
-
|
|
110058
|
-
|
|
110059
|
-
|
|
110504
|
+
if (nativeHdrImageIds.has(el.id)) {
|
|
110505
|
+
blitHdrImageLayer(
|
|
110506
|
+
sceneBuf,
|
|
110507
|
+
el,
|
|
110508
|
+
hdrImageBuffers,
|
|
110509
|
+
width,
|
|
110510
|
+
height,
|
|
110511
|
+
log,
|
|
110512
|
+
imageTransfers.get(el.id),
|
|
110513
|
+
effectiveHdr?.transfer
|
|
110514
|
+
);
|
|
110515
|
+
} else {
|
|
110516
|
+
blitHdrVideoLayer(
|
|
110517
|
+
sceneBuf,
|
|
110518
|
+
el,
|
|
110519
|
+
time,
|
|
110520
|
+
job.config.fps,
|
|
110521
|
+
hdrFrameDirs,
|
|
110522
|
+
hdrVideoStartTimes,
|
|
110523
|
+
width,
|
|
110524
|
+
height,
|
|
110525
|
+
log,
|
|
110526
|
+
videoTransfers.get(el.id),
|
|
110527
|
+
effectiveHdr?.transfer
|
|
110528
|
+
);
|
|
110529
|
+
}
|
|
110060
110530
|
}
|
|
110061
110531
|
const showIds = Array.from(sceneIds);
|
|
110062
|
-
const hideIds = stackingInfo.map((e) => e.id).filter((id) => !sceneIds.has(id) ||
|
|
110532
|
+
const hideIds = stackingInfo.map((e) => e.id).filter((id) => !sceneIds.has(id) || nativeHdrIds.has(id));
|
|
110063
110533
|
await applyDomLayerMask(domSession.page, showIds, hideIds);
|
|
110064
110534
|
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
110065
110535
|
await removeDomLayerMask(domSession.page, hideIds);
|
|
@@ -110180,7 +110650,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110180
110650
|
fileServer.url,
|
|
110181
110651
|
workDir,
|
|
110182
110652
|
tasks,
|
|
110183
|
-
captureOptions,
|
|
110653
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
110184
110654
|
() => createVideoFrameInjector(frameLookup),
|
|
110185
110655
|
abortSignal,
|
|
110186
110656
|
(progress) => {
|
|
@@ -110210,7 +110680,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110210
110680
|
const session = probeSession ?? await createCaptureSession(
|
|
110211
110681
|
fileServer.url,
|
|
110212
110682
|
framesDir,
|
|
110213
|
-
captureOptions,
|
|
110683
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
110214
110684
|
videoInjector,
|
|
110215
110685
|
cfg
|
|
110216
110686
|
);
|
|
@@ -110261,7 +110731,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110261
110731
|
fileServer.url,
|
|
110262
110732
|
workDir,
|
|
110263
110733
|
tasks,
|
|
110264
|
-
captureOptions,
|
|
110734
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
110265
110735
|
() => createVideoFrameInjector(frameLookup),
|
|
110266
110736
|
abortSignal,
|
|
110267
110737
|
(progress) => {
|
|
@@ -110292,7 +110762,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110292
110762
|
const session = probeSession ?? await createCaptureSession(
|
|
110293
110763
|
fileServer.url,
|
|
110294
110764
|
framesDir,
|
|
110295
|
-
captureOptions,
|
|
110765
|
+
{ ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
|
|
110296
110766
|
videoInjector,
|
|
110297
110767
|
cfg
|
|
110298
110768
|
);
|
|
@@ -110410,6 +110880,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110410
110880
|
videoCount: composition.videos.length,
|
|
110411
110881
|
audioCount: composition.audios.length,
|
|
110412
110882
|
stages: perfStages,
|
|
110883
|
+
hdrDiagnostics: hdrDiagnostics.videoExtractionFailures > 0 || hdrDiagnostics.imageDecodeFailures > 0 ? { ...hdrDiagnostics } : void 0,
|
|
110413
110884
|
captureAvgMs: totalFrames > 0 ? Math.round((perfStages.captureMs ?? 0) / totalFrames) : void 0
|
|
110414
110885
|
};
|
|
110415
110886
|
job.perfSummary = perfSummary;
|
|
@@ -110490,7 +110961,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110490
110961
|
elapsedMs: elapsed,
|
|
110491
110962
|
freeMemoryMB: freeMemMB,
|
|
110492
110963
|
browserConsoleTail: lastBrowserConsole.length > 0 ? lastBrowserConsole.slice(-30) : void 0,
|
|
110493
|
-
perfStages: Object.keys(perfStages).length > 0 ? { ...perfStages } : void 0
|
|
110964
|
+
perfStages: Object.keys(perfStages).length > 0 ? { ...perfStages } : void 0,
|
|
110965
|
+
hdrDiagnostics: hdrDiagnostics.videoExtractionFailures > 0 || hdrDiagnostics.imageDecodeFailures > 0 ? { ...hdrDiagnostics } : void 0
|
|
110494
110966
|
};
|
|
110495
110967
|
if (fileServer) {
|
|
110496
110968
|
const fs8 = fileServer;
|
|
@@ -110521,7 +110993,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110521
110993
|
}
|
|
110522
110994
|
|
|
110523
110995
|
// src/services/hyperframeLint.ts
|
|
110524
|
-
import { existsSync as existsSync16, readFileSync as
|
|
110996
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11, statSync as statSync6 } from "node:fs";
|
|
110525
110997
|
import { resolve as resolve11, join as join16 } from "node:path";
|
|
110526
110998
|
function isStringRecord(value) {
|
|
110527
110999
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -110564,7 +111036,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
110564
111036
|
if (existsSync16(absoluteEntryPath) && statSync6(absoluteEntryPath).isFile()) {
|
|
110565
111037
|
return {
|
|
110566
111038
|
entryFile,
|
|
110567
|
-
html:
|
|
111039
|
+
html: readFileSync11(absoluteEntryPath, "utf-8"),
|
|
110568
111040
|
source: "projectDir"
|
|
110569
111041
|
};
|
|
110570
111042
|
}
|