@hyperframes/producer 0.4.7 → 0.4.9
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/public-server.js
CHANGED
|
@@ -5117,12 +5117,12 @@ var require_common = __commonJS({
|
|
|
5117
5117
|
createDebug.skips = [];
|
|
5118
5118
|
createDebug.formatters = {};
|
|
5119
5119
|
function selectColor(namespace) {
|
|
5120
|
-
let
|
|
5120
|
+
let hash2 = 0;
|
|
5121
5121
|
for (let i = 0; i < namespace.length; i++) {
|
|
5122
|
-
|
|
5123
|
-
|
|
5122
|
+
hash2 = (hash2 << 5) - hash2 + namespace.charCodeAt(i);
|
|
5123
|
+
hash2 |= 0;
|
|
5124
5124
|
}
|
|
5125
|
-
return createDebug.colors[Math.abs(
|
|
5125
|
+
return createDebug.colors[Math.abs(hash2) % createDebug.colors.length];
|
|
5126
5126
|
}
|
|
5127
5127
|
createDebug.selectColor = selectColor;
|
|
5128
5128
|
function createDebug(namespace) {
|
|
@@ -54350,25 +54350,25 @@ var require_data = __commonJS({
|
|
|
54350
54350
|
var notmodified_1 = __importDefault2(require_notmodified());
|
|
54351
54351
|
var debug6 = (0, debug_1.default)("get-uri:data");
|
|
54352
54352
|
var DataReadable = class extends stream_1.Readable {
|
|
54353
|
-
constructor(
|
|
54353
|
+
constructor(hash2, buf) {
|
|
54354
54354
|
super();
|
|
54355
54355
|
this.push(buf);
|
|
54356
54356
|
this.push(null);
|
|
54357
|
-
this.hash =
|
|
54357
|
+
this.hash = hash2;
|
|
54358
54358
|
}
|
|
54359
54359
|
};
|
|
54360
54360
|
var data = async ({ href: uri }, { cache } = {}) => {
|
|
54361
54361
|
const shasum = (0, crypto_1.createHash)("sha1");
|
|
54362
54362
|
shasum.update(uri);
|
|
54363
|
-
const
|
|
54364
|
-
debug6('generated SHA1 hash for "data:" URI: %o',
|
|
54365
|
-
if (cache?.hash ===
|
|
54366
|
-
debug6("got matching cache SHA1 hash: %o",
|
|
54363
|
+
const hash2 = shasum.digest("hex");
|
|
54364
|
+
debug6('generated SHA1 hash for "data:" URI: %o', hash2);
|
|
54365
|
+
if (cache?.hash === hash2) {
|
|
54366
|
+
debug6("got matching cache SHA1 hash: %o", hash2);
|
|
54367
54367
|
throw new notmodified_1.default();
|
|
54368
54368
|
} else {
|
|
54369
54369
|
debug6('creating Readable stream from "data:" URI buffer');
|
|
54370
54370
|
const { buffer } = (0, data_uri_to_buffer_1.dataUriToBuffer)(uri);
|
|
54371
|
-
return new DataReadable(
|
|
54371
|
+
return new DataReadable(hash2, Buffer.from(buffer));
|
|
54372
54372
|
}
|
|
54373
54373
|
};
|
|
54374
54374
|
exports.data = data;
|
|
@@ -75363,14 +75363,14 @@ var require_dist10 = __commonJS({
|
|
|
75363
75363
|
(0, quickjs_emscripten_1.getQuickJS)(),
|
|
75364
75364
|
this.loadPacFile()
|
|
75365
75365
|
]);
|
|
75366
|
-
const
|
|
75367
|
-
if (this.resolver && this.resolverHash ===
|
|
75366
|
+
const hash2 = crypto3.createHash("sha1").update(code).digest("hex");
|
|
75367
|
+
if (this.resolver && this.resolverHash === hash2) {
|
|
75368
75368
|
debug6("Same sha1 hash for code - contents have not changed, reusing previous proxy resolver");
|
|
75369
75369
|
return this.resolver;
|
|
75370
75370
|
}
|
|
75371
75371
|
debug6("Creating new proxy resolver instance");
|
|
75372
75372
|
this.resolver = (0, pac_resolver_1.createPacResolver)(qjs, code, this.opts);
|
|
75373
|
-
this.resolverHash =
|
|
75373
|
+
this.resolverHash = hash2;
|
|
75374
75374
|
return this.resolver;
|
|
75375
75375
|
} catch (err) {
|
|
75376
75376
|
if (this.resolver && err.code === "ENOTMODIFIED") {
|
|
@@ -102433,6 +102433,7 @@ var mediaRules = [
|
|
|
102433
102433
|
const timedTagPositions = [];
|
|
102434
102434
|
for (const tag of tags) {
|
|
102435
102435
|
if (tag.name === "video" || tag.name === "audio") continue;
|
|
102436
|
+
if (readAttr(tag.raw, "data-composition-id")) continue;
|
|
102436
102437
|
if (readAttr(tag.raw, "data-start")) {
|
|
102437
102438
|
timedTagPositions.push({
|
|
102438
102439
|
name: tag.name,
|
|
@@ -103539,7 +103540,8 @@ function lintHyperframeHtml(html, options = {}) {
|
|
|
103539
103540
|
}
|
|
103540
103541
|
|
|
103541
103542
|
// ../core/src/compiler/rewriteSubCompPaths.ts
|
|
103542
|
-
import {
|
|
103543
|
+
import { posix } from "path";
|
|
103544
|
+
var { join: join4, resolve: resolve6, dirname: dirname4 } = posix;
|
|
103543
103545
|
var PATH_ATTRS = ["src", "href"];
|
|
103544
103546
|
var CSS_URL_RE = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
|
|
103545
103547
|
function isAbsoluteOrSpecial(val) {
|
|
@@ -103706,11 +103708,19 @@ async function pageScreenshotCapture(page, options) {
|
|
|
103706
103708
|
});
|
|
103707
103709
|
return Buffer.from(result.data, "base64");
|
|
103708
103710
|
}
|
|
103711
|
+
var TRANSPARENT_BG_STYLE_ID = "__hf_transparent_bg__";
|
|
103709
103712
|
async function initTransparentBackground(page) {
|
|
103710
103713
|
const client = await getCdpSession(page);
|
|
103711
103714
|
await client.send("Emulation.setDefaultBackgroundColorOverride", {
|
|
103712
103715
|
color: { r: 0, g: 0, b: 0, a: 0 }
|
|
103713
103716
|
});
|
|
103717
|
+
await page.evaluate((styleId) => {
|
|
103718
|
+
if (document.getElementById(styleId)) return;
|
|
103719
|
+
const style = document.createElement("style");
|
|
103720
|
+
style.id = styleId;
|
|
103721
|
+
style.textContent = "html,body,[data-composition-id]{background:transparent !important;background-color:transparent !important;background-image:none !important;}";
|
|
103722
|
+
document.head.appendChild(style);
|
|
103723
|
+
}, TRANSPARENT_BG_STYLE_ID);
|
|
103714
103724
|
}
|
|
103715
103725
|
async function captureAlphaPng(page, width, height) {
|
|
103716
103726
|
const client = await getCdpSession(page);
|
|
@@ -103724,6 +103734,57 @@ async function captureAlphaPng(page, width, height) {
|
|
|
103724
103734
|
});
|
|
103725
103735
|
return Buffer.from(result.data, "base64");
|
|
103726
103736
|
}
|
|
103737
|
+
var DOM_LAYER_MASK_STYLE_ID = "__hf_dom_layer_mask__";
|
|
103738
|
+
async function applyDomLayerMask(page, showIds, extraHideIds) {
|
|
103739
|
+
await page.evaluate(
|
|
103740
|
+
(args) => {
|
|
103741
|
+
const existing = document.getElementById(args.styleId);
|
|
103742
|
+
if (existing) existing.remove();
|
|
103743
|
+
const showSelectors = [];
|
|
103744
|
+
for (const id of args.show) {
|
|
103745
|
+
const escaped = CSS.escape(id);
|
|
103746
|
+
showSelectors.push(`#${escaped}`, `#${escaped} *`);
|
|
103747
|
+
const renderEscaped = CSS.escape(`__render_frame_${id}__`);
|
|
103748
|
+
showSelectors.push(`#${renderEscaped}`, `#${renderEscaped} *`);
|
|
103749
|
+
}
|
|
103750
|
+
const massHideRule = "body *{visibility:hidden !important;}";
|
|
103751
|
+
const showRule = showSelectors.length === 0 ? "" : `${showSelectors.join(",")}{visibility:visible !important;}`;
|
|
103752
|
+
const style = document.createElement("style");
|
|
103753
|
+
style.id = args.styleId;
|
|
103754
|
+
style.textContent = `${massHideRule}
|
|
103755
|
+
${showRule}`;
|
|
103756
|
+
document.head.appendChild(style);
|
|
103757
|
+
for (const id of args.hide) {
|
|
103758
|
+
const el = document.getElementById(id);
|
|
103759
|
+
if (el) {
|
|
103760
|
+
el.style.setProperty("visibility", "hidden", "important");
|
|
103761
|
+
}
|
|
103762
|
+
const img = document.getElementById(`__render_frame_${id}__`);
|
|
103763
|
+
if (img) {
|
|
103764
|
+
img.style.setProperty("visibility", "hidden", "important");
|
|
103765
|
+
}
|
|
103766
|
+
}
|
|
103767
|
+
},
|
|
103768
|
+
{ show: showIds, hide: extraHideIds, styleId: DOM_LAYER_MASK_STYLE_ID }
|
|
103769
|
+
);
|
|
103770
|
+
}
|
|
103771
|
+
async function removeDomLayerMask(page, extraHideIds) {
|
|
103772
|
+
await page.evaluate(
|
|
103773
|
+
(args) => {
|
|
103774
|
+
const style = document.getElementById(args.styleId);
|
|
103775
|
+
if (style) style.remove();
|
|
103776
|
+
for (const id of args.hide) {
|
|
103777
|
+
const el = document.getElementById(id);
|
|
103778
|
+
if (el) {
|
|
103779
|
+
el.style.removeProperty("visibility");
|
|
103780
|
+
}
|
|
103781
|
+
const img = document.getElementById(`__render_frame_${id}__`);
|
|
103782
|
+
if (img) img.style.removeProperty("visibility");
|
|
103783
|
+
}
|
|
103784
|
+
},
|
|
103785
|
+
{ hide: extraHideIds, styleId: DOM_LAYER_MASK_STYLE_ID }
|
|
103786
|
+
);
|
|
103787
|
+
}
|
|
103727
103788
|
async function injectVideoFramesBatch(page, updates) {
|
|
103728
103789
|
if (updates.length === 0) return;
|
|
103729
103790
|
await page.evaluate(
|
|
@@ -103764,6 +103825,7 @@ async function injectVideoFramesBatch(page, updates) {
|
|
|
103764
103825
|
img.style.objectPosition = computedStyle.objectPosition;
|
|
103765
103826
|
img.style.zIndex = computedStyle.zIndex;
|
|
103766
103827
|
for (const property of visualProperties) {
|
|
103828
|
+
if (property === "opacity") continue;
|
|
103767
103829
|
if (sourceIsStatic && (property === "top" || property === "left" || property === "right" || property === "bottom" || property === "inset")) {
|
|
103768
103830
|
continue;
|
|
103769
103831
|
}
|
|
@@ -104667,6 +104729,10 @@ function isHdrColorSpace(cs) {
|
|
|
104667
104729
|
if (!cs) return false;
|
|
104668
104730
|
return cs.colorPrimaries.includes("bt2020") || cs.colorSpace.includes("bt2020") || cs.colorTransfer === "smpte2084" || cs.colorTransfer === "arib-std-b67";
|
|
104669
104731
|
}
|
|
104732
|
+
function detectTransfer(cs) {
|
|
104733
|
+
if (cs?.colorTransfer === "smpte2084") return "pq";
|
|
104734
|
+
return "hlg";
|
|
104735
|
+
}
|
|
104670
104736
|
var DEFAULT_HDR10_MASTERING = {
|
|
104671
104737
|
masterDisplay: "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)",
|
|
104672
104738
|
maxCll: "1000,400"
|
|
@@ -105161,10 +105227,10 @@ import { finished } from "stream/promises";
|
|
|
105161
105227
|
var downloadPathCache = /* @__PURE__ */ new Map();
|
|
105162
105228
|
var inFlightDownloads = /* @__PURE__ */ new Map();
|
|
105163
105229
|
function getFilenameFromUrl(url) {
|
|
105164
|
-
const
|
|
105230
|
+
const hash2 = createHash("md5").update(url).digest("hex").slice(0, 12);
|
|
105165
105231
|
const urlObj = new URL(url);
|
|
105166
105232
|
const ext = extname2(urlObj.pathname) || ".mp4";
|
|
105167
|
-
return `download_${
|
|
105233
|
+
return `download_${hash2}${ext}`;
|
|
105168
105234
|
}
|
|
105169
105235
|
async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
|
|
105170
105236
|
const cachedPath = downloadPathCache.get(url);
|
|
@@ -105665,34 +105731,6 @@ function createVideoFrameInjector(frameLookup, config2) {
|
|
|
105665
105731
|
}
|
|
105666
105732
|
};
|
|
105667
105733
|
}
|
|
105668
|
-
async function hideVideoElements(page, videoIds) {
|
|
105669
|
-
if (videoIds.length === 0) return;
|
|
105670
|
-
await page.evaluate((ids) => {
|
|
105671
|
-
for (const id of ids) {
|
|
105672
|
-
const el = document.getElementById(id);
|
|
105673
|
-
if (el) {
|
|
105674
|
-
el.style.setProperty("visibility", "hidden", "important");
|
|
105675
|
-
el.style.setProperty("opacity", "0", "important");
|
|
105676
|
-
const img = document.getElementById(`__render_frame_${id}__`);
|
|
105677
|
-
if (img) img.style.setProperty("visibility", "hidden", "important");
|
|
105678
|
-
}
|
|
105679
|
-
}
|
|
105680
|
-
}, videoIds);
|
|
105681
|
-
}
|
|
105682
|
-
async function showVideoElements(page, videoIds) {
|
|
105683
|
-
if (videoIds.length === 0) return;
|
|
105684
|
-
await page.evaluate((ids) => {
|
|
105685
|
-
for (const id of ids) {
|
|
105686
|
-
const el = document.getElementById(id);
|
|
105687
|
-
if (el) {
|
|
105688
|
-
el.style.removeProperty("visibility");
|
|
105689
|
-
el.style.removeProperty("opacity");
|
|
105690
|
-
const img = document.getElementById(`__render_frame_${id}__`);
|
|
105691
|
-
if (img) img.style.removeProperty("visibility");
|
|
105692
|
-
}
|
|
105693
|
-
}
|
|
105694
|
-
}, videoIds);
|
|
105695
|
-
}
|
|
105696
105734
|
async function queryElementStacking(page, nativeHdrVideoIds) {
|
|
105697
105735
|
const hdrIds = Array.from(nativeHdrVideoIds);
|
|
105698
105736
|
return page.evaluate((hdrIdList) => {
|
|
@@ -105710,14 +105748,103 @@ async function queryElementStacking(page, nativeHdrVideoIds) {
|
|
|
105710
105748
|
}
|
|
105711
105749
|
return 0;
|
|
105712
105750
|
}
|
|
105751
|
+
function getEffectiveBorderRadius(node) {
|
|
105752
|
+
function resolveRadius(value, el) {
|
|
105753
|
+
if (value.includes("%")) {
|
|
105754
|
+
const pct = parseFloat(value) / 100;
|
|
105755
|
+
const htmlEl = el;
|
|
105756
|
+
const w = htmlEl.offsetWidth || 0;
|
|
105757
|
+
const h = htmlEl.offsetHeight || 0;
|
|
105758
|
+
return pct * Math.min(w, h);
|
|
105759
|
+
}
|
|
105760
|
+
return parseFloat(value) || 0;
|
|
105761
|
+
}
|
|
105762
|
+
const selfCs = window.getComputedStyle(node);
|
|
105763
|
+
const selfRadii = [
|
|
105764
|
+
resolveRadius(selfCs.borderTopLeftRadius, node),
|
|
105765
|
+
resolveRadius(selfCs.borderTopRightRadius, node),
|
|
105766
|
+
resolveRadius(selfCs.borderBottomRightRadius, node),
|
|
105767
|
+
resolveRadius(selfCs.borderBottomLeftRadius, node)
|
|
105768
|
+
];
|
|
105769
|
+
if (selfRadii[0] > 0 || selfRadii[1] > 0 || selfRadii[2] > 0 || selfRadii[3] > 0) {
|
|
105770
|
+
return selfRadii;
|
|
105771
|
+
}
|
|
105772
|
+
let current = node.parentElement;
|
|
105773
|
+
while (current) {
|
|
105774
|
+
const cs = window.getComputedStyle(current);
|
|
105775
|
+
if (cs.overflow !== "visible") {
|
|
105776
|
+
const tl = resolveRadius(cs.borderTopLeftRadius, current);
|
|
105777
|
+
const tr = resolveRadius(cs.borderTopRightRadius, current);
|
|
105778
|
+
const brr = resolveRadius(cs.borderBottomRightRadius, current);
|
|
105779
|
+
const bl = resolveRadius(cs.borderBottomLeftRadius, current);
|
|
105780
|
+
if (tl > 0 || tr > 0 || brr > 0 || bl > 0) {
|
|
105781
|
+
return [tl, tr, brr, bl];
|
|
105782
|
+
}
|
|
105783
|
+
}
|
|
105784
|
+
current = current.parentElement;
|
|
105785
|
+
}
|
|
105786
|
+
return [0, 0, 0, 0];
|
|
105787
|
+
}
|
|
105788
|
+
function getEffectiveOpacity(node) {
|
|
105789
|
+
let opacity = 1;
|
|
105790
|
+
let current = node;
|
|
105791
|
+
while (current) {
|
|
105792
|
+
const cs = window.getComputedStyle(current);
|
|
105793
|
+
const val = parseFloat(cs.opacity);
|
|
105794
|
+
opacity *= Number.isNaN(val) ? 1 : val;
|
|
105795
|
+
current = current.parentElement;
|
|
105796
|
+
}
|
|
105797
|
+
return opacity;
|
|
105798
|
+
}
|
|
105799
|
+
function getViewportMatrix(node) {
|
|
105800
|
+
const chain = [];
|
|
105801
|
+
let current = node;
|
|
105802
|
+
while (current instanceof HTMLElement) {
|
|
105803
|
+
chain.push(current);
|
|
105804
|
+
const next = current.offsetParent ?? current.parentElement;
|
|
105805
|
+
if (next === current) break;
|
|
105806
|
+
current = next;
|
|
105807
|
+
}
|
|
105808
|
+
let mat = new DOMMatrix();
|
|
105809
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
105810
|
+
const htmlEl = chain[i];
|
|
105811
|
+
if (!htmlEl) continue;
|
|
105812
|
+
mat = mat.translate(htmlEl.offsetLeft, htmlEl.offsetTop);
|
|
105813
|
+
const cs = window.getComputedStyle(htmlEl);
|
|
105814
|
+
if (cs.transform && cs.transform !== "none") {
|
|
105815
|
+
const origin = cs.transformOrigin.split(" ");
|
|
105816
|
+
const ox = resolveLength(origin[0] ?? "0", htmlEl.offsetWidth);
|
|
105817
|
+
const oy = resolveLength(origin[1] ?? "0", htmlEl.offsetHeight);
|
|
105818
|
+
try {
|
|
105819
|
+
const t = new DOMMatrix(cs.transform);
|
|
105820
|
+
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)) {
|
|
105821
|
+
mat = mat.translate(ox, oy).multiply(t).translate(-ox, -oy);
|
|
105822
|
+
}
|
|
105823
|
+
} catch {
|
|
105824
|
+
}
|
|
105825
|
+
}
|
|
105826
|
+
}
|
|
105827
|
+
return mat.toString();
|
|
105828
|
+
}
|
|
105829
|
+
function resolveLength(value, basis) {
|
|
105830
|
+
if (value.endsWith("%")) {
|
|
105831
|
+
const pct = parseFloat(value) / 100;
|
|
105832
|
+
return Number.isFinite(pct) ? pct * basis : 0;
|
|
105833
|
+
}
|
|
105834
|
+
const n = parseFloat(value);
|
|
105835
|
+
return Number.isFinite(n) ? n : 0;
|
|
105836
|
+
}
|
|
105713
105837
|
for (const el of elements) {
|
|
105714
105838
|
const id = el.id;
|
|
105715
105839
|
if (!id) continue;
|
|
105716
105840
|
const rect = el.getBoundingClientRect();
|
|
105717
105841
|
const style = window.getComputedStyle(el);
|
|
105718
105842
|
const zIndex = getEffectiveZIndex(el);
|
|
105719
|
-
const
|
|
105843
|
+
const isHdrEl = hdrSet.has(id);
|
|
105844
|
+
const opacityStartNode = isHdrEl ? el.parentElement : el;
|
|
105845
|
+
const opacity = opacityStartNode ? getEffectiveOpacity(opacityStartNode) : 1;
|
|
105720
105846
|
const visible = style.visibility !== "hidden" && style.display !== "none" && rect.width > 0 && rect.height > 0;
|
|
105847
|
+
const htmlEl = el instanceof HTMLElement ? el : null;
|
|
105721
105848
|
results.push({
|
|
105722
105849
|
id,
|
|
105723
105850
|
zIndex,
|
|
@@ -105725,9 +105852,16 @@ async function queryElementStacking(page, nativeHdrVideoIds) {
|
|
|
105725
105852
|
y: Math.round(rect.y),
|
|
105726
105853
|
width: Math.round(rect.width),
|
|
105727
105854
|
height: Math.round(rect.height),
|
|
105855
|
+
layoutWidth: htmlEl?.offsetWidth || Math.round(rect.width),
|
|
105856
|
+
layoutHeight: htmlEl?.offsetHeight || Math.round(rect.height),
|
|
105728
105857
|
opacity,
|
|
105729
105858
|
visible,
|
|
105730
|
-
isHdr: hdrSet.has(id)
|
|
105859
|
+
isHdr: hdrSet.has(id),
|
|
105860
|
+
// For HDR elements, use the full accumulated viewport matrix so the
|
|
105861
|
+
// affine blit can apply rotation/scale/translate properly. For DOM
|
|
105862
|
+
// elements, the element-level transform is sufficient for reference.
|
|
105863
|
+
transform: isHdrEl ? getViewportMatrix(el) : style.transform || "none",
|
|
105864
|
+
borderRadius: isHdrEl ? getEffectiveBorderRadius(el) : [0, 0, 0, 0]
|
|
105731
105865
|
});
|
|
105732
105866
|
}
|
|
105733
105867
|
return results;
|
|
@@ -106485,6 +106619,99 @@ function blitRgb48leRegion(canvas, source2, dx, dy, sw, sh, canvasWidth, canvasH
|
|
|
106485
106619
|
}
|
|
106486
106620
|
}
|
|
106487
106621
|
}
|
|
106622
|
+
function blitRgb48leAffine(canvas, source2, matrix, srcW, srcH, canvasW, canvasH, opacity, borderRadius) {
|
|
106623
|
+
const a = matrix[0];
|
|
106624
|
+
const b = matrix[1];
|
|
106625
|
+
const c = matrix[2];
|
|
106626
|
+
const d = matrix[3];
|
|
106627
|
+
const tx = matrix[4];
|
|
106628
|
+
const ty = matrix[5];
|
|
106629
|
+
if (a === void 0 || b === void 0 || c === void 0 || d === void 0 || tx === void 0 || ty === void 0)
|
|
106630
|
+
return;
|
|
106631
|
+
const det = a * d - b * c;
|
|
106632
|
+
if (Math.abs(det) < 1e-10) return;
|
|
106633
|
+
const invA = d / det;
|
|
106634
|
+
const invB = -b / det;
|
|
106635
|
+
const invC = -c / det;
|
|
106636
|
+
const invD = a / det;
|
|
106637
|
+
const invTx = -(invA * tx + invC * ty);
|
|
106638
|
+
const invTy = -(invB * tx + invD * ty);
|
|
106639
|
+
const op = opacity ?? 1;
|
|
106640
|
+
const hasMask = borderRadius !== void 0;
|
|
106641
|
+
const corners = [
|
|
106642
|
+
[tx, ty],
|
|
106643
|
+
[a * srcW + tx, b * srcW + ty],
|
|
106644
|
+
[c * srcH + tx, d * srcH + ty],
|
|
106645
|
+
[a * srcW + c * srcH + tx, b * srcW + d * srcH + ty]
|
|
106646
|
+
];
|
|
106647
|
+
let minX = canvasW, maxX = 0, minY = canvasH, maxY = 0;
|
|
106648
|
+
for (const corner of corners) {
|
|
106649
|
+
const cx = corner[0] ?? 0;
|
|
106650
|
+
const cy = corner[1] ?? 0;
|
|
106651
|
+
if (cx < minX) minX = cx;
|
|
106652
|
+
if (cx > maxX) maxX = cx;
|
|
106653
|
+
if (cy < minY) minY = cy;
|
|
106654
|
+
if (cy > maxY) maxY = cy;
|
|
106655
|
+
}
|
|
106656
|
+
const startX = Math.max(0, Math.floor(minX));
|
|
106657
|
+
const endX = Math.min(canvasW, Math.ceil(maxX));
|
|
106658
|
+
const startY = Math.max(0, Math.floor(minY));
|
|
106659
|
+
const endY = Math.min(canvasH, Math.ceil(maxY));
|
|
106660
|
+
for (let dy = startY; dy < endY; dy++) {
|
|
106661
|
+
for (let dx = startX; dx < endX; dx++) {
|
|
106662
|
+
const sx = invA * dx + invC * dy + invTx;
|
|
106663
|
+
const sy = invB * dx + invD * dy + invTy;
|
|
106664
|
+
if (sx < 0 || sy < 0 || sx >= srcW || sy >= srcH) continue;
|
|
106665
|
+
let effectiveOp = op;
|
|
106666
|
+
if (hasMask) {
|
|
106667
|
+
const ma = roundedRectAlpha(sx, sy, srcW, srcH, borderRadius);
|
|
106668
|
+
if (ma <= 0) continue;
|
|
106669
|
+
effectiveOp *= ma;
|
|
106670
|
+
}
|
|
106671
|
+
const x0 = Math.floor(sx);
|
|
106672
|
+
const y0 = Math.floor(sy);
|
|
106673
|
+
const fx = sx - x0;
|
|
106674
|
+
const fy = sy - y0;
|
|
106675
|
+
const x1 = Math.min(x0 + 1, srcW - 1);
|
|
106676
|
+
const y1 = Math.min(y0 + 1, srcH - 1);
|
|
106677
|
+
const off00 = (y0 * srcW + x0) * 6;
|
|
106678
|
+
const off10 = (y0 * srcW + x1) * 6;
|
|
106679
|
+
const off01 = (y1 * srcW + x0) * 6;
|
|
106680
|
+
const off11 = (y1 * srcW + x1) * 6;
|
|
106681
|
+
const w00 = (1 - fx) * (1 - fy);
|
|
106682
|
+
const w10 = fx * (1 - fy);
|
|
106683
|
+
const w01 = (1 - fx) * fy;
|
|
106684
|
+
const w11 = fx * fy;
|
|
106685
|
+
const sr = source2.readUInt16LE(off00) * w00 + source2.readUInt16LE(off10) * w10 + source2.readUInt16LE(off01) * w01 + source2.readUInt16LE(off11) * w11;
|
|
106686
|
+
const sg = source2.readUInt16LE(off00 + 2) * w00 + source2.readUInt16LE(off10 + 2) * w10 + source2.readUInt16LE(off01 + 2) * w01 + source2.readUInt16LE(off11 + 2) * w11;
|
|
106687
|
+
const sb = source2.readUInt16LE(off00 + 4) * w00 + source2.readUInt16LE(off10 + 4) * w10 + source2.readUInt16LE(off01 + 4) * w01 + source2.readUInt16LE(off11 + 4) * w11;
|
|
106688
|
+
const dstOff = (dy * canvasW + dx) * 6;
|
|
106689
|
+
if (effectiveOp >= 0.999) {
|
|
106690
|
+
canvas.writeUInt16LE(Math.round(sr), dstOff);
|
|
106691
|
+
canvas.writeUInt16LE(Math.round(sg), dstOff + 2);
|
|
106692
|
+
canvas.writeUInt16LE(Math.round(sb), dstOff + 4);
|
|
106693
|
+
} else {
|
|
106694
|
+
const invEff = 1 - effectiveOp;
|
|
106695
|
+
const dr = canvas.readUInt16LE(dstOff);
|
|
106696
|
+
const dg = canvas.readUInt16LE(dstOff + 2);
|
|
106697
|
+
const db = canvas.readUInt16LE(dstOff + 4);
|
|
106698
|
+
canvas.writeUInt16LE(Math.round(sr * effectiveOp + dr * invEff), dstOff);
|
|
106699
|
+
canvas.writeUInt16LE(Math.round(sg * effectiveOp + dg * invEff), dstOff + 2);
|
|
106700
|
+
canvas.writeUInt16LE(Math.round(sb * effectiveOp + db * invEff), dstOff + 4);
|
|
106701
|
+
}
|
|
106702
|
+
}
|
|
106703
|
+
}
|
|
106704
|
+
}
|
|
106705
|
+
function parseTransformMatrix(css) {
|
|
106706
|
+
if (!css || css === "none") return null;
|
|
106707
|
+
const match2 = css.match(
|
|
106708
|
+
/^matrix\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,)]+)\s*\)$/
|
|
106709
|
+
);
|
|
106710
|
+
if (!match2) return null;
|
|
106711
|
+
const values = match2.slice(1, 7).map(Number);
|
|
106712
|
+
if (!values.every(Number.isFinite)) return null;
|
|
106713
|
+
return values;
|
|
106714
|
+
}
|
|
106488
106715
|
|
|
106489
106716
|
// ../engine/src/utils/layerCompositor.ts
|
|
106490
106717
|
function groupIntoLayers(elements) {
|
|
@@ -106505,6 +106732,637 @@ function groupIntoLayers(elements) {
|
|
|
106505
106732
|
return layers;
|
|
106506
106733
|
}
|
|
106507
106734
|
|
|
106735
|
+
// ../engine/src/utils/shaderTransitions.ts
|
|
106736
|
+
var PQ_M1 = 0.1593017578125;
|
|
106737
|
+
var PQ_M2 = 78.84375;
|
|
106738
|
+
var PQ_C1 = 0.8359375;
|
|
106739
|
+
var PQ_C2 = 18.8515625;
|
|
106740
|
+
var PQ_C3 = 18.6875;
|
|
106741
|
+
function pqEotf(signal) {
|
|
106742
|
+
const sp = Math.pow(Math.max(0, signal), 1 / PQ_M2);
|
|
106743
|
+
const num = Math.max(sp - PQ_C1, 0);
|
|
106744
|
+
const den = PQ_C2 - PQ_C3 * sp;
|
|
106745
|
+
return den > 0 ? Math.pow(num / den, 1 / PQ_M1) : 0;
|
|
106746
|
+
}
|
|
106747
|
+
function pqOetf(linear) {
|
|
106748
|
+
const lp = Math.pow(Math.max(0, linear), PQ_M1);
|
|
106749
|
+
return Math.pow((PQ_C1 + PQ_C2 * lp) / (1 + PQ_C3 * lp), PQ_M2);
|
|
106750
|
+
}
|
|
106751
|
+
function hlgEotf(signal) {
|
|
106752
|
+
const a = 0.17883277;
|
|
106753
|
+
const b = 1 - 4 * a;
|
|
106754
|
+
const c = 0.5 - a * Math.log(4 * a);
|
|
106755
|
+
if (signal <= 0.5) {
|
|
106756
|
+
return signal * signal / 3;
|
|
106757
|
+
}
|
|
106758
|
+
return (Math.exp((signal - c) / a) + b) / 12;
|
|
106759
|
+
}
|
|
106760
|
+
function hlgOetf(linear) {
|
|
106761
|
+
const a = 0.17883277;
|
|
106762
|
+
const b = 1 - 4 * a;
|
|
106763
|
+
const c = 0.5 - a * Math.log(4 * a);
|
|
106764
|
+
if (linear <= 1 / 12) {
|
|
106765
|
+
return Math.sqrt(3 * linear);
|
|
106766
|
+
}
|
|
106767
|
+
return a * Math.log(12 * linear - b) + c;
|
|
106768
|
+
}
|
|
106769
|
+
function buildLut(fn) {
|
|
106770
|
+
const lut = new Uint16Array(65536);
|
|
106771
|
+
for (let i = 0; i < 65536; i++) {
|
|
106772
|
+
lut[i] = Math.round(fn(i / 65535) * 65535);
|
|
106773
|
+
}
|
|
106774
|
+
return lut;
|
|
106775
|
+
}
|
|
106776
|
+
var HLG_OOTF_LW = 1e3;
|
|
106777
|
+
var HLG_OOTF_GAMMA = 1.2 * Math.pow(1.111, Math.log2(HLG_OOTF_LW / 1e3));
|
|
106778
|
+
function hlgSceneToPqDisplay(sceneLinear) {
|
|
106779
|
+
const displayNits = HLG_OOTF_LW * Math.pow(Math.max(0, sceneLinear), HLG_OOTF_GAMMA);
|
|
106780
|
+
return displayNits / 1e4;
|
|
106781
|
+
}
|
|
106782
|
+
function pqDisplayToHlgScene(displayNormalized) {
|
|
106783
|
+
const displayNits = displayNormalized * 1e4;
|
|
106784
|
+
return Math.pow(Math.max(0, displayNits / HLG_OOTF_LW), 1 / HLG_OOTF_GAMMA);
|
|
106785
|
+
}
|
|
106786
|
+
var hlgToPqLut = null;
|
|
106787
|
+
var pqToHlgLut = null;
|
|
106788
|
+
function getHlgToPqLut() {
|
|
106789
|
+
if (!hlgToPqLut) hlgToPqLut = buildLut((v) => pqOetf(hlgSceneToPqDisplay(hlgEotf(v))));
|
|
106790
|
+
return hlgToPqLut;
|
|
106791
|
+
}
|
|
106792
|
+
function getPqToHlgLut() {
|
|
106793
|
+
if (!pqToHlgLut) pqToHlgLut = buildLut((v) => hlgOetf(pqDisplayToHlgScene(pqEotf(v))));
|
|
106794
|
+
return pqToHlgLut;
|
|
106795
|
+
}
|
|
106796
|
+
function convertTransfer(buf, from2, to) {
|
|
106797
|
+
if (from2 === to) return;
|
|
106798
|
+
const lut = from2 === "hlg" ? getHlgToPqLut() : getPqToHlgLut();
|
|
106799
|
+
const len = buf.length / 2;
|
|
106800
|
+
for (let i = 0; i < len; i++) {
|
|
106801
|
+
const off = i * 2;
|
|
106802
|
+
buf.writeUInt16LE(lut[buf.readUInt16LE(off)] ?? 0, off);
|
|
106803
|
+
}
|
|
106804
|
+
}
|
|
106805
|
+
function sampleRgb48le(buf, u, v, w, h) {
|
|
106806
|
+
const uc = Math.max(0, Math.min(1, u));
|
|
106807
|
+
const vc = Math.max(0, Math.min(1, v));
|
|
106808
|
+
const sx = uc * (w - 1);
|
|
106809
|
+
const sy = vc * (h - 1);
|
|
106810
|
+
const x0 = Math.floor(sx);
|
|
106811
|
+
const y0 = Math.floor(sy);
|
|
106812
|
+
const x1 = Math.min(x0 + 1, w - 1);
|
|
106813
|
+
const y1 = Math.min(y0 + 1, h - 1);
|
|
106814
|
+
const fx = sx - x0;
|
|
106815
|
+
const fy = sy - y0;
|
|
106816
|
+
const w00 = (1 - fx) * (1 - fy);
|
|
106817
|
+
const w10 = fx * (1 - fy);
|
|
106818
|
+
const w01 = (1 - fx) * fy;
|
|
106819
|
+
const w11 = fx * fy;
|
|
106820
|
+
const off00 = (y0 * w + x0) * 6;
|
|
106821
|
+
const off10 = (y0 * w + x1) * 6;
|
|
106822
|
+
const off01 = (y1 * w + x0) * 6;
|
|
106823
|
+
const off11 = (y1 * w + x1) * 6;
|
|
106824
|
+
const r = Math.round(
|
|
106825
|
+
buf.readUInt16LE(off00) * w00 + buf.readUInt16LE(off10) * w10 + buf.readUInt16LE(off01) * w01 + buf.readUInt16LE(off11) * w11
|
|
106826
|
+
);
|
|
106827
|
+
const g = Math.round(
|
|
106828
|
+
buf.readUInt16LE(off00 + 2) * w00 + buf.readUInt16LE(off10 + 2) * w10 + buf.readUInt16LE(off01 + 2) * w01 + buf.readUInt16LE(off11 + 2) * w11
|
|
106829
|
+
);
|
|
106830
|
+
const b = Math.round(
|
|
106831
|
+
buf.readUInt16LE(off00 + 4) * w00 + buf.readUInt16LE(off10 + 4) * w10 + buf.readUInt16LE(off01 + 4) * w01 + buf.readUInt16LE(off11 + 4) * w11
|
|
106832
|
+
);
|
|
106833
|
+
return [r, g, b];
|
|
106834
|
+
}
|
|
106835
|
+
function mix16(a, b, t) {
|
|
106836
|
+
return Math.round(a * (1 - t) + b * t);
|
|
106837
|
+
}
|
|
106838
|
+
function clamp16(v) {
|
|
106839
|
+
return Math.max(0, Math.min(65535, v));
|
|
106840
|
+
}
|
|
106841
|
+
function smoothstep(edge0, edge1, x) {
|
|
106842
|
+
const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
|
|
106843
|
+
return t * t * (3 - 2 * t);
|
|
106844
|
+
}
|
|
106845
|
+
function hash(x, y) {
|
|
106846
|
+
return (Math.sin(x * 127.1 + y * 311.7) * 43758.5453 % 1 + 1) % 1;
|
|
106847
|
+
}
|
|
106848
|
+
function vnoise(px, py) {
|
|
106849
|
+
const ix = Math.floor(px);
|
|
106850
|
+
const iy = Math.floor(py);
|
|
106851
|
+
let fx = px - ix;
|
|
106852
|
+
let fy = py - iy;
|
|
106853
|
+
fx = fx * fx * fx * (fx * (fx * 6 - 15) + 10);
|
|
106854
|
+
fy = fy * fy * fy * (fy * (fy * 6 - 15) + 10);
|
|
106855
|
+
const h00 = hash(ix, iy);
|
|
106856
|
+
const h10 = hash(ix + 1, iy);
|
|
106857
|
+
const h01 = hash(ix, iy + 1);
|
|
106858
|
+
const h11 = hash(ix + 1, iy + 1);
|
|
106859
|
+
return h00 * (1 - fx) * (1 - fy) + h10 * fx * (1 - fy) + h01 * (1 - fx) * fy + h11 * fx * fy;
|
|
106860
|
+
}
|
|
106861
|
+
var ROT_A = 0.8;
|
|
106862
|
+
var ROT_B = 0.6;
|
|
106863
|
+
function fbm(px, py) {
|
|
106864
|
+
let value = 0;
|
|
106865
|
+
let amplitude = 0.5;
|
|
106866
|
+
let x = px;
|
|
106867
|
+
let y = py;
|
|
106868
|
+
for (let i = 0; i < 5; i++) {
|
|
106869
|
+
value += amplitude * vnoise(x, y);
|
|
106870
|
+
const nx = ROT_A * x - ROT_B * y;
|
|
106871
|
+
const ny = ROT_B * x + ROT_A * y;
|
|
106872
|
+
x = nx * 2.02;
|
|
106873
|
+
y = ny * 2.02;
|
|
106874
|
+
amplitude *= 0.5;
|
|
106875
|
+
}
|
|
106876
|
+
return value;
|
|
106877
|
+
}
|
|
106878
|
+
var TRANSITIONS = {};
|
|
106879
|
+
var crossfade = (from2, to, out, w, h, p) => {
|
|
106880
|
+
const inv = 1 - p;
|
|
106881
|
+
for (let i = 0; i < w * h; i++) {
|
|
106882
|
+
const o = i * 6;
|
|
106883
|
+
out.writeUInt16LE(Math.round(from2.readUInt16LE(o) * inv + to.readUInt16LE(o) * p), o);
|
|
106884
|
+
out.writeUInt16LE(
|
|
106885
|
+
Math.round(from2.readUInt16LE(o + 2) * inv + to.readUInt16LE(o + 2) * p),
|
|
106886
|
+
o + 2
|
|
106887
|
+
);
|
|
106888
|
+
out.writeUInt16LE(
|
|
106889
|
+
Math.round(from2.readUInt16LE(o + 4) * inv + to.readUInt16LE(o + 4) * p),
|
|
106890
|
+
o + 4
|
|
106891
|
+
);
|
|
106892
|
+
}
|
|
106893
|
+
};
|
|
106894
|
+
TRANSITIONS["crossfade"] = crossfade;
|
|
106895
|
+
var flashThroughWhite = (from2, to, out, w, h, p) => {
|
|
106896
|
+
const toWhite = smoothstep(0, 0.45, p);
|
|
106897
|
+
const fromWhite = 1 - smoothstep(0.5, 1, p);
|
|
106898
|
+
const blend = smoothstep(0.35, 0.65, p);
|
|
106899
|
+
for (let i = 0; i < w * h; i++) {
|
|
106900
|
+
const o = i * 6;
|
|
106901
|
+
const fromR = mix16(from2.readUInt16LE(o), 65535, toWhite);
|
|
106902
|
+
const fromG = mix16(from2.readUInt16LE(o + 2), 65535, toWhite);
|
|
106903
|
+
const fromB = mix16(from2.readUInt16LE(o + 4), 65535, toWhite);
|
|
106904
|
+
const toR = mix16(to.readUInt16LE(o), 65535, fromWhite);
|
|
106905
|
+
const toG = mix16(to.readUInt16LE(o + 2), 65535, fromWhite);
|
|
106906
|
+
const toB = mix16(to.readUInt16LE(o + 4), 65535, fromWhite);
|
|
106907
|
+
out.writeUInt16LE(mix16(fromR, toR, blend), o);
|
|
106908
|
+
out.writeUInt16LE(mix16(fromG, toG, blend), o + 2);
|
|
106909
|
+
out.writeUInt16LE(mix16(fromB, toB, blend), o + 4);
|
|
106910
|
+
}
|
|
106911
|
+
};
|
|
106912
|
+
TRANSITIONS["flash-through-white"] = flashThroughWhite;
|
|
106913
|
+
var chromaticSplit = (from2, to, out, w, h, p) => {
|
|
106914
|
+
for (let i = 0; i < w * h; i++) {
|
|
106915
|
+
const ux = i % w / w;
|
|
106916
|
+
const uy = Math.floor(i / w) / h;
|
|
106917
|
+
const o = i * 6;
|
|
106918
|
+
const cx = ux - 0.5;
|
|
106919
|
+
const cy = uy - 0.5;
|
|
106920
|
+
const fromShift = p * 0.06;
|
|
106921
|
+
const fr = sampleRgb48le(from2, ux + cx * fromShift, uy + cy * fromShift, w, h)[0];
|
|
106922
|
+
const fg = sampleRgb48le(from2, ux, uy, w, h)[1];
|
|
106923
|
+
const fb = sampleRgb48le(from2, ux - cx * fromShift, uy - cy * fromShift, w, h)[2];
|
|
106924
|
+
const toShift = (1 - p) * 0.06;
|
|
106925
|
+
const tr = sampleRgb48le(to, ux - cx * toShift, uy - cy * toShift, w, h)[0];
|
|
106926
|
+
const tg = sampleRgb48le(to, ux, uy, w, h)[1];
|
|
106927
|
+
const tb = sampleRgb48le(to, ux + cx * toShift, uy + cy * toShift, w, h)[2];
|
|
106928
|
+
out.writeUInt16LE(clamp16(mix16(fr, tr, p)), o);
|
|
106929
|
+
out.writeUInt16LE(clamp16(mix16(fg, tg, p)), o + 2);
|
|
106930
|
+
out.writeUInt16LE(clamp16(mix16(fb, tb, p)), o + 4);
|
|
106931
|
+
}
|
|
106932
|
+
};
|
|
106933
|
+
TRANSITIONS["chromatic-split"] = chromaticSplit;
|
|
106934
|
+
var sdfIris = (from2, to, out, w, h, p) => {
|
|
106935
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
106936
|
+
for (let i = 0; i < w * h; i++) {
|
|
106937
|
+
const ux = i % w / w;
|
|
106938
|
+
const uy = Math.floor(i / w) / h;
|
|
106939
|
+
const o = i * 6;
|
|
106940
|
+
const ax = (ux - 0.5) * (w / h);
|
|
106941
|
+
const ay = uy - 0.5;
|
|
106942
|
+
const d = Math.sqrt(ax * ax + ay * ay);
|
|
106943
|
+
const radius = p * 1.2;
|
|
106944
|
+
const fw = 3e-3;
|
|
106945
|
+
const edge = smoothstep(radius + fw, radius - fw, d);
|
|
106946
|
+
const ring1 = Math.exp(-Math.abs(d - radius) * 25);
|
|
106947
|
+
const ring2 = Math.exp(-Math.abs(d - radius + 0.04) * 20) * 0.5;
|
|
106948
|
+
const ring3 = Math.exp(-Math.abs(d - radius + 0.08) * 15) * 0.25;
|
|
106949
|
+
const glow = (ring1 + ring2 + ring3) * p * (1 - p) * 4;
|
|
106950
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, ux, uy, w, h);
|
|
106951
|
+
const [toR, toG, toB] = sampleRgb48le(to, ux, uy, w, h);
|
|
106952
|
+
out.writeUInt16LE(clamp16(mix16(fromR, toR, edge) + accentBright[0] * glow * 0.6), o);
|
|
106953
|
+
out.writeUInt16LE(clamp16(mix16(fromG, toG, edge) + accentBright[1] * glow * 0.6), o + 2);
|
|
106954
|
+
out.writeUInt16LE(clamp16(mix16(fromB, toB, edge) + accentBright[2] * glow * 0.6), o + 4);
|
|
106955
|
+
}
|
|
106956
|
+
};
|
|
106957
|
+
TRANSITIONS["sdf-iris"] = sdfIris;
|
|
106958
|
+
function glitchRand(x, y) {
|
|
106959
|
+
return (Math.sin(x * 12.9898 + y * 78.233) * 43758.5453 % 1 + 1) % 1;
|
|
106960
|
+
}
|
|
106961
|
+
var glitch = (from2, to, out, w, h, p) => {
|
|
106962
|
+
const intensity = p * (1 - p) * 4;
|
|
106963
|
+
for (let i = 0; i < w * h; i++) {
|
|
106964
|
+
const ux = i % w / w;
|
|
106965
|
+
const uy = Math.floor(i / w) / h;
|
|
106966
|
+
const o = i * 6;
|
|
106967
|
+
const lineY = Math.floor(uy * 60) / 60;
|
|
106968
|
+
const lineDisp = (glitchRand(lineY, Math.floor(p * 17)) - 0.5) * 0.18 * intensity;
|
|
106969
|
+
const blockX = Math.floor(ux * 12);
|
|
106970
|
+
const blockY = Math.floor(uy * 8);
|
|
106971
|
+
const progressStep = Math.floor(p * 11);
|
|
106972
|
+
const br = glitchRand(blockX + progressStep, blockY + progressStep);
|
|
106973
|
+
const ba = (br >= 0.83 ? 1 : 0) * intensity;
|
|
106974
|
+
const bdx = (glitchRand(blockX * 2.1, blockY * 2.1) - 0.5) * 0.35 * ba;
|
|
106975
|
+
const bdy = (glitchRand(blockX * 3.7, blockY * 3.7) - 0.5) * 0.35 * ba;
|
|
106976
|
+
const uvx = Math.max(0, Math.min(1, ux + lineDisp + bdx));
|
|
106977
|
+
const uvy = Math.max(0, Math.min(1, uy + bdy));
|
|
106978
|
+
const shift = intensity * 0.035;
|
|
106979
|
+
const r = sampleRgb48le(from2, uvx + shift, uvy, w, h)[0];
|
|
106980
|
+
const g = sampleRgb48le(from2, uvx, uvy, w, h)[1];
|
|
106981
|
+
const b = sampleRgb48le(from2, uvx - shift, uvy, w, h)[2];
|
|
106982
|
+
let cr = r / 65535;
|
|
106983
|
+
let cg = g / 65535;
|
|
106984
|
+
let cb = b / 65535;
|
|
106985
|
+
const scanline = (uy * h * 0.5 % 1 + 1) % 1 >= 0.5 ? 0.05 * intensity : 0;
|
|
106986
|
+
cr -= scanline;
|
|
106987
|
+
cg -= scanline;
|
|
106988
|
+
cb -= scanline;
|
|
106989
|
+
const flicker = 1 + (glitchRand(Math.floor(p * 23), 0) - 0.5) * 0.3 * intensity;
|
|
106990
|
+
cr *= flicker;
|
|
106991
|
+
cg *= flicker;
|
|
106992
|
+
cb *= flicker;
|
|
106993
|
+
const levels = 256 - (256 - 8) * (intensity * 0.5);
|
|
106994
|
+
cr = Math.floor(cr * levels) / levels;
|
|
106995
|
+
cg = Math.floor(cg * levels) / levels;
|
|
106996
|
+
cb = Math.floor(cb * levels) / levels;
|
|
106997
|
+
const [toR, toG, toB] = sampleRgb48le(to, ux, uy, w, h);
|
|
106998
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(cr * 65535), toR, p)), o);
|
|
106999
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(cg * 65535), toG, p)), o + 2);
|
|
107000
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(cb * 65535), toB, p)), o + 4);
|
|
107001
|
+
}
|
|
107002
|
+
};
|
|
107003
|
+
TRANSITIONS["glitch"] = glitch;
|
|
107004
|
+
function aces(x) {
|
|
107005
|
+
return Math.max(0, Math.min(1, x * (2.51 * x + 0.03) / (x * (2.43 * x + 0.59) + 0.14)));
|
|
107006
|
+
}
|
|
107007
|
+
var lightLeak = (from2, to, out, w, h, p) => {
|
|
107008
|
+
const accent = [5e4 / 65535, 25e3 / 65535, 5e3 / 65535];
|
|
107009
|
+
const accentBright = [65535 / 65535, 55e3 / 65535, 35e3 / 65535];
|
|
107010
|
+
const lpx = 1.3;
|
|
107011
|
+
const lpy = -0.2;
|
|
107012
|
+
for (let i = 0; i < w * h; i++) {
|
|
107013
|
+
const ux = i % w / w;
|
|
107014
|
+
const uy = Math.floor(i / w) / h;
|
|
107015
|
+
const o = i * 6;
|
|
107016
|
+
const dx = ux - lpx;
|
|
107017
|
+
const dy = uy - lpy;
|
|
107018
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
107019
|
+
const leak = Math.max(0, Math.min(1, Math.exp(-dist * 1.8) * p * 4));
|
|
107020
|
+
const warmR = accent[0] + (accentBright[0] - accent[0]) * dist * 0.7;
|
|
107021
|
+
const warmG = accent[1] + (accentBright[1] - accent[1]) * dist * 0.7;
|
|
107022
|
+
const warmB = accent[2] + (accentBright[2] - accent[2]) * dist * 0.7;
|
|
107023
|
+
const flare = Math.exp(-Math.abs(uy - (-0.2 + ux * 0.3)) * 15) * leak * 0.3;
|
|
107024
|
+
const [fr, fg, fb] = sampleRgb48le(from2, ux, uy, w, h);
|
|
107025
|
+
const fromR = fr / 65535;
|
|
107026
|
+
const fromG = fg / 65535;
|
|
107027
|
+
const fromB = fb / 65535;
|
|
107028
|
+
const overR = aces(fromR + warmR * leak * 3 + accentBright[0] * flare);
|
|
107029
|
+
const overG = aces(fromG + warmG * leak * 3 + accentBright[1] * flare);
|
|
107030
|
+
const overB = aces(fromB + warmB * leak * 3 + accentBright[2] * flare);
|
|
107031
|
+
const [toR, toG, toB] = sampleRgb48le(to, ux, uy, w, h);
|
|
107032
|
+
const blend = smoothstep(0.15, 0.85, p);
|
|
107033
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(overR * 65535), toR, blend)), o);
|
|
107034
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(overG * 65535), toG, blend)), o + 2);
|
|
107035
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(overB * 65535), toB, blend)), o + 4);
|
|
107036
|
+
}
|
|
107037
|
+
};
|
|
107038
|
+
TRANSITIONS["light-leak"] = lightLeak;
|
|
107039
|
+
var crossWarpMorph = (from2, to, out, w, h, p) => {
|
|
107040
|
+
for (let i = 0; i < w * h; i++) {
|
|
107041
|
+
const ux = i % w / w;
|
|
107042
|
+
const uy = Math.floor(i / w) / h;
|
|
107043
|
+
const o = i * 6;
|
|
107044
|
+
const dispX = fbm(ux * 3, uy * 3) - 0.5;
|
|
107045
|
+
const dispY = fbm(ux * 3 + 7.3, uy * 3 + 3.7) - 0.5;
|
|
107046
|
+
const fromUx = Math.max(0, Math.min(1, ux + dispX * p * 0.5));
|
|
107047
|
+
const fromUy = Math.max(0, Math.min(1, uy + dispY * p * 0.5));
|
|
107048
|
+
const toUx = Math.max(0, Math.min(1, ux - dispX * (1 - p) * 0.5));
|
|
107049
|
+
const toUy = Math.max(0, Math.min(1, uy - dispY * (1 - p) * 0.5));
|
|
107050
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, fromUx, fromUy, w, h);
|
|
107051
|
+
const [toR, toG, toB] = sampleRgb48le(to, toUx, toUy, w, h);
|
|
107052
|
+
const n = fbm(ux * 4 + 3.1, uy * 4 + 1.7);
|
|
107053
|
+
const blend = smoothstep(0.4, 0.6, n + p * 1.2 - 0.6);
|
|
107054
|
+
out.writeUInt16LE(clamp16(mix16(fromR, toR, blend)), o);
|
|
107055
|
+
out.writeUInt16LE(clamp16(mix16(fromG, toG, blend)), o + 2);
|
|
107056
|
+
out.writeUInt16LE(clamp16(mix16(fromB, toB, blend)), o + 4);
|
|
107057
|
+
}
|
|
107058
|
+
};
|
|
107059
|
+
TRANSITIONS["cross-warp-morph"] = crossWarpMorph;
|
|
107060
|
+
var whipPan = (from2, to, out, w, h, p) => {
|
|
107061
|
+
const fromOff = p * 1.5;
|
|
107062
|
+
const toOff = (1 - p) * 1.5;
|
|
107063
|
+
for (let i = 0; i < w * h; i++) {
|
|
107064
|
+
const ux = i % w / w;
|
|
107065
|
+
const uy = Math.floor(i / w) / h;
|
|
107066
|
+
const o = i * 6;
|
|
107067
|
+
let fromR = 0, fromG = 0, fromB = 0;
|
|
107068
|
+
for (let s = 0; s < 10; s++) {
|
|
107069
|
+
const f = s / 10;
|
|
107070
|
+
const fuv = Math.max(0, Math.min(1, ux + fromOff + p * 0.08 * f));
|
|
107071
|
+
const [r, g, b] = sampleRgb48le(from2, fuv, uy, w, h);
|
|
107072
|
+
fromR += r;
|
|
107073
|
+
fromG += g;
|
|
107074
|
+
fromB += b;
|
|
107075
|
+
}
|
|
107076
|
+
fromR /= 10;
|
|
107077
|
+
fromG /= 10;
|
|
107078
|
+
fromB /= 10;
|
|
107079
|
+
let toR = 0, toG = 0, toB = 0;
|
|
107080
|
+
for (let s = 0; s < 10; s++) {
|
|
107081
|
+
const f = s / 10;
|
|
107082
|
+
const tuv = Math.max(0, Math.min(1, ux - toOff - (1 - p) * 0.08 * f));
|
|
107083
|
+
const [r, g, b] = sampleRgb48le(to, tuv, uy, w, h);
|
|
107084
|
+
toR += r;
|
|
107085
|
+
toG += g;
|
|
107086
|
+
toB += b;
|
|
107087
|
+
}
|
|
107088
|
+
toR /= 10;
|
|
107089
|
+
toG /= 10;
|
|
107090
|
+
toB /= 10;
|
|
107091
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromR), Math.round(toR), p)), o);
|
|
107092
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromG), Math.round(toG), p)), o + 2);
|
|
107093
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromB), Math.round(toB), p)), o + 4);
|
|
107094
|
+
}
|
|
107095
|
+
};
|
|
107096
|
+
TRANSITIONS["whip-pan"] = whipPan;
|
|
107097
|
+
var cinematicZoom = (from2, to, out, w, h, p) => {
|
|
107098
|
+
const fromS = p * 0.08;
|
|
107099
|
+
const toS = (1 - p) * 0.06;
|
|
107100
|
+
for (let i = 0; i < w * h; i++) {
|
|
107101
|
+
const ux = i % w / w;
|
|
107102
|
+
const uy = Math.floor(i / w) / h;
|
|
107103
|
+
const o = i * 6;
|
|
107104
|
+
const dx = ux - 0.5;
|
|
107105
|
+
const dy = uy - 0.5;
|
|
107106
|
+
let fr = 0, fg = 0, fb = 0;
|
|
107107
|
+
for (let s = 0; s < 12; s++) {
|
|
107108
|
+
const f = s / 12;
|
|
107109
|
+
const rr = sampleRgb48le(
|
|
107110
|
+
from2,
|
|
107111
|
+
ux - dx * fromS * 1.06 * f,
|
|
107112
|
+
uy - dy * fromS * 1.06 * f,
|
|
107113
|
+
w,
|
|
107114
|
+
h
|
|
107115
|
+
)[0];
|
|
107116
|
+
const gg = sampleRgb48le(from2, ux - dx * fromS * f, uy - dy * fromS * f, w, h)[1];
|
|
107117
|
+
const bb = sampleRgb48le(
|
|
107118
|
+
from2,
|
|
107119
|
+
ux - dx * fromS * 0.94 * f,
|
|
107120
|
+
uy - dy * fromS * 0.94 * f,
|
|
107121
|
+
w,
|
|
107122
|
+
h
|
|
107123
|
+
)[2];
|
|
107124
|
+
fr += rr;
|
|
107125
|
+
fg += gg;
|
|
107126
|
+
fb += bb;
|
|
107127
|
+
}
|
|
107128
|
+
fr /= 12;
|
|
107129
|
+
fg /= 12;
|
|
107130
|
+
fb /= 12;
|
|
107131
|
+
let tr = 0, tg = 0, tb = 0;
|
|
107132
|
+
for (let s = 0; s < 12; s++) {
|
|
107133
|
+
const f = s / 12;
|
|
107134
|
+
const rr = sampleRgb48le(to, ux + dx * toS * 1.06 * f, uy + dy * toS * 1.06 * f, w, h)[0];
|
|
107135
|
+
const gg = sampleRgb48le(to, ux + dx * toS * f, uy + dy * toS * f, w, h)[1];
|
|
107136
|
+
const bb = sampleRgb48le(to, ux + dx * toS * 0.94 * f, uy + dy * toS * 0.94 * f, w, h)[2];
|
|
107137
|
+
tr += rr;
|
|
107138
|
+
tg += gg;
|
|
107139
|
+
tb += bb;
|
|
107140
|
+
}
|
|
107141
|
+
tr /= 12;
|
|
107142
|
+
tg /= 12;
|
|
107143
|
+
tb /= 12;
|
|
107144
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fr), Math.round(tr), p)), o);
|
|
107145
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fg), Math.round(tg), p)), o + 2);
|
|
107146
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fb), Math.round(tb), p)), o + 4);
|
|
107147
|
+
}
|
|
107148
|
+
};
|
|
107149
|
+
TRANSITIONS["cinematic-zoom"] = cinematicZoom;
|
|
107150
|
+
var gravitationalLens = (from2, to, out, w, h, p) => {
|
|
107151
|
+
for (let i = 0; i < w * h; i++) {
|
|
107152
|
+
const ux = i % w / w;
|
|
107153
|
+
const uy = Math.floor(i / w) / h;
|
|
107154
|
+
const o = i * 6;
|
|
107155
|
+
const uvx = ux - 0.5;
|
|
107156
|
+
const uvy = uy - 0.5;
|
|
107157
|
+
const dist = Math.sqrt(uvx * uvx + uvy * uvy);
|
|
107158
|
+
const pull = p * 2;
|
|
107159
|
+
const warpStr = pull * 0.3 / (dist + 0.1);
|
|
107160
|
+
const warpedX = Math.max(0, Math.min(1, ux - uvx * warpStr));
|
|
107161
|
+
const warpedY = Math.max(0, Math.min(1, uy - uvy * warpStr));
|
|
107162
|
+
const [, ag] = sampleRgb48le(from2, warpedX, warpedY, w, h);
|
|
107163
|
+
const horizon = smoothstep(0, 0.3, dist / (1 - p * 0.85 + 1e-3));
|
|
107164
|
+
const shift = pull * 0.02 / (dist + 0.2);
|
|
107165
|
+
const rSampX = Math.max(0, Math.min(1, ux - uvx * (warpStr + shift)));
|
|
107166
|
+
const rSampY = Math.max(0, Math.min(1, uy - uvy * (warpStr + shift)));
|
|
107167
|
+
const bSampX = Math.max(0, Math.min(1, ux - uvx * (warpStr - shift)));
|
|
107168
|
+
const bSampY = Math.max(0, Math.min(1, uy - uvy * (warpStr - shift)));
|
|
107169
|
+
const ar = sampleRgb48le(from2, rSampX, rSampY, w, h)[0];
|
|
107170
|
+
const ab = sampleRgb48le(from2, bSampX, bSampY, w, h)[2];
|
|
107171
|
+
const lensedR = Math.round(ar * horizon);
|
|
107172
|
+
const lensedG = Math.round(ag * horizon);
|
|
107173
|
+
const lensedB = Math.round(ab * horizon);
|
|
107174
|
+
const [toR, toG, toB] = sampleRgb48le(to, ux, uy, w, h);
|
|
107175
|
+
const blend = smoothstep(0.3, 0.9, p);
|
|
107176
|
+
out.writeUInt16LE(clamp16(mix16(lensedR, toR, blend)), o);
|
|
107177
|
+
out.writeUInt16LE(clamp16(mix16(lensedG, toG, blend)), o + 2);
|
|
107178
|
+
out.writeUInt16LE(clamp16(mix16(lensedB, toB, blend)), o + 4);
|
|
107179
|
+
}
|
|
107180
|
+
};
|
|
107181
|
+
TRANSITIONS["gravitational-lens"] = gravitationalLens;
|
|
107182
|
+
var rippleWaves = (from2, to, out, w, h, p) => {
|
|
107183
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
107184
|
+
for (let i = 0; i < w * h; i++) {
|
|
107185
|
+
const ux = i % w / w;
|
|
107186
|
+
const uy = Math.floor(i / w) / h;
|
|
107187
|
+
const o = i * 6;
|
|
107188
|
+
const uvx = ux - 0.5;
|
|
107189
|
+
const uvy = uy - 0.5;
|
|
107190
|
+
const dist = Math.sqrt(uvx * uvx + uvy * uvy);
|
|
107191
|
+
const nux = uvx + 1e-3;
|
|
107192
|
+
const nuy = uvy + 1e-3;
|
|
107193
|
+
const nlen = Math.sqrt(nux * nux + nuy * nuy);
|
|
107194
|
+
const dirx = nux / nlen;
|
|
107195
|
+
const diry = nuy / nlen;
|
|
107196
|
+
const fromAmp = p * 0.04;
|
|
107197
|
+
const fw1 = Math.exp(Math.sin(dist * 25 - p * 12) - 1);
|
|
107198
|
+
const fw2 = Math.exp(Math.sin(dist * 50 - p * 18) - 1) * 0.5;
|
|
107199
|
+
const fromUx = Math.max(0, Math.min(1, ux + dirx * (fw1 + fw2) * fromAmp));
|
|
107200
|
+
const fromUy = Math.max(0, Math.min(1, uy + diry * (fw1 + fw2) * fromAmp));
|
|
107201
|
+
const toAmp = (1 - p) * 0.04;
|
|
107202
|
+
const tw1 = Math.exp(Math.sin(dist * 25 + p * 12) - 1);
|
|
107203
|
+
const tw2 = Math.exp(Math.sin(dist * 50 + p * 18) - 1) * 0.5;
|
|
107204
|
+
const toUx = Math.max(0, Math.min(1, ux - dirx * (tw1 + tw2) * toAmp));
|
|
107205
|
+
const toUy = Math.max(0, Math.min(1, uy - diry * (tw1 + tw2) * toAmp));
|
|
107206
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, fromUx, fromUy, w, h);
|
|
107207
|
+
const [toR, toG, toB] = sampleRgb48le(to, toUx, toUy, w, h);
|
|
107208
|
+
const peak = fw1 * p;
|
|
107209
|
+
const tintR = accentBright[0] * peak * 0.1;
|
|
107210
|
+
const tintG = accentBright[1] * peak * 0.1;
|
|
107211
|
+
const tintB = accentBright[2] * peak * 0.1;
|
|
107212
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromR + tintR), toR, p)), o);
|
|
107213
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromG + tintG), toG, p)), o + 2);
|
|
107214
|
+
out.writeUInt16LE(clamp16(mix16(Math.round(fromB + tintB), toB, p)), o + 4);
|
|
107215
|
+
}
|
|
107216
|
+
};
|
|
107217
|
+
TRANSITIONS["ripple-waves"] = rippleWaves;
|
|
107218
|
+
var swirlVortex = (from2, to, out, w, h, p) => {
|
|
107219
|
+
for (let i = 0; i < w * h; i++) {
|
|
107220
|
+
const ux = i % w / w;
|
|
107221
|
+
const uy = Math.floor(i / w) / h;
|
|
107222
|
+
const o = i * 6;
|
|
107223
|
+
const uvx = ux - 0.5;
|
|
107224
|
+
const uvy = uy - 0.5;
|
|
107225
|
+
const dist = Math.sqrt(uvx * uvx + uvy * uvy);
|
|
107226
|
+
const warp = fbm(ux * 4, uy * 4) * 0.5;
|
|
107227
|
+
const fromAng = p * (1 - dist) * 10 + warp * p * 3;
|
|
107228
|
+
const fs8 = Math.sin(fromAng);
|
|
107229
|
+
const fc = Math.cos(fromAng);
|
|
107230
|
+
const fromUx = Math.max(0, Math.min(1, uvx * fc - uvy * fs8 + 0.5));
|
|
107231
|
+
const fromUy = Math.max(0, Math.min(1, uvx * fs8 + uvy * fc + 0.5));
|
|
107232
|
+
const toAng = -(1 - p) * (1 - dist) * 10 - warp * (1 - p) * 3;
|
|
107233
|
+
const ts = Math.sin(toAng);
|
|
107234
|
+
const tc = Math.cos(toAng);
|
|
107235
|
+
const toUx = Math.max(0, Math.min(1, uvx * tc - uvy * ts + 0.5));
|
|
107236
|
+
const toUy = Math.max(0, Math.min(1, uvx * ts + uvy * tc + 0.5));
|
|
107237
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, fromUx, fromUy, w, h);
|
|
107238
|
+
const [toR, toG, toB] = sampleRgb48le(to, toUx, toUy, w, h);
|
|
107239
|
+
out.writeUInt16LE(clamp16(mix16(fromR, toR, p)), o);
|
|
107240
|
+
out.writeUInt16LE(clamp16(mix16(fromG, toG, p)), o + 2);
|
|
107241
|
+
out.writeUInt16LE(clamp16(mix16(fromB, toB, p)), o + 4);
|
|
107242
|
+
}
|
|
107243
|
+
};
|
|
107244
|
+
TRANSITIONS["swirl-vortex"] = swirlVortex;
|
|
107245
|
+
var thermalDistortion = (from2, to, out, w, h, p) => {
|
|
107246
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
107247
|
+
for (let i = 0; i < w * h; i++) {
|
|
107248
|
+
const ux = i % w / w;
|
|
107249
|
+
const uy = Math.floor(i / w) / h;
|
|
107250
|
+
const o = i * 6;
|
|
107251
|
+
const heat = p * 1.5;
|
|
107252
|
+
const yFade = smoothstep(1, 0, uy);
|
|
107253
|
+
const shimmer = Math.sin(uy * 40 + fbm(ux * 6, uy * 6) * 8) * fbm(ux * 3 + 0, uy * 3 + p * 2);
|
|
107254
|
+
const dispX = shimmer * heat * 0.03 * yFade;
|
|
107255
|
+
const fromUx = Math.max(0, Math.min(1, ux + dispX));
|
|
107256
|
+
const [fromR, fromG, fromB] = sampleRgb48le(from2, fromUx, uy, w, h);
|
|
107257
|
+
const invShimmer = Math.sin(uy * 40 + fbm(ux * 6 + 3, uy * 6 + 3) * 8) * fbm(ux * 3 + 3, uy * 3 + p * 2);
|
|
107258
|
+
const dispX2 = invShimmer * (1 - p) * 0.03 * yFade;
|
|
107259
|
+
const toUx = Math.max(0, Math.min(1, ux + dispX2));
|
|
107260
|
+
const [toR, toG, toB] = sampleRgb48le(to, toUx, uy, w, h);
|
|
107261
|
+
const haze = heat * yFade * 0.15 * (1 - p);
|
|
107262
|
+
out.writeUInt16LE(clamp16(mix16(fromR, toR, p) + Math.round(accentBright[0] * haze)), o);
|
|
107263
|
+
out.writeUInt16LE(clamp16(mix16(fromG, toG, p) + Math.round(accentBright[1] * haze)), o + 2);
|
|
107264
|
+
out.writeUInt16LE(clamp16(mix16(fromB, toB, p) + Math.round(accentBright[2] * haze)), o + 4);
|
|
107265
|
+
}
|
|
107266
|
+
};
|
|
107267
|
+
TRANSITIONS["thermal-distortion"] = thermalDistortion;
|
|
107268
|
+
var domainWarp = (from2, to, out, w, h, p) => {
|
|
107269
|
+
const accentDark = [25e3, 8e3, 2e3];
|
|
107270
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
107271
|
+
for (let i = 0; i < w * h; i++) {
|
|
107272
|
+
const ux = i % w / w;
|
|
107273
|
+
const uy = Math.floor(i / w) / h;
|
|
107274
|
+
const o = i * 6;
|
|
107275
|
+
const qx = fbm(ux * 3, uy * 3);
|
|
107276
|
+
const qy = fbm(ux * 3 + 5.2, uy * 3 + 1.3);
|
|
107277
|
+
const rx = fbm(ux * 3 + qx * 4 + 1.7, uy * 3 + qy * 4 + 9.2);
|
|
107278
|
+
const ry = fbm(ux * 3 + qx * 4 + 8.3, uy * 3 + qy * 4 + 2.8);
|
|
107279
|
+
const n = fbm(ux * 3 + rx * 2, uy * 3 + ry * 2);
|
|
107280
|
+
const warpDirX = (qx - 0.5) * 0.4;
|
|
107281
|
+
const warpDirY = (qy - 0.5) * 0.4;
|
|
107282
|
+
const aUx = Math.max(0, Math.min(1, ux + warpDirX * p));
|
|
107283
|
+
const aUy = Math.max(0, Math.min(1, uy + warpDirY * p));
|
|
107284
|
+
const bUx = Math.max(0, Math.min(1, ux - warpDirX * (1 - p)));
|
|
107285
|
+
const bUy = Math.max(0, Math.min(1, uy - warpDirY * (1 - p)));
|
|
107286
|
+
const [aR, aG, aB] = sampleRgb48le(from2, aUx, aUy, w, h);
|
|
107287
|
+
const [bR, bG, bB] = sampleRgb48le(to, bUx, bUy, w, h);
|
|
107288
|
+
const e = smoothstep(p - 0.08, p + 0.08, n);
|
|
107289
|
+
const ed = Math.abs(n - p);
|
|
107290
|
+
const pStep = p >= 1 ? 1 : 0;
|
|
107291
|
+
const em = smoothstep(0.1, 0, ed) * (1 - pStep);
|
|
107292
|
+
const ecBlend = smoothstep(0, 0.1, ed);
|
|
107293
|
+
const ecR = accentDark[0] + (accentBright[0] - accentDark[0]) * (1 - ecBlend);
|
|
107294
|
+
const ecG = accentDark[1] + (accentBright[1] - accentDark[1]) * (1 - ecBlend);
|
|
107295
|
+
const ecB = accentDark[2] + (accentBright[2] - accentDark[2]) * (1 - ecBlend);
|
|
107296
|
+
out.writeUInt16LE(clamp16(mix16(bR, aR, e) + Math.round(ecR * em * 2)), o);
|
|
107297
|
+
out.writeUInt16LE(clamp16(mix16(bG, aG, e) + Math.round(ecG * em * 2)), o + 2);
|
|
107298
|
+
out.writeUInt16LE(clamp16(mix16(bB, aB, e) + Math.round(ecB * em * 2)), o + 4);
|
|
107299
|
+
}
|
|
107300
|
+
};
|
|
107301
|
+
TRANSITIONS["domain-warp"] = domainWarp;
|
|
107302
|
+
function ridged(px, py) {
|
|
107303
|
+
let value = 0;
|
|
107304
|
+
let amplitude = 0.5;
|
|
107305
|
+
let x = px;
|
|
107306
|
+
let y = py;
|
|
107307
|
+
for (let i = 0; i < 5; i++) {
|
|
107308
|
+
value += amplitude * Math.abs(vnoise(x, y) * 2 - 1);
|
|
107309
|
+
const nx = ROT_A * x - ROT_B * y;
|
|
107310
|
+
const ny = ROT_B * x + ROT_A * y;
|
|
107311
|
+
x = nx * 2.02;
|
|
107312
|
+
y = ny * 2.02;
|
|
107313
|
+
amplitude *= 0.5;
|
|
107314
|
+
}
|
|
107315
|
+
return value;
|
|
107316
|
+
}
|
|
107317
|
+
var ridgedBurn = (from2, to, out, w, h, p) => {
|
|
107318
|
+
const accent = [5e4, 25e3, 5e3];
|
|
107319
|
+
const accentDark = [25e3, 8e3, 2e3];
|
|
107320
|
+
const accentBright = [65535, 55e3, 35e3];
|
|
107321
|
+
for (let i = 0; i < w * h; i++) {
|
|
107322
|
+
const ux = i % w / w;
|
|
107323
|
+
const uy = Math.floor(i / w) / h;
|
|
107324
|
+
const o = i * 6;
|
|
107325
|
+
const [aR, aG, aB] = sampleRgb48le(from2, ux, uy, w, h);
|
|
107326
|
+
const [bR, bG, bB] = sampleRgb48le(to, ux, uy, w, h);
|
|
107327
|
+
const n = ridged(ux * 4, uy * 4);
|
|
107328
|
+
const e = smoothstep(p - 0.04, p + 0.04, n);
|
|
107329
|
+
const heat = smoothstep(0.12, 0, Math.abs(n - p));
|
|
107330
|
+
const pStep = p >= 1 ? 1 : 0;
|
|
107331
|
+
const heatMasked = heat * (1 - pStep);
|
|
107332
|
+
let burnR = accentDark[0] + (accent[0] - accentDark[0]) * smoothstep(0, 0.25, heatMasked);
|
|
107333
|
+
let burnG = accentDark[1] + (accent[1] - accentDark[1]) * smoothstep(0, 0.25, heatMasked);
|
|
107334
|
+
let burnB = accentDark[2] + (accent[2] - accentDark[2]) * smoothstep(0, 0.25, heatMasked);
|
|
107335
|
+
const blend2 = smoothstep(0.25, 0.5, heatMasked);
|
|
107336
|
+
burnR = burnR + (accentBright[0] - burnR) * blend2;
|
|
107337
|
+
burnG = burnG + (accentBright[1] - burnG) * blend2;
|
|
107338
|
+
burnB = burnB + (accentBright[2] - burnB) * blend2;
|
|
107339
|
+
const blend3 = smoothstep(0.5, 1, heatMasked);
|
|
107340
|
+
burnR = burnR + (65535 - burnR) * blend3;
|
|
107341
|
+
burnG = burnG + (65535 - burnG) * blend3;
|
|
107342
|
+
burnB = burnB + (65535 - burnB) * blend3;
|
|
107343
|
+
const sparks = (vnoise(ux * 80, uy * 80) >= 0.92 ? 1 : 0) * heatMasked * 3;
|
|
107344
|
+
out.writeUInt16LE(
|
|
107345
|
+
clamp16(
|
|
107346
|
+
mix16(bR, aR, e) + Math.round(burnR * heatMasked * 3.5) + Math.round(accentBright[0] * sparks)
|
|
107347
|
+
),
|
|
107348
|
+
o
|
|
107349
|
+
);
|
|
107350
|
+
out.writeUInt16LE(
|
|
107351
|
+
clamp16(
|
|
107352
|
+
mix16(bG, aG, e) + Math.round(burnG * heatMasked * 3.5) + Math.round(accentBright[1] * sparks)
|
|
107353
|
+
),
|
|
107354
|
+
o + 2
|
|
107355
|
+
);
|
|
107356
|
+
out.writeUInt16LE(
|
|
107357
|
+
clamp16(
|
|
107358
|
+
mix16(bB, aB, e) + Math.round(burnB * heatMasked * 3.5) + Math.round(accentBright[2] * sparks)
|
|
107359
|
+
),
|
|
107360
|
+
o + 4
|
|
107361
|
+
);
|
|
107362
|
+
}
|
|
107363
|
+
};
|
|
107364
|
+
TRANSITIONS["ridged-burn"] = ridgedBurn;
|
|
107365
|
+
|
|
106508
107366
|
// src/services/renderOrchestrator.ts
|
|
106509
107367
|
import { join as join15, dirname as dirname10, resolve as resolve10 } from "path";
|
|
106510
107368
|
import { randomUUID } from "crypto";
|
|
@@ -108352,6 +109210,63 @@ function applyRenderModeHints(cfg, compiled, log = defaultLogger) {
|
|
|
108352
109210
|
reasons: compiled.renderModeHints.reasons.map((reason) => reason.message)
|
|
108353
109211
|
});
|
|
108354
109212
|
}
|
|
109213
|
+
function blitHdrVideoLayer(canvas, el, time, fps, hdrFrameDirs, hdrStartTimes, width, height, log, sourceTransfer, targetTransfer) {
|
|
109214
|
+
const frameDir = hdrFrameDirs.get(el.id);
|
|
109215
|
+
const startTime = hdrStartTimes.get(el.id);
|
|
109216
|
+
if (!frameDir || startTime === void 0) {
|
|
109217
|
+
return;
|
|
109218
|
+
}
|
|
109219
|
+
const videoFrameIndex = Math.round((time - startTime) * fps) + 1;
|
|
109220
|
+
if (videoFrameIndex < 1) return;
|
|
109221
|
+
const maxIndex = getMaxFrameIndex(frameDir);
|
|
109222
|
+
const effectiveIndex = maxIndex > 0 ? Math.min(videoFrameIndex, maxIndex) : videoFrameIndex;
|
|
109223
|
+
const framePath = join15(frameDir, `frame_${String(effectiveIndex).padStart(4, "0")}.png`);
|
|
109224
|
+
if (!existsSync15(framePath)) {
|
|
109225
|
+
return;
|
|
109226
|
+
}
|
|
109227
|
+
try {
|
|
109228
|
+
const { data: hdrRgb, width: srcW, height: srcH } = decodePngToRgb48le(readFileSync9(framePath));
|
|
109229
|
+
if (sourceTransfer && targetTransfer && sourceTransfer !== targetTransfer) {
|
|
109230
|
+
convertTransfer(hdrRgb, sourceTransfer, targetTransfer);
|
|
109231
|
+
}
|
|
109232
|
+
const viewportMatrix = parseTransformMatrix(el.transform);
|
|
109233
|
+
const br = el.borderRadius;
|
|
109234
|
+
const hasBorderRadius = br[0] > 0 || br[1] > 0 || br[2] > 0 || br[3] > 0;
|
|
109235
|
+
const borderRadiusParam = hasBorderRadius ? br : void 0;
|
|
109236
|
+
if (viewportMatrix) {
|
|
109237
|
+
blitRgb48leAffine(
|
|
109238
|
+
canvas,
|
|
109239
|
+
hdrRgb,
|
|
109240
|
+
viewportMatrix,
|
|
109241
|
+
srcW,
|
|
109242
|
+
srcH,
|
|
109243
|
+
width,
|
|
109244
|
+
height,
|
|
109245
|
+
el.opacity < 0.999 ? el.opacity : void 0,
|
|
109246
|
+
borderRadiusParam
|
|
109247
|
+
);
|
|
109248
|
+
} else {
|
|
109249
|
+
blitRgb48leRegion(
|
|
109250
|
+
canvas,
|
|
109251
|
+
hdrRgb,
|
|
109252
|
+
el.x,
|
|
109253
|
+
el.y,
|
|
109254
|
+
srcW,
|
|
109255
|
+
srcH,
|
|
109256
|
+
width,
|
|
109257
|
+
height,
|
|
109258
|
+
el.opacity < 0.999 ? el.opacity : void 0,
|
|
109259
|
+
borderRadiusParam
|
|
109260
|
+
);
|
|
109261
|
+
}
|
|
109262
|
+
} catch (err) {
|
|
109263
|
+
if (log) {
|
|
109264
|
+
log.debug(`HDR blit failed for ${el.id}`, {
|
|
109265
|
+
error: err instanceof Error ? err.message : String(err)
|
|
109266
|
+
});
|
|
109267
|
+
}
|
|
109268
|
+
}
|
|
109269
|
+
}
|
|
108355
109270
|
function createRenderJob(config2) {
|
|
108356
109271
|
return {
|
|
108357
109272
|
id: randomUUID(),
|
|
@@ -108622,6 +109537,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108622
109537
|
perfStages.browserProbeMs = Date.now() - probeStart;
|
|
108623
109538
|
job.duration = composition.duration;
|
|
108624
109539
|
job.totalFrames = Math.ceil(composition.duration * job.config.fps);
|
|
109540
|
+
const totalFrames = job.totalFrames;
|
|
108625
109541
|
if (job.duration <= 0) {
|
|
108626
109542
|
const diagnostics = [];
|
|
108627
109543
|
try {
|
|
@@ -108679,7 +109595,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108679
109595
|
const compiledDir = join15(workDir, "compiled");
|
|
108680
109596
|
let extractionResult = null;
|
|
108681
109597
|
const nativeHdrVideoIds = /* @__PURE__ */ new Set();
|
|
108682
|
-
|
|
109598
|
+
const videoTransfers = /* @__PURE__ */ new Map();
|
|
109599
|
+
if (job.config.hdr && composition.videos.length > 0) {
|
|
108683
109600
|
await Promise.all(
|
|
108684
109601
|
composition.videos.map(async (v) => {
|
|
108685
109602
|
let videoPath = v.src;
|
|
@@ -108691,6 +109608,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108691
109608
|
const meta = await extractVideoMetadata(videoPath);
|
|
108692
109609
|
if (isHdrColorSpace(meta.colorSpace)) {
|
|
108693
109610
|
nativeHdrVideoIds.add(v.id);
|
|
109611
|
+
videoTransfers.set(v.id, detectTransfer(meta.colorSpace));
|
|
108694
109612
|
}
|
|
108695
109613
|
})
|
|
108696
109614
|
);
|
|
@@ -108732,13 +109650,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108732
109650
|
perfStages.videoExtractMs = Date.now() - stage2Start;
|
|
108733
109651
|
}
|
|
108734
109652
|
let effectiveHdr;
|
|
108735
|
-
if (frameLookup) {
|
|
109653
|
+
if (job.config.hdr && frameLookup) {
|
|
108736
109654
|
const colorSpaces = (extractionResult?.extracted ?? []).map((ext) => ext.metadata.colorSpace);
|
|
108737
109655
|
const info = analyzeCompositionHdr(colorSpaces);
|
|
108738
109656
|
if (info.hasHdr && info.dominantTransfer) {
|
|
108739
109657
|
effectiveHdr = { transfer: info.dominantTransfer };
|
|
108740
109658
|
}
|
|
108741
109659
|
}
|
|
109660
|
+
if (job.config.hdr && !effectiveHdr && nativeHdrVideoIds.size > 0) {
|
|
109661
|
+
const firstTransfer = videoTransfers.values().next().value;
|
|
109662
|
+
if (firstTransfer) {
|
|
109663
|
+
effectiveHdr = { transfer: firstTransfer };
|
|
109664
|
+
}
|
|
109665
|
+
}
|
|
108742
109666
|
if (effectiveHdr && outputFormat !== "mp4") {
|
|
108743
109667
|
log.info(`[Render] HDR source detected but format is ${outputFormat} \u2014 using SDR`);
|
|
108744
109668
|
effectiveHdr = void 0;
|
|
@@ -108789,15 +109713,15 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108789
109713
|
format: needsAlpha ? "png" : "jpeg",
|
|
108790
109714
|
quality: needsAlpha ? void 0 : job.config.quality === "draft" ? 80 : 95
|
|
108791
109715
|
};
|
|
108792
|
-
const workerCount = calculateOptimalWorkers(
|
|
109716
|
+
const workerCount = calculateOptimalWorkers(totalFrames, job.config.workers, cfg);
|
|
108793
109717
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
108794
109718
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
108795
109719
|
const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
|
|
108796
|
-
const
|
|
108797
|
-
const encoderHdr =
|
|
109720
|
+
const hasHdrContent = effectiveHdr && nativeHdrVideoIds.size > 0;
|
|
109721
|
+
const encoderHdr = hasHdrContent ? effectiveHdr : void 0;
|
|
108798
109722
|
const preset = getEncoderPreset(job.config.quality, outputFormat, encoderHdr);
|
|
108799
109723
|
job.framesRendered = 0;
|
|
108800
|
-
if (
|
|
109724
|
+
if (hasHdrContent) {
|
|
108801
109725
|
log.info("[Render] HDR layered composite: z-ordered DOM + native HLG video layers");
|
|
108802
109726
|
const hdrVideoIds = composition.videos.filter((v) => nativeHdrVideoIds.has(v.id)).map((v) => v.id);
|
|
108803
109727
|
const hdrVideoSrcPaths = /* @__PURE__ */ new Map();
|
|
@@ -108810,6 +109734,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108810
109734
|
}
|
|
108811
109735
|
hdrVideoSrcPaths.set(v.id, srcPath);
|
|
108812
109736
|
}
|
|
109737
|
+
if (!fileServer) throw new Error("fileServer must be initialized before HDR compositing");
|
|
108813
109738
|
const domSession = await createCaptureSession(
|
|
108814
109739
|
fileServer.url,
|
|
108815
109740
|
framesDir,
|
|
@@ -108821,6 +109746,34 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108821
109746
|
assertNotAborted();
|
|
108822
109747
|
lastBrowserConsole = domSession.browserConsoleBuffer;
|
|
108823
109748
|
await initTransparentBackground(domSession.page);
|
|
109749
|
+
const transitionMeta = await domSession.page.evaluate(() => {
|
|
109750
|
+
return window.__hf?.transitions ?? [];
|
|
109751
|
+
});
|
|
109752
|
+
const sceneElements = await domSession.page.evaluate(() => {
|
|
109753
|
+
const scenes = document.querySelectorAll(".scene");
|
|
109754
|
+
const map2 = {};
|
|
109755
|
+
for (const scene of scenes) {
|
|
109756
|
+
const els = scene.querySelectorAll("[data-start]");
|
|
109757
|
+
map2[scene.id] = Array.from(els).map((e) => e.id);
|
|
109758
|
+
}
|
|
109759
|
+
return map2;
|
|
109760
|
+
});
|
|
109761
|
+
const transitionRanges = transitionMeta.map((t) => ({
|
|
109762
|
+
...t,
|
|
109763
|
+
startFrame: Math.floor(t.time * job.config.fps),
|
|
109764
|
+
endFrame: Math.ceil((t.time + t.duration) * job.config.fps)
|
|
109765
|
+
}));
|
|
109766
|
+
if (transitionRanges.length > 0) {
|
|
109767
|
+
log.info("[Render] Detected shader transitions for HDR compositing", {
|
|
109768
|
+
count: transitionRanges.length,
|
|
109769
|
+
transitions: transitionRanges.map((t) => ({
|
|
109770
|
+
shader: t.shader,
|
|
109771
|
+
from: t.fromScene,
|
|
109772
|
+
to: t.toScene,
|
|
109773
|
+
frames: `${t.startFrame}-${t.endFrame}`
|
|
109774
|
+
}))
|
|
109775
|
+
});
|
|
109776
|
+
}
|
|
108824
109777
|
const hdrEncoder = await spawnStreamingEncoder(
|
|
108825
109778
|
videoOnlyPath,
|
|
108826
109779
|
{
|
|
@@ -108838,7 +109791,28 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108838
109791
|
{ ffmpegStreamingTimeout: 36e5 }
|
|
108839
109792
|
);
|
|
108840
109793
|
assertNotAborted();
|
|
108841
|
-
const
|
|
109794
|
+
const hdrExtractionDims = /* @__PURE__ */ new Map();
|
|
109795
|
+
const hdrVideoStartTimes = /* @__PURE__ */ new Map();
|
|
109796
|
+
for (const v of composition.videos) {
|
|
109797
|
+
if (hdrVideoIds.includes(v.id)) {
|
|
109798
|
+
hdrVideoStartTimes.set(v.id, v.start);
|
|
109799
|
+
}
|
|
109800
|
+
}
|
|
109801
|
+
const uniqueStartTimes = [...new Set(hdrVideoStartTimes.values())].sort((a, b) => a - b);
|
|
109802
|
+
for (const seekTime of uniqueStartTimes) {
|
|
109803
|
+
await domSession.page.evaluate((t) => {
|
|
109804
|
+
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
109805
|
+
}, seekTime);
|
|
109806
|
+
if (domSession.onBeforeCapture) {
|
|
109807
|
+
await domSession.onBeforeCapture(domSession.page, seekTime);
|
|
109808
|
+
}
|
|
109809
|
+
const stacking = await queryElementStacking(domSession.page, nativeHdrVideoIds);
|
|
109810
|
+
for (const el of stacking) {
|
|
109811
|
+
if (el.isHdr && el.layoutWidth > 0 && el.layoutHeight > 0 && !hdrExtractionDims.has(el.id)) {
|
|
109812
|
+
hdrExtractionDims.set(el.id, { width: el.layoutWidth, height: el.layoutHeight });
|
|
109813
|
+
}
|
|
109814
|
+
}
|
|
109815
|
+
}
|
|
108842
109816
|
const hdrFrameDirs = /* @__PURE__ */ new Map();
|
|
108843
109817
|
for (const [videoId, srcPath] of hdrVideoSrcPaths) {
|
|
108844
109818
|
const video = composition.videos.find((v) => v.id === videoId);
|
|
@@ -108846,24 +109820,190 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108846
109820
|
const frameDir = join15(framesDir, `hdr_${videoId}`);
|
|
108847
109821
|
mkdirSync10(frameDir, { recursive: true });
|
|
108848
109822
|
const duration = video.end - video.start;
|
|
108849
|
-
|
|
108850
|
-
|
|
108851
|
-
|
|
108852
|
-
|
|
108853
|
-
|
|
108854
|
-
|
|
109823
|
+
const dims = hdrExtractionDims.get(videoId) ?? { width, height };
|
|
109824
|
+
const ffmpegArgs = [
|
|
109825
|
+
"-ss",
|
|
109826
|
+
String(video.mediaStart),
|
|
109827
|
+
"-i",
|
|
109828
|
+
srcPath,
|
|
109829
|
+
"-t",
|
|
109830
|
+
String(duration),
|
|
109831
|
+
"-r",
|
|
109832
|
+
String(job.config.fps),
|
|
109833
|
+
"-vf",
|
|
109834
|
+
`scale=${dims.width}:${dims.height}:force_original_aspect_ratio=increase,crop=${dims.width}:${dims.height}`,
|
|
109835
|
+
"-pix_fmt",
|
|
109836
|
+
"rgb48le",
|
|
109837
|
+
"-c:v",
|
|
109838
|
+
"png",
|
|
109839
|
+
"-y",
|
|
109840
|
+
join15(frameDir, "frame_%04d.png")
|
|
109841
|
+
];
|
|
109842
|
+
const result = await runFfmpeg(ffmpegArgs, { signal: abortSignal });
|
|
109843
|
+
if (!result.success) {
|
|
108855
109844
|
log.warn("HDR frame pre-extraction failed; loop will fill with black", {
|
|
108856
109845
|
videoId,
|
|
108857
109846
|
srcPath,
|
|
108858
|
-
|
|
109847
|
+
stderr: result.stderr.slice(-400)
|
|
108859
109848
|
});
|
|
108860
109849
|
}
|
|
108861
109850
|
hdrFrameDirs.set(videoId, frameDir);
|
|
108862
109851
|
}
|
|
108863
109852
|
assertNotAborted();
|
|
108864
109853
|
try {
|
|
109854
|
+
let countNonZeroAlpha2 = function(rgba) {
|
|
109855
|
+
let n = 0;
|
|
109856
|
+
for (let p = 3; p < rgba.length; p += 4) {
|
|
109857
|
+
if (rgba[p] !== 0) n++;
|
|
109858
|
+
}
|
|
109859
|
+
return n;
|
|
109860
|
+
}, countNonZeroRgb482 = function(buf) {
|
|
109861
|
+
let n = 0;
|
|
109862
|
+
for (let p = 0; p < buf.length; p += 6) {
|
|
109863
|
+
if (buf[p] !== 0 || buf[p + 1] !== 0 || buf[p + 2] !== 0) n++;
|
|
109864
|
+
}
|
|
109865
|
+
return n;
|
|
109866
|
+
};
|
|
109867
|
+
var countNonZeroAlpha = countNonZeroAlpha2, countNonZeroRgb48 = countNonZeroRgb482;
|
|
108865
109868
|
const beforeCaptureHook = domSession.onBeforeCapture;
|
|
108866
|
-
|
|
109869
|
+
const cleanedUpVideos = /* @__PURE__ */ new Set();
|
|
109870
|
+
const hdrVideoEndTimes = /* @__PURE__ */ new Map();
|
|
109871
|
+
for (const v of composition.videos) {
|
|
109872
|
+
if (hdrFrameDirs.has(v.id)) {
|
|
109873
|
+
hdrVideoEndTimes.set(v.id, v.end);
|
|
109874
|
+
}
|
|
109875
|
+
}
|
|
109876
|
+
const debugDumpEnabled = process.env.KEEP_TEMP === "1";
|
|
109877
|
+
const debugDumpDir = debugDumpEnabled ? join15(framesDir, "debug-composite") : null;
|
|
109878
|
+
if (debugDumpDir && !existsSync15(debugDumpDir)) {
|
|
109879
|
+
mkdirSync10(debugDumpDir, { recursive: true });
|
|
109880
|
+
}
|
|
109881
|
+
async function compositeToBuffer(canvas, time, fullStacking, elementFilter, debugFrameIndex = -1) {
|
|
109882
|
+
const filteredStacking = elementFilter ? fullStacking.filter((e) => elementFilter.has(e.id)) : fullStacking;
|
|
109883
|
+
const layers = groupIntoLayers(filteredStacking);
|
|
109884
|
+
const shouldLog = debugDumpEnabled && debugFrameIndex >= 0;
|
|
109885
|
+
if (shouldLog) {
|
|
109886
|
+
log.info("[diag] compositeToBuffer plan", {
|
|
109887
|
+
frame: debugFrameIndex,
|
|
109888
|
+
time: time.toFixed(3),
|
|
109889
|
+
filterSize: elementFilter?.size,
|
|
109890
|
+
fullStackingCount: fullStacking.length,
|
|
109891
|
+
filteredCount: filteredStacking.length,
|
|
109892
|
+
layerCount: layers.length,
|
|
109893
|
+
layers: layers.map(
|
|
109894
|
+
(l) => l.type === "hdr" ? {
|
|
109895
|
+
type: "hdr",
|
|
109896
|
+
id: l.element.id,
|
|
109897
|
+
z: l.element.zIndex,
|
|
109898
|
+
visible: l.element.visible,
|
|
109899
|
+
opacity: l.element.opacity,
|
|
109900
|
+
bounds: `${Math.round(l.element.x)},${Math.round(l.element.y)} ${Math.round(l.element.width)}x${Math.round(l.element.height)}`
|
|
109901
|
+
} : { type: "dom", ids: l.elementIds }
|
|
109902
|
+
)
|
|
109903
|
+
});
|
|
109904
|
+
}
|
|
109905
|
+
for (let layerIdx = 0; layerIdx < layers.length; layerIdx++) {
|
|
109906
|
+
const layer = layers[layerIdx];
|
|
109907
|
+
if (layer.type === "hdr") {
|
|
109908
|
+
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
109909
|
+
blitHdrVideoLayer(
|
|
109910
|
+
canvas,
|
|
109911
|
+
layer.element,
|
|
109912
|
+
time,
|
|
109913
|
+
job.config.fps,
|
|
109914
|
+
hdrFrameDirs,
|
|
109915
|
+
hdrVideoStartTimes,
|
|
109916
|
+
width,
|
|
109917
|
+
height,
|
|
109918
|
+
log,
|
|
109919
|
+
videoTransfers.get(layer.element.id),
|
|
109920
|
+
effectiveHdr?.transfer
|
|
109921
|
+
);
|
|
109922
|
+
if (shouldLog) {
|
|
109923
|
+
const after2 = countNonZeroRgb482(canvas);
|
|
109924
|
+
const frameDir = hdrFrameDirs.get(layer.element.id);
|
|
109925
|
+
const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
|
|
109926
|
+
const localTime = time - startTime;
|
|
109927
|
+
const frameNum = Math.floor(localTime * job.config.fps) + 1;
|
|
109928
|
+
const expectedFrame = frameDir ? join15(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
|
|
109929
|
+
log.info("[diag] hdr layer blit", {
|
|
109930
|
+
frame: debugFrameIndex,
|
|
109931
|
+
layerIdx,
|
|
109932
|
+
id: layer.element.id,
|
|
109933
|
+
pixelsAdded: after2 - before2,
|
|
109934
|
+
totalNonZero: after2,
|
|
109935
|
+
startTime,
|
|
109936
|
+
localTime: localTime.toFixed(3),
|
|
109937
|
+
hdrFrameNum: frameNum,
|
|
109938
|
+
expectedFrame,
|
|
109939
|
+
expectedFrameExists: expectedFrame ? existsSync15(expectedFrame) : false
|
|
109940
|
+
});
|
|
109941
|
+
}
|
|
109942
|
+
} else {
|
|
109943
|
+
const allElementIds = fullStacking.map((e) => e.id);
|
|
109944
|
+
const layerIds = new Set(layer.elementIds);
|
|
109945
|
+
const hideIds = allElementIds.filter((id) => !layerIds.has(id));
|
|
109946
|
+
await domSession.page.evaluate((t) => {
|
|
109947
|
+
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
109948
|
+
}, time);
|
|
109949
|
+
if (beforeCaptureHook) {
|
|
109950
|
+
await beforeCaptureHook(domSession.page, time);
|
|
109951
|
+
}
|
|
109952
|
+
await applyDomLayerMask(domSession.page, layer.elementIds, hideIds);
|
|
109953
|
+
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
109954
|
+
await removeDomLayerMask(domSession.page, hideIds);
|
|
109955
|
+
try {
|
|
109956
|
+
const { data: domRgba } = decodePng(domPng);
|
|
109957
|
+
if (!effectiveHdr) {
|
|
109958
|
+
throw new Error(
|
|
109959
|
+
"Invariant violation: effectiveHdr is undefined inside HDR layer branch"
|
|
109960
|
+
);
|
|
109961
|
+
}
|
|
109962
|
+
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
109963
|
+
const alphaPixels = shouldLog ? countNonZeroAlpha2(domRgba) : 0;
|
|
109964
|
+
blitRgba8OverRgb48le(domRgba, canvas, width, height, effectiveHdr.transfer);
|
|
109965
|
+
if (shouldLog && debugDumpDir) {
|
|
109966
|
+
const after2 = countNonZeroRgb482(canvas);
|
|
109967
|
+
const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
|
|
109968
|
+
const dumpPath = join15(debugDumpDir, dumpName);
|
|
109969
|
+
writeFileSync4(dumpPath, domPng);
|
|
109970
|
+
log.info("[diag] dom layer blit", {
|
|
109971
|
+
frame: debugFrameIndex,
|
|
109972
|
+
layerIdx,
|
|
109973
|
+
layerIds: layer.elementIds,
|
|
109974
|
+
hideCount: hideIds.length,
|
|
109975
|
+
pngBytes: domPng.length,
|
|
109976
|
+
alphaPixels,
|
|
109977
|
+
pixelsAdded: after2 - before2,
|
|
109978
|
+
totalNonZero: after2,
|
|
109979
|
+
dumpPath
|
|
109980
|
+
});
|
|
109981
|
+
}
|
|
109982
|
+
} catch (err) {
|
|
109983
|
+
log.warn("DOM layer decode/blit failed; skipping overlay", {
|
|
109984
|
+
layerIds: layer.elementIds,
|
|
109985
|
+
error: err instanceof Error ? err.message : String(err)
|
|
109986
|
+
});
|
|
109987
|
+
}
|
|
109988
|
+
}
|
|
109989
|
+
}
|
|
109990
|
+
if (shouldLog && debugDumpDir) {
|
|
109991
|
+
const finalNonZero = countNonZeroRgb482(canvas);
|
|
109992
|
+
log.info("[diag] compositeToBuffer end", {
|
|
109993
|
+
frame: debugFrameIndex,
|
|
109994
|
+
finalNonZeroPixels: finalNonZero,
|
|
109995
|
+
totalPixels: width * height,
|
|
109996
|
+
coverage: (finalNonZero / (width * height) * 100).toFixed(1) + "%"
|
|
109997
|
+
});
|
|
109998
|
+
}
|
|
109999
|
+
}
|
|
110000
|
+
const bufSize = width * height * 6;
|
|
110001
|
+
const hasTransitions = transitionRanges.length > 0;
|
|
110002
|
+
const transBufferA = hasTransitions ? Buffer.alloc(bufSize) : null;
|
|
110003
|
+
const transBufferB = hasTransitions ? Buffer.alloc(bufSize) : null;
|
|
110004
|
+
const transOutput = hasTransitions ? Buffer.alloc(bufSize) : null;
|
|
110005
|
+
const normalCanvas = Buffer.alloc(bufSize);
|
|
110006
|
+
for (let i = 0; i < totalFrames; i++) {
|
|
108867
110007
|
assertNotAborted();
|
|
108868
110008
|
const time = i / job.config.fps;
|
|
108869
110009
|
await domSession.page.evaluate((t) => {
|
|
@@ -108873,81 +110013,118 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108873
110013
|
await beforeCaptureHook(domSession.page, time);
|
|
108874
110014
|
}
|
|
108875
110015
|
const stackingInfo = await queryElementStacking(domSession.page, nativeHdrVideoIds);
|
|
108876
|
-
const
|
|
110016
|
+
const activeTransition = transitionRanges.find(
|
|
110017
|
+
(t) => i >= t.startFrame && i <= t.endFrame
|
|
110018
|
+
);
|
|
108877
110019
|
if (i % 30 === 0) {
|
|
108878
110020
|
const hdrEl = stackingInfo.find((e) => e.isHdr);
|
|
108879
|
-
const hdrInLayers = layers.some((l) => l.type === "hdr");
|
|
108880
110021
|
log.debug("[Render] HDR layer composite frame", {
|
|
108881
110022
|
frame: i,
|
|
108882
110023
|
time: time.toFixed(2),
|
|
108883
110024
|
hdrElement: hdrEl ? { z: hdrEl.zIndex, visible: hdrEl.visible, width: hdrEl.width } : null,
|
|
108884
|
-
|
|
108885
|
-
|
|
110025
|
+
stackingCount: stackingInfo.length,
|
|
110026
|
+
activeTransition: activeTransition?.shader
|
|
108886
110027
|
});
|
|
108887
110028
|
}
|
|
108888
|
-
|
|
108889
|
-
|
|
108890
|
-
|
|
108891
|
-
|
|
108892
|
-
|
|
108893
|
-
|
|
108894
|
-
|
|
108895
|
-
|
|
108896
|
-
|
|
108897
|
-
|
|
108898
|
-
const framePath = inBounds ? join15(frameDir, `frame_${String(videoFrameIndex).padStart(4, "0")}.png`) : null;
|
|
108899
|
-
if (framePath !== null && existsSync15(framePath)) {
|
|
108900
|
-
try {
|
|
108901
|
-
const hdrRgb = decodePngToRgb48le(readFileSync9(framePath)).data;
|
|
108902
|
-
blitRgb48leRegion(
|
|
108903
|
-
canvas,
|
|
108904
|
-
hdrRgb,
|
|
108905
|
-
el.x,
|
|
108906
|
-
el.y,
|
|
108907
|
-
el.width,
|
|
108908
|
-
el.height,
|
|
108909
|
-
width,
|
|
108910
|
-
height,
|
|
108911
|
-
el.opacity < 0.999 ? el.opacity : void 0
|
|
108912
|
-
);
|
|
108913
|
-
} catch (err) {
|
|
108914
|
-
log.warn("HDR layer decode/blit failed; skipping layer for frame", {
|
|
108915
|
-
frameIndex: i,
|
|
108916
|
-
videoId: el.id,
|
|
108917
|
-
framePath,
|
|
108918
|
-
error: err instanceof Error ? err.message : String(err)
|
|
108919
|
-
});
|
|
108920
|
-
}
|
|
108921
|
-
}
|
|
108922
|
-
} else {
|
|
108923
|
-
const allElementIds = stackingInfo.map((e) => e.id);
|
|
108924
|
-
const layerIds = new Set(layer.elementIds);
|
|
108925
|
-
const hideIds = allElementIds.filter(
|
|
108926
|
-
(id) => !layerIds.has(id) || nativeHdrVideoIds.has(id)
|
|
108927
|
-
);
|
|
108928
|
-
await hideVideoElements(domSession.page, hideIds);
|
|
108929
|
-
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
108930
|
-
await showVideoElements(domSession.page, hideIds);
|
|
110029
|
+
if (activeTransition && transBufferA && transBufferB && transOutput) {
|
|
110030
|
+
const progress = activeTransition.endFrame === activeTransition.startFrame ? 1 : (i - activeTransition.startFrame) / (activeTransition.endFrame - activeTransition.startFrame);
|
|
110031
|
+
const sceneAIds = new Set(sceneElements[activeTransition.fromScene] ?? []);
|
|
110032
|
+
const sceneBIds = new Set(sceneElements[activeTransition.toScene] ?? []);
|
|
110033
|
+
transBufferA.fill(0);
|
|
110034
|
+
transBufferB.fill(0);
|
|
110035
|
+
for (const [sceneBuf, sceneIds] of [
|
|
110036
|
+
[transBufferA, sceneAIds],
|
|
110037
|
+
[transBufferB, sceneBIds]
|
|
110038
|
+
]) {
|
|
108931
110039
|
await domSession.page.evaluate((t) => {
|
|
108932
110040
|
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
108933
110041
|
}, time);
|
|
110042
|
+
if (beforeCaptureHook) {
|
|
110043
|
+
await beforeCaptureHook(domSession.page, time);
|
|
110044
|
+
}
|
|
110045
|
+
for (const el of stackingInfo) {
|
|
110046
|
+
if (!el.isHdr || !sceneIds.has(el.id)) continue;
|
|
110047
|
+
blitHdrVideoLayer(
|
|
110048
|
+
sceneBuf,
|
|
110049
|
+
el,
|
|
110050
|
+
time,
|
|
110051
|
+
job.config.fps,
|
|
110052
|
+
hdrFrameDirs,
|
|
110053
|
+
hdrVideoStartTimes,
|
|
110054
|
+
width,
|
|
110055
|
+
height,
|
|
110056
|
+
log,
|
|
110057
|
+
videoTransfers.get(el.id),
|
|
110058
|
+
effectiveHdr?.transfer
|
|
110059
|
+
);
|
|
110060
|
+
}
|
|
110061
|
+
const showIds = Array.from(sceneIds);
|
|
110062
|
+
const hideIds = stackingInfo.map((e) => e.id).filter((id) => !sceneIds.has(id) || nativeHdrVideoIds.has(id));
|
|
110063
|
+
await applyDomLayerMask(domSession.page, showIds, hideIds);
|
|
110064
|
+
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
110065
|
+
await removeDomLayerMask(domSession.page, hideIds);
|
|
108934
110066
|
try {
|
|
108935
110067
|
const { data: domRgba } = decodePng(domPng);
|
|
108936
|
-
|
|
108937
|
-
|
|
110068
|
+
if (!effectiveHdr) {
|
|
110069
|
+
throw new Error(
|
|
110070
|
+
"Invariant violation: effectiveHdr is undefined inside hasHdrVideo branch"
|
|
110071
|
+
);
|
|
110072
|
+
}
|
|
110073
|
+
blitRgba8OverRgb48le(
|
|
110074
|
+
domRgba,
|
|
110075
|
+
sceneBuf,
|
|
110076
|
+
width,
|
|
110077
|
+
height,
|
|
110078
|
+
effectiveHdr.transfer
|
|
110079
|
+
);
|
|
108938
110080
|
} catch (err) {
|
|
108939
|
-
log.warn("DOM layer decode/blit failed; skipping overlay for
|
|
110081
|
+
log.warn("DOM layer decode/blit failed; skipping overlay for transition scene", {
|
|
108940
110082
|
frameIndex: i,
|
|
108941
|
-
|
|
110083
|
+
sceneIds: Array.from(sceneIds),
|
|
108942
110084
|
error: err instanceof Error ? err.message : String(err)
|
|
108943
110085
|
});
|
|
108944
110086
|
}
|
|
108945
110087
|
}
|
|
110088
|
+
const transitionFn = TRANSITIONS[activeTransition.shader] ?? crossfade;
|
|
110089
|
+
transitionFn(transBufferA, transBufferB, transOutput, width, height, progress);
|
|
110090
|
+
hdrEncoder.writeFrame(transOutput);
|
|
110091
|
+
} else {
|
|
110092
|
+
normalCanvas.fill(0);
|
|
110093
|
+
await compositeToBuffer(normalCanvas, time, stackingInfo, void 0, i);
|
|
110094
|
+
if (debugDumpEnabled && debugDumpDir && i % 30 === 0) {
|
|
110095
|
+
const previewPath = join15(
|
|
110096
|
+
debugDumpDir,
|
|
110097
|
+
`frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`
|
|
110098
|
+
);
|
|
110099
|
+
writeFileSync4(previewPath, normalCanvas);
|
|
110100
|
+
}
|
|
110101
|
+
hdrEncoder.writeFrame(normalCanvas);
|
|
110102
|
+
}
|
|
110103
|
+
if (process.env.KEEP_TEMP !== "1") {
|
|
110104
|
+
for (const [videoId, endTime] of hdrVideoEndTimes) {
|
|
110105
|
+
if (time > endTime && !cleanedUpVideos.has(videoId)) {
|
|
110106
|
+
const stillNeeded = activeTransition && (sceneElements[activeTransition.fromScene]?.includes(videoId) || sceneElements[activeTransition.toScene]?.includes(videoId));
|
|
110107
|
+
if (!stillNeeded) {
|
|
110108
|
+
const frameDir = hdrFrameDirs.get(videoId);
|
|
110109
|
+
if (frameDir) {
|
|
110110
|
+
try {
|
|
110111
|
+
rmSync3(frameDir, { recursive: true, force: true });
|
|
110112
|
+
} catch (err) {
|
|
110113
|
+
log.warn("Failed to clean up HDR frame directory", {
|
|
110114
|
+
videoId,
|
|
110115
|
+
frameDir,
|
|
110116
|
+
error: err instanceof Error ? err.message : String(err)
|
|
110117
|
+
});
|
|
110118
|
+
}
|
|
110119
|
+
}
|
|
110120
|
+
cleanedUpVideos.add(videoId);
|
|
110121
|
+
}
|
|
110122
|
+
}
|
|
110123
|
+
}
|
|
108946
110124
|
}
|
|
108947
|
-
hdrEncoder.writeFrame(canvas);
|
|
108948
110125
|
job.framesRendered = i + 1;
|
|
108949
|
-
if ((i + 1) % 10 === 0 || i + 1 ===
|
|
108950
|
-
const frameProgress = (i + 1) /
|
|
110126
|
+
if ((i + 1) % 10 === 0 || i + 1 === totalFrames) {
|
|
110127
|
+
const frameProgress = (i + 1) / totalFrames;
|
|
108951
110128
|
updateJobStatus(
|
|
108952
110129
|
job,
|
|
108953
110130
|
"rendering",
|
|
@@ -108990,7 +110167,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108990
110167
|
assertNotAborted();
|
|
108991
110168
|
}
|
|
108992
110169
|
if (enableStreamingEncode && streamingEncoder) {
|
|
108993
|
-
const reorderBuffer = createFrameReorderBuffer(0,
|
|
110170
|
+
const reorderBuffer = createFrameReorderBuffer(0, totalFrames);
|
|
108994
110171
|
const currentEncoder = streamingEncoder;
|
|
108995
110172
|
if (workerCount > 1) {
|
|
108996
110173
|
const tasks = distributeFrames(job.totalFrames, workerCount, workDir);
|
|
@@ -109047,7 +110224,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109047
110224
|
}
|
|
109048
110225
|
assertNotAborted();
|
|
109049
110226
|
lastBrowserConsole = session.browserConsoleBuffer;
|
|
109050
|
-
for (let i = 0; i <
|
|
110227
|
+
for (let i = 0; i < totalFrames; i++) {
|
|
109051
110228
|
assertNotAborted();
|
|
109052
110229
|
const time = i / job.config.fps;
|
|
109053
110230
|
const { buffer } = await captureFrameToBuffer(session, i, time);
|
|
@@ -109055,7 +110232,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109055
110232
|
currentEncoder.writeFrame(buffer);
|
|
109056
110233
|
reorderBuffer.advanceTo(i + 1);
|
|
109057
110234
|
job.framesRendered = i + 1;
|
|
109058
|
-
const frameProgress = (i + 1) /
|
|
110235
|
+
const frameProgress = (i + 1) / totalFrames;
|
|
109059
110236
|
const progress = 25 + frameProgress * 55;
|
|
109060
110237
|
updateJobStatus(
|
|
109061
110238
|
job,
|
|
@@ -109228,12 +110405,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109228
110405
|
chunkedEncode: enableChunkedEncode,
|
|
109229
110406
|
chunkSizeFrames: enableChunkedEncode ? chunkedEncodeSize : null,
|
|
109230
110407
|
compositionDurationSeconds: composition.duration,
|
|
109231
|
-
totalFrames
|
|
110408
|
+
totalFrames,
|
|
109232
110409
|
resolution: { width, height },
|
|
109233
110410
|
videoCount: composition.videos.length,
|
|
109234
110411
|
audioCount: composition.audios.length,
|
|
109235
110412
|
stages: perfStages,
|
|
109236
|
-
captureAvgMs:
|
|
110413
|
+
captureAvgMs: totalFrames > 0 ? Math.round((perfStages.captureMs ?? 0) / totalFrames) : void 0
|
|
109237
110414
|
};
|
|
109238
110415
|
job.perfSummary = perfSummary;
|
|
109239
110416
|
if (job.config.debug) {
|
|
@@ -109251,6 +110428,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109251
110428
|
const debugOutput = join15(workDir, `output${videoExt}`);
|
|
109252
110429
|
copyFileSync2(outputPath, debugOutput);
|
|
109253
110430
|
}
|
|
110431
|
+
} else if (process.env.KEEP_TEMP === "1") {
|
|
110432
|
+
log.info("KEEP_TEMP=1 \u2014 leaving workDir on disk for inspection", { workDir });
|
|
109254
110433
|
} else {
|
|
109255
110434
|
await safeCleanup(
|
|
109256
110435
|
"remove workDir",
|