@hyperframes/producer 0.4.7 → 0.4.8
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 +1300 -121
- package/dist/index.js.map +4 -4
- package/dist/public-server.js +1300 -121
- package/dist/public-server.js.map +4 -4
- package/dist/services/renderOrchestrator.d.ts +2 -0
- package/dist/services/renderOrchestrator.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5116,12 +5116,12 @@ var require_common = __commonJS({
|
|
|
5116
5116
|
createDebug.skips = [];
|
|
5117
5117
|
createDebug.formatters = {};
|
|
5118
5118
|
function selectColor(namespace) {
|
|
5119
|
-
let
|
|
5119
|
+
let hash2 = 0;
|
|
5120
5120
|
for (let i = 0; i < namespace.length; i++) {
|
|
5121
|
-
|
|
5122
|
-
|
|
5121
|
+
hash2 = (hash2 << 5) - hash2 + namespace.charCodeAt(i);
|
|
5122
|
+
hash2 |= 0;
|
|
5123
5123
|
}
|
|
5124
|
-
return createDebug.colors[Math.abs(
|
|
5124
|
+
return createDebug.colors[Math.abs(hash2) % createDebug.colors.length];
|
|
5125
5125
|
}
|
|
5126
5126
|
createDebug.selectColor = selectColor;
|
|
5127
5127
|
function createDebug(namespace) {
|
|
@@ -54349,25 +54349,25 @@ var require_data = __commonJS({
|
|
|
54349
54349
|
var notmodified_1 = __importDefault2(require_notmodified());
|
|
54350
54350
|
var debug6 = (0, debug_1.default)("get-uri:data");
|
|
54351
54351
|
var DataReadable = class extends stream_1.Readable {
|
|
54352
|
-
constructor(
|
|
54352
|
+
constructor(hash2, buf) {
|
|
54353
54353
|
super();
|
|
54354
54354
|
this.push(buf);
|
|
54355
54355
|
this.push(null);
|
|
54356
|
-
this.hash =
|
|
54356
|
+
this.hash = hash2;
|
|
54357
54357
|
}
|
|
54358
54358
|
};
|
|
54359
54359
|
var data = async ({ href: uri }, { cache } = {}) => {
|
|
54360
54360
|
const shasum = (0, crypto_1.createHash)("sha1");
|
|
54361
54361
|
shasum.update(uri);
|
|
54362
|
-
const
|
|
54363
|
-
debug6('generated SHA1 hash for "data:" URI: %o',
|
|
54364
|
-
if (cache?.hash ===
|
|
54365
|
-
debug6("got matching cache SHA1 hash: %o",
|
|
54362
|
+
const hash2 = shasum.digest("hex");
|
|
54363
|
+
debug6('generated SHA1 hash for "data:" URI: %o', hash2);
|
|
54364
|
+
if (cache?.hash === hash2) {
|
|
54365
|
+
debug6("got matching cache SHA1 hash: %o", hash2);
|
|
54366
54366
|
throw new notmodified_1.default();
|
|
54367
54367
|
} else {
|
|
54368
54368
|
debug6('creating Readable stream from "data:" URI buffer');
|
|
54369
54369
|
const { buffer } = (0, data_uri_to_buffer_1.dataUriToBuffer)(uri);
|
|
54370
|
-
return new DataReadable(
|
|
54370
|
+
return new DataReadable(hash2, Buffer.from(buffer));
|
|
54371
54371
|
}
|
|
54372
54372
|
};
|
|
54373
54373
|
exports.data = data;
|
|
@@ -75362,14 +75362,14 @@ var require_dist10 = __commonJS({
|
|
|
75362
75362
|
(0, quickjs_emscripten_1.getQuickJS)(),
|
|
75363
75363
|
this.loadPacFile()
|
|
75364
75364
|
]);
|
|
75365
|
-
const
|
|
75366
|
-
if (this.resolver && this.resolverHash ===
|
|
75365
|
+
const hash2 = crypto3.createHash("sha1").update(code).digest("hex");
|
|
75366
|
+
if (this.resolver && this.resolverHash === hash2) {
|
|
75367
75367
|
debug6("Same sha1 hash for code - contents have not changed, reusing previous proxy resolver");
|
|
75368
75368
|
return this.resolver;
|
|
75369
75369
|
}
|
|
75370
75370
|
debug6("Creating new proxy resolver instance");
|
|
75371
75371
|
this.resolver = (0, pac_resolver_1.createPacResolver)(qjs, code, this.opts);
|
|
75372
|
-
this.resolverHash =
|
|
75372
|
+
this.resolverHash = hash2;
|
|
75373
75373
|
return this.resolver;
|
|
75374
75374
|
} catch (err) {
|
|
75375
75375
|
if (this.resolver && err.code === "ENOTMODIFIED") {
|
|
@@ -99644,6 +99644,7 @@ var mediaRules = [
|
|
|
99644
99644
|
const timedTagPositions = [];
|
|
99645
99645
|
for (const tag of tags) {
|
|
99646
99646
|
if (tag.name === "video" || tag.name === "audio") continue;
|
|
99647
|
+
if (readAttr(tag.raw, "data-composition-id")) continue;
|
|
99647
99648
|
if (readAttr(tag.raw, "data-start")) {
|
|
99648
99649
|
timedTagPositions.push({
|
|
99649
99650
|
name: tag.name,
|
|
@@ -100750,7 +100751,8 @@ function lintHyperframeHtml(html, options = {}) {
|
|
|
100750
100751
|
}
|
|
100751
100752
|
|
|
100752
100753
|
// ../core/src/compiler/rewriteSubCompPaths.ts
|
|
100753
|
-
import {
|
|
100754
|
+
import { posix } from "path";
|
|
100755
|
+
var { join: join4, resolve: resolve6, dirname: dirname4 } = posix;
|
|
100754
100756
|
var PATH_ATTRS = ["src", "href"];
|
|
100755
100757
|
var CSS_URL_RE = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
|
|
100756
100758
|
function isAbsoluteOrSpecial(val) {
|
|
@@ -100917,11 +100919,19 @@ async function pageScreenshotCapture(page, options) {
|
|
|
100917
100919
|
});
|
|
100918
100920
|
return Buffer.from(result.data, "base64");
|
|
100919
100921
|
}
|
|
100922
|
+
var TRANSPARENT_BG_STYLE_ID = "__hf_transparent_bg__";
|
|
100920
100923
|
async function initTransparentBackground(page) {
|
|
100921
100924
|
const client = await getCdpSession(page);
|
|
100922
100925
|
await client.send("Emulation.setDefaultBackgroundColorOverride", {
|
|
100923
100926
|
color: { r: 0, g: 0, b: 0, a: 0 }
|
|
100924
100927
|
});
|
|
100928
|
+
await page.evaluate((styleId) => {
|
|
100929
|
+
if (document.getElementById(styleId)) return;
|
|
100930
|
+
const style = document.createElement("style");
|
|
100931
|
+
style.id = styleId;
|
|
100932
|
+
style.textContent = "html,body,[data-composition-id]{background:transparent !important;background-color:transparent !important;background-image:none !important;}";
|
|
100933
|
+
document.head.appendChild(style);
|
|
100934
|
+
}, TRANSPARENT_BG_STYLE_ID);
|
|
100925
100935
|
}
|
|
100926
100936
|
async function captureAlphaPng(page, width, height) {
|
|
100927
100937
|
const client = await getCdpSession(page);
|
|
@@ -100935,6 +100945,57 @@ async function captureAlphaPng(page, width, height) {
|
|
|
100935
100945
|
});
|
|
100936
100946
|
return Buffer.from(result.data, "base64");
|
|
100937
100947
|
}
|
|
100948
|
+
var DOM_LAYER_MASK_STYLE_ID = "__hf_dom_layer_mask__";
|
|
100949
|
+
async function applyDomLayerMask(page, showIds, extraHideIds) {
|
|
100950
|
+
await page.evaluate(
|
|
100951
|
+
(args) => {
|
|
100952
|
+
const existing = document.getElementById(args.styleId);
|
|
100953
|
+
if (existing) existing.remove();
|
|
100954
|
+
const showSelectors = [];
|
|
100955
|
+
for (const id of args.show) {
|
|
100956
|
+
const escaped = CSS.escape(id);
|
|
100957
|
+
showSelectors.push(`#${escaped}`, `#${escaped} *`);
|
|
100958
|
+
const renderEscaped = CSS.escape(`__render_frame_${id}__`);
|
|
100959
|
+
showSelectors.push(`#${renderEscaped}`, `#${renderEscaped} *`);
|
|
100960
|
+
}
|
|
100961
|
+
const massHideRule = "body *{visibility:hidden !important;}";
|
|
100962
|
+
const showRule = showSelectors.length === 0 ? "" : `${showSelectors.join(",")}{visibility:visible !important;}`;
|
|
100963
|
+
const style = document.createElement("style");
|
|
100964
|
+
style.id = args.styleId;
|
|
100965
|
+
style.textContent = `${massHideRule}
|
|
100966
|
+
${showRule}`;
|
|
100967
|
+
document.head.appendChild(style);
|
|
100968
|
+
for (const id of args.hide) {
|
|
100969
|
+
const el = document.getElementById(id);
|
|
100970
|
+
if (el) {
|
|
100971
|
+
el.style.setProperty("visibility", "hidden", "important");
|
|
100972
|
+
}
|
|
100973
|
+
const img = document.getElementById(`__render_frame_${id}__`);
|
|
100974
|
+
if (img) {
|
|
100975
|
+
img.style.setProperty("visibility", "hidden", "important");
|
|
100976
|
+
}
|
|
100977
|
+
}
|
|
100978
|
+
},
|
|
100979
|
+
{ show: showIds, hide: extraHideIds, styleId: DOM_LAYER_MASK_STYLE_ID }
|
|
100980
|
+
);
|
|
100981
|
+
}
|
|
100982
|
+
async function removeDomLayerMask(page, extraHideIds) {
|
|
100983
|
+
await page.evaluate(
|
|
100984
|
+
(args) => {
|
|
100985
|
+
const style = document.getElementById(args.styleId);
|
|
100986
|
+
if (style) style.remove();
|
|
100987
|
+
for (const id of args.hide) {
|
|
100988
|
+
const el = document.getElementById(id);
|
|
100989
|
+
if (el) {
|
|
100990
|
+
el.style.removeProperty("visibility");
|
|
100991
|
+
}
|
|
100992
|
+
const img = document.getElementById(`__render_frame_${id}__`);
|
|
100993
|
+
if (img) img.style.removeProperty("visibility");
|
|
100994
|
+
}
|
|
100995
|
+
},
|
|
100996
|
+
{ hide: extraHideIds, styleId: DOM_LAYER_MASK_STYLE_ID }
|
|
100997
|
+
);
|
|
100998
|
+
}
|
|
100938
100999
|
async function injectVideoFramesBatch(page, updates) {
|
|
100939
101000
|
if (updates.length === 0) return;
|
|
100940
101001
|
await page.evaluate(
|
|
@@ -100975,6 +101036,7 @@ async function injectVideoFramesBatch(page, updates) {
|
|
|
100975
101036
|
img.style.objectPosition = computedStyle.objectPosition;
|
|
100976
101037
|
img.style.zIndex = computedStyle.zIndex;
|
|
100977
101038
|
for (const property of visualProperties) {
|
|
101039
|
+
if (property === "opacity") continue;
|
|
100978
101040
|
if (sourceIsStatic && (property === "top" || property === "left" || property === "right" || property === "bottom" || property === "inset")) {
|
|
100979
101041
|
continue;
|
|
100980
101042
|
}
|
|
@@ -101878,6 +101940,10 @@ function isHdrColorSpace(cs) {
|
|
|
101878
101940
|
if (!cs) return false;
|
|
101879
101941
|
return cs.colorPrimaries.includes("bt2020") || cs.colorSpace.includes("bt2020") || cs.colorTransfer === "smpte2084" || cs.colorTransfer === "arib-std-b67";
|
|
101880
101942
|
}
|
|
101943
|
+
function detectTransfer(cs) {
|
|
101944
|
+
if (cs?.colorTransfer === "smpte2084") return "pq";
|
|
101945
|
+
return "hlg";
|
|
101946
|
+
}
|
|
101881
101947
|
var DEFAULT_HDR10_MASTERING = {
|
|
101882
101948
|
masterDisplay: "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)",
|
|
101883
101949
|
maxCll: "1000,400"
|
|
@@ -102372,10 +102438,10 @@ import { finished } from "stream/promises";
|
|
|
102372
102438
|
var downloadPathCache = /* @__PURE__ */ new Map();
|
|
102373
102439
|
var inFlightDownloads = /* @__PURE__ */ new Map();
|
|
102374
102440
|
function getFilenameFromUrl(url) {
|
|
102375
|
-
const
|
|
102441
|
+
const hash2 = createHash("md5").update(url).digest("hex").slice(0, 12);
|
|
102376
102442
|
const urlObj = new URL(url);
|
|
102377
102443
|
const ext = extname2(urlObj.pathname) || ".mp4";
|
|
102378
|
-
return `download_${
|
|
102444
|
+
return `download_${hash2}${ext}`;
|
|
102379
102445
|
}
|
|
102380
102446
|
async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
|
|
102381
102447
|
const cachedPath = downloadPathCache.get(url);
|
|
@@ -102876,34 +102942,6 @@ function createVideoFrameInjector(frameLookup, config2) {
|
|
|
102876
102942
|
}
|
|
102877
102943
|
};
|
|
102878
102944
|
}
|
|
102879
|
-
async function hideVideoElements(page, videoIds) {
|
|
102880
|
-
if (videoIds.length === 0) return;
|
|
102881
|
-
await page.evaluate((ids) => {
|
|
102882
|
-
for (const id of ids) {
|
|
102883
|
-
const el = document.getElementById(id);
|
|
102884
|
-
if (el) {
|
|
102885
|
-
el.style.setProperty("visibility", "hidden", "important");
|
|
102886
|
-
el.style.setProperty("opacity", "0", "important");
|
|
102887
|
-
const img = document.getElementById(`__render_frame_${id}__`);
|
|
102888
|
-
if (img) img.style.setProperty("visibility", "hidden", "important");
|
|
102889
|
-
}
|
|
102890
|
-
}
|
|
102891
|
-
}, videoIds);
|
|
102892
|
-
}
|
|
102893
|
-
async function showVideoElements(page, videoIds) {
|
|
102894
|
-
if (videoIds.length === 0) return;
|
|
102895
|
-
await page.evaluate((ids) => {
|
|
102896
|
-
for (const id of ids) {
|
|
102897
|
-
const el = document.getElementById(id);
|
|
102898
|
-
if (el) {
|
|
102899
|
-
el.style.removeProperty("visibility");
|
|
102900
|
-
el.style.removeProperty("opacity");
|
|
102901
|
-
const img = document.getElementById(`__render_frame_${id}__`);
|
|
102902
|
-
if (img) img.style.removeProperty("visibility");
|
|
102903
|
-
}
|
|
102904
|
-
}
|
|
102905
|
-
}, videoIds);
|
|
102906
|
-
}
|
|
102907
102945
|
async function queryElementStacking(page, nativeHdrVideoIds) {
|
|
102908
102946
|
const hdrIds = Array.from(nativeHdrVideoIds);
|
|
102909
102947
|
return page.evaluate((hdrIdList) => {
|
|
@@ -102921,14 +102959,103 @@ async function queryElementStacking(page, nativeHdrVideoIds) {
|
|
|
102921
102959
|
}
|
|
102922
102960
|
return 0;
|
|
102923
102961
|
}
|
|
102962
|
+
function getEffectiveBorderRadius(node) {
|
|
102963
|
+
function resolveRadius(value, el) {
|
|
102964
|
+
if (value.includes("%")) {
|
|
102965
|
+
const pct = parseFloat(value) / 100;
|
|
102966
|
+
const htmlEl = el;
|
|
102967
|
+
const w = htmlEl.offsetWidth || 0;
|
|
102968
|
+
const h = htmlEl.offsetHeight || 0;
|
|
102969
|
+
return pct * Math.min(w, h);
|
|
102970
|
+
}
|
|
102971
|
+
return parseFloat(value) || 0;
|
|
102972
|
+
}
|
|
102973
|
+
const selfCs = window.getComputedStyle(node);
|
|
102974
|
+
const selfRadii = [
|
|
102975
|
+
resolveRadius(selfCs.borderTopLeftRadius, node),
|
|
102976
|
+
resolveRadius(selfCs.borderTopRightRadius, node),
|
|
102977
|
+
resolveRadius(selfCs.borderBottomRightRadius, node),
|
|
102978
|
+
resolveRadius(selfCs.borderBottomLeftRadius, node)
|
|
102979
|
+
];
|
|
102980
|
+
if (selfRadii[0] > 0 || selfRadii[1] > 0 || selfRadii[2] > 0 || selfRadii[3] > 0) {
|
|
102981
|
+
return selfRadii;
|
|
102982
|
+
}
|
|
102983
|
+
let current = node.parentElement;
|
|
102984
|
+
while (current) {
|
|
102985
|
+
const cs = window.getComputedStyle(current);
|
|
102986
|
+
if (cs.overflow !== "visible") {
|
|
102987
|
+
const tl = resolveRadius(cs.borderTopLeftRadius, current);
|
|
102988
|
+
const tr = resolveRadius(cs.borderTopRightRadius, current);
|
|
102989
|
+
const brr = resolveRadius(cs.borderBottomRightRadius, current);
|
|
102990
|
+
const bl = resolveRadius(cs.borderBottomLeftRadius, current);
|
|
102991
|
+
if (tl > 0 || tr > 0 || brr > 0 || bl > 0) {
|
|
102992
|
+
return [tl, tr, brr, bl];
|
|
102993
|
+
}
|
|
102994
|
+
}
|
|
102995
|
+
current = current.parentElement;
|
|
102996
|
+
}
|
|
102997
|
+
return [0, 0, 0, 0];
|
|
102998
|
+
}
|
|
102999
|
+
function getEffectiveOpacity(node) {
|
|
103000
|
+
let opacity = 1;
|
|
103001
|
+
let current = node;
|
|
103002
|
+
while (current) {
|
|
103003
|
+
const cs = window.getComputedStyle(current);
|
|
103004
|
+
const val = parseFloat(cs.opacity);
|
|
103005
|
+
opacity *= Number.isNaN(val) ? 1 : val;
|
|
103006
|
+
current = current.parentElement;
|
|
103007
|
+
}
|
|
103008
|
+
return opacity;
|
|
103009
|
+
}
|
|
103010
|
+
function getViewportMatrix(node) {
|
|
103011
|
+
const chain = [];
|
|
103012
|
+
let current = node;
|
|
103013
|
+
while (current instanceof HTMLElement) {
|
|
103014
|
+
chain.push(current);
|
|
103015
|
+
const next = current.offsetParent ?? current.parentElement;
|
|
103016
|
+
if (next === current) break;
|
|
103017
|
+
current = next;
|
|
103018
|
+
}
|
|
103019
|
+
let mat = new DOMMatrix();
|
|
103020
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
103021
|
+
const htmlEl = chain[i];
|
|
103022
|
+
if (!htmlEl) continue;
|
|
103023
|
+
mat = mat.translate(htmlEl.offsetLeft, htmlEl.offsetTop);
|
|
103024
|
+
const cs = window.getComputedStyle(htmlEl);
|
|
103025
|
+
if (cs.transform && cs.transform !== "none") {
|
|
103026
|
+
const origin = cs.transformOrigin.split(" ");
|
|
103027
|
+
const ox = resolveLength(origin[0] ?? "0", htmlEl.offsetWidth);
|
|
103028
|
+
const oy = resolveLength(origin[1] ?? "0", htmlEl.offsetHeight);
|
|
103029
|
+
try {
|
|
103030
|
+
const t = new DOMMatrix(cs.transform);
|
|
103031
|
+
if (Number.isFinite(t.a) && Number.isFinite(t.b) && Number.isFinite(t.c) && Number.isFinite(t.d) && Number.isFinite(t.e) && Number.isFinite(t.f)) {
|
|
103032
|
+
mat = mat.translate(ox, oy).multiply(t).translate(-ox, -oy);
|
|
103033
|
+
}
|
|
103034
|
+
} catch {
|
|
103035
|
+
}
|
|
103036
|
+
}
|
|
103037
|
+
}
|
|
103038
|
+
return mat.toString();
|
|
103039
|
+
}
|
|
103040
|
+
function resolveLength(value, basis) {
|
|
103041
|
+
if (value.endsWith("%")) {
|
|
103042
|
+
const pct = parseFloat(value) / 100;
|
|
103043
|
+
return Number.isFinite(pct) ? pct * basis : 0;
|
|
103044
|
+
}
|
|
103045
|
+
const n = parseFloat(value);
|
|
103046
|
+
return Number.isFinite(n) ? n : 0;
|
|
103047
|
+
}
|
|
102924
103048
|
for (const el of elements) {
|
|
102925
103049
|
const id = el.id;
|
|
102926
103050
|
if (!id) continue;
|
|
102927
103051
|
const rect = el.getBoundingClientRect();
|
|
102928
103052
|
const style = window.getComputedStyle(el);
|
|
102929
103053
|
const zIndex = getEffectiveZIndex(el);
|
|
102930
|
-
const
|
|
103054
|
+
const isHdrEl = hdrSet.has(id);
|
|
103055
|
+
const opacityStartNode = isHdrEl ? el.parentElement : el;
|
|
103056
|
+
const opacity = opacityStartNode ? getEffectiveOpacity(opacityStartNode) : 1;
|
|
102931
103057
|
const visible = style.visibility !== "hidden" && style.display !== "none" && rect.width > 0 && rect.height > 0;
|
|
103058
|
+
const htmlEl = el instanceof HTMLElement ? el : null;
|
|
102932
103059
|
results.push({
|
|
102933
103060
|
id,
|
|
102934
103061
|
zIndex,
|
|
@@ -102936,9 +103063,16 @@ async function queryElementStacking(page, nativeHdrVideoIds) {
|
|
|
102936
103063
|
y: Math.round(rect.y),
|
|
102937
103064
|
width: Math.round(rect.width),
|
|
102938
103065
|
height: Math.round(rect.height),
|
|
103066
|
+
layoutWidth: htmlEl?.offsetWidth || Math.round(rect.width),
|
|
103067
|
+
layoutHeight: htmlEl?.offsetHeight || Math.round(rect.height),
|
|
102939
103068
|
opacity,
|
|
102940
103069
|
visible,
|
|
102941
|
-
isHdr: hdrSet.has(id)
|
|
103070
|
+
isHdr: hdrSet.has(id),
|
|
103071
|
+
// For HDR elements, use the full accumulated viewport matrix so the
|
|
103072
|
+
// affine blit can apply rotation/scale/translate properly. For DOM
|
|
103073
|
+
// elements, the element-level transform is sufficient for reference.
|
|
103074
|
+
transform: isHdrEl ? getViewportMatrix(el) : style.transform || "none",
|
|
103075
|
+
borderRadius: isHdrEl ? getEffectiveBorderRadius(el) : [0, 0, 0, 0]
|
|
102942
103076
|
});
|
|
102943
103077
|
}
|
|
102944
103078
|
return results;
|
|
@@ -106320,6 +106454,99 @@ function blitRgb48leRegion(canvas, source2, dx, dy, sw, sh, canvasWidth, canvasH
|
|
|
106320
106454
|
}
|
|
106321
106455
|
}
|
|
106322
106456
|
}
|
|
106457
|
+
function blitRgb48leAffine(canvas, source2, matrix, srcW, srcH, canvasW, canvasH, opacity, borderRadius) {
|
|
106458
|
+
const a = matrix[0];
|
|
106459
|
+
const b = matrix[1];
|
|
106460
|
+
const c = matrix[2];
|
|
106461
|
+
const d = matrix[3];
|
|
106462
|
+
const tx = matrix[4];
|
|
106463
|
+
const ty = matrix[5];
|
|
106464
|
+
if (a === void 0 || b === void 0 || c === void 0 || d === void 0 || tx === void 0 || ty === void 0)
|
|
106465
|
+
return;
|
|
106466
|
+
const det = a * d - b * c;
|
|
106467
|
+
if (Math.abs(det) < 1e-10) return;
|
|
106468
|
+
const invA = d / det;
|
|
106469
|
+
const invB = -b / det;
|
|
106470
|
+
const invC = -c / det;
|
|
106471
|
+
const invD = a / det;
|
|
106472
|
+
const invTx = -(invA * tx + invC * ty);
|
|
106473
|
+
const invTy = -(invB * tx + invD * ty);
|
|
106474
|
+
const op = opacity ?? 1;
|
|
106475
|
+
const hasMask = borderRadius !== void 0;
|
|
106476
|
+
const corners = [
|
|
106477
|
+
[tx, ty],
|
|
106478
|
+
[a * srcW + tx, b * srcW + ty],
|
|
106479
|
+
[c * srcH + tx, d * srcH + ty],
|
|
106480
|
+
[a * srcW + c * srcH + tx, b * srcW + d * srcH + ty]
|
|
106481
|
+
];
|
|
106482
|
+
let minX = canvasW, maxX = 0, minY = canvasH, maxY = 0;
|
|
106483
|
+
for (const corner of corners) {
|
|
106484
|
+
const cx = corner[0] ?? 0;
|
|
106485
|
+
const cy = corner[1] ?? 0;
|
|
106486
|
+
if (cx < minX) minX = cx;
|
|
106487
|
+
if (cx > maxX) maxX = cx;
|
|
106488
|
+
if (cy < minY) minY = cy;
|
|
106489
|
+
if (cy > maxY) maxY = cy;
|
|
106490
|
+
}
|
|
106491
|
+
const startX = Math.max(0, Math.floor(minX));
|
|
106492
|
+
const endX = Math.min(canvasW, Math.ceil(maxX));
|
|
106493
|
+
const startY = Math.max(0, Math.floor(minY));
|
|
106494
|
+
const endY = Math.min(canvasH, Math.ceil(maxY));
|
|
106495
|
+
for (let dy = startY; dy < endY; dy++) {
|
|
106496
|
+
for (let dx = startX; dx < endX; dx++) {
|
|
106497
|
+
const sx = invA * dx + invC * dy + invTx;
|
|
106498
|
+
const sy = invB * dx + invD * dy + invTy;
|
|
106499
|
+
if (sx < 0 || sy < 0 || sx >= srcW || sy >= srcH) continue;
|
|
106500
|
+
let effectiveOp = op;
|
|
106501
|
+
if (hasMask) {
|
|
106502
|
+
const ma = roundedRectAlpha(sx, sy, srcW, srcH, borderRadius);
|
|
106503
|
+
if (ma <= 0) continue;
|
|
106504
|
+
effectiveOp *= ma;
|
|
106505
|
+
}
|
|
106506
|
+
const x0 = Math.floor(sx);
|
|
106507
|
+
const y0 = Math.floor(sy);
|
|
106508
|
+
const fx = sx - x0;
|
|
106509
|
+
const fy = sy - y0;
|
|
106510
|
+
const x1 = Math.min(x0 + 1, srcW - 1);
|
|
106511
|
+
const y1 = Math.min(y0 + 1, srcH - 1);
|
|
106512
|
+
const off00 = (y0 * srcW + x0) * 6;
|
|
106513
|
+
const off10 = (y0 * srcW + x1) * 6;
|
|
106514
|
+
const off01 = (y1 * srcW + x0) * 6;
|
|
106515
|
+
const off11 = (y1 * srcW + x1) * 6;
|
|
106516
|
+
const w00 = (1 - fx) * (1 - fy);
|
|
106517
|
+
const w10 = fx * (1 - fy);
|
|
106518
|
+
const w01 = (1 - fx) * fy;
|
|
106519
|
+
const w11 = fx * fy;
|
|
106520
|
+
const sr = source2.readUInt16LE(off00) * w00 + source2.readUInt16LE(off10) * w10 + source2.readUInt16LE(off01) * w01 + source2.readUInt16LE(off11) * w11;
|
|
106521
|
+
const sg = source2.readUInt16LE(off00 + 2) * w00 + source2.readUInt16LE(off10 + 2) * w10 + source2.readUInt16LE(off01 + 2) * w01 + source2.readUInt16LE(off11 + 2) * w11;
|
|
106522
|
+
const sb = source2.readUInt16LE(off00 + 4) * w00 + source2.readUInt16LE(off10 + 4) * w10 + source2.readUInt16LE(off01 + 4) * w01 + source2.readUInt16LE(off11 + 4) * w11;
|
|
106523
|
+
const dstOff = (dy * canvasW + dx) * 6;
|
|
106524
|
+
if (effectiveOp >= 0.999) {
|
|
106525
|
+
canvas.writeUInt16LE(Math.round(sr), dstOff);
|
|
106526
|
+
canvas.writeUInt16LE(Math.round(sg), dstOff + 2);
|
|
106527
|
+
canvas.writeUInt16LE(Math.round(sb), dstOff + 4);
|
|
106528
|
+
} else {
|
|
106529
|
+
const invEff = 1 - effectiveOp;
|
|
106530
|
+
const dr = canvas.readUInt16LE(dstOff);
|
|
106531
|
+
const dg = canvas.readUInt16LE(dstOff + 2);
|
|
106532
|
+
const db = canvas.readUInt16LE(dstOff + 4);
|
|
106533
|
+
canvas.writeUInt16LE(Math.round(sr * effectiveOp + dr * invEff), dstOff);
|
|
106534
|
+
canvas.writeUInt16LE(Math.round(sg * effectiveOp + dg * invEff), dstOff + 2);
|
|
106535
|
+
canvas.writeUInt16LE(Math.round(sb * effectiveOp + db * invEff), dstOff + 4);
|
|
106536
|
+
}
|
|
106537
|
+
}
|
|
106538
|
+
}
|
|
106539
|
+
}
|
|
106540
|
+
function parseTransformMatrix(css) {
|
|
106541
|
+
if (!css || css === "none") return null;
|
|
106542
|
+
const match2 = css.match(
|
|
106543
|
+
/^matrix\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,)]+)\s*\)$/
|
|
106544
|
+
);
|
|
106545
|
+
if (!match2) return null;
|
|
106546
|
+
const values = match2.slice(1, 7).map(Number);
|
|
106547
|
+
if (!values.every(Number.isFinite)) return null;
|
|
106548
|
+
return values;
|
|
106549
|
+
}
|
|
106323
106550
|
|
|
106324
106551
|
// ../engine/src/utils/layerCompositor.ts
|
|
106325
106552
|
function groupIntoLayers(elements) {
|
|
@@ -106340,6 +106567,637 @@ function groupIntoLayers(elements) {
|
|
|
106340
106567
|
return layers;
|
|
106341
106568
|
}
|
|
106342
106569
|
|
|
106570
|
+
// ../engine/src/utils/shaderTransitions.ts
|
|
106571
|
+
var PQ_M1 = 0.1593017578125;
|
|
106572
|
+
var PQ_M2 = 78.84375;
|
|
106573
|
+
var PQ_C1 = 0.8359375;
|
|
106574
|
+
var PQ_C2 = 18.8515625;
|
|
106575
|
+
var PQ_C3 = 18.6875;
|
|
106576
|
+
function pqEotf(signal) {
|
|
106577
|
+
const sp = Math.pow(Math.max(0, signal), 1 / PQ_M2);
|
|
106578
|
+
const num = Math.max(sp - PQ_C1, 0);
|
|
106579
|
+
const den = PQ_C2 - PQ_C3 * sp;
|
|
106580
|
+
return den > 0 ? Math.pow(num / den, 1 / PQ_M1) : 0;
|
|
106581
|
+
}
|
|
106582
|
+
function pqOetf(linear) {
|
|
106583
|
+
const lp = Math.pow(Math.max(0, linear), PQ_M1);
|
|
106584
|
+
return Math.pow((PQ_C1 + PQ_C2 * lp) / (1 + PQ_C3 * lp), PQ_M2);
|
|
106585
|
+
}
|
|
106586
|
+
function hlgEotf(signal) {
|
|
106587
|
+
const a = 0.17883277;
|
|
106588
|
+
const b = 1 - 4 * a;
|
|
106589
|
+
const c = 0.5 - a * Math.log(4 * a);
|
|
106590
|
+
if (signal <= 0.5) {
|
|
106591
|
+
return signal * signal / 3;
|
|
106592
|
+
}
|
|
106593
|
+
return (Math.exp((signal - c) / a) + b) / 12;
|
|
106594
|
+
}
|
|
106595
|
+
function hlgOetf(linear) {
|
|
106596
|
+
const a = 0.17883277;
|
|
106597
|
+
const b = 1 - 4 * a;
|
|
106598
|
+
const c = 0.5 - a * Math.log(4 * a);
|
|
106599
|
+
if (linear <= 1 / 12) {
|
|
106600
|
+
return Math.sqrt(3 * linear);
|
|
106601
|
+
}
|
|
106602
|
+
return a * Math.log(12 * linear - b) + c;
|
|
106603
|
+
}
|
|
106604
|
+
function buildLut(fn) {
|
|
106605
|
+
const lut = new Uint16Array(65536);
|
|
106606
|
+
for (let i = 0; i < 65536; i++) {
|
|
106607
|
+
lut[i] = Math.round(fn(i / 65535) * 65535);
|
|
106608
|
+
}
|
|
106609
|
+
return lut;
|
|
106610
|
+
}
|
|
106611
|
+
var HLG_OOTF_LW = 1e3;
|
|
106612
|
+
var HLG_OOTF_GAMMA = 1.2 * Math.pow(1.111, Math.log2(HLG_OOTF_LW / 1e3));
|
|
106613
|
+
function hlgSceneToPqDisplay(sceneLinear) {
|
|
106614
|
+
const displayNits = HLG_OOTF_LW * Math.pow(Math.max(0, sceneLinear), HLG_OOTF_GAMMA);
|
|
106615
|
+
return displayNits / 1e4;
|
|
106616
|
+
}
|
|
106617
|
+
function pqDisplayToHlgScene(displayNormalized) {
|
|
106618
|
+
const displayNits = displayNormalized * 1e4;
|
|
106619
|
+
return Math.pow(Math.max(0, displayNits / HLG_OOTF_LW), 1 / HLG_OOTF_GAMMA);
|
|
106620
|
+
}
|
|
106621
|
+
var hlgToPqLut = null;
|
|
106622
|
+
var pqToHlgLut = null;
|
|
106623
|
+
function getHlgToPqLut() {
|
|
106624
|
+
if (!hlgToPqLut) hlgToPqLut = buildLut((v) => pqOetf(hlgSceneToPqDisplay(hlgEotf(v))));
|
|
106625
|
+
return hlgToPqLut;
|
|
106626
|
+
}
|
|
106627
|
+
function getPqToHlgLut() {
|
|
106628
|
+
if (!pqToHlgLut) pqToHlgLut = buildLut((v) => hlgOetf(pqDisplayToHlgScene(pqEotf(v))));
|
|
106629
|
+
return pqToHlgLut;
|
|
106630
|
+
}
|
|
106631
|
+
function convertTransfer(buf, from2, to) {
|
|
106632
|
+
if (from2 === to) return;
|
|
106633
|
+
const lut = from2 === "hlg" ? getHlgToPqLut() : getPqToHlgLut();
|
|
106634
|
+
const len = buf.length / 2;
|
|
106635
|
+
for (let i = 0; i < len; i++) {
|
|
106636
|
+
const off = i * 2;
|
|
106637
|
+
buf.writeUInt16LE(lut[buf.readUInt16LE(off)] ?? 0, off);
|
|
106638
|
+
}
|
|
106639
|
+
}
|
|
106640
|
+
function sampleRgb48le(buf, u, v, w, h) {
|
|
106641
|
+
const uc = Math.max(0, Math.min(1, u));
|
|
106642
|
+
const vc = Math.max(0, Math.min(1, v));
|
|
106643
|
+
const sx = uc * (w - 1);
|
|
106644
|
+
const sy = vc * (h - 1);
|
|
106645
|
+
const x0 = Math.floor(sx);
|
|
106646
|
+
const y0 = Math.floor(sy);
|
|
106647
|
+
const x1 = Math.min(x0 + 1, w - 1);
|
|
106648
|
+
const y1 = Math.min(y0 + 1, h - 1);
|
|
106649
|
+
const fx = sx - x0;
|
|
106650
|
+
const fy = sy - y0;
|
|
106651
|
+
const w00 = (1 - fx) * (1 - fy);
|
|
106652
|
+
const w10 = fx * (1 - fy);
|
|
106653
|
+
const w01 = (1 - fx) * fy;
|
|
106654
|
+
const w11 = fx * fy;
|
|
106655
|
+
const off00 = (y0 * w + x0) * 6;
|
|
106656
|
+
const off10 = (y0 * w + x1) * 6;
|
|
106657
|
+
const off01 = (y1 * w + x0) * 6;
|
|
106658
|
+
const off11 = (y1 * w + x1) * 6;
|
|
106659
|
+
const r = Math.round(
|
|
106660
|
+
buf.readUInt16LE(off00) * w00 + buf.readUInt16LE(off10) * w10 + buf.readUInt16LE(off01) * w01 + buf.readUInt16LE(off11) * w11
|
|
106661
|
+
);
|
|
106662
|
+
const g = Math.round(
|
|
106663
|
+
buf.readUInt16LE(off00 + 2) * w00 + buf.readUInt16LE(off10 + 2) * w10 + buf.readUInt16LE(off01 + 2) * w01 + buf.readUInt16LE(off11 + 2) * w11
|
|
106664
|
+
);
|
|
106665
|
+
const b = Math.round(
|
|
106666
|
+
buf.readUInt16LE(off00 + 4) * w00 + buf.readUInt16LE(off10 + 4) * w10 + buf.readUInt16LE(off01 + 4) * w01 + buf.readUInt16LE(off11 + 4) * w11
|
|
106667
|
+
);
|
|
106668
|
+
return [r, g, b];
|
|
106669
|
+
}
|
|
106670
|
+
function mix16(a, b, t) {
|
|
106671
|
+
return Math.round(a * (1 - t) + b * t);
|
|
106672
|
+
}
|
|
106673
|
+
function clamp16(v) {
|
|
106674
|
+
return Math.max(0, Math.min(65535, v));
|
|
106675
|
+
}
|
|
106676
|
+
function smoothstep(edge0, edge1, x) {
|
|
106677
|
+
const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
|
|
106678
|
+
return t * t * (3 - 2 * t);
|
|
106679
|
+
}
|
|
106680
|
+
function hash(x, y) {
|
|
106681
|
+
return (Math.sin(x * 127.1 + y * 311.7) * 43758.5453 % 1 + 1) % 1;
|
|
106682
|
+
}
|
|
106683
|
+
function vnoise(px, py) {
|
|
106684
|
+
const ix = Math.floor(px);
|
|
106685
|
+
const iy = Math.floor(py);
|
|
106686
|
+
let fx = px - ix;
|
|
106687
|
+
let fy = py - iy;
|
|
106688
|
+
fx = fx * fx * fx * (fx * (fx * 6 - 15) + 10);
|
|
106689
|
+
fy = fy * fy * fy * (fy * (fy * 6 - 15) + 10);
|
|
106690
|
+
const h00 = hash(ix, iy);
|
|
106691
|
+
const h10 = hash(ix + 1, iy);
|
|
106692
|
+
const h01 = hash(ix, iy + 1);
|
|
106693
|
+
const h11 = hash(ix + 1, iy + 1);
|
|
106694
|
+
return h00 * (1 - fx) * (1 - fy) + h10 * fx * (1 - fy) + h01 * (1 - fx) * fy + h11 * fx * fy;
|
|
106695
|
+
}
|
|
106696
|
+
var ROT_A = 0.8;
|
|
106697
|
+
var ROT_B = 0.6;
|
|
106698
|
+
function fbm(px, py) {
|
|
106699
|
+
let value = 0;
|
|
106700
|
+
let amplitude = 0.5;
|
|
106701
|
+
let x = px;
|
|
106702
|
+
let y = py;
|
|
106703
|
+
for (let i = 0; i < 5; i++) {
|
|
106704
|
+
value += amplitude * vnoise(x, y);
|
|
106705
|
+
const nx = ROT_A * x - ROT_B * y;
|
|
106706
|
+
const ny = ROT_B * x + ROT_A * y;
|
|
106707
|
+
x = nx * 2.02;
|
|
106708
|
+
y = ny * 2.02;
|
|
106709
|
+
amplitude *= 0.5;
|
|
106710
|
+
}
|
|
106711
|
+
return value;
|
|
106712
|
+
}
|
|
106713
|
+
var TRANSITIONS = {};
|
|
106714
|
+
var crossfade = (from2, to, out, w, h, p) => {
|
|
106715
|
+
const inv = 1 - p;
|
|
106716
|
+
for (let i = 0; i < w * h; i++) {
|
|
106717
|
+
const o = i * 6;
|
|
106718
|
+
out.writeUInt16LE(Math.round(from2.readUInt16LE(o) * inv + to.readUInt16LE(o) * p), o);
|
|
106719
|
+
out.writeUInt16LE(
|
|
106720
|
+
Math.round(from2.readUInt16LE(o + 2) * inv + to.readUInt16LE(o + 2) * p),
|
|
106721
|
+
o + 2
|
|
106722
|
+
);
|
|
106723
|
+
out.writeUInt16LE(
|
|
106724
|
+
Math.round(from2.readUInt16LE(o + 4) * inv + to.readUInt16LE(o + 4) * p),
|
|
106725
|
+
o + 4
|
|
106726
|
+
);
|
|
106727
|
+
}
|
|
106728
|
+
};
|
|
106729
|
+
TRANSITIONS["crossfade"] = crossfade;
|
|
106730
|
+
var flashThroughWhite = (from2, to, out, w, h, p) => {
|
|
106731
|
+
const toWhite = smoothstep(0, 0.45, p);
|
|
106732
|
+
const fromWhite = 1 - smoothstep(0.5, 1, p);
|
|
106733
|
+
const blend = smoothstep(0.35, 0.65, p);
|
|
106734
|
+
for (let i = 0; i < w * h; i++) {
|
|
106735
|
+
const o = i * 6;
|
|
106736
|
+
const fromR = mix16(from2.readUInt16LE(o), 65535, toWhite);
|
|
106737
|
+
const fromG = mix16(from2.readUInt16LE(o + 2), 65535, toWhite);
|
|
106738
|
+
const fromB = mix16(from2.readUInt16LE(o + 4), 65535, toWhite);
|
|
106739
|
+
const toR = mix16(to.readUInt16LE(o), 65535, fromWhite);
|
|
106740
|
+
const toG = mix16(to.readUInt16LE(o + 2), 65535, fromWhite);
|
|
106741
|
+
const toB = mix16(to.readUInt16LE(o + 4), 65535, fromWhite);
|
|
106742
|
+
out.writeUInt16LE(mix16(fromR, toR, blend), o);
|
|
106743
|
+
out.writeUInt16LE(mix16(fromG, toG, blend), o + 2);
|
|
106744
|
+
out.writeUInt16LE(mix16(fromB, toB, blend), o + 4);
|
|
106745
|
+
}
|
|
106746
|
+
};
|
|
106747
|
+
TRANSITIONS["flash-through-white"] = flashThroughWhite;
|
|
106748
|
+
var chromaticSplit = (from2, to, out, w, h, p) => {
|
|
106749
|
+
for (let i = 0; i < w * h; i++) {
|
|
106750
|
+
const ux = i % w / w;
|
|
106751
|
+
const uy = Math.floor(i / w) / h;
|
|
106752
|
+
const o = i * 6;
|
|
106753
|
+
const cx = ux - 0.5;
|
|
106754
|
+
const cy = uy - 0.5;
|
|
106755
|
+
const fromShift = p * 0.06;
|
|
106756
|
+
const fr = sampleRgb48le(from2, ux + cx * fromShift, uy + cy * fromShift, w, h)[0];
|
|
106757
|
+
const fg = sampleRgb48le(from2, ux, uy, w, h)[1];
|
|
106758
|
+
const fb = sampleRgb48le(from2, ux - cx * fromShift, uy - cy * fromShift, w, h)[2];
|
|
106759
|
+
const toShift = (1 - p) * 0.06;
|
|
106760
|
+
const tr = sampleRgb48le(to, ux - cx * toShift, uy - cy * toShift, w, h)[0];
|
|
106761
|
+
const tg = sampleRgb48le(to, ux, uy, w, h)[1];
|
|
106762
|
+
const tb = sampleRgb48le(to, ux + cx * toShift, uy + cy * toShift, w, h)[2];
|
|
106763
|
+
out.writeUInt16LE(clamp16(mix16(fr, tr, p)), o);
|
|
106764
|
+
out.writeUInt16LE(clamp16(mix16(fg, tg, p)), o + 2);
|
|
106765
|
+
out.writeUInt16LE(clamp16(mix16(fb, tb, p)), o + 4);
|
|
106766
|
+
}
|
|
106767
|
+
};
|
|
106768
|
+
TRANSITIONS["chromatic-split"] = chromaticSplit;
|
|
106769
|
+
var sdfIris = (from2, to, out, w, h, p) => {
|
|
106770
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
106771
|
+
for (let i = 0; i < w * h; i++) {
|
|
106772
|
+
const ux = i % w / w;
|
|
106773
|
+
const uy = Math.floor(i / w) / h;
|
|
106774
|
+
const o = i * 6;
|
|
106775
|
+
const ax = (ux - 0.5) * (w / h);
|
|
106776
|
+
const ay = uy - 0.5;
|
|
106777
|
+
const d = Math.sqrt(ax * ax + ay * ay);
|
|
106778
|
+
const radius = p * 1.2;
|
|
106779
|
+
const fw = 3e-3;
|
|
106780
|
+
const edge = smoothstep(radius + fw, radius - fw, d);
|
|
106781
|
+
const ring1 = Math.exp(-Math.abs(d - radius) * 25);
|
|
106782
|
+
const ring2 = Math.exp(-Math.abs(d - radius + 0.04) * 20) * 0.5;
|
|
106783
|
+
const ring3 = Math.exp(-Math.abs(d - radius + 0.08) * 15) * 0.25;
|
|
106784
|
+
const glow = (ring1 + ring2 + ring3) * p * (1 - p) * 4;
|
|
106785
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, ux, uy, w, h);
|
|
106786
|
+
const [toR, toG, toB] = sampleRgb48le(to, ux, uy, w, h);
|
|
106787
|
+
out.writeUInt16LE(clamp16(mix16(fromR, toR, edge) + accentBright[0] * glow * 0.6), o);
|
|
106788
|
+
out.writeUInt16LE(clamp16(mix16(fromG, toG, edge) + accentBright[1] * glow * 0.6), o + 2);
|
|
106789
|
+
out.writeUInt16LE(clamp16(mix16(fromB, toB, edge) + accentBright[2] * glow * 0.6), o + 4);
|
|
106790
|
+
}
|
|
106791
|
+
};
|
|
106792
|
+
TRANSITIONS["sdf-iris"] = sdfIris;
|
|
106793
|
+
function glitchRand(x, y) {
|
|
106794
|
+
return (Math.sin(x * 12.9898 + y * 78.233) * 43758.5453 % 1 + 1) % 1;
|
|
106795
|
+
}
|
|
106796
|
+
var glitch = (from2, to, out, w, h, p) => {
|
|
106797
|
+
const intensity = p * (1 - p) * 4;
|
|
106798
|
+
for (let i = 0; i < w * h; i++) {
|
|
106799
|
+
const ux = i % w / w;
|
|
106800
|
+
const uy = Math.floor(i / w) / h;
|
|
106801
|
+
const o = i * 6;
|
|
106802
|
+
const lineY = Math.floor(uy * 60) / 60;
|
|
106803
|
+
const lineDisp = (glitchRand(lineY, Math.floor(p * 17)) - 0.5) * 0.18 * intensity;
|
|
106804
|
+
const blockX = Math.floor(ux * 12);
|
|
106805
|
+
const blockY = Math.floor(uy * 8);
|
|
106806
|
+
const progressStep = Math.floor(p * 11);
|
|
106807
|
+
const br = glitchRand(blockX + progressStep, blockY + progressStep);
|
|
106808
|
+
const ba = (br >= 0.83 ? 1 : 0) * intensity;
|
|
106809
|
+
const bdx = (glitchRand(blockX * 2.1, blockY * 2.1) - 0.5) * 0.35 * ba;
|
|
106810
|
+
const bdy = (glitchRand(blockX * 3.7, blockY * 3.7) - 0.5) * 0.35 * ba;
|
|
106811
|
+
const uvx = Math.max(0, Math.min(1, ux + lineDisp + bdx));
|
|
106812
|
+
const uvy = Math.max(0, Math.min(1, uy + bdy));
|
|
106813
|
+
const shift = intensity * 0.035;
|
|
106814
|
+
const r = sampleRgb48le(from2, uvx + shift, uvy, w, h)[0];
|
|
106815
|
+
const g = sampleRgb48le(from2, uvx, uvy, w, h)[1];
|
|
106816
|
+
const b = sampleRgb48le(from2, uvx - shift, uvy, w, h)[2];
|
|
106817
|
+
let cr = r / 65535;
|
|
106818
|
+
let cg = g / 65535;
|
|
106819
|
+
let cb = b / 65535;
|
|
106820
|
+
const scanline = (uy * h * 0.5 % 1 + 1) % 1 >= 0.5 ? 0.05 * intensity : 0;
|
|
106821
|
+
cr -= scanline;
|
|
106822
|
+
cg -= scanline;
|
|
106823
|
+
cb -= scanline;
|
|
106824
|
+
const flicker = 1 + (glitchRand(Math.floor(p * 23), 0) - 0.5) * 0.3 * intensity;
|
|
106825
|
+
cr *= flicker;
|
|
106826
|
+
cg *= flicker;
|
|
106827
|
+
cb *= flicker;
|
|
106828
|
+
const levels = 256 - (256 - 8) * (intensity * 0.5);
|
|
106829
|
+
cr = Math.floor(cr * levels) / levels;
|
|
106830
|
+
cg = Math.floor(cg * levels) / levels;
|
|
106831
|
+
cb = Math.floor(cb * levels) / levels;
|
|
106832
|
+
const [toR, toG, toB] = sampleRgb48le(to, ux, uy, w, h);
|
|
106833
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(cr * 65535), toR, p)), o);
|
|
106834
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(cg * 65535), toG, p)), o + 2);
|
|
106835
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(cb * 65535), toB, p)), o + 4);
|
|
106836
|
+
}
|
|
106837
|
+
};
|
|
106838
|
+
TRANSITIONS["glitch"] = glitch;
|
|
106839
|
+
function aces(x) {
|
|
106840
|
+
return Math.max(0, Math.min(1, x * (2.51 * x + 0.03) / (x * (2.43 * x + 0.59) + 0.14)));
|
|
106841
|
+
}
|
|
106842
|
+
var lightLeak = (from2, to, out, w, h, p) => {
|
|
106843
|
+
const accent = [5e4 / 65535, 25e3 / 65535, 5e3 / 65535];
|
|
106844
|
+
const accentBright = [65535 / 65535, 55e3 / 65535, 35e3 / 65535];
|
|
106845
|
+
const lpx = 1.3;
|
|
106846
|
+
const lpy = -0.2;
|
|
106847
|
+
for (let i = 0; i < w * h; i++) {
|
|
106848
|
+
const ux = i % w / w;
|
|
106849
|
+
const uy = Math.floor(i / w) / h;
|
|
106850
|
+
const o = i * 6;
|
|
106851
|
+
const dx = ux - lpx;
|
|
106852
|
+
const dy = uy - lpy;
|
|
106853
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
106854
|
+
const leak = Math.max(0, Math.min(1, Math.exp(-dist * 1.8) * p * 4));
|
|
106855
|
+
const warmR = accent[0] + (accentBright[0] - accent[0]) * dist * 0.7;
|
|
106856
|
+
const warmG = accent[1] + (accentBright[1] - accent[1]) * dist * 0.7;
|
|
106857
|
+
const warmB = accent[2] + (accentBright[2] - accent[2]) * dist * 0.7;
|
|
106858
|
+
const flare = Math.exp(-Math.abs(uy - (-0.2 + ux * 0.3)) * 15) * leak * 0.3;
|
|
106859
|
+
const [fr, fg, fb] = sampleRgb48le(from2, ux, uy, w, h);
|
|
106860
|
+
const fromR = fr / 65535;
|
|
106861
|
+
const fromG = fg / 65535;
|
|
106862
|
+
const fromB = fb / 65535;
|
|
106863
|
+
const overR = aces(fromR + warmR * leak * 3 + accentBright[0] * flare);
|
|
106864
|
+
const overG = aces(fromG + warmG * leak * 3 + accentBright[1] * flare);
|
|
106865
|
+
const overB = aces(fromB + warmB * leak * 3 + accentBright[2] * flare);
|
|
106866
|
+
const [toR, toG, toB] = sampleRgb48le(to, ux, uy, w, h);
|
|
106867
|
+
const blend = smoothstep(0.15, 0.85, p);
|
|
106868
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(overR * 65535), toR, blend)), o);
|
|
106869
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(overG * 65535), toG, blend)), o + 2);
|
|
106870
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(overB * 65535), toB, blend)), o + 4);
|
|
106871
|
+
}
|
|
106872
|
+
};
|
|
106873
|
+
TRANSITIONS["light-leak"] = lightLeak;
|
|
106874
|
+
var crossWarpMorph = (from2, to, out, w, h, p) => {
|
|
106875
|
+
for (let i = 0; i < w * h; i++) {
|
|
106876
|
+
const ux = i % w / w;
|
|
106877
|
+
const uy = Math.floor(i / w) / h;
|
|
106878
|
+
const o = i * 6;
|
|
106879
|
+
const dispX = fbm(ux * 3, uy * 3) - 0.5;
|
|
106880
|
+
const dispY = fbm(ux * 3 + 7.3, uy * 3 + 3.7) - 0.5;
|
|
106881
|
+
const fromUx = Math.max(0, Math.min(1, ux + dispX * p * 0.5));
|
|
106882
|
+
const fromUy = Math.max(0, Math.min(1, uy + dispY * p * 0.5));
|
|
106883
|
+
const toUx = Math.max(0, Math.min(1, ux - dispX * (1 - p) * 0.5));
|
|
106884
|
+
const toUy = Math.max(0, Math.min(1, uy - dispY * (1 - p) * 0.5));
|
|
106885
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, fromUx, fromUy, w, h);
|
|
106886
|
+
const [toR, toG, toB] = sampleRgb48le(to, toUx, toUy, w, h);
|
|
106887
|
+
const n = fbm(ux * 4 + 3.1, uy * 4 + 1.7);
|
|
106888
|
+
const blend = smoothstep(0.4, 0.6, n + p * 1.2 - 0.6);
|
|
106889
|
+
out.writeUInt16LE(clamp16(mix16(fromR, toR, blend)), o);
|
|
106890
|
+
out.writeUInt16LE(clamp16(mix16(fromG, toG, blend)), o + 2);
|
|
106891
|
+
out.writeUInt16LE(clamp16(mix16(fromB, toB, blend)), o + 4);
|
|
106892
|
+
}
|
|
106893
|
+
};
|
|
106894
|
+
TRANSITIONS["cross-warp-morph"] = crossWarpMorph;
|
|
106895
|
+
var whipPan = (from2, to, out, w, h, p) => {
|
|
106896
|
+
const fromOff = p * 1.5;
|
|
106897
|
+
const toOff = (1 - p) * 1.5;
|
|
106898
|
+
for (let i = 0; i < w * h; i++) {
|
|
106899
|
+
const ux = i % w / w;
|
|
106900
|
+
const uy = Math.floor(i / w) / h;
|
|
106901
|
+
const o = i * 6;
|
|
106902
|
+
let fromR = 0, fromG = 0, fromB = 0;
|
|
106903
|
+
for (let s = 0; s < 10; s++) {
|
|
106904
|
+
const f = s / 10;
|
|
106905
|
+
const fuv = Math.max(0, Math.min(1, ux + fromOff + p * 0.08 * f));
|
|
106906
|
+
const [r, g, b] = sampleRgb48le(from2, fuv, uy, w, h);
|
|
106907
|
+
fromR += r;
|
|
106908
|
+
fromG += g;
|
|
106909
|
+
fromB += b;
|
|
106910
|
+
}
|
|
106911
|
+
fromR /= 10;
|
|
106912
|
+
fromG /= 10;
|
|
106913
|
+
fromB /= 10;
|
|
106914
|
+
let toR = 0, toG = 0, toB = 0;
|
|
106915
|
+
for (let s = 0; s < 10; s++) {
|
|
106916
|
+
const f = s / 10;
|
|
106917
|
+
const tuv = Math.max(0, Math.min(1, ux - toOff - (1 - p) * 0.08 * f));
|
|
106918
|
+
const [r, g, b] = sampleRgb48le(to, tuv, uy, w, h);
|
|
106919
|
+
toR += r;
|
|
106920
|
+
toG += g;
|
|
106921
|
+
toB += b;
|
|
106922
|
+
}
|
|
106923
|
+
toR /= 10;
|
|
106924
|
+
toG /= 10;
|
|
106925
|
+
toB /= 10;
|
|
106926
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromR), Math.round(toR), p)), o);
|
|
106927
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromG), Math.round(toG), p)), o + 2);
|
|
106928
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromB), Math.round(toB), p)), o + 4);
|
|
106929
|
+
}
|
|
106930
|
+
};
|
|
106931
|
+
TRANSITIONS["whip-pan"] = whipPan;
|
|
106932
|
+
var cinematicZoom = (from2, to, out, w, h, p) => {
|
|
106933
|
+
const fromS = p * 0.08;
|
|
106934
|
+
const toS = (1 - p) * 0.06;
|
|
106935
|
+
for (let i = 0; i < w * h; i++) {
|
|
106936
|
+
const ux = i % w / w;
|
|
106937
|
+
const uy = Math.floor(i / w) / h;
|
|
106938
|
+
const o = i * 6;
|
|
106939
|
+
const dx = ux - 0.5;
|
|
106940
|
+
const dy = uy - 0.5;
|
|
106941
|
+
let fr = 0, fg = 0, fb = 0;
|
|
106942
|
+
for (let s = 0; s < 12; s++) {
|
|
106943
|
+
const f = s / 12;
|
|
106944
|
+
const rr = sampleRgb48le(
|
|
106945
|
+
from2,
|
|
106946
|
+
ux - dx * fromS * 1.06 * f,
|
|
106947
|
+
uy - dy * fromS * 1.06 * f,
|
|
106948
|
+
w,
|
|
106949
|
+
h
|
|
106950
|
+
)[0];
|
|
106951
|
+
const gg = sampleRgb48le(from2, ux - dx * fromS * f, uy - dy * fromS * f, w, h)[1];
|
|
106952
|
+
const bb = sampleRgb48le(
|
|
106953
|
+
from2,
|
|
106954
|
+
ux - dx * fromS * 0.94 * f,
|
|
106955
|
+
uy - dy * fromS * 0.94 * f,
|
|
106956
|
+
w,
|
|
106957
|
+
h
|
|
106958
|
+
)[2];
|
|
106959
|
+
fr += rr;
|
|
106960
|
+
fg += gg;
|
|
106961
|
+
fb += bb;
|
|
106962
|
+
}
|
|
106963
|
+
fr /= 12;
|
|
106964
|
+
fg /= 12;
|
|
106965
|
+
fb /= 12;
|
|
106966
|
+
let tr = 0, tg = 0, tb = 0;
|
|
106967
|
+
for (let s = 0; s < 12; s++) {
|
|
106968
|
+
const f = s / 12;
|
|
106969
|
+
const rr = sampleRgb48le(to, ux + dx * toS * 1.06 * f, uy + dy * toS * 1.06 * f, w, h)[0];
|
|
106970
|
+
const gg = sampleRgb48le(to, ux + dx * toS * f, uy + dy * toS * f, w, h)[1];
|
|
106971
|
+
const bb = sampleRgb48le(to, ux + dx * toS * 0.94 * f, uy + dy * toS * 0.94 * f, w, h)[2];
|
|
106972
|
+
tr += rr;
|
|
106973
|
+
tg += gg;
|
|
106974
|
+
tb += bb;
|
|
106975
|
+
}
|
|
106976
|
+
tr /= 12;
|
|
106977
|
+
tg /= 12;
|
|
106978
|
+
tb /= 12;
|
|
106979
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fr), Math.round(tr), p)), o);
|
|
106980
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fg), Math.round(tg), p)), o + 2);
|
|
106981
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fb), Math.round(tb), p)), o + 4);
|
|
106982
|
+
}
|
|
106983
|
+
};
|
|
106984
|
+
TRANSITIONS["cinematic-zoom"] = cinematicZoom;
|
|
106985
|
+
var gravitationalLens = (from2, to, out, w, h, p) => {
|
|
106986
|
+
for (let i = 0; i < w * h; i++) {
|
|
106987
|
+
const ux = i % w / w;
|
|
106988
|
+
const uy = Math.floor(i / w) / h;
|
|
106989
|
+
const o = i * 6;
|
|
106990
|
+
const uvx = ux - 0.5;
|
|
106991
|
+
const uvy = uy - 0.5;
|
|
106992
|
+
const dist = Math.sqrt(uvx * uvx + uvy * uvy);
|
|
106993
|
+
const pull = p * 2;
|
|
106994
|
+
const warpStr = pull * 0.3 / (dist + 0.1);
|
|
106995
|
+
const warpedX = Math.max(0, Math.min(1, ux - uvx * warpStr));
|
|
106996
|
+
const warpedY = Math.max(0, Math.min(1, uy - uvy * warpStr));
|
|
106997
|
+
const [, ag] = sampleRgb48le(from2, warpedX, warpedY, w, h);
|
|
106998
|
+
const horizon = smoothstep(0, 0.3, dist / (1 - p * 0.85 + 1e-3));
|
|
106999
|
+
const shift = pull * 0.02 / (dist + 0.2);
|
|
107000
|
+
const rSampX = Math.max(0, Math.min(1, ux - uvx * (warpStr + shift)));
|
|
107001
|
+
const rSampY = Math.max(0, Math.min(1, uy - uvy * (warpStr + shift)));
|
|
107002
|
+
const bSampX = Math.max(0, Math.min(1, ux - uvx * (warpStr - shift)));
|
|
107003
|
+
const bSampY = Math.max(0, Math.min(1, uy - uvy * (warpStr - shift)));
|
|
107004
|
+
const ar = sampleRgb48le(from2, rSampX, rSampY, w, h)[0];
|
|
107005
|
+
const ab = sampleRgb48le(from2, bSampX, bSampY, w, h)[2];
|
|
107006
|
+
const lensedR = Math.round(ar * horizon);
|
|
107007
|
+
const lensedG = Math.round(ag * horizon);
|
|
107008
|
+
const lensedB = Math.round(ab * horizon);
|
|
107009
|
+
const [toR, toG, toB] = sampleRgb48le(to, ux, uy, w, h);
|
|
107010
|
+
const blend = smoothstep(0.3, 0.9, p);
|
|
107011
|
+
out.writeUInt16LE(clamp16(mix16(lensedR, toR, blend)), o);
|
|
107012
|
+
out.writeUInt16LE(clamp16(mix16(lensedG, toG, blend)), o + 2);
|
|
107013
|
+
out.writeUInt16LE(clamp16(mix16(lensedB, toB, blend)), o + 4);
|
|
107014
|
+
}
|
|
107015
|
+
};
|
|
107016
|
+
TRANSITIONS["gravitational-lens"] = gravitationalLens;
|
|
107017
|
+
var rippleWaves = (from2, to, out, w, h, p) => {
|
|
107018
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
107019
|
+
for (let i = 0; i < w * h; i++) {
|
|
107020
|
+
const ux = i % w / w;
|
|
107021
|
+
const uy = Math.floor(i / w) / h;
|
|
107022
|
+
const o = i * 6;
|
|
107023
|
+
const uvx = ux - 0.5;
|
|
107024
|
+
const uvy = uy - 0.5;
|
|
107025
|
+
const dist = Math.sqrt(uvx * uvx + uvy * uvy);
|
|
107026
|
+
const nux = uvx + 1e-3;
|
|
107027
|
+
const nuy = uvy + 1e-3;
|
|
107028
|
+
const nlen = Math.sqrt(nux * nux + nuy * nuy);
|
|
107029
|
+
const dirx = nux / nlen;
|
|
107030
|
+
const diry = nuy / nlen;
|
|
107031
|
+
const fromAmp = p * 0.04;
|
|
107032
|
+
const fw1 = Math.exp(Math.sin(dist * 25 - p * 12) - 1);
|
|
107033
|
+
const fw2 = Math.exp(Math.sin(dist * 50 - p * 18) - 1) * 0.5;
|
|
107034
|
+
const fromUx = Math.max(0, Math.min(1, ux + dirx * (fw1 + fw2) * fromAmp));
|
|
107035
|
+
const fromUy = Math.max(0, Math.min(1, uy + diry * (fw1 + fw2) * fromAmp));
|
|
107036
|
+
const toAmp = (1 - p) * 0.04;
|
|
107037
|
+
const tw1 = Math.exp(Math.sin(dist * 25 + p * 12) - 1);
|
|
107038
|
+
const tw2 = Math.exp(Math.sin(dist * 50 + p * 18) - 1) * 0.5;
|
|
107039
|
+
const toUx = Math.max(0, Math.min(1, ux - dirx * (tw1 + tw2) * toAmp));
|
|
107040
|
+
const toUy = Math.max(0, Math.min(1, uy - diry * (tw1 + tw2) * toAmp));
|
|
107041
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, fromUx, fromUy, w, h);
|
|
107042
|
+
const [toR, toG, toB] = sampleRgb48le(to, toUx, toUy, w, h);
|
|
107043
|
+
const peak = fw1 * p;
|
|
107044
|
+
const tintR = accentBright[0] * peak * 0.1;
|
|
107045
|
+
const tintG = accentBright[1] * peak * 0.1;
|
|
107046
|
+
const tintB = accentBright[2] * peak * 0.1;
|
|
107047
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromR + tintR), toR, p)), o);
|
|
107048
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromG + tintG), toG, p)), o + 2);
|
|
107049
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromB + tintB), toB, p)), o + 4);
|
|
107050
|
+
}
|
|
107051
|
+
};
|
|
107052
|
+
TRANSITIONS["ripple-waves"] = rippleWaves;
|
|
107053
|
+
var swirlVortex = (from2, to, out, w, h, p) => {
|
|
107054
|
+
for (let i = 0; i < w * h; i++) {
|
|
107055
|
+
const ux = i % w / w;
|
|
107056
|
+
const uy = Math.floor(i / w) / h;
|
|
107057
|
+
const o = i * 6;
|
|
107058
|
+
const uvx = ux - 0.5;
|
|
107059
|
+
const uvy = uy - 0.5;
|
|
107060
|
+
const dist = Math.sqrt(uvx * uvx + uvy * uvy);
|
|
107061
|
+
const warp = fbm(ux * 4, uy * 4) * 0.5;
|
|
107062
|
+
const fromAng = p * (1 - dist) * 10 + warp * p * 3;
|
|
107063
|
+
const fs8 = Math.sin(fromAng);
|
|
107064
|
+
const fc = Math.cos(fromAng);
|
|
107065
|
+
const fromUx = Math.max(0, Math.min(1, uvx * fc - uvy * fs8 + 0.5));
|
|
107066
|
+
const fromUy = Math.max(0, Math.min(1, uvx * fs8 + uvy * fc + 0.5));
|
|
107067
|
+
const toAng = -(1 - p) * (1 - dist) * 10 - warp * (1 - p) * 3;
|
|
107068
|
+
const ts = Math.sin(toAng);
|
|
107069
|
+
const tc = Math.cos(toAng);
|
|
107070
|
+
const toUx = Math.max(0, Math.min(1, uvx * tc - uvy * ts + 0.5));
|
|
107071
|
+
const toUy = Math.max(0, Math.min(1, uvx * ts + uvy * tc + 0.5));
|
|
107072
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, fromUx, fromUy, w, h);
|
|
107073
|
+
const [toR, toG, toB] = sampleRgb48le(to, toUx, toUy, w, h);
|
|
107074
|
+
out.writeUInt16LE(clamp16(mix16(fromR, toR, p)), o);
|
|
107075
|
+
out.writeUInt16LE(clamp16(mix16(fromG, toG, p)), o + 2);
|
|
107076
|
+
out.writeUInt16LE(clamp16(mix16(fromB, toB, p)), o + 4);
|
|
107077
|
+
}
|
|
107078
|
+
};
|
|
107079
|
+
TRANSITIONS["swirl-vortex"] = swirlVortex;
|
|
107080
|
+
var thermalDistortion = (from2, to, out, w, h, p) => {
|
|
107081
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
107082
|
+
for (let i = 0; i < w * h; i++) {
|
|
107083
|
+
const ux = i % w / w;
|
|
107084
|
+
const uy = Math.floor(i / w) / h;
|
|
107085
|
+
const o = i * 6;
|
|
107086
|
+
const heat = p * 1.5;
|
|
107087
|
+
const yFade = smoothstep(1, 0, uy);
|
|
107088
|
+
const shimmer = Math.sin(uy * 40 + fbm(ux * 6, uy * 6) * 8) * fbm(ux * 3 + 0, uy * 3 + p * 2);
|
|
107089
|
+
const dispX = shimmer * heat * 0.03 * yFade;
|
|
107090
|
+
const fromUx = Math.max(0, Math.min(1, ux + dispX));
|
|
107091
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, fromUx, uy, w, h);
|
|
107092
|
+
const invShimmer = Math.sin(uy * 40 + fbm(ux * 6 + 3, uy * 6 + 3) * 8) * fbm(ux * 3 + 3, uy * 3 + p * 2);
|
|
107093
|
+
const dispX2 = invShimmer * (1 - p) * 0.03 * yFade;
|
|
107094
|
+
const toUx = Math.max(0, Math.min(1, ux + dispX2));
|
|
107095
|
+
const [toR, toG, toB] = sampleRgb48le(to, toUx, uy, w, h);
|
|
107096
|
+
const haze = heat * yFade * 0.15 * (1 - p);
|
|
107097
|
+
out.writeUInt16LE(clamp16(mix16(fromR, toR, p) + Math.round(accentBright[0] * haze)), o);
|
|
107098
|
+
out.writeUInt16LE(clamp16(mix16(fromG, toG, p) + Math.round(accentBright[1] * haze)), o + 2);
|
|
107099
|
+
out.writeUInt16LE(clamp16(mix16(fromB, toB, p) + Math.round(accentBright[2] * haze)), o + 4);
|
|
107100
|
+
}
|
|
107101
|
+
};
|
|
107102
|
+
TRANSITIONS["thermal-distortion"] = thermalDistortion;
|
|
107103
|
+
var domainWarp = (from2, to, out, w, h, p) => {
|
|
107104
|
+
const accentDark = [25e3, 8e3, 2e3];
|
|
107105
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
107106
|
+
for (let i = 0; i < w * h; i++) {
|
|
107107
|
+
const ux = i % w / w;
|
|
107108
|
+
const uy = Math.floor(i / w) / h;
|
|
107109
|
+
const o = i * 6;
|
|
107110
|
+
const qx = fbm(ux * 3, uy * 3);
|
|
107111
|
+
const qy = fbm(ux * 3 + 5.2, uy * 3 + 1.3);
|
|
107112
|
+
const rx = fbm(ux * 3 + qx * 4 + 1.7, uy * 3 + qy * 4 + 9.2);
|
|
107113
|
+
const ry = fbm(ux * 3 + qx * 4 + 8.3, uy * 3 + qy * 4 + 2.8);
|
|
107114
|
+
const n = fbm(ux * 3 + rx * 2, uy * 3 + ry * 2);
|
|
107115
|
+
const warpDirX = (qx - 0.5) * 0.4;
|
|
107116
|
+
const warpDirY = (qy - 0.5) * 0.4;
|
|
107117
|
+
const aUx = Math.max(0, Math.min(1, ux + warpDirX * p));
|
|
107118
|
+
const aUy = Math.max(0, Math.min(1, uy + warpDirY * p));
|
|
107119
|
+
const bUx = Math.max(0, Math.min(1, ux - warpDirX * (1 - p)));
|
|
107120
|
+
const bUy = Math.max(0, Math.min(1, uy - warpDirY * (1 - p)));
|
|
107121
|
+
const [aR, aG, aB] = sampleRgb48le(from2, aUx, aUy, w, h);
|
|
107122
|
+
const [bR, bG, bB] = sampleRgb48le(to, bUx, bUy, w, h);
|
|
107123
|
+
const e = smoothstep(p - 0.08, p + 0.08, n);
|
|
107124
|
+
const ed = Math.abs(n - p);
|
|
107125
|
+
const pStep = p >= 1 ? 1 : 0;
|
|
107126
|
+
const em = smoothstep(0.1, 0, ed) * (1 - pStep);
|
|
107127
|
+
const ecBlend = smoothstep(0, 0.1, ed);
|
|
107128
|
+
const ecR = accentDark[0] + (accentBright[0] - accentDark[0]) * (1 - ecBlend);
|
|
107129
|
+
const ecG = accentDark[1] + (accentBright[1] - accentDark[1]) * (1 - ecBlend);
|
|
107130
|
+
const ecB = accentDark[2] + (accentBright[2] - accentDark[2]) * (1 - ecBlend);
|
|
107131
|
+
out.writeUInt16LE(clamp16(mix16(bR, aR, e) + Math.round(ecR * em * 2)), o);
|
|
107132
|
+
out.writeUInt16LE(clamp16(mix16(bG, aG, e) + Math.round(ecG * em * 2)), o + 2);
|
|
107133
|
+
out.writeUInt16LE(clamp16(mix16(bB, aB, e) + Math.round(ecB * em * 2)), o + 4);
|
|
107134
|
+
}
|
|
107135
|
+
};
|
|
107136
|
+
TRANSITIONS["domain-warp"] = domainWarp;
|
|
107137
|
+
function ridged(px, py) {
|
|
107138
|
+
let value = 0;
|
|
107139
|
+
let amplitude = 0.5;
|
|
107140
|
+
let x = px;
|
|
107141
|
+
let y = py;
|
|
107142
|
+
for (let i = 0; i < 5; i++) {
|
|
107143
|
+
value += amplitude * Math.abs(vnoise(x, y) * 2 - 1);
|
|
107144
|
+
const nx = ROT_A * x - ROT_B * y;
|
|
107145
|
+
const ny = ROT_B * x + ROT_A * y;
|
|
107146
|
+
x = nx * 2.02;
|
|
107147
|
+
y = ny * 2.02;
|
|
107148
|
+
amplitude *= 0.5;
|
|
107149
|
+
}
|
|
107150
|
+
return value;
|
|
107151
|
+
}
|
|
107152
|
+
var ridgedBurn = (from2, to, out, w, h, p) => {
|
|
107153
|
+
const accent = [5e4, 25e3, 5e3];
|
|
107154
|
+
const accentDark = [25e3, 8e3, 2e3];
|
|
107155
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
107156
|
+
for (let i = 0; i < w * h; i++) {
|
|
107157
|
+
const ux = i % w / w;
|
|
107158
|
+
const uy = Math.floor(i / w) / h;
|
|
107159
|
+
const o = i * 6;
|
|
107160
|
+
const [aR, aG, aB] = sampleRgb48le(from2, ux, uy, w, h);
|
|
107161
|
+
const [bR, bG, bB] = sampleRgb48le(to, ux, uy, w, h);
|
|
107162
|
+
const n = ridged(ux * 4, uy * 4);
|
|
107163
|
+
const e = smoothstep(p - 0.04, p + 0.04, n);
|
|
107164
|
+
const heat = smoothstep(0.12, 0, Math.abs(n - p));
|
|
107165
|
+
const pStep = p >= 1 ? 1 : 0;
|
|
107166
|
+
const heatMasked = heat * (1 - pStep);
|
|
107167
|
+
let burnR = accentDark[0] + (accent[0] - accentDark[0]) * smoothstep(0, 0.25, heatMasked);
|
|
107168
|
+
let burnG = accentDark[1] + (accent[1] - accentDark[1]) * smoothstep(0, 0.25, heatMasked);
|
|
107169
|
+
let burnB = accentDark[2] + (accent[2] - accentDark[2]) * smoothstep(0, 0.25, heatMasked);
|
|
107170
|
+
const blend2 = smoothstep(0.25, 0.5, heatMasked);
|
|
107171
|
+
burnR = burnR + (accentBright[0] - burnR) * blend2;
|
|
107172
|
+
burnG = burnG + (accentBright[1] - burnG) * blend2;
|
|
107173
|
+
burnB = burnB + (accentBright[2] - burnB) * blend2;
|
|
107174
|
+
const blend3 = smoothstep(0.5, 1, heatMasked);
|
|
107175
|
+
burnR = burnR + (65535 - burnR) * blend3;
|
|
107176
|
+
burnG = burnG + (65535 - burnG) * blend3;
|
|
107177
|
+
burnB = burnB + (65535 - burnB) * blend3;
|
|
107178
|
+
const sparks = (vnoise(ux * 80, uy * 80) >= 0.92 ? 1 : 0) * heatMasked * 3;
|
|
107179
|
+
out.writeUInt16LE(
|
|
107180
|
+
clamp16(
|
|
107181
|
+
mix16(bR, aR, e) + Math.round(burnR * heatMasked * 3.5) + Math.round(accentBright[0] * sparks)
|
|
107182
|
+
),
|
|
107183
|
+
o
|
|
107184
|
+
);
|
|
107185
|
+
out.writeUInt16LE(
|
|
107186
|
+
clamp16(
|
|
107187
|
+
mix16(bG, aG, e) + Math.round(burnG * heatMasked * 3.5) + Math.round(accentBright[1] * sparks)
|
|
107188
|
+
),
|
|
107189
|
+
o + 2
|
|
107190
|
+
);
|
|
107191
|
+
out.writeUInt16LE(
|
|
107192
|
+
clamp16(
|
|
107193
|
+
mix16(bB, aB, e) + Math.round(burnB * heatMasked * 3.5) + Math.round(accentBright[2] * sparks)
|
|
107194
|
+
),
|
|
107195
|
+
o + 4
|
|
107196
|
+
);
|
|
107197
|
+
}
|
|
107198
|
+
};
|
|
107199
|
+
TRANSITIONS["ridged-burn"] = ridgedBurn;
|
|
107200
|
+
|
|
106343
107201
|
// src/services/renderOrchestrator.ts
|
|
106344
107202
|
import { join as join15, dirname as dirname10, resolve as resolve10 } from "path";
|
|
106345
107203
|
import { randomUUID } from "crypto";
|
|
@@ -108187,6 +109045,63 @@ function applyRenderModeHints(cfg, compiled, log = defaultLogger) {
|
|
|
108187
109045
|
reasons: compiled.renderModeHints.reasons.map((reason) => reason.message)
|
|
108188
109046
|
});
|
|
108189
109047
|
}
|
|
109048
|
+
function blitHdrVideoLayer(canvas, el, time, fps, hdrFrameDirs, hdrStartTimes, width, height, log, sourceTransfer, targetTransfer) {
|
|
109049
|
+
const frameDir = hdrFrameDirs.get(el.id);
|
|
109050
|
+
const startTime = hdrStartTimes.get(el.id);
|
|
109051
|
+
if (!frameDir || startTime === void 0) {
|
|
109052
|
+
return;
|
|
109053
|
+
}
|
|
109054
|
+
const videoFrameIndex = Math.round((time - startTime) * fps) + 1;
|
|
109055
|
+
if (videoFrameIndex < 1) return;
|
|
109056
|
+
const maxIndex = getMaxFrameIndex(frameDir);
|
|
109057
|
+
const effectiveIndex = maxIndex > 0 ? Math.min(videoFrameIndex, maxIndex) : videoFrameIndex;
|
|
109058
|
+
const framePath = join15(frameDir, `frame_${String(effectiveIndex).padStart(4, "0")}.png`);
|
|
109059
|
+
if (!existsSync15(framePath)) {
|
|
109060
|
+
return;
|
|
109061
|
+
}
|
|
109062
|
+
try {
|
|
109063
|
+
const { data: hdrRgb, width: srcW, height: srcH } = decodePngToRgb48le(readFileSync9(framePath));
|
|
109064
|
+
if (sourceTransfer && targetTransfer && sourceTransfer !== targetTransfer) {
|
|
109065
|
+
convertTransfer(hdrRgb, sourceTransfer, targetTransfer);
|
|
109066
|
+
}
|
|
109067
|
+
const viewportMatrix = parseTransformMatrix(el.transform);
|
|
109068
|
+
const br = el.borderRadius;
|
|
109069
|
+
const hasBorderRadius = br[0] > 0 || br[1] > 0 || br[2] > 0 || br[3] > 0;
|
|
109070
|
+
const borderRadiusParam = hasBorderRadius ? br : void 0;
|
|
109071
|
+
if (viewportMatrix) {
|
|
109072
|
+
blitRgb48leAffine(
|
|
109073
|
+
canvas,
|
|
109074
|
+
hdrRgb,
|
|
109075
|
+
viewportMatrix,
|
|
109076
|
+
srcW,
|
|
109077
|
+
srcH,
|
|
109078
|
+
width,
|
|
109079
|
+
height,
|
|
109080
|
+
el.opacity < 0.999 ? el.opacity : void 0,
|
|
109081
|
+
borderRadiusParam
|
|
109082
|
+
);
|
|
109083
|
+
} else {
|
|
109084
|
+
blitRgb48leRegion(
|
|
109085
|
+
canvas,
|
|
109086
|
+
hdrRgb,
|
|
109087
|
+
el.x,
|
|
109088
|
+
el.y,
|
|
109089
|
+
srcW,
|
|
109090
|
+
srcH,
|
|
109091
|
+
width,
|
|
109092
|
+
height,
|
|
109093
|
+
el.opacity < 0.999 ? el.opacity : void 0,
|
|
109094
|
+
borderRadiusParam
|
|
109095
|
+
);
|
|
109096
|
+
}
|
|
109097
|
+
} catch (err) {
|
|
109098
|
+
if (log) {
|
|
109099
|
+
log.debug(`HDR blit failed for ${el.id}`, {
|
|
109100
|
+
error: err instanceof Error ? err.message : String(err)
|
|
109101
|
+
});
|
|
109102
|
+
}
|
|
109103
|
+
}
|
|
109104
|
+
}
|
|
108190
109105
|
function createRenderJob(config2) {
|
|
108191
109106
|
return {
|
|
108192
109107
|
id: randomUUID(),
|
|
@@ -108457,6 +109372,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108457
109372
|
perfStages.browserProbeMs = Date.now() - probeStart;
|
|
108458
109373
|
job.duration = composition.duration;
|
|
108459
109374
|
job.totalFrames = Math.ceil(composition.duration * job.config.fps);
|
|
109375
|
+
const totalFrames = job.totalFrames;
|
|
108460
109376
|
if (job.duration <= 0) {
|
|
108461
109377
|
const diagnostics = [];
|
|
108462
109378
|
try {
|
|
@@ -108514,7 +109430,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108514
109430
|
const compiledDir = join15(workDir, "compiled");
|
|
108515
109431
|
let extractionResult = null;
|
|
108516
109432
|
const nativeHdrVideoIds = /* @__PURE__ */ new Set();
|
|
108517
|
-
|
|
109433
|
+
const videoTransfers = /* @__PURE__ */ new Map();
|
|
109434
|
+
if (job.config.hdr && composition.videos.length > 0) {
|
|
108518
109435
|
await Promise.all(
|
|
108519
109436
|
composition.videos.map(async (v) => {
|
|
108520
109437
|
let videoPath = v.src;
|
|
@@ -108526,6 +109443,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108526
109443
|
const meta = await extractVideoMetadata(videoPath);
|
|
108527
109444
|
if (isHdrColorSpace(meta.colorSpace)) {
|
|
108528
109445
|
nativeHdrVideoIds.add(v.id);
|
|
109446
|
+
videoTransfers.set(v.id, detectTransfer(meta.colorSpace));
|
|
108529
109447
|
}
|
|
108530
109448
|
})
|
|
108531
109449
|
);
|
|
@@ -108567,13 +109485,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108567
109485
|
perfStages.videoExtractMs = Date.now() - stage2Start;
|
|
108568
109486
|
}
|
|
108569
109487
|
let effectiveHdr;
|
|
108570
|
-
if (frameLookup) {
|
|
109488
|
+
if (job.config.hdr && frameLookup) {
|
|
108571
109489
|
const colorSpaces = (extractionResult?.extracted ?? []).map((ext) => ext.metadata.colorSpace);
|
|
108572
109490
|
const info = analyzeCompositionHdr(colorSpaces);
|
|
108573
109491
|
if (info.hasHdr && info.dominantTransfer) {
|
|
108574
109492
|
effectiveHdr = { transfer: info.dominantTransfer };
|
|
108575
109493
|
}
|
|
108576
109494
|
}
|
|
109495
|
+
if (job.config.hdr && !effectiveHdr && nativeHdrVideoIds.size > 0) {
|
|
109496
|
+
const firstTransfer = videoTransfers.values().next().value;
|
|
109497
|
+
if (firstTransfer) {
|
|
109498
|
+
effectiveHdr = { transfer: firstTransfer };
|
|
109499
|
+
}
|
|
109500
|
+
}
|
|
108577
109501
|
if (effectiveHdr && outputFormat !== "mp4") {
|
|
108578
109502
|
log.info(`[Render] HDR source detected but format is ${outputFormat} \u2014 using SDR`);
|
|
108579
109503
|
effectiveHdr = void 0;
|
|
@@ -108624,15 +109548,15 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108624
109548
|
format: needsAlpha ? "png" : "jpeg",
|
|
108625
109549
|
quality: needsAlpha ? void 0 : job.config.quality === "draft" ? 80 : 95
|
|
108626
109550
|
};
|
|
108627
|
-
const workerCount = calculateOptimalWorkers(
|
|
109551
|
+
const workerCount = calculateOptimalWorkers(totalFrames, job.config.workers, cfg);
|
|
108628
109552
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
108629
109553
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
108630
109554
|
const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
|
|
108631
|
-
const
|
|
108632
|
-
const encoderHdr =
|
|
109555
|
+
const hasHdrContent = effectiveHdr && nativeHdrVideoIds.size > 0;
|
|
109556
|
+
const encoderHdr = hasHdrContent ? effectiveHdr : void 0;
|
|
108633
109557
|
const preset = getEncoderPreset(job.config.quality, outputFormat, encoderHdr);
|
|
108634
109558
|
job.framesRendered = 0;
|
|
108635
|
-
if (
|
|
109559
|
+
if (hasHdrContent) {
|
|
108636
109560
|
log.info("[Render] HDR layered composite: z-ordered DOM + native HLG video layers");
|
|
108637
109561
|
const hdrVideoIds = composition.videos.filter((v) => nativeHdrVideoIds.has(v.id)).map((v) => v.id);
|
|
108638
109562
|
const hdrVideoSrcPaths = /* @__PURE__ */ new Map();
|
|
@@ -108645,6 +109569,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108645
109569
|
}
|
|
108646
109570
|
hdrVideoSrcPaths.set(v.id, srcPath);
|
|
108647
109571
|
}
|
|
109572
|
+
if (!fileServer) throw new Error("fileServer must be initialized before HDR compositing");
|
|
108648
109573
|
const domSession = await createCaptureSession(
|
|
108649
109574
|
fileServer.url,
|
|
108650
109575
|
framesDir,
|
|
@@ -108656,6 +109581,34 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108656
109581
|
assertNotAborted();
|
|
108657
109582
|
lastBrowserConsole = domSession.browserConsoleBuffer;
|
|
108658
109583
|
await initTransparentBackground(domSession.page);
|
|
109584
|
+
const transitionMeta = await domSession.page.evaluate(() => {
|
|
109585
|
+
return window.__hf?.transitions ?? [];
|
|
109586
|
+
});
|
|
109587
|
+
const sceneElements = await domSession.page.evaluate(() => {
|
|
109588
|
+
const scenes = document.querySelectorAll(".scene");
|
|
109589
|
+
const map2 = {};
|
|
109590
|
+
for (const scene of scenes) {
|
|
109591
|
+
const els = scene.querySelectorAll("[data-start]");
|
|
109592
|
+
map2[scene.id] = Array.from(els).map((e) => e.id);
|
|
109593
|
+
}
|
|
109594
|
+
return map2;
|
|
109595
|
+
});
|
|
109596
|
+
const transitionRanges = transitionMeta.map((t) => ({
|
|
109597
|
+
...t,
|
|
109598
|
+
startFrame: Math.floor(t.time * job.config.fps),
|
|
109599
|
+
endFrame: Math.ceil((t.time + t.duration) * job.config.fps)
|
|
109600
|
+
}));
|
|
109601
|
+
if (transitionRanges.length > 0) {
|
|
109602
|
+
log.info("[Render] Detected shader transitions for HDR compositing", {
|
|
109603
|
+
count: transitionRanges.length,
|
|
109604
|
+
transitions: transitionRanges.map((t) => ({
|
|
109605
|
+
shader: t.shader,
|
|
109606
|
+
from: t.fromScene,
|
|
109607
|
+
to: t.toScene,
|
|
109608
|
+
frames: `${t.startFrame}-${t.endFrame}`
|
|
109609
|
+
}))
|
|
109610
|
+
});
|
|
109611
|
+
}
|
|
108659
109612
|
const hdrEncoder = await spawnStreamingEncoder(
|
|
108660
109613
|
videoOnlyPath,
|
|
108661
109614
|
{
|
|
@@ -108673,7 +109626,28 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108673
109626
|
{ ffmpegStreamingTimeout: 36e5 }
|
|
108674
109627
|
);
|
|
108675
109628
|
assertNotAborted();
|
|
108676
|
-
const
|
|
109629
|
+
const hdrExtractionDims = /* @__PURE__ */ new Map();
|
|
109630
|
+
const hdrVideoStartTimes = /* @__PURE__ */ new Map();
|
|
109631
|
+
for (const v of composition.videos) {
|
|
109632
|
+
if (hdrVideoIds.includes(v.id)) {
|
|
109633
|
+
hdrVideoStartTimes.set(v.id, v.start);
|
|
109634
|
+
}
|
|
109635
|
+
}
|
|
109636
|
+
const uniqueStartTimes = [...new Set(hdrVideoStartTimes.values())].sort((a, b) => a - b);
|
|
109637
|
+
for (const seekTime of uniqueStartTimes) {
|
|
109638
|
+
await domSession.page.evaluate((t) => {
|
|
109639
|
+
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
109640
|
+
}, seekTime);
|
|
109641
|
+
if (domSession.onBeforeCapture) {
|
|
109642
|
+
await domSession.onBeforeCapture(domSession.page, seekTime);
|
|
109643
|
+
}
|
|
109644
|
+
const stacking = await queryElementStacking(domSession.page, nativeHdrVideoIds);
|
|
109645
|
+
for (const el of stacking) {
|
|
109646
|
+
if (el.isHdr && el.layoutWidth > 0 && el.layoutHeight > 0 && !hdrExtractionDims.has(el.id)) {
|
|
109647
|
+
hdrExtractionDims.set(el.id, { width: el.layoutWidth, height: el.layoutHeight });
|
|
109648
|
+
}
|
|
109649
|
+
}
|
|
109650
|
+
}
|
|
108677
109651
|
const hdrFrameDirs = /* @__PURE__ */ new Map();
|
|
108678
109652
|
for (const [videoId, srcPath] of hdrVideoSrcPaths) {
|
|
108679
109653
|
const video = composition.videos.find((v) => v.id === videoId);
|
|
@@ -108681,24 +109655,190 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108681
109655
|
const frameDir = join15(framesDir, `hdr_${videoId}`);
|
|
108682
109656
|
mkdirSync10(frameDir, { recursive: true });
|
|
108683
109657
|
const duration = video.end - video.start;
|
|
108684
|
-
|
|
108685
|
-
|
|
108686
|
-
|
|
108687
|
-
|
|
108688
|
-
|
|
108689
|
-
|
|
109658
|
+
const dims = hdrExtractionDims.get(videoId) ?? { width, height };
|
|
109659
|
+
const ffmpegArgs = [
|
|
109660
|
+
"-ss",
|
|
109661
|
+
String(video.mediaStart),
|
|
109662
|
+
"-i",
|
|
109663
|
+
srcPath,
|
|
109664
|
+
"-t",
|
|
109665
|
+
String(duration),
|
|
109666
|
+
"-r",
|
|
109667
|
+
String(job.config.fps),
|
|
109668
|
+
"-vf",
|
|
109669
|
+
`scale=${dims.width}:${dims.height}:force_original_aspect_ratio=increase,crop=${dims.width}:${dims.height}`,
|
|
109670
|
+
"-pix_fmt",
|
|
109671
|
+
"rgb48le",
|
|
109672
|
+
"-c:v",
|
|
109673
|
+
"png",
|
|
109674
|
+
"-y",
|
|
109675
|
+
join15(frameDir, "frame_%04d.png")
|
|
109676
|
+
];
|
|
109677
|
+
const result = await runFfmpeg(ffmpegArgs, { signal: abortSignal });
|
|
109678
|
+
if (!result.success) {
|
|
108690
109679
|
log.warn("HDR frame pre-extraction failed; loop will fill with black", {
|
|
108691
109680
|
videoId,
|
|
108692
109681
|
srcPath,
|
|
108693
|
-
|
|
109682
|
+
stderr: result.stderr.slice(-400)
|
|
108694
109683
|
});
|
|
108695
109684
|
}
|
|
108696
109685
|
hdrFrameDirs.set(videoId, frameDir);
|
|
108697
109686
|
}
|
|
108698
109687
|
assertNotAborted();
|
|
108699
109688
|
try {
|
|
109689
|
+
let countNonZeroAlpha2 = function(rgba) {
|
|
109690
|
+
let n = 0;
|
|
109691
|
+
for (let p = 3; p < rgba.length; p += 4) {
|
|
109692
|
+
if (rgba[p] !== 0) n++;
|
|
109693
|
+
}
|
|
109694
|
+
return n;
|
|
109695
|
+
}, countNonZeroRgb482 = function(buf) {
|
|
109696
|
+
let n = 0;
|
|
109697
|
+
for (let p = 0; p < buf.length; p += 6) {
|
|
109698
|
+
if (buf[p] !== 0 || buf[p + 1] !== 0 || buf[p + 2] !== 0) n++;
|
|
109699
|
+
}
|
|
109700
|
+
return n;
|
|
109701
|
+
};
|
|
109702
|
+
var countNonZeroAlpha = countNonZeroAlpha2, countNonZeroRgb48 = countNonZeroRgb482;
|
|
108700
109703
|
const beforeCaptureHook = domSession.onBeforeCapture;
|
|
108701
|
-
|
|
109704
|
+
const cleanedUpVideos = /* @__PURE__ */ new Set();
|
|
109705
|
+
const hdrVideoEndTimes = /* @__PURE__ */ new Map();
|
|
109706
|
+
for (const v of composition.videos) {
|
|
109707
|
+
if (hdrFrameDirs.has(v.id)) {
|
|
109708
|
+
hdrVideoEndTimes.set(v.id, v.end);
|
|
109709
|
+
}
|
|
109710
|
+
}
|
|
109711
|
+
const debugDumpEnabled = process.env.KEEP_TEMP === "1";
|
|
109712
|
+
const debugDumpDir = debugDumpEnabled ? join15(framesDir, "debug-composite") : null;
|
|
109713
|
+
if (debugDumpDir && !existsSync15(debugDumpDir)) {
|
|
109714
|
+
mkdirSync10(debugDumpDir, { recursive: true });
|
|
109715
|
+
}
|
|
109716
|
+
async function compositeToBuffer(canvas, time, fullStacking, elementFilter, debugFrameIndex = -1) {
|
|
109717
|
+
const filteredStacking = elementFilter ? fullStacking.filter((e) => elementFilter.has(e.id)) : fullStacking;
|
|
109718
|
+
const layers = groupIntoLayers(filteredStacking);
|
|
109719
|
+
const shouldLog = debugDumpEnabled && debugFrameIndex >= 0;
|
|
109720
|
+
if (shouldLog) {
|
|
109721
|
+
log.info("[diag] compositeToBuffer plan", {
|
|
109722
|
+
frame: debugFrameIndex,
|
|
109723
|
+
time: time.toFixed(3),
|
|
109724
|
+
filterSize: elementFilter?.size,
|
|
109725
|
+
fullStackingCount: fullStacking.length,
|
|
109726
|
+
filteredCount: filteredStacking.length,
|
|
109727
|
+
layerCount: layers.length,
|
|
109728
|
+
layers: layers.map(
|
|
109729
|
+
(l) => l.type === "hdr" ? {
|
|
109730
|
+
type: "hdr",
|
|
109731
|
+
id: l.element.id,
|
|
109732
|
+
z: l.element.zIndex,
|
|
109733
|
+
visible: l.element.visible,
|
|
109734
|
+
opacity: l.element.opacity,
|
|
109735
|
+
bounds: `${Math.round(l.element.x)},${Math.round(l.element.y)} ${Math.round(l.element.width)}x${Math.round(l.element.height)}`
|
|
109736
|
+
} : { type: "dom", ids: l.elementIds }
|
|
109737
|
+
)
|
|
109738
|
+
});
|
|
109739
|
+
}
|
|
109740
|
+
for (let layerIdx = 0; layerIdx < layers.length; layerIdx++) {
|
|
109741
|
+
const layer = layers[layerIdx];
|
|
109742
|
+
if (layer.type === "hdr") {
|
|
109743
|
+
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
109744
|
+
blitHdrVideoLayer(
|
|
109745
|
+
canvas,
|
|
109746
|
+
layer.element,
|
|
109747
|
+
time,
|
|
109748
|
+
job.config.fps,
|
|
109749
|
+
hdrFrameDirs,
|
|
109750
|
+
hdrVideoStartTimes,
|
|
109751
|
+
width,
|
|
109752
|
+
height,
|
|
109753
|
+
log,
|
|
109754
|
+
videoTransfers.get(layer.element.id),
|
|
109755
|
+
effectiveHdr?.transfer
|
|
109756
|
+
);
|
|
109757
|
+
if (shouldLog) {
|
|
109758
|
+
const after2 = countNonZeroRgb482(canvas);
|
|
109759
|
+
const frameDir = hdrFrameDirs.get(layer.element.id);
|
|
109760
|
+
const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
|
|
109761
|
+
const localTime = time - startTime;
|
|
109762
|
+
const frameNum = Math.floor(localTime * job.config.fps) + 1;
|
|
109763
|
+
const expectedFrame = frameDir ? join15(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
|
|
109764
|
+
log.info("[diag] hdr layer blit", {
|
|
109765
|
+
frame: debugFrameIndex,
|
|
109766
|
+
layerIdx,
|
|
109767
|
+
id: layer.element.id,
|
|
109768
|
+
pixelsAdded: after2 - before2,
|
|
109769
|
+
totalNonZero: after2,
|
|
109770
|
+
startTime,
|
|
109771
|
+
localTime: localTime.toFixed(3),
|
|
109772
|
+
hdrFrameNum: frameNum,
|
|
109773
|
+
expectedFrame,
|
|
109774
|
+
expectedFrameExists: expectedFrame ? existsSync15(expectedFrame) : false
|
|
109775
|
+
});
|
|
109776
|
+
}
|
|
109777
|
+
} else {
|
|
109778
|
+
const allElementIds = fullStacking.map((e) => e.id);
|
|
109779
|
+
const layerIds = new Set(layer.elementIds);
|
|
109780
|
+
const hideIds = allElementIds.filter((id) => !layerIds.has(id));
|
|
109781
|
+
await domSession.page.evaluate((t) => {
|
|
109782
|
+
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
109783
|
+
}, time);
|
|
109784
|
+
if (beforeCaptureHook) {
|
|
109785
|
+
await beforeCaptureHook(domSession.page, time);
|
|
109786
|
+
}
|
|
109787
|
+
await applyDomLayerMask(domSession.page, layer.elementIds, hideIds);
|
|
109788
|
+
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
109789
|
+
await removeDomLayerMask(domSession.page, hideIds);
|
|
109790
|
+
try {
|
|
109791
|
+
const { data: domRgba } = decodePng(domPng);
|
|
109792
|
+
if (!effectiveHdr) {
|
|
109793
|
+
throw new Error(
|
|
109794
|
+
"Invariant violation: effectiveHdr is undefined inside HDR layer branch"
|
|
109795
|
+
);
|
|
109796
|
+
}
|
|
109797
|
+
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
109798
|
+
const alphaPixels = shouldLog ? countNonZeroAlpha2(domRgba) : 0;
|
|
109799
|
+
blitRgba8OverRgb48le(domRgba, canvas, width, height, effectiveHdr.transfer);
|
|
109800
|
+
if (shouldLog && debugDumpDir) {
|
|
109801
|
+
const after2 = countNonZeroRgb482(canvas);
|
|
109802
|
+
const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
|
|
109803
|
+
const dumpPath = join15(debugDumpDir, dumpName);
|
|
109804
|
+
writeFileSync4(dumpPath, domPng);
|
|
109805
|
+
log.info("[diag] dom layer blit", {
|
|
109806
|
+
frame: debugFrameIndex,
|
|
109807
|
+
layerIdx,
|
|
109808
|
+
layerIds: layer.elementIds,
|
|
109809
|
+
hideCount: hideIds.length,
|
|
109810
|
+
pngBytes: domPng.length,
|
|
109811
|
+
alphaPixels,
|
|
109812
|
+
pixelsAdded: after2 - before2,
|
|
109813
|
+
totalNonZero: after2,
|
|
109814
|
+
dumpPath
|
|
109815
|
+
});
|
|
109816
|
+
}
|
|
109817
|
+
} catch (err) {
|
|
109818
|
+
log.warn("DOM layer decode/blit failed; skipping overlay", {
|
|
109819
|
+
layerIds: layer.elementIds,
|
|
109820
|
+
error: err instanceof Error ? err.message : String(err)
|
|
109821
|
+
});
|
|
109822
|
+
}
|
|
109823
|
+
}
|
|
109824
|
+
}
|
|
109825
|
+
if (shouldLog && debugDumpDir) {
|
|
109826
|
+
const finalNonZero = countNonZeroRgb482(canvas);
|
|
109827
|
+
log.info("[diag] compositeToBuffer end", {
|
|
109828
|
+
frame: debugFrameIndex,
|
|
109829
|
+
finalNonZeroPixels: finalNonZero,
|
|
109830
|
+
totalPixels: width * height,
|
|
109831
|
+
coverage: (finalNonZero / (width * height) * 100).toFixed(1) + "%"
|
|
109832
|
+
});
|
|
109833
|
+
}
|
|
109834
|
+
}
|
|
109835
|
+
const bufSize = width * height * 6;
|
|
109836
|
+
const hasTransitions = transitionRanges.length > 0;
|
|
109837
|
+
const transBufferA = hasTransitions ? Buffer.alloc(bufSize) : null;
|
|
109838
|
+
const transBufferB = hasTransitions ? Buffer.alloc(bufSize) : null;
|
|
109839
|
+
const transOutput = hasTransitions ? Buffer.alloc(bufSize) : null;
|
|
109840
|
+
const normalCanvas = Buffer.alloc(bufSize);
|
|
109841
|
+
for (let i = 0; i < totalFrames; i++) {
|
|
108702
109842
|
assertNotAborted();
|
|
108703
109843
|
const time = i / job.config.fps;
|
|
108704
109844
|
await domSession.page.evaluate((t) => {
|
|
@@ -108708,81 +109848,118 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108708
109848
|
await beforeCaptureHook(domSession.page, time);
|
|
108709
109849
|
}
|
|
108710
109850
|
const stackingInfo = await queryElementStacking(domSession.page, nativeHdrVideoIds);
|
|
108711
|
-
const
|
|
109851
|
+
const activeTransition = transitionRanges.find(
|
|
109852
|
+
(t) => i >= t.startFrame && i <= t.endFrame
|
|
109853
|
+
);
|
|
108712
109854
|
if (i % 30 === 0) {
|
|
108713
109855
|
const hdrEl = stackingInfo.find((e) => e.isHdr);
|
|
108714
|
-
const hdrInLayers = layers.some((l) => l.type === "hdr");
|
|
108715
109856
|
log.debug("[Render] HDR layer composite frame", {
|
|
108716
109857
|
frame: i,
|
|
108717
109858
|
time: time.toFixed(2),
|
|
108718
109859
|
hdrElement: hdrEl ? { z: hdrEl.zIndex, visible: hdrEl.visible, width: hdrEl.width } : null,
|
|
108719
|
-
|
|
108720
|
-
|
|
109860
|
+
stackingCount: stackingInfo.length,
|
|
109861
|
+
activeTransition: activeTransition?.shader
|
|
108721
109862
|
});
|
|
108722
109863
|
}
|
|
108723
|
-
|
|
108724
|
-
|
|
108725
|
-
|
|
108726
|
-
|
|
108727
|
-
|
|
108728
|
-
|
|
108729
|
-
|
|
108730
|
-
|
|
108731
|
-
|
|
108732
|
-
|
|
108733
|
-
const framePath = inBounds ? join15(frameDir, `frame_${String(videoFrameIndex).padStart(4, "0")}.png`) : null;
|
|
108734
|
-
if (framePath !== null && existsSync15(framePath)) {
|
|
108735
|
-
try {
|
|
108736
|
-
const hdrRgb = decodePngToRgb48le(readFileSync9(framePath)).data;
|
|
108737
|
-
blitRgb48leRegion(
|
|
108738
|
-
canvas,
|
|
108739
|
-
hdrRgb,
|
|
108740
|
-
el.x,
|
|
108741
|
-
el.y,
|
|
108742
|
-
el.width,
|
|
108743
|
-
el.height,
|
|
108744
|
-
width,
|
|
108745
|
-
height,
|
|
108746
|
-
el.opacity < 0.999 ? el.opacity : void 0
|
|
108747
|
-
);
|
|
108748
|
-
} catch (err) {
|
|
108749
|
-
log.warn("HDR layer decode/blit failed; skipping layer for frame", {
|
|
108750
|
-
frameIndex: i,
|
|
108751
|
-
videoId: el.id,
|
|
108752
|
-
framePath,
|
|
108753
|
-
error: err instanceof Error ? err.message : String(err)
|
|
108754
|
-
});
|
|
108755
|
-
}
|
|
108756
|
-
}
|
|
108757
|
-
} else {
|
|
108758
|
-
const allElementIds = stackingInfo.map((e) => e.id);
|
|
108759
|
-
const layerIds = new Set(layer.elementIds);
|
|
108760
|
-
const hideIds = allElementIds.filter(
|
|
108761
|
-
(id) => !layerIds.has(id) || nativeHdrVideoIds.has(id)
|
|
108762
|
-
);
|
|
108763
|
-
await hideVideoElements(domSession.page, hideIds);
|
|
108764
|
-
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
108765
|
-
await showVideoElements(domSession.page, hideIds);
|
|
109864
|
+
if (activeTransition && transBufferA && transBufferB && transOutput) {
|
|
109865
|
+
const progress = activeTransition.endFrame === activeTransition.startFrame ? 1 : (i - activeTransition.startFrame) / (activeTransition.endFrame - activeTransition.startFrame);
|
|
109866
|
+
const sceneAIds = new Set(sceneElements[activeTransition.fromScene] ?? []);
|
|
109867
|
+
const sceneBIds = new Set(sceneElements[activeTransition.toScene] ?? []);
|
|
109868
|
+
transBufferA.fill(0);
|
|
109869
|
+
transBufferB.fill(0);
|
|
109870
|
+
for (const [sceneBuf, sceneIds] of [
|
|
109871
|
+
[transBufferA, sceneAIds],
|
|
109872
|
+
[transBufferB, sceneBIds]
|
|
109873
|
+
]) {
|
|
108766
109874
|
await domSession.page.evaluate((t) => {
|
|
108767
109875
|
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
108768
109876
|
}, time);
|
|
109877
|
+
if (beforeCaptureHook) {
|
|
109878
|
+
await beforeCaptureHook(domSession.page, time);
|
|
109879
|
+
}
|
|
109880
|
+
for (const el of stackingInfo) {
|
|
109881
|
+
if (!el.isHdr || !sceneIds.has(el.id)) continue;
|
|
109882
|
+
blitHdrVideoLayer(
|
|
109883
|
+
sceneBuf,
|
|
109884
|
+
el,
|
|
109885
|
+
time,
|
|
109886
|
+
job.config.fps,
|
|
109887
|
+
hdrFrameDirs,
|
|
109888
|
+
hdrVideoStartTimes,
|
|
109889
|
+
width,
|
|
109890
|
+
height,
|
|
109891
|
+
log,
|
|
109892
|
+
videoTransfers.get(el.id),
|
|
109893
|
+
effectiveHdr?.transfer
|
|
109894
|
+
);
|
|
109895
|
+
}
|
|
109896
|
+
const showIds = Array.from(sceneIds);
|
|
109897
|
+
const hideIds = stackingInfo.map((e) => e.id).filter((id) => !sceneIds.has(id) || nativeHdrVideoIds.has(id));
|
|
109898
|
+
await applyDomLayerMask(domSession.page, showIds, hideIds);
|
|
109899
|
+
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
109900
|
+
await removeDomLayerMask(domSession.page, hideIds);
|
|
108769
109901
|
try {
|
|
108770
109902
|
const { data: domRgba } = decodePng(domPng);
|
|
108771
|
-
|
|
108772
|
-
|
|
109903
|
+
if (!effectiveHdr) {
|
|
109904
|
+
throw new Error(
|
|
109905
|
+
"Invariant violation: effectiveHdr is undefined inside hasHdrVideo branch"
|
|
109906
|
+
);
|
|
109907
|
+
}
|
|
109908
|
+
blitRgba8OverRgb48le(
|
|
109909
|
+
domRgba,
|
|
109910
|
+
sceneBuf,
|
|
109911
|
+
width,
|
|
109912
|
+
height,
|
|
109913
|
+
effectiveHdr.transfer
|
|
109914
|
+
);
|
|
108773
109915
|
} catch (err) {
|
|
108774
|
-
log.warn("DOM layer decode/blit failed; skipping overlay for
|
|
109916
|
+
log.warn("DOM layer decode/blit failed; skipping overlay for transition scene", {
|
|
108775
109917
|
frameIndex: i,
|
|
108776
|
-
|
|
109918
|
+
sceneIds: Array.from(sceneIds),
|
|
108777
109919
|
error: err instanceof Error ? err.message : String(err)
|
|
108778
109920
|
});
|
|
108779
109921
|
}
|
|
108780
109922
|
}
|
|
109923
|
+
const transitionFn = TRANSITIONS[activeTransition.shader] ?? crossfade;
|
|
109924
|
+
transitionFn(transBufferA, transBufferB, transOutput, width, height, progress);
|
|
109925
|
+
hdrEncoder.writeFrame(transOutput);
|
|
109926
|
+
} else {
|
|
109927
|
+
normalCanvas.fill(0);
|
|
109928
|
+
await compositeToBuffer(normalCanvas, time, stackingInfo, void 0, i);
|
|
109929
|
+
if (debugDumpEnabled && debugDumpDir && i % 30 === 0) {
|
|
109930
|
+
const previewPath = join15(
|
|
109931
|
+
debugDumpDir,
|
|
109932
|
+
`frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`
|
|
109933
|
+
);
|
|
109934
|
+
writeFileSync4(previewPath, normalCanvas);
|
|
109935
|
+
}
|
|
109936
|
+
hdrEncoder.writeFrame(normalCanvas);
|
|
109937
|
+
}
|
|
109938
|
+
if (process.env.KEEP_TEMP !== "1") {
|
|
109939
|
+
for (const [videoId, endTime] of hdrVideoEndTimes) {
|
|
109940
|
+
if (time > endTime && !cleanedUpVideos.has(videoId)) {
|
|
109941
|
+
const stillNeeded = activeTransition && (sceneElements[activeTransition.fromScene]?.includes(videoId) || sceneElements[activeTransition.toScene]?.includes(videoId));
|
|
109942
|
+
if (!stillNeeded) {
|
|
109943
|
+
const frameDir = hdrFrameDirs.get(videoId);
|
|
109944
|
+
if (frameDir) {
|
|
109945
|
+
try {
|
|
109946
|
+
rmSync3(frameDir, { recursive: true, force: true });
|
|
109947
|
+
} catch (err) {
|
|
109948
|
+
log.warn("Failed to clean up HDR frame directory", {
|
|
109949
|
+
videoId,
|
|
109950
|
+
frameDir,
|
|
109951
|
+
error: err instanceof Error ? err.message : String(err)
|
|
109952
|
+
});
|
|
109953
|
+
}
|
|
109954
|
+
}
|
|
109955
|
+
cleanedUpVideos.add(videoId);
|
|
109956
|
+
}
|
|
109957
|
+
}
|
|
109958
|
+
}
|
|
108781
109959
|
}
|
|
108782
|
-
hdrEncoder.writeFrame(canvas);
|
|
108783
109960
|
job.framesRendered = i + 1;
|
|
108784
|
-
if ((i + 1) % 10 === 0 || i + 1 ===
|
|
108785
|
-
const frameProgress = (i + 1) /
|
|
109961
|
+
if ((i + 1) % 10 === 0 || i + 1 === totalFrames) {
|
|
109962
|
+
const frameProgress = (i + 1) / totalFrames;
|
|
108786
109963
|
updateJobStatus(
|
|
108787
109964
|
job,
|
|
108788
109965
|
"rendering",
|
|
@@ -108825,7 +110002,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108825
110002
|
assertNotAborted();
|
|
108826
110003
|
}
|
|
108827
110004
|
if (enableStreamingEncode && streamingEncoder) {
|
|
108828
|
-
const reorderBuffer = createFrameReorderBuffer(0,
|
|
110005
|
+
const reorderBuffer = createFrameReorderBuffer(0, totalFrames);
|
|
108829
110006
|
const currentEncoder = streamingEncoder;
|
|
108830
110007
|
if (workerCount > 1) {
|
|
108831
110008
|
const tasks = distributeFrames(job.totalFrames, workerCount, workDir);
|
|
@@ -108882,7 +110059,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108882
110059
|
}
|
|
108883
110060
|
assertNotAborted();
|
|
108884
110061
|
lastBrowserConsole = session.browserConsoleBuffer;
|
|
108885
|
-
for (let i = 0; i <
|
|
110062
|
+
for (let i = 0; i < totalFrames; i++) {
|
|
108886
110063
|
assertNotAborted();
|
|
108887
110064
|
const time = i / job.config.fps;
|
|
108888
110065
|
const { buffer } = await captureFrameToBuffer(session, i, time);
|
|
@@ -108890,7 +110067,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108890
110067
|
currentEncoder.writeFrame(buffer);
|
|
108891
110068
|
reorderBuffer.advanceTo(i + 1);
|
|
108892
110069
|
job.framesRendered = i + 1;
|
|
108893
|
-
const frameProgress = (i + 1) /
|
|
110070
|
+
const frameProgress = (i + 1) / totalFrames;
|
|
108894
110071
|
const progress = 25 + frameProgress * 55;
|
|
108895
110072
|
updateJobStatus(
|
|
108896
110073
|
job,
|
|
@@ -109063,12 +110240,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109063
110240
|
chunkedEncode: enableChunkedEncode,
|
|
109064
110241
|
chunkSizeFrames: enableChunkedEncode ? chunkedEncodeSize : null,
|
|
109065
110242
|
compositionDurationSeconds: composition.duration,
|
|
109066
|
-
totalFrames
|
|
110243
|
+
totalFrames,
|
|
109067
110244
|
resolution: { width, height },
|
|
109068
110245
|
videoCount: composition.videos.length,
|
|
109069
110246
|
audioCount: composition.audios.length,
|
|
109070
110247
|
stages: perfStages,
|
|
109071
|
-
captureAvgMs:
|
|
110248
|
+
captureAvgMs: totalFrames > 0 ? Math.round((perfStages.captureMs ?? 0) / totalFrames) : void 0
|
|
109072
110249
|
};
|
|
109073
110250
|
job.perfSummary = perfSummary;
|
|
109074
110251
|
if (job.config.debug) {
|
|
@@ -109086,6 +110263,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109086
110263
|
const debugOutput = join15(workDir, `output${videoExt}`);
|
|
109087
110264
|
copyFileSync2(outputPath, debugOutput);
|
|
109088
110265
|
}
|
|
110266
|
+
} else if (process.env.KEEP_TEMP === "1") {
|
|
110267
|
+
log.info("KEEP_TEMP=1 \u2014 leaving workDir on disk for inspection", { workDir });
|
|
109089
110268
|
} else {
|
|
109090
110269
|
await safeCleanup(
|
|
109091
110270
|
"remove workDir",
|