@hyperframes/studio-server 0.7.15
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/LICENSE +190 -0
- package/dist/helpers/draftMarkers.d.ts +12 -0
- package/dist/helpers/draftMarkers.js +14 -0
- package/dist/helpers/draftMarkers.js.map +1 -0
- package/dist/helpers/finiteMutation.d.ts +11 -0
- package/dist/helpers/finiteMutation.js +29 -0
- package/dist/helpers/finiteMutation.js.map +1 -0
- package/dist/helpers/manualEditsRenderScript.d.ts +14 -0
- package/dist/helpers/manualEditsRenderScript.js +583 -0
- package/dist/helpers/manualEditsRenderScript.js.map +1 -0
- package/dist/helpers/screenshotClip.d.ts +9 -0
- package/dist/helpers/screenshotClip.js +26 -0
- package/dist/helpers/screenshotClip.js.map +1 -0
- package/dist/helpers/studioMotionRenderScript.d.ts +10 -0
- package/dist/helpers/studioMotionRenderScript.js +191 -0
- package/dist/helpers/studioMotionRenderScript.js.map +1 -0
- package/dist/index.d.ts +167 -0
- package/dist/index.js +3869 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
// src/helpers/manualEditsRenderScript.ts
|
|
2
|
+
var STUDIO_MANUAL_EDITS_PATH = ".hyperframes/studio-manual-edits.json";
|
|
3
|
+
function createStudioManualEditsRenderBodyScript(manifestContent, options = {}) {
|
|
4
|
+
if (!manifestContent.trim()) return null;
|
|
5
|
+
return `(${studioManualEditsRenderRuntime.toString()})(${JSON.stringify(manifestContent)}, ${JSON.stringify(options.activeCompositionPath ?? null)});`;
|
|
6
|
+
}
|
|
7
|
+
function createStudioPositionSeekReapplyScript() {
|
|
8
|
+
return `(${studioPositionSeekReapplyRuntime.toString()})();`;
|
|
9
|
+
}
|
|
10
|
+
function studioPositionSeekReapplyRuntime() {
|
|
11
|
+
const OFFSET_X_PROP = "--hf-studio-offset-x";
|
|
12
|
+
const OFFSET_Y_PROP = "--hf-studio-offset-y";
|
|
13
|
+
const WIDTH_PROP = "--hf-studio-width";
|
|
14
|
+
const HEIGHT_PROP = "--hf-studio-height";
|
|
15
|
+
const ROTATION_PROP = "--hf-studio-rotation";
|
|
16
|
+
const PATH_OFFSET_ATTR = "data-hf-studio-path-offset";
|
|
17
|
+
const BOX_SIZE_ATTR = "data-hf-studio-box-size";
|
|
18
|
+
const ROTATION_ATTR = "data-hf-studio-rotation";
|
|
19
|
+
const ORIGINAL_TRANSLATE_ATTR = "data-hf-studio-original-translate";
|
|
20
|
+
const ORIGINAL_ROTATE_ATTR = "data-hf-studio-original-rotate";
|
|
21
|
+
const MOTION_ATTR = "data-hf-studio-motion";
|
|
22
|
+
const MOTION_TL_KEY = "studio-motion";
|
|
23
|
+
const WRAPPED_PROP = "__hfStudioPositionSeekReapplyWrapped";
|
|
24
|
+
if (!document.querySelector("[" + PATH_OFFSET_ATTR + '="true"]') && !document.querySelector("[" + BOX_SIZE_ATTR + '="true"]') && !document.querySelector("[" + ROTATION_ATTR + '="true"]') && !document.querySelector("[" + MOTION_ATTR + "]"))
|
|
25
|
+
return;
|
|
26
|
+
const splitTopLevelWhitespace = (value) => {
|
|
27
|
+
const parts = [];
|
|
28
|
+
let depth = 0;
|
|
29
|
+
let current = "";
|
|
30
|
+
for (const char of value.trim()) {
|
|
31
|
+
if (char === "(") depth += 1;
|
|
32
|
+
if (char === ")") depth = Math.max(0, depth - 1);
|
|
33
|
+
if (/\s/.test(char) && depth === 0) {
|
|
34
|
+
if (current) parts.push(current);
|
|
35
|
+
current = "";
|
|
36
|
+
} else {
|
|
37
|
+
current += char;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (current) parts.push(current);
|
|
41
|
+
return parts;
|
|
42
|
+
};
|
|
43
|
+
const composeTranslate = (element, x, y) => {
|
|
44
|
+
const original = element.getAttribute(ORIGINAL_TRANSLATE_ATTR)?.trim();
|
|
45
|
+
if (!original || original === "none") return x + " " + y;
|
|
46
|
+
const parts = splitTopLevelWhitespace(original);
|
|
47
|
+
if (parts.length === 1) return "calc(" + parts[0] + " + " + x + ") " + y;
|
|
48
|
+
if (parts.length >= 2) {
|
|
49
|
+
const z = parts.length >= 3 ? " " + parts[2] : "";
|
|
50
|
+
return "calc(" + parts[0] + " + " + x + ") calc(" + parts[1] + " + " + y + ")" + z;
|
|
51
|
+
}
|
|
52
|
+
return x + " " + y;
|
|
53
|
+
};
|
|
54
|
+
const isSimpleRotateAngle = (value) => /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:deg|rad|turn|grad)$/.test(value.trim());
|
|
55
|
+
const composeRotation = (element, rotationValue) => {
|
|
56
|
+
const original = element.getAttribute(ORIGINAL_ROTATE_ATTR)?.trim();
|
|
57
|
+
if (!original || original === "none" || !isSimpleRotateAngle(original)) return rotationValue;
|
|
58
|
+
return "calc(" + original + " + " + rotationValue + ")";
|
|
59
|
+
};
|
|
60
|
+
let lastSeekTime = 0;
|
|
61
|
+
let cachedMotionKey = "";
|
|
62
|
+
const finiteNum = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
63
|
+
const computeMotionKey = (motionEls) => {
|
|
64
|
+
let key = "";
|
|
65
|
+
for (let i = 0; i < motionEls.length; i++) {
|
|
66
|
+
const json = motionEls[i].getAttribute?.(MOTION_ATTR);
|
|
67
|
+
if (json) key += (key ? "\n" : "") + json;
|
|
68
|
+
}
|
|
69
|
+
return key;
|
|
70
|
+
};
|
|
71
|
+
const reapplyMotionTimeline = () => {
|
|
72
|
+
const motionEls = document.querySelectorAll("[" + MOTION_ATTR + "]");
|
|
73
|
+
if (motionEls.length === 0) {
|
|
74
|
+
cachedMotionKey = "";
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const win = window;
|
|
78
|
+
const gsap = win.gsap;
|
|
79
|
+
if (!gsap || typeof gsap.timeline !== "function") return;
|
|
80
|
+
win.__timelines = win.__timelines || {};
|
|
81
|
+
const motionKey = computeMotionKey(motionEls);
|
|
82
|
+
const existing = win.__timelines[MOTION_TL_KEY];
|
|
83
|
+
if (motionKey && motionKey === cachedMotionKey && existing && typeof existing.totalTime === "function") {
|
|
84
|
+
existing.totalTime(lastSeekTime, false);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (existing && typeof existing.kill === "function") existing.kill();
|
|
88
|
+
const tl = gsap.timeline({ paused: true, defaults: { overwrite: "auto" } });
|
|
89
|
+
const fromTo = tl.fromTo;
|
|
90
|
+
if (typeof fromTo !== "function") return;
|
|
91
|
+
let applied = 0;
|
|
92
|
+
for (let i = 0; i < motionEls.length; i++) {
|
|
93
|
+
const el = motionEls[i];
|
|
94
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
95
|
+
const json = el.getAttribute(MOTION_ATTR);
|
|
96
|
+
if (!json) continue;
|
|
97
|
+
try {
|
|
98
|
+
const m = JSON.parse(json);
|
|
99
|
+
const start = finiteNum(m.start);
|
|
100
|
+
const duration = finiteNum(m.duration);
|
|
101
|
+
if (start == null || duration == null || duration <= 0) continue;
|
|
102
|
+
const ease = typeof m.ease === "string" ? m.ease : "none";
|
|
103
|
+
const from = m.from && typeof m.from === "object" ? m.from : {};
|
|
104
|
+
const to = m.to && typeof m.to === "object" ? m.to : {};
|
|
105
|
+
const customEase = m.customEase;
|
|
106
|
+
let resolvedEase = ease;
|
|
107
|
+
if (customEase?.id && customEase?.data && win.CustomEase?.create) {
|
|
108
|
+
try {
|
|
109
|
+
gsap.registerPlugin?.(win.CustomEase);
|
|
110
|
+
win.CustomEase.create(customEase.id, customEase.data);
|
|
111
|
+
resolvedEase = customEase.id;
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
fromTo.call(
|
|
116
|
+
tl,
|
|
117
|
+
el,
|
|
118
|
+
{ ...from },
|
|
119
|
+
{ ...to, duration, ease: resolvedEase, overwrite: "auto", immediateRender: false },
|
|
120
|
+
start
|
|
121
|
+
);
|
|
122
|
+
applied += 1;
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (applied === 0) {
|
|
127
|
+
cachedMotionKey = "";
|
|
128
|
+
if (typeof tl.kill === "function")
|
|
129
|
+
tl.kill();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
cachedMotionKey = motionKey;
|
|
133
|
+
win.__timelines[MOTION_TL_KEY] = tl;
|
|
134
|
+
if (typeof tl.pause === "function") tl.pause();
|
|
135
|
+
if (typeof tl.totalTime === "function")
|
|
136
|
+
tl.totalTime(lastSeekTime, false);
|
|
137
|
+
};
|
|
138
|
+
const stripGsapTranslateFromTransform = (el) => {
|
|
139
|
+
const transform = el.style.getPropertyValue("transform");
|
|
140
|
+
if (!transform || transform === "none") return;
|
|
141
|
+
const win = el.ownerDocument.defaultView;
|
|
142
|
+
const MatrixCtor = win?.DOMMatrix;
|
|
143
|
+
if (!MatrixCtor) return;
|
|
144
|
+
try {
|
|
145
|
+
const m = new MatrixCtor(transform);
|
|
146
|
+
if (m.m41 === 0 && m.m42 === 0) return;
|
|
147
|
+
m.m41 = 0;
|
|
148
|
+
m.m42 = 0;
|
|
149
|
+
if (m.is2D && m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1) {
|
|
150
|
+
el.style.removeProperty("transform");
|
|
151
|
+
} else {
|
|
152
|
+
el.style.setProperty("transform", m.toString());
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const reapplyAll = () => {
|
|
158
|
+
const offsetEls = document.querySelectorAll("[" + PATH_OFFSET_ATTR + '="true"]');
|
|
159
|
+
for (let i = 0; i < offsetEls.length; i++) {
|
|
160
|
+
const el = offsetEls[i];
|
|
161
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
162
|
+
const x = el.style.getPropertyValue(OFFSET_X_PROP);
|
|
163
|
+
const y = el.style.getPropertyValue(OFFSET_Y_PROP);
|
|
164
|
+
if (x || y) {
|
|
165
|
+
el.style.setProperty(
|
|
166
|
+
"translate",
|
|
167
|
+
composeTranslate(
|
|
168
|
+
el,
|
|
169
|
+
"var(" + OFFSET_X_PROP + ", 0px)",
|
|
170
|
+
"var(" + OFFSET_Y_PROP + ", 0px)"
|
|
171
|
+
)
|
|
172
|
+
);
|
|
173
|
+
stripGsapTranslateFromTransform(el);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const boxSizeEls = document.querySelectorAll("[" + BOX_SIZE_ATTR + '="true"]');
|
|
177
|
+
for (let i = 0; i < boxSizeEls.length; i++) {
|
|
178
|
+
const el = boxSizeEls[i];
|
|
179
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
180
|
+
const w = el.style.getPropertyValue(WIDTH_PROP);
|
|
181
|
+
const h = el.style.getPropertyValue(HEIGHT_PROP);
|
|
182
|
+
if (w) el.style.setProperty("width", w);
|
|
183
|
+
if (h) el.style.setProperty("height", h);
|
|
184
|
+
}
|
|
185
|
+
const rotEls = document.querySelectorAll("[" + ROTATION_ATTR + '="true"]');
|
|
186
|
+
for (let i = 0; i < rotEls.length; i++) {
|
|
187
|
+
const el = rotEls[i];
|
|
188
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
189
|
+
const rot = el.style.getPropertyValue(ROTATION_PROP);
|
|
190
|
+
if (rot) {
|
|
191
|
+
el.style.setProperty("rotate", composeRotation(el, "var(" + ROTATION_PROP + ", 0deg)"));
|
|
192
|
+
stripGsapTranslateFromTransform(el);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
reapplyMotionTimeline();
|
|
196
|
+
};
|
|
197
|
+
const runtimeWindow = window;
|
|
198
|
+
const isWrapped = (fn) => Boolean(fn[WRAPPED_PROP]);
|
|
199
|
+
const markWrapped = (fn) => {
|
|
200
|
+
try {
|
|
201
|
+
Object.defineProperty(fn, WRAPPED_PROP, {
|
|
202
|
+
configurable: false,
|
|
203
|
+
enumerable: false,
|
|
204
|
+
value: true
|
|
205
|
+
});
|
|
206
|
+
} catch {
|
|
207
|
+
try {
|
|
208
|
+
fn[WRAPPED_PROP] = true;
|
|
209
|
+
} catch {
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
const wrapFn = (get, set) => {
|
|
214
|
+
const fn = get();
|
|
215
|
+
if (typeof fn !== "function") return false;
|
|
216
|
+
const seek = fn;
|
|
217
|
+
if (isWrapped(seek)) {
|
|
218
|
+
reapplyAll();
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
const wrapped = function(time) {
|
|
222
|
+
lastSeekTime = typeof time === "number" && Number.isFinite(time) ? Math.max(0, time) : 0;
|
|
223
|
+
const result = seek.call(this, time);
|
|
224
|
+
reapplyAll();
|
|
225
|
+
return result;
|
|
226
|
+
};
|
|
227
|
+
markWrapped(wrapped);
|
|
228
|
+
set(wrapped);
|
|
229
|
+
reapplyAll();
|
|
230
|
+
return true;
|
|
231
|
+
};
|
|
232
|
+
const wrapSeekFunctions = () => {
|
|
233
|
+
const a = wrapFn(
|
|
234
|
+
() => runtimeWindow.__hf?.["seek"],
|
|
235
|
+
(fn) => {
|
|
236
|
+
if (runtimeWindow.__hf) runtimeWindow.__hf["seek"] = fn;
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
const b = wrapFn(
|
|
240
|
+
() => runtimeWindow.__player?.["renderSeek"],
|
|
241
|
+
(fn) => {
|
|
242
|
+
if (runtimeWindow.__player) runtimeWindow.__player["renderSeek"] = fn;
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
return a || b;
|
|
246
|
+
};
|
|
247
|
+
const installSeekTrap = (obj, key, getter, setter) => {
|
|
248
|
+
if (!obj) return;
|
|
249
|
+
try {
|
|
250
|
+
let current = obj[key];
|
|
251
|
+
Object.defineProperty(obj, key, {
|
|
252
|
+
configurable: true,
|
|
253
|
+
enumerable: true,
|
|
254
|
+
get() {
|
|
255
|
+
return current;
|
|
256
|
+
},
|
|
257
|
+
set(value) {
|
|
258
|
+
current = value;
|
|
259
|
+
if (typeof value === "function" && !isWrapped(value)) {
|
|
260
|
+
wrapFn(getter, setter);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
} catch {
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
if (document.readyState === "loading") {
|
|
268
|
+
document.addEventListener("DOMContentLoaded", () => reapplyAll(), { once: true });
|
|
269
|
+
} else {
|
|
270
|
+
reapplyAll();
|
|
271
|
+
}
|
|
272
|
+
wrapSeekFunctions();
|
|
273
|
+
installSeekTrap(
|
|
274
|
+
runtimeWindow.__hf,
|
|
275
|
+
"seek",
|
|
276
|
+
() => runtimeWindow.__hf?.["seek"],
|
|
277
|
+
(fn) => {
|
|
278
|
+
if (runtimeWindow.__hf) runtimeWindow.__hf["seek"] = fn;
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
installSeekTrap(
|
|
282
|
+
runtimeWindow.__player,
|
|
283
|
+
"renderSeek",
|
|
284
|
+
() => runtimeWindow.__player?.["renderSeek"],
|
|
285
|
+
(fn) => {
|
|
286
|
+
if (runtimeWindow.__player) runtimeWindow.__player["renderSeek"] = fn;
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
let remaining = 120;
|
|
290
|
+
const interval = setInterval(() => {
|
|
291
|
+
wrapSeekFunctions();
|
|
292
|
+
remaining -= 1;
|
|
293
|
+
if (remaining <= 0) clearInterval(interval);
|
|
294
|
+
}, 50);
|
|
295
|
+
}
|
|
296
|
+
function studioManualEditsRenderRuntime(manifestContent, activeCompositionPath) {
|
|
297
|
+
const OFFSET_X_PROP = "--hf-studio-offset-x";
|
|
298
|
+
const OFFSET_Y_PROP = "--hf-studio-offset-y";
|
|
299
|
+
const WIDTH_PROP = "--hf-studio-width";
|
|
300
|
+
const HEIGHT_PROP = "--hf-studio-height";
|
|
301
|
+
const ROTATION_PROP = "--hf-studio-rotation";
|
|
302
|
+
const PATH_OFFSET_ATTR = "data-hf-studio-path-offset";
|
|
303
|
+
const BOX_SIZE_ATTR = "data-hf-studio-box-size";
|
|
304
|
+
const ROTATION_ATTR = "data-hf-studio-rotation";
|
|
305
|
+
const ORIGINAL_TRANSLATE_ATTR = "data-hf-studio-original-translate";
|
|
306
|
+
const ORIGINAL_ROTATE_ATTR = "data-hf-studio-original-rotate";
|
|
307
|
+
const WRAPPED_SEEK_PROP = "__hfStudioManualEditsWrapped";
|
|
308
|
+
const ROTATION_TRANSFORM_ORIGIN = "center center";
|
|
309
|
+
const finiteNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
310
|
+
const objectRecord = (value) => value && typeof value === "object" ? value : null;
|
|
311
|
+
const runtimeWindow = window;
|
|
312
|
+
const parsedManifest = (() => {
|
|
313
|
+
try {
|
|
314
|
+
return objectRecord(JSON.parse(manifestContent));
|
|
315
|
+
} catch {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
})();
|
|
319
|
+
const manifestEdits = Array.isArray(parsedManifest?.edits) ? parsedManifest.edits : [];
|
|
320
|
+
if (manifestEdits.length === 0) return;
|
|
321
|
+
const sourceFileForElement = (element) => {
|
|
322
|
+
let current = element;
|
|
323
|
+
while (current) {
|
|
324
|
+
const sourceFile = current.getAttribute("data-composition-file") ?? current.getAttribute("data-composition-src");
|
|
325
|
+
if (sourceFile) return sourceFile;
|
|
326
|
+
current = current.parentElement;
|
|
327
|
+
}
|
|
328
|
+
return activeCompositionPath ?? "index.html";
|
|
329
|
+
};
|
|
330
|
+
const elementMatchesSourceFile = (element, sourceFile) => sourceFileForElement(element) === sourceFile;
|
|
331
|
+
const styleUsesStudioOffset = (value) => value.includes(OFFSET_X_PROP) || value.includes(OFFSET_Y_PROP);
|
|
332
|
+
const styleUsesStudioRotation = (value) => value.includes(ROTATION_PROP);
|
|
333
|
+
const splitTopLevelWhitespace = (value) => {
|
|
334
|
+
const parts = [];
|
|
335
|
+
let depth = 0;
|
|
336
|
+
let current = "";
|
|
337
|
+
for (const char of value.trim()) {
|
|
338
|
+
if (char === "(") depth += 1;
|
|
339
|
+
if (char === ")") depth = Math.max(0, depth - 1);
|
|
340
|
+
if (/\s/.test(char) && depth === 0) {
|
|
341
|
+
if (current) parts.push(current);
|
|
342
|
+
current = "";
|
|
343
|
+
} else {
|
|
344
|
+
current += char;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (current) parts.push(current);
|
|
348
|
+
return parts;
|
|
349
|
+
};
|
|
350
|
+
const composeTranslate = (element, x, y) => {
|
|
351
|
+
const original = element.getAttribute(ORIGINAL_TRANSLATE_ATTR)?.trim();
|
|
352
|
+
if (!original || original === "none") return `${x} ${y}`;
|
|
353
|
+
const parts = splitTopLevelWhitespace(original);
|
|
354
|
+
if (parts.length === 1) return `calc(${parts[0]} + ${x}) ${y}`;
|
|
355
|
+
if (parts.length === 2) return `calc(${parts[0]} + ${x}) calc(${parts[1]} + ${y})`;
|
|
356
|
+
if (parts.length === 3) {
|
|
357
|
+
return `calc(${parts[0]} + ${x}) calc(${parts[1]} + ${y}) ${parts[2]}`;
|
|
358
|
+
}
|
|
359
|
+
return `${x} ${y}`;
|
|
360
|
+
};
|
|
361
|
+
const readStyleOrComputed = (element, property) => {
|
|
362
|
+
try {
|
|
363
|
+
return element.style.getPropertyValue(property) || getComputedStyle(element).getPropertyValue(property);
|
|
364
|
+
} catch {
|
|
365
|
+
return element.style.getPropertyValue(property);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
const readTransformLonghandBase = (element, property) => {
|
|
369
|
+
const value = readStyleOrComputed(element, property).trim();
|
|
370
|
+
return value === "none" ? "" : value;
|
|
371
|
+
};
|
|
372
|
+
const preparePathOffsetBase = (element) => {
|
|
373
|
+
const currentTranslate = readTransformLonghandBase(element, "translate");
|
|
374
|
+
const hasMarker = element.hasAttribute(PATH_OFFSET_ATTR);
|
|
375
|
+
const wasResetByAnimation = !styleUsesStudioOffset(currentTranslate);
|
|
376
|
+
if (!hasMarker) {
|
|
377
|
+
element.setAttribute(ORIGINAL_TRANSLATE_ATTR, wasResetByAnimation ? currentTranslate : "");
|
|
378
|
+
} else if (wasResetByAnimation) {
|
|
379
|
+
element.setAttribute(ORIGINAL_TRANSLATE_ATTR, currentTranslate);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
const prepareRotationBase = (element) => {
|
|
383
|
+
const currentRotate = readTransformLonghandBase(element, "rotate");
|
|
384
|
+
const hasMarker = element.hasAttribute(ROTATION_ATTR);
|
|
385
|
+
const wasResetByAnimation = !styleUsesStudioRotation(currentRotate);
|
|
386
|
+
if (!hasMarker) {
|
|
387
|
+
element.setAttribute(ORIGINAL_ROTATE_ATTR, wasResetByAnimation ? currentRotate : "");
|
|
388
|
+
} else if (wasResetByAnimation) {
|
|
389
|
+
element.setAttribute(ORIGINAL_ROTATE_ATTR, currentRotate);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
const querySelectorCandidates = (selector) => {
|
|
393
|
+
const isCandidate = (element) => element instanceof HTMLElement;
|
|
394
|
+
const className = selector.match(/^\.([A-Za-z0-9_-]+)$/)?.[1];
|
|
395
|
+
if (className) {
|
|
396
|
+
return Array.from(document.getElementsByTagName("*")).filter(
|
|
397
|
+
(element) => isCandidate(element) && element.classList.contains(className)
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
if (/^[A-Za-z][A-Za-z0-9-]*$/.test(selector)) {
|
|
401
|
+
return Array.from(document.getElementsByTagName(selector)).filter(isCandidate);
|
|
402
|
+
}
|
|
403
|
+
return Array.from(document.querySelectorAll(selector)).filter(isCandidate);
|
|
404
|
+
};
|
|
405
|
+
const resolveTarget = (edit) => {
|
|
406
|
+
const targetRecord = objectRecord(edit.target);
|
|
407
|
+
if (!targetRecord) return null;
|
|
408
|
+
const sourceFile = typeof targetRecord.sourceFile === "string" ? targetRecord.sourceFile : "";
|
|
409
|
+
if (!sourceFile) return null;
|
|
410
|
+
const id = typeof targetRecord.id === "string" ? targetRecord.id : "";
|
|
411
|
+
if (id) {
|
|
412
|
+
const byId = document.getElementById(id);
|
|
413
|
+
if (byId instanceof HTMLElement && elementMatchesSourceFile(byId, sourceFile)) return byId;
|
|
414
|
+
const matchesById = [
|
|
415
|
+
document.documentElement,
|
|
416
|
+
...Array.from(document.getElementsByTagName("*"))
|
|
417
|
+
].filter(
|
|
418
|
+
(element) => element instanceof HTMLElement && element.id === id && elementMatchesSourceFile(element, sourceFile)
|
|
419
|
+
);
|
|
420
|
+
if (matchesById[0]) return matchesById[0];
|
|
421
|
+
}
|
|
422
|
+
const selector = typeof targetRecord.selector === "string" ? targetRecord.selector : "";
|
|
423
|
+
if (!selector) return null;
|
|
424
|
+
try {
|
|
425
|
+
const matches = querySelectorCandidates(selector).filter(
|
|
426
|
+
(element) => elementMatchesSourceFile(element, sourceFile)
|
|
427
|
+
);
|
|
428
|
+
const selectorIndex = finiteNumber(targetRecord.selectorIndex) ?? 0;
|
|
429
|
+
return matches[Math.max(0, Math.floor(selectorIndex))] ?? null;
|
|
430
|
+
} catch {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
const roundRotationAngle = (angle) => Math.round(angle * 10) / 10;
|
|
435
|
+
const isSimpleRotateAngle = (value) => /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:deg|rad|turn|grad)$/.test(value.trim());
|
|
436
|
+
const composeRotation = (element, rotationValue) => {
|
|
437
|
+
const original = element.getAttribute(ORIGINAL_ROTATE_ATTR)?.trim();
|
|
438
|
+
if (!original || original === "none" || !isSimpleRotateAngle(original)) {
|
|
439
|
+
return rotationValue;
|
|
440
|
+
}
|
|
441
|
+
return `calc(${original} + ${rotationValue})`;
|
|
442
|
+
};
|
|
443
|
+
const applyPathOffset = (element, edit) => {
|
|
444
|
+
const x = finiteNumber(edit.x);
|
|
445
|
+
const y = finiteNumber(edit.y);
|
|
446
|
+
if (x == null || y == null) return;
|
|
447
|
+
preparePathOffsetBase(element);
|
|
448
|
+
element.setAttribute(PATH_OFFSET_ATTR, "true");
|
|
449
|
+
element.style.setProperty(OFFSET_X_PROP, `${Math.round(x)}px`);
|
|
450
|
+
element.style.setProperty(OFFSET_Y_PROP, `${Math.round(y)}px`);
|
|
451
|
+
element.style.setProperty(
|
|
452
|
+
"translate",
|
|
453
|
+
composeTranslate(element, `var(${OFFSET_X_PROP}, 0px)`, `var(${OFFSET_Y_PROP}, 0px)`)
|
|
454
|
+
);
|
|
455
|
+
};
|
|
456
|
+
const readParentFlexBasisPixels = (element, size) => {
|
|
457
|
+
const parent = element.parentElement;
|
|
458
|
+
if (!parent) return null;
|
|
459
|
+
const styles = getComputedStyle(parent);
|
|
460
|
+
if (styles.display !== "flex" && styles.display !== "inline-flex") return null;
|
|
461
|
+
return Math.round(
|
|
462
|
+
Math.max(1, styles.flexDirection.startsWith("column") ? size.height : size.width)
|
|
463
|
+
);
|
|
464
|
+
};
|
|
465
|
+
const applyBoxSize = (element, edit) => {
|
|
466
|
+
const width = finiteNumber(edit.width);
|
|
467
|
+
const height = finiteNumber(edit.height);
|
|
468
|
+
if (width == null || height == null || width <= 0 || height <= 0) return;
|
|
469
|
+
const rounded = {
|
|
470
|
+
width: Math.round(Math.max(1, width)),
|
|
471
|
+
height: Math.round(Math.max(1, height))
|
|
472
|
+
};
|
|
473
|
+
element.setAttribute(BOX_SIZE_ATTR, "true");
|
|
474
|
+
element.style.setProperty(WIDTH_PROP, `${rounded.width}px`);
|
|
475
|
+
element.style.setProperty(HEIGHT_PROP, `${rounded.height}px`);
|
|
476
|
+
element.style.setProperty("box-sizing", "border-box");
|
|
477
|
+
element.style.setProperty("width", `${rounded.width}px`);
|
|
478
|
+
element.style.setProperty("height", `${rounded.height}px`);
|
|
479
|
+
element.style.setProperty("min-width", "0px");
|
|
480
|
+
element.style.setProperty("min-height", "0px");
|
|
481
|
+
element.style.setProperty("max-width", "none");
|
|
482
|
+
element.style.setProperty("max-height", "none");
|
|
483
|
+
const flexBasis = readParentFlexBasisPixels(element, rounded);
|
|
484
|
+
if (flexBasis != null) {
|
|
485
|
+
element.style.setProperty("flex-basis", `${flexBasis}px`);
|
|
486
|
+
element.style.setProperty("flex-grow", "0");
|
|
487
|
+
element.style.setProperty("flex-shrink", "0");
|
|
488
|
+
}
|
|
489
|
+
if (getComputedStyle(element).display === "inline") {
|
|
490
|
+
element.style.setProperty("display", "inline-block");
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
const applyRotation = (element, edit) => {
|
|
494
|
+
const angle = finiteNumber(edit.angle);
|
|
495
|
+
if (angle == null) return;
|
|
496
|
+
prepareRotationBase(element);
|
|
497
|
+
element.setAttribute(ROTATION_ATTR, "true");
|
|
498
|
+
element.style.setProperty(ROTATION_PROP, `${roundRotationAngle(angle)}deg`);
|
|
499
|
+
element.style.setProperty("transform-origin", ROTATION_TRANSFORM_ORIGIN);
|
|
500
|
+
element.style.setProperty("rotate", composeRotation(element, `var(${ROTATION_PROP}, 0deg)`));
|
|
501
|
+
};
|
|
502
|
+
const applyManifest = () => {
|
|
503
|
+
let applied = 0;
|
|
504
|
+
for (const edit of manifestEdits) {
|
|
505
|
+
const editRecord = objectRecord(edit);
|
|
506
|
+
if (!editRecord) continue;
|
|
507
|
+
const element = resolveTarget(editRecord);
|
|
508
|
+
if (!element) continue;
|
|
509
|
+
if (editRecord.kind === "path-offset") applyPathOffset(element, editRecord);
|
|
510
|
+
if (editRecord.kind === "box-size") applyBoxSize(element, editRecord);
|
|
511
|
+
if (editRecord.kind === "rotation") applyRotation(element, editRecord);
|
|
512
|
+
applied += 1;
|
|
513
|
+
}
|
|
514
|
+
return applied;
|
|
515
|
+
};
|
|
516
|
+
runtimeWindow.__hfStudioManualEditsApply = applyManifest;
|
|
517
|
+
const markWrapped = (fn) => {
|
|
518
|
+
try {
|
|
519
|
+
Object.defineProperty(fn, WRAPPED_SEEK_PROP, {
|
|
520
|
+
configurable: false,
|
|
521
|
+
enumerable: false,
|
|
522
|
+
value: true
|
|
523
|
+
});
|
|
524
|
+
} catch {
|
|
525
|
+
try {
|
|
526
|
+
fn[WRAPPED_SEEK_PROP] = true;
|
|
527
|
+
} catch {
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
const isWrapped = (fn) => Boolean(fn[WRAPPED_SEEK_PROP]);
|
|
532
|
+
const wrapFunction = (get, set) => {
|
|
533
|
+
const fn = get();
|
|
534
|
+
if (!fn) return false;
|
|
535
|
+
const seek = fn;
|
|
536
|
+
if (isWrapped(seek)) {
|
|
537
|
+
applyManifest();
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
const wrappedSeek = function(time) {
|
|
541
|
+
const result = seek.call(this, time);
|
|
542
|
+
applyManifest();
|
|
543
|
+
return result;
|
|
544
|
+
};
|
|
545
|
+
markWrapped(wrappedSeek);
|
|
546
|
+
set(wrappedSeek);
|
|
547
|
+
applyManifest();
|
|
548
|
+
return true;
|
|
549
|
+
};
|
|
550
|
+
const wrapSeekFunctions = () => {
|
|
551
|
+
const wrappedHfSeek = wrapFunction(
|
|
552
|
+
() => runtimeWindow.__hf?.seek,
|
|
553
|
+
(fn) => {
|
|
554
|
+
if (runtimeWindow.__hf) runtimeWindow.__hf.seek = fn;
|
|
555
|
+
}
|
|
556
|
+
);
|
|
557
|
+
const wrappedPlayerRenderSeek = wrapFunction(
|
|
558
|
+
() => runtimeWindow.__player?.renderSeek,
|
|
559
|
+
(fn) => {
|
|
560
|
+
if (runtimeWindow.__player) runtimeWindow.__player.renderSeek = fn;
|
|
561
|
+
}
|
|
562
|
+
);
|
|
563
|
+
return wrappedHfSeek || wrappedPlayerRenderSeek;
|
|
564
|
+
};
|
|
565
|
+
if (document.readyState === "loading") {
|
|
566
|
+
document.addEventListener("DOMContentLoaded", () => applyManifest(), { once: true });
|
|
567
|
+
} else {
|
|
568
|
+
applyManifest();
|
|
569
|
+
}
|
|
570
|
+
wrapSeekFunctions();
|
|
571
|
+
let remainingSeekWrapAttempts = 120;
|
|
572
|
+
const seekWrapInterval = setInterval(() => {
|
|
573
|
+
wrapSeekFunctions();
|
|
574
|
+
remainingSeekWrapAttempts -= 1;
|
|
575
|
+
if (remainingSeekWrapAttempts <= 0) clearInterval(seekWrapInterval);
|
|
576
|
+
}, 50);
|
|
577
|
+
}
|
|
578
|
+
export {
|
|
579
|
+
STUDIO_MANUAL_EDITS_PATH,
|
|
580
|
+
createStudioManualEditsRenderBodyScript,
|
|
581
|
+
createStudioPositionSeekReapplyScript
|
|
582
|
+
};
|
|
583
|
+
//# sourceMappingURL=manualEditsRenderScript.js.map
|