@hyperframes/core 0.9.20 → 0.9.22
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/compiler/htmlDocument.d.ts +1 -1
- package/dist/compiler/htmlDocument.js +2 -2
- package/dist/generated/runtime-inline.js +1 -1
- package/dist/hyperframe.runtime.iife.js +74 -74
- package/dist/index.d.ts +1 -0
- package/dist/previewProxyBox.d.ts +2 -0
- package/dist/runtime/bridge.js +2 -1
- package/dist/runtime/clock.d.ts +5 -0
- package/dist/runtime/clock.js +49 -3
- package/dist/runtime/mediaSteer.d.ts +1 -1
- package/dist/runtime/mediaSteer.js +1 -10
- package/dist/runtime/pausedVideoCallbacks.d.ts +10 -0
- package/dist/runtime/pausedVideoCallbacks.js +157 -0
- package/dist/runtime/pausedVideoFrames.d.ts +52 -0
- package/dist/runtime/pausedVideoFrames.js +366 -0
- package/dist/runtime/types.d.ts +1 -0
- package/dist/runtime/wallClock.d.ts +8 -0
- package/dist/runtime/wallClock.js +13 -0
- package/dist/studioPreviewMark.d.ts +5 -1
- package/dist/studioPreviewMark.js +7 -0
- package/package.json +4 -4
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { MEDIA_ELEMENT_LEAD_SECONDS } from "./mediaClock.js";
|
|
2
|
+
import { COLOR_GRADING_SOURCE_HIDDEN_ATTR } from "../colorGrading.js";
|
|
3
|
+
import { installPausedVideoCallbacks, stagePausedVideoCallbacks, flushPausedVideoCallbacks, releasePausedVideoCallbacks, observeNativeVideoFrames, } from "./pausedVideoCallbacks.js";
|
|
4
|
+
import { PREVIEW_VIDEO_FRAME_ATTR as FRAME_ATTR, PREVIEW_VIDEO_SOURCE_ATTR, PREVIEW_VIDEO_CANVAS_ATTR, } from "../studioPreviewMark.js";
|
|
5
|
+
const SURFACE_BUDGET = 128 * 1024 * 1024;
|
|
6
|
+
const presented = new Map();
|
|
7
|
+
const authoredSeeks = new WeakSet();
|
|
8
|
+
export function getPausedVideoFrame(video) {
|
|
9
|
+
return presented.get(video)?.canvas ?? null;
|
|
10
|
+
}
|
|
11
|
+
export function ownsPausedVideoTime(video) {
|
|
12
|
+
return presented.get(video)?.driving === true;
|
|
13
|
+
}
|
|
14
|
+
export function getPausedExternalVideoFrame(video) {
|
|
15
|
+
const entry = presented.get(video);
|
|
16
|
+
if (!entry || typeof VideoFrame === "undefined")
|
|
17
|
+
return null;
|
|
18
|
+
entry.gpuFrame ??= new VideoFrame(entry.canvas, { timestamp: Math.round(entry.time * 1e6) });
|
|
19
|
+
return entry.gpuFrame;
|
|
20
|
+
}
|
|
21
|
+
export function captureNativeVideoFrame(video) {
|
|
22
|
+
const canvas = document.createElement("canvas");
|
|
23
|
+
canvas.width = video.videoWidth;
|
|
24
|
+
canvas.height = video.videoHeight;
|
|
25
|
+
const context = canvas.getContext("2d");
|
|
26
|
+
if (!context)
|
|
27
|
+
return null;
|
|
28
|
+
try {
|
|
29
|
+
context.drawImage(video, 0, 0);
|
|
30
|
+
return canvas;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function nativeSnapshotStyle(video) {
|
|
37
|
+
if (getPausedVideoFrame(video))
|
|
38
|
+
return null;
|
|
39
|
+
// Its grading canvas already holds the picture; hiding the source would retire that canvas on refresh.
|
|
40
|
+
if (video.hasAttribute(COLOR_GRADING_SOURCE_HIDDEN_ATTR))
|
|
41
|
+
return null;
|
|
42
|
+
const css = getComputedStyle(video);
|
|
43
|
+
if (css.display === "none" || css.visibility === "hidden" || video.readyState < 2)
|
|
44
|
+
return null;
|
|
45
|
+
if (!video.videoWidth || !video.videoHeight)
|
|
46
|
+
return null;
|
|
47
|
+
return css;
|
|
48
|
+
}
|
|
49
|
+
function virtualTime(entry) {
|
|
50
|
+
let proto = Object.getPrototypeOf(entry.video);
|
|
51
|
+
let descriptor;
|
|
52
|
+
while (proto && !descriptor) {
|
|
53
|
+
descriptor = Object.getOwnPropertyDescriptor(proto, "currentTime");
|
|
54
|
+
proto = Object.getPrototypeOf(proto);
|
|
55
|
+
}
|
|
56
|
+
const nativeSet = descriptor?.set;
|
|
57
|
+
Object.defineProperty(entry.video, "currentTime", {
|
|
58
|
+
configurable: true,
|
|
59
|
+
get: () => entry.time,
|
|
60
|
+
set: (value) => {
|
|
61
|
+
if (Math.abs(value - entry.time) <= MEDIA_ELEMENT_LEAD_SECONDS * 2)
|
|
62
|
+
return;
|
|
63
|
+
authoredSeeks.add(entry.video);
|
|
64
|
+
remove(entry);
|
|
65
|
+
nativeSet?.call(entry.video, value);
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
entry.restoreTime = () => {
|
|
69
|
+
Reflect.deleteProperty(entry.video, "currentTime");
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function remove(entry) {
|
|
73
|
+
entry.stopWaiting?.();
|
|
74
|
+
entry.restoreTime();
|
|
75
|
+
releasePausedVideoCallbacks(entry.video);
|
|
76
|
+
entry.gpuFrame?.close();
|
|
77
|
+
entry.video.removeAttribute(FRAME_ATTR);
|
|
78
|
+
entry.video.removeAttribute(PREVIEW_VIDEO_SOURCE_ATTR);
|
|
79
|
+
entry.canvas.remove();
|
|
80
|
+
entry.canvas.width = entry.canvas.height = 0;
|
|
81
|
+
presented.delete(entry.video);
|
|
82
|
+
}
|
|
83
|
+
export function releasePausedVideoFrame(video) {
|
|
84
|
+
const entry = presented.get(video);
|
|
85
|
+
if (entry)
|
|
86
|
+
remove(entry);
|
|
87
|
+
}
|
|
88
|
+
function refresh(entry) {
|
|
89
|
+
const { video, canvas } = entry;
|
|
90
|
+
video.removeAttribute(FRAME_ATTR);
|
|
91
|
+
if (video.hasAttribute(COLOR_GRADING_SOURCE_HIDDEN_ATTR)) {
|
|
92
|
+
canvas.remove();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const css = getComputedStyle(video);
|
|
96
|
+
for (const key of Array.from(css)) {
|
|
97
|
+
const value = css.getPropertyValue(key);
|
|
98
|
+
if (canvas.style.getPropertyValue(key) !== value)
|
|
99
|
+
canvas.style.setProperty(key, value);
|
|
100
|
+
}
|
|
101
|
+
if (css.position !== "absolute" && css.position !== "fixed") {
|
|
102
|
+
canvas.style.position = "absolute";
|
|
103
|
+
canvas.style.inset = "auto";
|
|
104
|
+
canvas.style.left = `${video.offsetLeft}px`;
|
|
105
|
+
canvas.style.top = `${video.offsetTop}px`;
|
|
106
|
+
canvas.style.margin = "0";
|
|
107
|
+
}
|
|
108
|
+
canvas.style.setProperty("pointer-events", "none", "important");
|
|
109
|
+
canvas.style.setProperty("animation", "none", "important");
|
|
110
|
+
canvas.style.setProperty("transition", "none", "important");
|
|
111
|
+
if (video.previousElementSibling !== canvas)
|
|
112
|
+
video.before(canvas);
|
|
113
|
+
video.setAttribute(FRAME_ATTR, "");
|
|
114
|
+
}
|
|
115
|
+
function markFrameCanvas(canvas) {
|
|
116
|
+
canvas.setAttribute(PREVIEW_VIDEO_CANVAS_ATTR, "");
|
|
117
|
+
canvas.setAttribute("data-layout-ignore", "");
|
|
118
|
+
canvas.setAttribute("data-hyperframes-ignore", "");
|
|
119
|
+
canvas.setAttribute("data-hyperframes-picker-ignore", "");
|
|
120
|
+
canvas.setAttribute("data-hf-ignore", "");
|
|
121
|
+
canvas.setAttribute("aria-hidden", "true");
|
|
122
|
+
}
|
|
123
|
+
function adoptStagedFrame(next, existing) {
|
|
124
|
+
if (existing) {
|
|
125
|
+
const { entry, context } = existing;
|
|
126
|
+
entry.stopWaiting?.();
|
|
127
|
+
entry.stopWaiting = undefined;
|
|
128
|
+
entry.gpuFrame?.close();
|
|
129
|
+
entry.gpuFrame = undefined;
|
|
130
|
+
context.clearRect(0, 0, entry.canvas.width, entry.canvas.height);
|
|
131
|
+
context.drawImage(next.canvas, 0, 0);
|
|
132
|
+
next.canvas.width = next.canvas.height = 0;
|
|
133
|
+
entry.time = next.time;
|
|
134
|
+
if (!entry.driving)
|
|
135
|
+
virtualTime(entry);
|
|
136
|
+
entry.driving = true;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const { video, canvas } = next;
|
|
140
|
+
releasePausedVideoFrame(video);
|
|
141
|
+
markFrameCanvas(canvas);
|
|
142
|
+
presented.set(video, next);
|
|
143
|
+
video.setAttribute(PREVIEW_VIDEO_SOURCE_ATTR, "");
|
|
144
|
+
virtualTime(next);
|
|
145
|
+
}
|
|
146
|
+
/** Keeps original nodes, URLs, intrinsic sizes and the displayed source clock intact. */
|
|
147
|
+
export function createPausedVideoFrames() {
|
|
148
|
+
installPausedVideoCallbacks();
|
|
149
|
+
let provider = null;
|
|
150
|
+
const style = document.createElement("style");
|
|
151
|
+
style.textContent = `[${FRAME_ATTR}] { opacity: 0 !important; }`;
|
|
152
|
+
const observer = new MutationObserver((records) => {
|
|
153
|
+
for (const entry of [...presented.values()]) {
|
|
154
|
+
if (!entry.video.isConnected ||
|
|
155
|
+
records.some((record) => (record.type === "childList" && record.target === entry.video) ||
|
|
156
|
+
(record.type === "attributes" &&
|
|
157
|
+
record.attributeName === "src" &&
|
|
158
|
+
(record.target === entry.video || record.target.parentElement === entry.video))))
|
|
159
|
+
remove(entry);
|
|
160
|
+
else if (records.some((record) => record.target.contains(entry.video)))
|
|
161
|
+
refresh(entry);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
observer.observe(document.body, {
|
|
165
|
+
childList: true,
|
|
166
|
+
subtree: true,
|
|
167
|
+
attributes: true,
|
|
168
|
+
attributeFilter: ["src", "style", "class", "hidden", "data-hidden"],
|
|
169
|
+
});
|
|
170
|
+
const clear = (keep, current) => {
|
|
171
|
+
for (const entry of [...presented.values()]) {
|
|
172
|
+
if (!keep?.has(entry.video)) {
|
|
173
|
+
remove(entry);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
entry.nativeSkipped = true;
|
|
177
|
+
const reveal = (nativeFrame) => {
|
|
178
|
+
if (presented.get(entry.video) !== entry)
|
|
179
|
+
return true;
|
|
180
|
+
if (entry.video.readyState < 2 ||
|
|
181
|
+
entry.video.seeking ||
|
|
182
|
+
(current && !current(entry.video, nativeFrame)))
|
|
183
|
+
return false;
|
|
184
|
+
remove(entry);
|
|
185
|
+
return true;
|
|
186
|
+
};
|
|
187
|
+
const ready = () => {
|
|
188
|
+
reveal(false);
|
|
189
|
+
};
|
|
190
|
+
const events = ["loadeddata", "canplay", "seeked"];
|
|
191
|
+
entry.stopWaiting?.();
|
|
192
|
+
for (const event of events)
|
|
193
|
+
entry.video.addEventListener(event, ready);
|
|
194
|
+
const stopFrames = observeNativeVideoFrames(entry.video, () => reveal(true));
|
|
195
|
+
entry.stopWaiting = () => {
|
|
196
|
+
for (const event of events)
|
|
197
|
+
entry.video.removeEventListener(event, ready);
|
|
198
|
+
stopFrames();
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (presented.size === 0)
|
|
202
|
+
style.remove();
|
|
203
|
+
};
|
|
204
|
+
return {
|
|
205
|
+
get active() {
|
|
206
|
+
// A skipped native clip may keep a fallback picture without owning paused playback.
|
|
207
|
+
return [...presented.values()].some((entry) => !entry.stopWaiting);
|
|
208
|
+
},
|
|
209
|
+
holdNative(videos) {
|
|
210
|
+
const held = [];
|
|
211
|
+
for (const video of videos) {
|
|
212
|
+
if (!nativeSnapshotStyle(video))
|
|
213
|
+
continue;
|
|
214
|
+
const canvas = captureNativeVideoFrame(video);
|
|
215
|
+
if (!canvas)
|
|
216
|
+
continue;
|
|
217
|
+
const entry = {
|
|
218
|
+
video,
|
|
219
|
+
canvas,
|
|
220
|
+
time: video.currentTime,
|
|
221
|
+
driving: false,
|
|
222
|
+
restoreTime: () => { },
|
|
223
|
+
};
|
|
224
|
+
held.push(entry);
|
|
225
|
+
markFrameCanvas(canvas);
|
|
226
|
+
presented.set(video, entry);
|
|
227
|
+
video.setAttribute(PREVIEW_VIDEO_SOURCE_ATTR, "");
|
|
228
|
+
if (!style.isConnected)
|
|
229
|
+
document.head.append(style);
|
|
230
|
+
refresh(entry);
|
|
231
|
+
}
|
|
232
|
+
return () => {
|
|
233
|
+
for (const entry of held)
|
|
234
|
+
if (presented.get(entry.video) === entry && !entry.driving)
|
|
235
|
+
remove(entry);
|
|
236
|
+
};
|
|
237
|
+
},
|
|
238
|
+
skipped: (el) => presented.get(el)?.nativeSkipped === true,
|
|
239
|
+
retained: (el) => presented.get(el)?.stopWaiting !== undefined,
|
|
240
|
+
available: () => provider !== null,
|
|
241
|
+
setProvider(next) {
|
|
242
|
+
if (provider === next)
|
|
243
|
+
return;
|
|
244
|
+
provider?.dispose();
|
|
245
|
+
provider = next;
|
|
246
|
+
},
|
|
247
|
+
async prepare(requests, signal) {
|
|
248
|
+
if (!provider ||
|
|
249
|
+
requests.length === 0 ||
|
|
250
|
+
requests.some(({ video }) => authoredSeeks.has(video) ||
|
|
251
|
+
(!presented.has(video) && Object.hasOwn(video, "currentTime"))))
|
|
252
|
+
return null;
|
|
253
|
+
const owner = provider;
|
|
254
|
+
const identity = (video) => JSON.stringify([
|
|
255
|
+
video.src,
|
|
256
|
+
...Array.from(video.querySelectorAll("source"), (source) => source.src),
|
|
257
|
+
]);
|
|
258
|
+
const sources = requests.map(({ video }) => identity(video));
|
|
259
|
+
const frames = await owner.decode(requests, signal);
|
|
260
|
+
let released = false;
|
|
261
|
+
const release = () => {
|
|
262
|
+
if (released)
|
|
263
|
+
return;
|
|
264
|
+
released = true;
|
|
265
|
+
for (const frame of frames)
|
|
266
|
+
frame.release();
|
|
267
|
+
};
|
|
268
|
+
const current = () => !signal.aborted &&
|
|
269
|
+
provider === owner &&
|
|
270
|
+
requests.every(({ video }, index) => video.isConnected && identity(video) === sources[index]);
|
|
271
|
+
if (!current()) {
|
|
272
|
+
release();
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
const valid = frames.reduce((sum, frame) => sum + frame.width * frame.height * 4, 0) <= SURFACE_BUDGET &&
|
|
276
|
+
frames.length === requests.length &&
|
|
277
|
+
frames.every((frame, index) => {
|
|
278
|
+
const time = requests[index].time;
|
|
279
|
+
return (frame.width > 0 &&
|
|
280
|
+
frame.height > 0 &&
|
|
281
|
+
frame.timestamp <= time + 1e-5 &&
|
|
282
|
+
time < frame.timestamp + frame.duration + 1e-5);
|
|
283
|
+
});
|
|
284
|
+
if (!valid) {
|
|
285
|
+
release();
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
valid: current,
|
|
290
|
+
present() {
|
|
291
|
+
if (!current()) {
|
|
292
|
+
release();
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
const staged = [];
|
|
296
|
+
const reusable = new Map();
|
|
297
|
+
try {
|
|
298
|
+
frames.forEach((frame, index) => {
|
|
299
|
+
const { video, time } = requests[index];
|
|
300
|
+
const canvas = document.createElement("canvas");
|
|
301
|
+
canvas.width = frame.width;
|
|
302
|
+
canvas.height = frame.height;
|
|
303
|
+
staged.push({ video, canvas, time, driving: true, restoreTime: () => { } });
|
|
304
|
+
const context = canvas.getContext("2d");
|
|
305
|
+
if (!context)
|
|
306
|
+
throw new Error("Preview canvas unavailable");
|
|
307
|
+
context.drawImage(frame.source, 0, 0, canvas.width, canvas.height);
|
|
308
|
+
const prior = presented.get(video);
|
|
309
|
+
if (prior &&
|
|
310
|
+
prior.canvas.width === frame.width &&
|
|
311
|
+
prior.canvas.height === frame.height) {
|
|
312
|
+
const destination = prior.canvas.getContext("2d");
|
|
313
|
+
if (!destination)
|
|
314
|
+
throw new Error("Preview canvas unavailable");
|
|
315
|
+
reusable.set(staged[staged.length - 1], { entry: prior, context: destination });
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
for (const { canvas } of staged)
|
|
321
|
+
canvas.width = canvas.height = 0;
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
finally {
|
|
325
|
+
release();
|
|
326
|
+
}
|
|
327
|
+
const wanted = new Set(requests.map(({ video }) => video));
|
|
328
|
+
for (const entry of [...presented.values()])
|
|
329
|
+
if (!wanted.has(entry.video))
|
|
330
|
+
remove(entry);
|
|
331
|
+
if (!style.isConnected)
|
|
332
|
+
document.head.append(style);
|
|
333
|
+
for (const [index, next] of staged.entries()) {
|
|
334
|
+
adoptStagedFrame(next, reusable.get(next));
|
|
335
|
+
const { timestamp, width, height } = frames[index];
|
|
336
|
+
stagePausedVideoCallbacks(next.video, { mediaTime: timestamp, width, height });
|
|
337
|
+
}
|
|
338
|
+
return true;
|
|
339
|
+
},
|
|
340
|
+
refresh() {
|
|
341
|
+
for (const entry of presented.values())
|
|
342
|
+
refresh(entry);
|
|
343
|
+
},
|
|
344
|
+
release,
|
|
345
|
+
};
|
|
346
|
+
},
|
|
347
|
+
suspendProvider: () => provider?.suspend?.(),
|
|
348
|
+
prepareNative() {
|
|
349
|
+
for (const entry of presented.values()) {
|
|
350
|
+
entry.driving = false;
|
|
351
|
+
entry.restoreTime();
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
notify() {
|
|
355
|
+
for (const { video } of presented.values())
|
|
356
|
+
flushPausedVideoCallbacks(video);
|
|
357
|
+
},
|
|
358
|
+
clear,
|
|
359
|
+
destroy() {
|
|
360
|
+
observer.disconnect();
|
|
361
|
+
clear();
|
|
362
|
+
provider?.dispose();
|
|
363
|
+
provider = null;
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -275,6 +275,7 @@ export type RuntimePlayer = {
|
|
|
275
275
|
pause: () => void;
|
|
276
276
|
seek: (timeSeconds: number, options?: {
|
|
277
277
|
keepPlaying?: boolean;
|
|
278
|
+
settled?: boolean;
|
|
278
279
|
}) => HeldSeek;
|
|
279
280
|
renderSeek: (timeSeconds: number, options?: RuntimeSeekOptions) => void;
|
|
280
281
|
getTime: () => number;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type TimeoutId = ReturnType<typeof setTimeout>;
|
|
2
|
+
type IntervalId = ReturnType<typeof setInterval>;
|
|
3
|
+
type Handler = (...args: never[]) => void;
|
|
4
|
+
export declare function wallSetTimeout(handler: Handler, timeout?: number, ...args: unknown[]): TimeoutId;
|
|
5
|
+
export declare function wallClearTimeout(id: TimeoutId | null | undefined): void;
|
|
6
|
+
export declare function wallSetInterval(handler: Handler, timeout?: number, ...args: unknown[]): IntervalId;
|
|
7
|
+
export declare function wallClearInterval(id: IntervalId | null | undefined): void;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const shim = () => globalThis.__HF_VIRTUAL_TIME__;
|
|
2
|
+
export function wallSetTimeout(handler, timeout, ...args) {
|
|
3
|
+
return (shim()?.originalSetTimeout ?? setTimeout)(handler, timeout, ...args);
|
|
4
|
+
}
|
|
5
|
+
export function wallClearTimeout(id) {
|
|
6
|
+
(shim()?.originalClearTimeout ?? clearTimeout)(id ?? undefined);
|
|
7
|
+
}
|
|
8
|
+
export function wallSetInterval(handler, timeout, ...args) {
|
|
9
|
+
return (shim()?.originalSetInterval ?? setInterval)(handler, timeout, ...args);
|
|
10
|
+
}
|
|
11
|
+
export function wallClearInterval(id) {
|
|
12
|
+
(shim()?.originalClearInterval ?? clearInterval)(id ?? undefined);
|
|
13
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export declare const STUDIO_PREVIEW_MARK_META = "hyperframes-studio-preview";
|
|
2
|
+
export declare const PREVIEW_SEEK_HOLD_ATTR = "data-hf-preview-seek-hold";
|
|
3
|
+
export declare const PREVIEW_VIDEO_FRAME_ATTR = "data-hf-preview-video-frame";
|
|
4
|
+
export declare const PREVIEW_VIDEO_SOURCE_ATTR = "data-hf-preview-video-source";
|
|
5
|
+
export declare const PREVIEW_VIDEO_CANVAS_ATTR = "data-hf-preview-video-canvas";
|
|
2
6
|
export declare const STUDIO_PREVIEW_CAPTURE_MODE = "capture";
|
|
3
7
|
export declare const PLAYER_FRAME_ATTR = "data-hf-player-frame";
|
|
4
8
|
export declare function inPlayerFrame(doc: Document): boolean;
|
|
@@ -14,6 +18,6 @@ export declare const RUNTIME_STAMPED_ATTR = "data-hf-autostamped";
|
|
|
14
18
|
export declare const CLIP_HIDDEN_ATTR = "data-hf-clip-hidden";
|
|
15
19
|
export declare const STUDIO_PREVIEW_FAR_SCENE_ATTR = "data-hf-far-scene";
|
|
16
20
|
export declare const STUDIO_PREVIEW_PARKED_SCENE_ATTR = "data-hf-parked-scene";
|
|
17
|
-
export declare const PREVIEW_ONLY_ATTRS: readonly ["data-hf-upcoming", "data-hf-far-scene", "data-hf-parked-scene", "data-hf-preview-lazy", "data-hf-preview-raster", "data-hf-autostamped"];
|
|
21
|
+
export declare const PREVIEW_ONLY_ATTRS: readonly ["data-hf-preview-video-frame", "data-hf-preview-video-source", "data-hf-preview-video-canvas", "data-hf-upcoming", "data-hf-far-scene", "data-hf-parked-scene", "data-hf-preview-lazy", "data-hf-preview-raster", "data-hf-autostamped"];
|
|
18
22
|
export declare const isClipHiddenByRuntime: (el: HTMLElement) => boolean;
|
|
19
23
|
export declare function applyAuthoredTiming(el: Element, attrs: ReadonlyArray<readonly [name: string, value: string]>): void;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { isWebKit } from "./runtime/mediaClock.js";
|
|
2
2
|
export const STUDIO_PREVIEW_MARK_META = "hyperframes-studio-preview";
|
|
3
|
+
export const PREVIEW_SEEK_HOLD_ATTR = "data-hf-preview-seek-hold";
|
|
4
|
+
export const PREVIEW_VIDEO_FRAME_ATTR = "data-hf-preview-video-frame";
|
|
5
|
+
export const PREVIEW_VIDEO_SOURCE_ATTR = "data-hf-preview-video-source";
|
|
6
|
+
export const PREVIEW_VIDEO_CANVAS_ATTR = "data-hf-preview-video-canvas";
|
|
3
7
|
export const STUDIO_PREVIEW_CAPTURE_MODE = "capture";
|
|
4
8
|
export const PLAYER_FRAME_ATTR = "data-hf-player-frame";
|
|
5
9
|
export function inPlayerFrame(doc) {
|
|
@@ -23,6 +27,9 @@ export const CLIP_HIDDEN_ATTR = "data-hf-clip-hidden";
|
|
|
23
27
|
export const STUDIO_PREVIEW_FAR_SCENE_ATTR = "data-hf-far-scene";
|
|
24
28
|
export const STUDIO_PREVIEW_PARKED_SCENE_ATTR = "data-hf-parked-scene";
|
|
25
29
|
export const PREVIEW_ONLY_ATTRS = [
|
|
30
|
+
PREVIEW_VIDEO_FRAME_ATTR,
|
|
31
|
+
PREVIEW_VIDEO_SOURCE_ATTR,
|
|
32
|
+
PREVIEW_VIDEO_CANVAS_ATTR,
|
|
26
33
|
STUDIO_PREVIEW_UPCOMING_ATTR,
|
|
27
34
|
STUDIO_PREVIEW_FAR_SCENE_ATTR,
|
|
28
35
|
STUDIO_PREVIEW_PARKED_SCENE_ATTR,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/core",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.22",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -437,9 +437,9 @@
|
|
|
437
437
|
"linkedom": "^0.18.12",
|
|
438
438
|
"postcss": "^8.5.8",
|
|
439
439
|
"wawoff2": "^2.0.1",
|
|
440
|
-
"@hyperframes/lint": "0.9.
|
|
441
|
-
"@hyperframes/studio-server": "0.9.
|
|
442
|
-
"@hyperframes/parsers": "0.9.
|
|
440
|
+
"@hyperframes/lint": "0.9.22",
|
|
441
|
+
"@hyperframes/studio-server": "0.9.22",
|
|
442
|
+
"@hyperframes/parsers": "0.9.22"
|
|
443
443
|
},
|
|
444
444
|
"devDependencies": {
|
|
445
445
|
"@fontsource/archivo-black": "^5.2.8",
|