@hyperframes/studio 0.5.3 → 0.5.4
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/assets/hyperframes-player-CEnWY28J.js +417 -0
- package/dist/assets/index-04Mp2wOn.css +1 -0
- package/dist/assets/{index-BkBbJZGa.js → index-960mgQMI.js} +22 -22
- package/dist/index.html +2 -2
- package/package.json +4 -4
- package/src/App.tsx +3 -1
- package/src/components/renders/RenderQueue.tsx +62 -6
- package/src/components/renders/useRenderQueue.ts +30 -6
- package/dist/assets/hyperframes-player-ItPxPpgM.js +0 -353
- package/dist/assets/index-BKjcNNNd.css +0 -1
package/dist/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
6
|
<title>HyperFrames Studio</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-960mgQMI.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-04Mp2wOn.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"@phosphor-icons/react": "^2.1.10",
|
|
33
33
|
"codemirror": "^6.0.1",
|
|
34
34
|
"motion": "^12.38.0",
|
|
35
|
-
"@hyperframes/
|
|
36
|
-
"@hyperframes/
|
|
35
|
+
"@hyperframes/player": "0.5.4",
|
|
36
|
+
"@hyperframes/core": "0.5.4"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/react": "^19.0.0",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"vite": "^6.4.2",
|
|
48
48
|
"vitest": "^3.2.4",
|
|
49
49
|
"zustand": "^5.0.0",
|
|
50
|
-
"@hyperframes/producer": "0.5.
|
|
50
|
+
"@hyperframes/producer": "0.5.4"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"react": "^18.0.0 || ^19.0.0",
|
package/src/App.tsx
CHANGED
|
@@ -1684,7 +1684,9 @@ export function StudioApp() {
|
|
|
1684
1684
|
projectId={projectId}
|
|
1685
1685
|
onDelete={renderQueue.deleteRender}
|
|
1686
1686
|
onClearCompleted={renderQueue.clearCompleted}
|
|
1687
|
-
onStartRender={(format, quality) =>
|
|
1687
|
+
onStartRender={(format, quality, resolution) =>
|
|
1688
|
+
renderQueue.startRender({ format, quality, resolution })
|
|
1689
|
+
}
|
|
1688
1690
|
isRendering={renderQueue.isRendering}
|
|
1689
1691
|
/>
|
|
1690
1692
|
)}
|
|
@@ -1,16 +1,50 @@
|
|
|
1
1
|
import { memo, useState, useRef, useEffect } from "react";
|
|
2
2
|
import { RenderQueueItem } from "./RenderQueueItem";
|
|
3
|
-
import type { RenderJob } from "./useRenderQueue";
|
|
3
|
+
import type { RenderJob, ResolutionPreset } from "./useRenderQueue";
|
|
4
4
|
|
|
5
5
|
interface RenderQueueProps {
|
|
6
6
|
jobs: RenderJob[];
|
|
7
7
|
projectId: string;
|
|
8
8
|
onDelete: (jobId: string) => void;
|
|
9
9
|
onClearCompleted: () => void;
|
|
10
|
-
onStartRender: (
|
|
10
|
+
onStartRender: (
|
|
11
|
+
format: "mp4" | "webm" | "mov",
|
|
12
|
+
quality: "draft" | "standard" | "high",
|
|
13
|
+
resolution: ResolutionPreset | "auto",
|
|
14
|
+
) => void;
|
|
11
15
|
isRendering: boolean;
|
|
12
16
|
}
|
|
13
17
|
|
|
18
|
+
// Indexing the table by `ResolutionPreset | "auto"` makes adding a new preset
|
|
19
|
+
// to `core.types` (e.g. an 8K row) a TypeScript error here instead of a
|
|
20
|
+
// silently missing dropdown entry. Order is fixed by the array below.
|
|
21
|
+
const RESOLUTION_LABELS: Record<ResolutionPreset | "auto", { label: string; title: string }> = {
|
|
22
|
+
auto: { label: "Auto", title: "Render at the composition's authored resolution" },
|
|
23
|
+
landscape: { label: "1080p ↔", title: "1920×1080 landscape" },
|
|
24
|
+
portrait: { label: "1080p ↕", title: "1080×1920 portrait" },
|
|
25
|
+
"landscape-4k": {
|
|
26
|
+
label: "4K ↔",
|
|
27
|
+
title: "3840×2160 — supersamples a 1080p composition via Chrome DPR. Slower, larger files.",
|
|
28
|
+
},
|
|
29
|
+
"portrait-4k": {
|
|
30
|
+
label: "4K ↕",
|
|
31
|
+
title: "2160×3840 — supersamples a 1080p portrait composition via Chrome DPR.",
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const RESOLUTION_OPTION_ORDER: (ResolutionPreset | "auto")[] = [
|
|
36
|
+
"auto",
|
|
37
|
+
"landscape",
|
|
38
|
+
"portrait",
|
|
39
|
+
"landscape-4k",
|
|
40
|
+
"portrait-4k",
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const RESOLUTION_OPTIONS = RESOLUTION_OPTION_ORDER.map((value) => ({
|
|
44
|
+
value,
|
|
45
|
+
...RESOLUTION_LABELS[value],
|
|
46
|
+
}));
|
|
47
|
+
|
|
14
48
|
const FORMAT_INFO: Record<"mp4" | "webm" | "mov", { label: string; desc: string }> = {
|
|
15
49
|
mp4: { label: "MP4", desc: "Best for general use. Smallest file, universal playback." },
|
|
16
50
|
mov: {
|
|
@@ -91,11 +125,16 @@ function FormatExportButton({
|
|
|
91
125
|
onStartRender,
|
|
92
126
|
isRendering,
|
|
93
127
|
}: {
|
|
94
|
-
onStartRender: (
|
|
128
|
+
onStartRender: (
|
|
129
|
+
format: "mp4" | "webm" | "mov",
|
|
130
|
+
quality: "draft" | "standard" | "high",
|
|
131
|
+
resolution: ResolutionPreset | "auto",
|
|
132
|
+
) => void;
|
|
95
133
|
isRendering: boolean;
|
|
96
134
|
}) {
|
|
97
135
|
const [format, setFormat] = useState<"mp4" | "webm" | "mov">("mp4");
|
|
98
136
|
const [quality, setQuality] = useState<"draft" | "standard" | "high">("standard");
|
|
137
|
+
const [resolution, setResolution] = useState<ResolutionPreset | "auto">("auto");
|
|
99
138
|
|
|
100
139
|
// MOV (ProRes) is a fixed-quality codec — quality selector has no effect.
|
|
101
140
|
const showQuality = format !== "mov";
|
|
@@ -103,13 +142,30 @@ function FormatExportButton({
|
|
|
103
142
|
return (
|
|
104
143
|
<div className="flex items-center gap-1">
|
|
105
144
|
<FormatInfoTooltip format={format} />
|
|
145
|
+
{/* Resolution must remain the leftmost <select> in this row — it
|
|
146
|
+
carries `rounded-l` for the joined-button look. If you ever hide it
|
|
147
|
+
(feature-flag, etc.), move `rounded-l` to whichever element ends up
|
|
148
|
+
leftmost. */}
|
|
149
|
+
<select
|
|
150
|
+
value={resolution}
|
|
151
|
+
onChange={(e) => setResolution(e.target.value as ResolutionPreset | "auto")}
|
|
152
|
+
disabled={isRendering}
|
|
153
|
+
title={RESOLUTION_OPTIONS.find((r) => r.value === resolution)?.title}
|
|
154
|
+
className="h-5 px-1 text-[10px] rounded-l bg-neutral-800 border border-neutral-700 text-neutral-300 outline-none disabled:opacity-50"
|
|
155
|
+
>
|
|
156
|
+
{RESOLUTION_OPTIONS.map((r) => (
|
|
157
|
+
<option key={r.value} value={r.value} title={r.title}>
|
|
158
|
+
{r.label}
|
|
159
|
+
</option>
|
|
160
|
+
))}
|
|
161
|
+
</select>
|
|
106
162
|
{showQuality && (
|
|
107
163
|
<select
|
|
108
164
|
value={quality}
|
|
109
165
|
onChange={(e) => setQuality(e.target.value as "draft" | "standard" | "high")}
|
|
110
166
|
disabled={isRendering}
|
|
111
167
|
title={QUALITY_OPTIONS.find((q) => q.value === quality)?.title}
|
|
112
|
-
className="h-5 px-1 text-[10px]
|
|
168
|
+
className="h-5 px-1 text-[10px] bg-neutral-800 border border-neutral-700 text-neutral-300 outline-none disabled:opacity-50"
|
|
113
169
|
>
|
|
114
170
|
{QUALITY_OPTIONS.map((q) => (
|
|
115
171
|
<option key={q.value} value={q.value} title={q.title}>
|
|
@@ -122,14 +178,14 @@ function FormatExportButton({
|
|
|
122
178
|
value={format}
|
|
123
179
|
onChange={(e) => setFormat(e.target.value as "mp4" | "webm" | "mov")}
|
|
124
180
|
disabled={isRendering}
|
|
125
|
-
className=
|
|
181
|
+
className="h-5 px-1 text-[10px] bg-neutral-800 border border-neutral-700 text-neutral-300 outline-none disabled:opacity-50"
|
|
126
182
|
>
|
|
127
183
|
<option value="mp4">MP4</option>
|
|
128
184
|
<option value="mov">MOV</option>
|
|
129
185
|
<option value="webm">WebM</option>
|
|
130
186
|
</select>
|
|
131
187
|
<button
|
|
132
|
-
onClick={() => onStartRender(format, quality)}
|
|
188
|
+
onClick={() => onStartRender(format, quality, resolution)}
|
|
133
189
|
disabled={isRendering}
|
|
134
190
|
className="flex items-center gap-1 px-2 py-0.5 text-[10px] font-semibold rounded-r bg-studio-accent text-[#09090B] hover:brightness-110 transition-colors disabled:opacity-50"
|
|
135
191
|
>
|
|
@@ -11,6 +11,20 @@ export interface RenderJob {
|
|
|
11
11
|
durationMs?: number;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
// Mirrors `CanvasResolution` from @hyperframes/core. Kept local because
|
|
15
|
+
// studio's tsconfig doesn't include node types, and the core barrel
|
|
16
|
+
// transitively pulls in modules with `node:fs` imports. Drift risk is
|
|
17
|
+
// low (4 string literals tied to a stable enum).
|
|
18
|
+
export type ResolutionPreset = "landscape" | "portrait" | "landscape-4k" | "portrait-4k";
|
|
19
|
+
|
|
20
|
+
export interface StartRenderOptions {
|
|
21
|
+
fps?: number;
|
|
22
|
+
quality?: "draft" | "standard" | "high";
|
|
23
|
+
format?: "mp4" | "webm" | "mov";
|
|
24
|
+
/** `"auto"` (default) renders at the composition's authored dimensions. */
|
|
25
|
+
resolution?: ResolutionPreset | "auto";
|
|
26
|
+
}
|
|
27
|
+
|
|
14
28
|
export function useRenderQueue(projectId: string | null) {
|
|
15
29
|
const [jobs, setJobs] = useState<RenderJob[]>([]);
|
|
16
30
|
const eventSourceRef = useRef<EventSource | null>(null);
|
|
@@ -59,20 +73,30 @@ export function useRenderQueue(projectId: string | null) {
|
|
|
59
73
|
|
|
60
74
|
// Start a render and track progress via SSE
|
|
61
75
|
const startRender = useCallback(
|
|
62
|
-
async (
|
|
63
|
-
fps = 30,
|
|
64
|
-
quality: "draft" | "standard" | "high" = "standard",
|
|
65
|
-
format: "mp4" | "webm" | "mov" = "mp4",
|
|
66
|
-
) => {
|
|
76
|
+
async (opts: StartRenderOptions = {}) => {
|
|
67
77
|
if (!projectId) return;
|
|
68
78
|
|
|
79
|
+
const fps = opts.fps ?? 30;
|
|
80
|
+
const quality = opts.quality ?? "standard";
|
|
81
|
+
const format = opts.format ?? "mp4";
|
|
82
|
+
const resolution = opts.resolution;
|
|
83
|
+
|
|
69
84
|
const startTime = Date.now();
|
|
85
|
+
// "auto" / undefined means "render at the composition's authored size".
|
|
86
|
+
// Omit the field entirely — sending "auto" would trip the route's
|
|
87
|
+
// enum validation set.
|
|
88
|
+
const body: { fps: number; quality: string; format: string; resolution?: string } = {
|
|
89
|
+
fps,
|
|
90
|
+
quality,
|
|
91
|
+
format,
|
|
92
|
+
};
|
|
93
|
+
if (resolution && resolution !== "auto") body.resolution = resolution;
|
|
70
94
|
let res: Response;
|
|
71
95
|
try {
|
|
72
96
|
res = await fetch(`/api/projects/${projectId}/render`, {
|
|
73
97
|
method: "POST",
|
|
74
98
|
headers: { "Content-Type": "application/json" },
|
|
75
|
-
body: JSON.stringify(
|
|
99
|
+
body: JSON.stringify(body),
|
|
76
100
|
});
|
|
77
101
|
} catch {
|
|
78
102
|
const failedJob: RenderJob = {
|
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
var j=Object.defineProperty;var V=(a,d,e)=>d in a?j(a,d,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[d]=e;var c=(a,d,e)=>V(a,typeof d!="symbol"?d+"":d,e);const z=`
|
|
2
|
-
:host {
|
|
3
|
-
display: block;
|
|
4
|
-
position: relative;
|
|
5
|
-
overflow: hidden;
|
|
6
|
-
background: #000;
|
|
7
|
-
contain: layout style;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.hfp-container {
|
|
11
|
-
position: absolute;
|
|
12
|
-
inset: 0;
|
|
13
|
-
overflow: hidden;
|
|
14
|
-
pointer-events: none;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
.hfp-iframe {
|
|
19
|
-
position: absolute;
|
|
20
|
-
top: 50%;
|
|
21
|
-
left: 50%;
|
|
22
|
-
border: none;
|
|
23
|
-
pointer-events: none;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.hfp-poster {
|
|
27
|
-
position: absolute;
|
|
28
|
-
inset: 0;
|
|
29
|
-
object-fit: contain;
|
|
30
|
-
z-index: 1;
|
|
31
|
-
pointer-events: none;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.hfp-shader-loader {
|
|
35
|
-
position: absolute;
|
|
36
|
-
inset: 0;
|
|
37
|
-
z-index: 20;
|
|
38
|
-
display: grid;
|
|
39
|
-
place-items: center;
|
|
40
|
-
visibility: hidden;
|
|
41
|
-
opacity: 0;
|
|
42
|
-
pointer-events: none;
|
|
43
|
-
background: #030504;
|
|
44
|
-
color: #f4f7fb;
|
|
45
|
-
cursor: default;
|
|
46
|
-
user-select: none;
|
|
47
|
-
-webkit-user-select: none;
|
|
48
|
-
transition: opacity 420ms ease-out, visibility 420ms ease-out;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.hfp-shader-loader.hfp-visible,
|
|
52
|
-
.hfp-shader-loader.hfp-hiding {
|
|
53
|
-
visibility: visible;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.hfp-shader-loader.hfp-visible {
|
|
57
|
-
opacity: 1;
|
|
58
|
-
pointer-events: auto;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.hfp-shader-loader.hfp-hiding {
|
|
62
|
-
opacity: 0;
|
|
63
|
-
pointer-events: none;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.hfp-shader-loader-panel {
|
|
67
|
-
display: grid;
|
|
68
|
-
grid-template-rows: 86px 40px 26px 12px 44px;
|
|
69
|
-
justify-items: center;
|
|
70
|
-
align-items: center;
|
|
71
|
-
gap: 8px;
|
|
72
|
-
width: min(620px, 82%);
|
|
73
|
-
text-align: center;
|
|
74
|
-
font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.hfp-shader-loader-mark {
|
|
78
|
-
width: 86px;
|
|
79
|
-
height: 86px;
|
|
80
|
-
display: grid;
|
|
81
|
-
place-items: center;
|
|
82
|
-
overflow: visible;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.hfp-shader-loader-mark svg {
|
|
86
|
-
display: block;
|
|
87
|
-
overflow: visible;
|
|
88
|
-
filter: drop-shadow(0 0 5px rgba(79, 219, 94, 0.16));
|
|
89
|
-
pointer-events: none;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.hfp-shader-loader-title {
|
|
93
|
-
width: 100%;
|
|
94
|
-
height: 40px;
|
|
95
|
-
overflow: hidden;
|
|
96
|
-
white-space: nowrap;
|
|
97
|
-
text-overflow: ellipsis;
|
|
98
|
-
font-size: 26px;
|
|
99
|
-
line-height: 40px;
|
|
100
|
-
font-weight: 700;
|
|
101
|
-
letter-spacing: 0;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.hfp-shader-loader-title-text {
|
|
105
|
-
color: transparent;
|
|
106
|
-
background: linear-gradient(
|
|
107
|
-
90deg,
|
|
108
|
-
rgba(244, 247, 251, 0.84) 0%,
|
|
109
|
-
#ffffff 42%,
|
|
110
|
-
#80efe4 52%,
|
|
111
|
-
#ffffff 62%,
|
|
112
|
-
rgba(244, 247, 251, 0.84) 100%
|
|
113
|
-
);
|
|
114
|
-
background-size: 220% 100%;
|
|
115
|
-
-webkit-background-clip: text;
|
|
116
|
-
background-clip: text;
|
|
117
|
-
animation: hfp-shader-loader-sheen 1.9s linear infinite;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.hfp-shader-loader-detail {
|
|
121
|
-
width: 100%;
|
|
122
|
-
height: 26px;
|
|
123
|
-
overflow: hidden;
|
|
124
|
-
white-space: nowrap;
|
|
125
|
-
text-overflow: ellipsis;
|
|
126
|
-
color: rgba(244, 247, 251, 0.62);
|
|
127
|
-
font-size: 15px;
|
|
128
|
-
line-height: 26px;
|
|
129
|
-
font-weight: 500;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
.hfp-shader-loader-track {
|
|
133
|
-
width: min(360px, 100%);
|
|
134
|
-
height: 8px;
|
|
135
|
-
overflow: hidden;
|
|
136
|
-
border-radius: 999px;
|
|
137
|
-
background: rgba(255, 255, 255, 0.1);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.hfp-shader-loader-fill {
|
|
141
|
-
width: 100%;
|
|
142
|
-
height: 100%;
|
|
143
|
-
border-radius: inherit;
|
|
144
|
-
background: linear-gradient(90deg, #06e3fa, #4fdb5e);
|
|
145
|
-
transform: scaleX(0);
|
|
146
|
-
transform-origin: left center;
|
|
147
|
-
transition: transform 160ms ease;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
.hfp-shader-loader-progress {
|
|
151
|
-
width: min(420px, 100%);
|
|
152
|
-
height: 44px;
|
|
153
|
-
display: grid;
|
|
154
|
-
grid-template-rows: repeat(2, 22px);
|
|
155
|
-
color: rgba(244, 247, 251, 0.48);
|
|
156
|
-
font: 600 13px/22px "IBM Plex Mono", "SF Mono", "Fira Code", "Courier New", monospace;
|
|
157
|
-
font-variant-numeric: tabular-nums;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
.hfp-shader-loader-row {
|
|
161
|
-
display: grid;
|
|
162
|
-
grid-template-columns: minmax(0, 1fr) 74px;
|
|
163
|
-
align-items: center;
|
|
164
|
-
column-gap: 20px;
|
|
165
|
-
width: 100%;
|
|
166
|
-
white-space: nowrap;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
.hfp-shader-loader-label {
|
|
170
|
-
min-width: 0;
|
|
171
|
-
overflow: hidden;
|
|
172
|
-
text-align: left;
|
|
173
|
-
text-overflow: ellipsis;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.hfp-shader-loader-value {
|
|
177
|
-
text-align: right;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
@keyframes hfp-shader-loader-sheen {
|
|
181
|
-
from {
|
|
182
|
-
background-position: 140% 0;
|
|
183
|
-
}
|
|
184
|
-
to {
|
|
185
|
-
background-position: -140% 0;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/* ── Theming via CSS custom properties ──
|
|
190
|
-
*
|
|
191
|
-
* Override from outside the shadow DOM:
|
|
192
|
-
* hyperframes-player {
|
|
193
|
-
* --hfp-controls-bg: linear-gradient(transparent, rgba(0,0,0,0.9));
|
|
194
|
-
* --hfp-accent: #ff6b6b;
|
|
195
|
-
* --hfp-font: "Inter", sans-serif;
|
|
196
|
-
* }
|
|
197
|
-
*/
|
|
198
|
-
|
|
199
|
-
.hfp-controls {
|
|
200
|
-
position: absolute;
|
|
201
|
-
bottom: 0;
|
|
202
|
-
left: 0;
|
|
203
|
-
right: 0;
|
|
204
|
-
display: flex;
|
|
205
|
-
align-items: center;
|
|
206
|
-
gap: var(--hfp-controls-gap, 12px);
|
|
207
|
-
padding: var(--hfp-controls-padding, 8px 16px);
|
|
208
|
-
background: var(--hfp-controls-bg, linear-gradient(transparent, rgba(0, 0, 0, 0.7)));
|
|
209
|
-
color: var(--hfp-color, #fff);
|
|
210
|
-
font-family: var(--hfp-font, system-ui, -apple-system, sans-serif);
|
|
211
|
-
font-size: var(--hfp-font-size, 13px);
|
|
212
|
-
z-index: 10;
|
|
213
|
-
pointer-events: auto;
|
|
214
|
-
opacity: 1;
|
|
215
|
-
transition: opacity 0.3s ease;
|
|
216
|
-
user-select: none;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.hfp-controls.hfp-hidden {
|
|
220
|
-
opacity: 0;
|
|
221
|
-
pointer-events: none;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.hfp-play-btn {
|
|
225
|
-
background: none;
|
|
226
|
-
border: none;
|
|
227
|
-
color: var(--hfp-color, #fff);
|
|
228
|
-
cursor: pointer;
|
|
229
|
-
padding: 8px;
|
|
230
|
-
display: flex;
|
|
231
|
-
align-items: center;
|
|
232
|
-
justify-content: center;
|
|
233
|
-
width: 40px;
|
|
234
|
-
height: 40px;
|
|
235
|
-
flex-shrink: 0;
|
|
236
|
-
z-index: 10;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
.hfp-play-btn:hover {
|
|
240
|
-
opacity: 0.8;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
.hfp-play-btn svg,
|
|
244
|
-
.hfp-play-btn svg * {
|
|
245
|
-
pointer-events: none;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
.hfp-scrubber {
|
|
249
|
-
flex: 1;
|
|
250
|
-
height: var(--hfp-scrubber-height, 4px);
|
|
251
|
-
background: var(--hfp-scrubber-bg, rgba(255, 255, 255, 0.3));
|
|
252
|
-
border-radius: var(--hfp-scrubber-radius, 2px);
|
|
253
|
-
cursor: pointer;
|
|
254
|
-
position: relative;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
.hfp-scrubber:hover {
|
|
258
|
-
height: var(--hfp-scrubber-height-hover, 6px);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
.hfp-progress {
|
|
262
|
-
position: absolute;
|
|
263
|
-
top: 0;
|
|
264
|
-
left: 0;
|
|
265
|
-
height: 100%;
|
|
266
|
-
background: var(--hfp-accent, #fff);
|
|
267
|
-
border-radius: var(--hfp-scrubber-radius, 2px);
|
|
268
|
-
pointer-events: none;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
.hfp-time {
|
|
272
|
-
flex-shrink: 0;
|
|
273
|
-
font-variant-numeric: tabular-nums;
|
|
274
|
-
opacity: 0.9;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
.hfp-speed-wrap {
|
|
278
|
-
position: relative;
|
|
279
|
-
flex-shrink: 0;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
.hfp-speed-btn {
|
|
283
|
-
background: var(--hfp-speed-btn-bg, rgba(255, 255, 255, 0.15));
|
|
284
|
-
border: none;
|
|
285
|
-
border-radius: var(--hfp-speed-btn-radius, 4px);
|
|
286
|
-
color: var(--hfp-color, #fff);
|
|
287
|
-
cursor: pointer;
|
|
288
|
-
font-family: var(--hfp-font, system-ui, -apple-system, sans-serif);
|
|
289
|
-
font-size: 12px;
|
|
290
|
-
font-variant-numeric: tabular-nums;
|
|
291
|
-
font-weight: 600;
|
|
292
|
-
padding: 4px 8px;
|
|
293
|
-
min-width: 40px;
|
|
294
|
-
text-align: center;
|
|
295
|
-
transition: background 0.15s ease;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
.hfp-speed-btn:hover {
|
|
299
|
-
background: var(--hfp-speed-btn-bg-hover, rgba(255, 255, 255, 0.3));
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
.hfp-speed-menu {
|
|
303
|
-
position: absolute;
|
|
304
|
-
bottom: calc(100% + 8px);
|
|
305
|
-
right: 0;
|
|
306
|
-
background: var(--hfp-menu-bg, rgba(20, 20, 20, 0.95));
|
|
307
|
-
backdrop-filter: blur(12px);
|
|
308
|
-
-webkit-backdrop-filter: blur(12px);
|
|
309
|
-
border: 1px solid var(--hfp-menu-border, rgba(255, 255, 255, 0.1));
|
|
310
|
-
border-radius: var(--hfp-menu-radius, 8px);
|
|
311
|
-
padding: 4px;
|
|
312
|
-
display: flex;
|
|
313
|
-
flex-direction: column;
|
|
314
|
-
gap: 2px;
|
|
315
|
-
min-width: 80px;
|
|
316
|
-
opacity: 0;
|
|
317
|
-
visibility: hidden;
|
|
318
|
-
transform: translateY(4px);
|
|
319
|
-
transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
|
|
320
|
-
box-shadow: var(--hfp-menu-shadow, 0 8px 24px rgba(0, 0, 0, 0.4));
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
.hfp-speed-menu.hfp-open {
|
|
324
|
-
opacity: 1;
|
|
325
|
-
visibility: visible;
|
|
326
|
-
transform: translateY(0);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
.hfp-speed-option {
|
|
330
|
-
background: none;
|
|
331
|
-
border: none;
|
|
332
|
-
border-radius: 4px;
|
|
333
|
-
color: var(--hfp-menu-color, rgba(255, 255, 255, 0.7));
|
|
334
|
-
cursor: pointer;
|
|
335
|
-
font-family: var(--hfp-font, system-ui, -apple-system, sans-serif);
|
|
336
|
-
font-size: 13px;
|
|
337
|
-
font-variant-numeric: tabular-nums;
|
|
338
|
-
padding: 6px 12px;
|
|
339
|
-
text-align: left;
|
|
340
|
-
transition: background 0.1s ease, color 0.1s ease;
|
|
341
|
-
white-space: nowrap;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
.hfp-speed-option:hover {
|
|
345
|
-
background: var(--hfp-menu-hover-bg, rgba(255, 255, 255, 0.1));
|
|
346
|
-
color: var(--hfp-color, #fff);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
.hfp-speed-option.hfp-active {
|
|
350
|
-
color: var(--hfp-accent, #fff);
|
|
351
|
-
font-weight: 600;
|
|
352
|
-
}
|
|
353
|
-
`,F='<svg width="24" height="24" viewBox="0 0 18 18" fill="currentColor"><polygon points="4,2 16,9 4,16"/></svg>',q='<svg width="24" height="24" viewBox="0 0 18 18" fill="currentColor"><rect x="3" y="2" width="4" height="14"/><rect x="11" y="2" width="4" height="14"/></svg>',B=[.25,.5,1,1.5,2,4];function C(a){return Number.isInteger(a)?`${a}x`:`${a}x`}function D(a){if(!Number.isFinite(a)||a<0)return"0:00";const d=Math.floor(a),e=Math.floor(d/60),t=d%60;return`${e}:${t.toString().padStart(2,"0")}`}function W(a,d,e={}){const t=e.speedPresets??B,r=document.createElement("div");r.className="hfp-controls",r.addEventListener("click",l=>{l.stopPropagation()});const i=document.createElement("button");i.className="hfp-play-btn",i.type="button",i.innerHTML=F,i.setAttribute("aria-label","Play");const s=document.createElement("div");s.className="hfp-scrubber";const n=document.createElement("div");n.className="hfp-progress",n.style.width="0%",s.appendChild(n);const o=document.createElement("span");o.className="hfp-time",o.textContent="0:00 / 0:00";const f=document.createElement("div");f.className="hfp-speed-wrap";const u=document.createElement("button");u.className="hfp-speed-btn",u.type="button",u.textContent="1x",u.setAttribute("aria-label","Playback speed");const h=document.createElement("div");h.className="hfp-speed-menu",h.setAttribute("role","menu");for(const l of t){const p=document.createElement("button");p.className="hfp-speed-option",p.type="button",p.setAttribute("role","menuitem"),p.dataset.speed=String(l),p.textContent=C(l),l===1&&p.classList.add("hfp-active"),h.appendChild(p)}f.appendChild(h),f.appendChild(u),r.appendChild(i),r.appendChild(s),r.appendChild(o),r.appendChild(f),a.appendChild(r);let m=!1,g=null;t.indexOf(1),i.addEventListener("click",l=>{l.stopPropagation(),m?d.onPause():d.onPlay()});const b=l=>{for(const p of h.querySelectorAll(".hfp-speed-option"))p.classList.toggle("hfp-active",p.dataset.speed===String(l))};u.addEventListener("click",l=>{l.stopPropagation();const p=h.classList.toggle("hfp-open");u.setAttribute("aria-expanded",String(p))}),h.addEventListener("click",l=>{l.stopPropagation();const p=l.target.closest(".hfp-speed-option");if(!p)return;const E=parseFloat(p.dataset.speed);t.indexOf(E),u.textContent=C(E),b(E),h.classList.remove("hfp-open"),u.setAttribute("aria-expanded","false"),d.onSpeedChange(E)});const _=()=>{h.classList.remove("hfp-open"),u.setAttribute("aria-expanded","false")};document.addEventListener("click",_);const y=l=>{const p=s.getBoundingClientRect(),E=Math.max(0,Math.min(1,(l-p.left)/p.width));d.onSeek(E)};let v=!1;s.addEventListener("mousedown",l=>{l.stopPropagation(),v=!0,y(l.clientX)});const w=l=>{v&&y(l.clientX)},P=()=>{v=!1};document.addEventListener("mousemove",w),document.addEventListener("mouseup",P),s.addEventListener("touchstart",l=>{v=!0;const p=l.touches[0];p&&y(p.clientX)},{passive:!0});const I=l=>{if(v){const p=l.touches[0];p&&y(p.clientX)}},R=()=>{v=!1};document.addEventListener("touchmove",I,{passive:!0}),document.addEventListener("touchend",R);const O=()=>{g&&clearTimeout(g),g=setTimeout(()=>{m&&r.classList.add("hfp-hidden")},3e3)},N=a instanceof ShadowRoot?a.host:a;return N.addEventListener("mousemove",()=>{r.classList.remove("hfp-hidden"),O()}),N.addEventListener("mouseleave",()=>{m&&r.classList.add("hfp-hidden")}),{updateTime(l,p){const E=p>0?l/p*100:0;n.style.width=`${E}%`,o.textContent=`${D(l)} / ${D(p)}`},updatePlaying(l){m=l,i.innerHTML=l?q:F,i.setAttribute("aria-label",l?"Pause":"Play"),l?O():r.classList.remove("hfp-hidden")},updateSpeed(l){t.indexOf(l),u.textContent=C(l),b(l)},show(){r.style.display=""},hide(){r.style.display="none"},destroy(){document.removeEventListener("mousemove",w),document.removeEventListener("mouseup",P),document.removeEventListener("touchmove",I),document.removeEventListener("touchend",R),document.removeEventListener("click",_),g&&clearTimeout(g)}}}function G(a){return a.hasRuntime||a.runtimeInjected?!1:!!(a.hasNestedCompositions||a.hasTimelines&&a.attempts>=5)}let k=null;function X(){if(k)return k;if(typeof CSSStyleSheet>"u")return null;try{const a=new CSSStyleSheet;return a.replaceSync(z),k=a,a}catch{return null}}const T=30,Q="https://cdn.jsdelivr.net/npm/@hyperframes/core/dist/hyperframe.runtime.iife.js",S="shader-capture-scale",L="shader-loading",Y="__hf_shader_capture_scale",J="__hf_shader_loading",A=["Preparing scene transitions","Sampling outgoing scene motion","Sampling incoming scene motion","Caching transition frames","Finalizing transition preview"];function H(a){if(a===null)return null;const d=Number(a);return!Number.isFinite(d)||d<=0?null:String(Math.min(1,Math.max(.25,d)))}function $(a){if(a===null||a.trim()==="")return"composition";const d=a.trim().toLowerCase();return d==="none"||d==="false"||d==="0"||d==="off"?"none":d==="player"||d==="true"||d==="1"||d==="on"?"player":"composition"}function U(a,d,e){e===null?a.delete(d):a.set(d,e)}function Z(a,d,e){const t=a.indexOf("#"),r=t>=0?a.slice(0,t):a,i=t>=0?a.slice(t):"",s=r.indexOf("?"),n=s>=0?r.slice(0,s):r,o=s>=0?r.slice(s+1):"",f=new URLSearchParams(o);U(f,Y,d),U(f,J,e==="composition"?null:e);const u=f.toString();return`${n}${u?`?${u}`:""}${i}`}function K(a,d,e){if(d===null&&e==="composition")return a;const t=[];d!==null&&t.push(`window.__HF_SHADER_CAPTURE_SCALE=${JSON.stringify(d)};`),e!=="composition"&&t.push(`window.__HF_SHADER_LOADING=${JSON.stringify(e)};`);const r=`<script data-hyperframes-player-shader-options>${t.join("")}<\/script>`;return/<head\b[^>]*>/i.test(a)?a.replace(/<head\b[^>]*>/i,i=>`${i}${r}`):/<html\b[^>]*>/i.test(a)?a.replace(/<html\b[^>]*>/i,i=>`${i}${r}`):`${r}${a}`}const x=class x extends HTMLElement{constructor(){super();c(this,"shadow");c(this,"container");c(this,"iframe");c(this,"posterEl",null);c(this,"controlsApi",null);c(this,"resizeObserver");c(this,"shaderLoaderEl");c(this,"shaderLoaderFillEl");c(this,"shaderLoaderTitleEl");c(this,"shaderLoaderDetailEl");c(this,"shaderLoaderTransitionValueEl");c(this,"shaderLoaderFrameLabelEl");c(this,"shaderLoaderFrameValueEl");c(this,"shaderLoaderFrameRowEl");c(this,"shaderLoaderHideTimeout",null);c(this,"_ready",!1);c(this,"_duration",0);c(this,"_currentTime",0);c(this,"_paused",!0);c(this,"_compositionWidth",1920);c(this,"_compositionHeight",1080);c(this,"_probeInterval",null);c(this,"_lastUpdateMs",0);c(this,"_parentMedia",[]);c(this,"_audioOwner","runtime");c(this,"_mediaObserver");c(this,"_playbackErrorPosted",!1);c(this,"_runtimeInjected",!1);this.shadow=this.attachShadow({mode:"open"});const e=X();if(e)this.shadow.adoptedStyleSheets=[e];else{const r=document.createElement("style");r.textContent=z,this.shadow.appendChild(r)}this.container=document.createElement("div"),this.container.className="hfp-container",this.iframe=document.createElement("iframe"),this.iframe.className="hfp-iframe",this.iframe.sandbox.add("allow-scripts","allow-same-origin"),this.iframe.allow="autoplay; fullscreen",this.iframe.referrerPolicy="no-referrer",this.iframe.title="HyperFrames Composition",this.container.appendChild(this.iframe),this.shadow.appendChild(this.container);const t=this._createShaderLoader();this.shaderLoaderEl=t.root,this.shaderLoaderFillEl=t.fill,this.shaderLoaderTitleEl=t.title,this.shaderLoaderDetailEl=t.detail,this.shaderLoaderTransitionValueEl=t.transitionValue,this.shaderLoaderFrameLabelEl=t.frameLabel,this.shaderLoaderFrameValueEl=t.frameValue,this.shaderLoaderFrameRowEl=t.frameRow,this.shadow.appendChild(this.shaderLoaderEl),this.addEventListener("click",r=>{this._isControlsClick(r)||(this._paused?this.play():this.pause())}),this.resizeObserver=new ResizeObserver(()=>this._updateScale()),this._onMessage=this._onMessage.bind(this),this._onIframeLoad=this._onIframeLoad.bind(this)}static get observedAttributes(){return["src","srcdoc","width","height","controls","muted","poster","playback-rate","audio-src",S,L]}connectedCallback(){this.resizeObserver.observe(this),window.addEventListener("message",this._onMessage),this.iframe.addEventListener("load",this._onIframeLoad),this.hasAttribute("controls")&&this._setupControls(),this.hasAttribute("poster")&&this._setupPoster(),this.hasAttribute("audio-src")&&this._setupParentAudioFromUrl(this.getAttribute("audio-src")),this.hasAttribute("srcdoc")&&(this.iframe.srcdoc=this._prepareSrcdoc(this.getAttribute("srcdoc"))),this.hasAttribute("src")&&(this.iframe.src=this._prepareSrc(this.getAttribute("src")))}disconnectedCallback(){var e;this.resizeObserver.disconnect(),window.removeEventListener("message",this._onMessage),this.iframe.removeEventListener("load",this._onIframeLoad),this._probeInterval&&clearInterval(this._probeInterval),this.shaderLoaderHideTimeout&&clearTimeout(this.shaderLoaderHideTimeout),this.shaderLoaderHideTimeout=null,this._teardownMediaObserver(),(e=this.controlsApi)==null||e.destroy();for(const t of this._parentMedia)t.el.pause(),t.el.src="";this._parentMedia=[]}attributeChangedCallback(e,t,r){var i,s;switch(e){case"src":r&&(this._ready=!1,this.iframe.src=this._prepareSrc(r));break;case"srcdoc":this._ready=!1,r!==null?this.iframe.srcdoc=this._prepareSrcdoc(r):this.iframe.removeAttribute("srcdoc");break;case"width":this._compositionWidth=parseInt(r||"1920",10),this._updateScale();break;case"height":this._compositionHeight=parseInt(r||"1080",10),this._updateScale();break;case"controls":r!==null?this._setupControls():((i=this.controlsApi)==null||i.destroy(),this.controlsApi=null);break;case"poster":this._setupPoster();break;case"playback-rate":{const n=parseFloat(r||"1");for(const o of this._parentMedia)o.el.playbackRate=n;this._sendControl("set-playback-rate",{playbackRate:n}),(s=this.controlsApi)==null||s.updateSpeed(n),this.dispatchEvent(new Event("ratechange"));break}case"muted":for(const n of this._parentMedia)n.el.muted=r!==null;this._sendControl("set-muted",{muted:r!==null});break;case"audio-src":r&&this._setupParentAudioFromUrl(r);break;case S:case L:this._reloadShaderOptions();break}}get iframeElement(){return this.iframe}play(){var e;this._hidePoster(),this._duration>0&&this._currentTime>=this._duration&&this.seek(0),this._sendControl("play"),this._audioOwner==="parent"&&this._playParentMedia(),this._paused=!1,(e=this.controlsApi)==null||e.updatePlaying(!0),this.dispatchEvent(new Event("play"))}pause(){var e;this._sendControl("pause"),this._audioOwner==="parent"&&this._pauseParentMedia(),this._paused=!0,(e=this.controlsApi)==null||e.updatePlaying(!1),this.dispatchEvent(new Event("pause"))}seek(e){var t,r;if(!this._trySyncSeek(e)){const i=Math.round(e*T);this._sendControl("seek",{frame:i})}if(this._currentTime=e,this._audioOwner==="parent")for(const i of this._parentMedia){const s=e-i.start;s>=0&&s<i.duration&&(i.el.currentTime=s)}this._paused=!0,(t=this.controlsApi)==null||t.updatePlaying(!1),(r=this.controlsApi)==null||r.updateTime(this._currentTime,this._duration)}get currentTime(){return this._currentTime}set currentTime(e){this.seek(e)}get duration(){return this._duration}get paused(){return this._paused}get ready(){return this._ready}get playbackRate(){return parseFloat(this.getAttribute("playback-rate")||"1")}set playbackRate(e){this.setAttribute("playback-rate",String(e))}get shaderCaptureScale(){return Number(H(this.getAttribute(S))??"1")}set shaderCaptureScale(e){this.setAttribute(S,String(e))}get shaderLoading(){return $(this.getAttribute(L))}set shaderLoading(e){e==="composition"?this.removeAttribute(L):this.setAttribute(L,e)}get muted(){return this.hasAttribute("muted")}set muted(e){e?this.setAttribute("muted",""):this.removeAttribute("muted")}get loop(){return this.hasAttribute("loop")}set loop(e){e?this.setAttribute("loop",""):this.removeAttribute("loop")}_sendControl(e,t={}){var r;try{(r=this.iframe.contentWindow)==null||r.postMessage({source:"hf-parent",type:"control",action:e,...t},"*")}catch{}}_shaderCaptureScaleParam(){return H(this.getAttribute(S))}_shaderLoadingMode(){return $(this.getAttribute(L))}_prepareSrc(e){return Z(e,this._shaderCaptureScaleParam(),this._shaderLoadingMode())}_prepareSrcdoc(e){return K(e,this._shaderCaptureScaleParam(),this._shaderLoadingMode())}_reloadShaderOptions(){if(this._shaderLoadingMode()!=="player"&&this._resetShaderLoader(),this.hasAttribute("srcdoc")){this.iframe.srcdoc=this._prepareSrcdoc(this.getAttribute("srcdoc")||"");return}this.hasAttribute("src")&&(this.iframe.src=this._prepareSrc(this.getAttribute("src")||""))}_createShaderLoader(){const e=document.createElement("div");e.className="hfp-shader-loader",e.setAttribute("role","status"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-label","Preparing scene transitions"),e.setAttribute("data-hyperframes-ignore",""),e.draggable=!1;const t=_=>{_.preventDefault(),_.stopPropagation()};for(const _ of["selectstart","dragstart","pointerdown","mousedown","click","dblclick","contextmenu","touchstart"])e.addEventListener(_,t,{capture:!0});const r=document.createElement("div");r.className="hfp-shader-loader-panel",r.draggable=!1;const i=document.createElement("div");i.className="hfp-shader-loader-mark",i.draggable=!1,i.innerHTML=['<svg width="78" height="78" viewBox="0 0 100 100" fill="none" aria-hidden="true" draggable="false">','<path d="M10.1851 57.8021L33.1145 73.8313C36.2202 75.9978 41.5173 73.5433 42.4816 69.4984L51.7611 30.4271C52.7253 26.3822 48.5802 23.9277 44.4602 26.0942L13.917 42.1235C6.96677 45.7676 4.97564 54.1579 10.1851 57.8021Z" fill="url(#hfp-shader-loader-grad-left)"/>','<path d="M87.5129 57.5141L56.9696 73.5433C52.8371 75.7098 48.7046 73.2553 49.6688 69.2104L58.9483 30.1391C59.9125 26.0942 65.2097 23.6397 68.3154 25.8062L91.2447 41.8354C96.4668 45.4796 94.4631 53.8699 87.5129 57.5141Z" fill="url(#hfp-shader-loader-grad-right)"/>',"<defs>",'<linearGradient id="hfp-shader-loader-grad-left" x1="48.5676" y1="25" x2="44.7804" y2="71.9384" gradientUnits="userSpaceOnUse">','<stop stop-color="#06E3FA"/>','<stop offset="1" stop-color="#4FDB5E"/>',"</linearGradient>",'<linearGradient id="hfp-shader-loader-grad-right" x1="54.8282" y1="73.8392" x2="72.0989" y2="32.8932" gradientUnits="userSpaceOnUse">','<stop stop-color="#06E3FA"/>','<stop offset="1" stop-color="#4FDB5E"/>',"</linearGradient>","</defs>","</svg>"].join("");const s=document.createElement("div");s.className="hfp-shader-loader-title";const n=document.createElement("span");n.className="hfp-shader-loader-title-text",n.textContent=A[0],s.appendChild(n);const o=document.createElement("div");o.className="hfp-shader-loader-detail",o.textContent="Rendering animated scene samples for shader transitions.";const f=document.createElement("div");f.className="hfp-shader-loader-track",f.setAttribute("aria-hidden","true");const u=document.createElement("div");u.className="hfp-shader-loader-fill",f.appendChild(u);const h=document.createElement("div");h.className="hfp-shader-loader-progress";const m=_=>{const y=document.createElement("div");y.className="hfp-shader-loader-row";const v=document.createElement("span");v.className="hfp-shader-loader-label",v.textContent=_;const w=document.createElement("span");return w.className="hfp-shader-loader-value",y.appendChild(v),y.appendChild(w),h.appendChild(y),{row:y,label:v,value:w}},g=m("transition"),b=m("transition frame");return r.appendChild(i),r.appendChild(s),r.appendChild(o),r.appendChild(f),r.appendChild(h),e.appendChild(r),{root:e,fill:u,title:n,detail:o,transitionValue:g.value,frameLabel:b.label,frameValue:b.value,frameRow:b.row}}_showShaderLoader(){this.shaderLoaderHideTimeout&&(clearTimeout(this.shaderLoaderHideTimeout),this.shaderLoaderHideTimeout=null),this.shaderLoaderEl.classList.remove("hfp-hiding"),this.shaderLoaderEl.classList.add("hfp-visible")}_hideShaderLoader(){if(this.shaderLoaderEl.classList.contains("hfp-hiding")){this.shaderLoaderHideTimeout||this._scheduleShaderLoaderHideCleanup();return}this.shaderLoaderEl.classList.contains("hfp-visible")&&(this.shaderLoaderEl.classList.add("hfp-hiding"),this.shaderLoaderEl.classList.remove("hfp-visible"),this._scheduleShaderLoaderHideCleanup())}_scheduleShaderLoaderHideCleanup(){this.shaderLoaderHideTimeout&&clearTimeout(this.shaderLoaderHideTimeout),this.shaderLoaderHideTimeout=setTimeout(()=>{this.shaderLoaderEl.classList.remove("hfp-hiding"),this.shaderLoaderHideTimeout=null},420)}_resetShaderLoader(){this.shaderLoaderHideTimeout&&(clearTimeout(this.shaderLoaderHideTimeout),this.shaderLoaderHideTimeout=null),this.shaderLoaderEl.classList.remove("hfp-visible","hfp-hiding"),this.shaderLoaderFillEl.style.transform="scaleX(0)",this.shaderLoaderTransitionValueEl.textContent="",this.shaderLoaderFrameValueEl.textContent="",this.shaderLoaderFrameRowEl.style.visibility="hidden"}_updateShaderLoader(e){if(this._shaderLoadingMode()!=="player"){this._resetShaderLoader();return}if(e.ready||!e.loading){this._hideShaderLoader();return}const t=typeof e.progress=="number"&&Number.isFinite(e.progress)?e.progress:0,r=typeof e.total=="number"&&Number.isFinite(e.total)?e.total:0,i=r>0?Math.min(1,Math.max(0,t/r)):0,s=Math.min(A.length-1,Math.floor(i*A.length));this.shaderLoaderTitleEl.textContent=A[s]||"Preparing scene transitions",this.shaderLoaderDetailEl.textContent=e.phase==="cached"?"Loading cached transition frames before playback.":e.phase==="finalizing"?"Uploading transition textures for smooth playback.":"Rendering animated scene samples for shader transitions.",this.shaderLoaderFillEl.style.transform=`scaleX(${i})`,this.shaderLoaderTransitionValueEl.textContent=e.currentTransition!==void 0&&e.transitionTotal!==void 0?`${e.currentTransition}/${e.transitionTotal}`:r>0?`${t}/${r}`:"";const n=e.transitionFrame!==void 0&&e.transitionFrames!==void 0?`${e.transitionFrame}/${e.transitionFrames}`:"";this.shaderLoaderFrameLabelEl.textContent=e.phase==="cached"?"cached transition frames":e.phase==="finalizing"?"finalizing transition frames":"rendering transition frames",this.shaderLoaderFrameValueEl.textContent=n,this.shaderLoaderFrameRowEl.style.visibility=n?"visible":"hidden",this.shaderLoaderEl.setAttribute("aria-valuenow",String(Math.round(i*100))),this._showShaderLoader()}_trySyncSeek(e){try{const t=this.iframe.contentWindow,r=t==null?void 0:t.__player,i=r==null?void 0:r.seek;return typeof i!="function"?!1:(i.call(r,e),!0)}catch{return!1}}_isControlsClick(e){return e.composedPath().some(t=>t instanceof HTMLElement&&t.classList.contains("hfp-controls"))}_onMessage(e){var r,i,s,n;if(e.source!==this.iframe.contentWindow)return;const t=e.data;if(!(!t||t.source!=="hf-preview")){if(t.type==="shader-transition-state"){const o=t.state&&typeof t.state=="object"?t.state:{};this._updateShaderLoader(o),this.dispatchEvent(new CustomEvent("shadertransitionstate",{detail:{compositionId:t.compositionId,state:o}}));return}if(t.type==="state"){this._currentTime=(t.frame??0)/T;const o=!this._paused,f=!t.isPlaying,u=this._duration>0&&this._currentTime>=this._duration&&(o||t.isPlaying);if(u&&this.loop){this._audioOwner==="parent"&&this._pauseParentMedia(),this._paused=f,this.seek(0),this.play();return}this._paused=f,this._audioOwner==="parent"&&(o&&this._paused?this._pauseParentMedia():!o&&!this._paused&&this._playParentMedia(),this._mirrorParentMediaTime(this._currentTime));const h=performance.now();(h-this._lastUpdateMs>100||this._paused!==o)&&(this._lastUpdateMs=h,(r=this.controlsApi)==null||r.updateTime(this._currentTime,this._duration),(i=this.controlsApi)==null||i.updatePlaying(!this._paused),this.dispatchEvent(new CustomEvent("timeupdate",{detail:{currentTime:this._currentTime}}))),u&&(this._audioOwner==="parent"&&this._pauseParentMedia(),this._paused=!0,(s=this.controlsApi)==null||s.updatePlaying(!1),this.dispatchEvent(new Event("ended")))}t.type==="media-autoplay-blocked"&&this._promoteToParentProxy(),t.type==="timeline"&&t.durationInFrames>0&&Number.isFinite(t.durationInFrames)&&(this._duration=t.durationInFrames/T,(n=this.controlsApi)==null||n.updateTime(this._currentTime,this._duration)),t.type==="stage-size"&&t.width>0&&t.height>0&&(this._compositionWidth=t.width,this._compositionHeight=t.height,this._updateScale())}}_onIframeLoad(){let e=0;this._runtimeInjected=!1,this._resetShaderLoader();const t=this._audioOwner==="parent";this._audioOwner="runtime",this._playbackErrorPosted=!1,this._pauseParentMedia(),this._teardownMediaObserver(),t&&this.dispatchEvent(new CustomEvent("audioownershipchange",{detail:{owner:"runtime",reason:"iframe-reload"}})),this._probeInterval&&clearInterval(this._probeInterval),this._probeInterval=setInterval(()=>{var r,i;e++;try{const s=this.iframe.contentWindow;if(!s)return;const n=!!(s.__hf||s.__player),o=!!(s.__timelines&&Object.keys(s.__timelines).length>0),f=!!((r=this.iframe.contentDocument)!=null&&r.querySelector("[data-composition-src]"));if(G({hasRuntime:n,hasTimelines:o,hasNestedCompositions:f,runtimeInjected:this._runtimeInjected,attempts:e})){this._injectRuntime();return}if(this._runtimeInjected&&!n)return;const h=(()=>{var m,g;if(s.__player&&typeof s.__player.getDuration=="function")return s.__player;if(s.__timelines){const b=Object.keys(s.__timelines);if(b.length>0){const _=(g=(m=this.iframe.contentDocument)==null?void 0:m.querySelector("[data-composition-id]"))==null?void 0:g.getAttribute("data-composition-id"),y=_&&_ in s.__timelines?_:b[b.length-1],v=s.__timelines[y];return{getDuration:()=>v.duration()}}}return null})();if(h&&h.getDuration()>0){clearInterval(this._probeInterval),this._duration=h.getDuration(),this._ready=!0,(i=this.controlsApi)==null||i.updateTime(0,this._duration),this.dispatchEvent(new CustomEvent("ready",{detail:{duration:this._duration}}));const m=this.iframe.contentDocument,g=m==null?void 0:m.querySelector("[data-composition-id]");if(g){const b=parseInt(g.getAttribute("data-width")||"0",10),_=parseInt(g.getAttribute("data-height")||"0",10);b>0&&_>0&&(this._compositionWidth=b,this._compositionHeight=_,this._updateScale())}this._setupParentMedia(),this.hasAttribute("autoplay")&&this.play();return}}catch{}e>=40&&(clearInterval(this._probeInterval),this.dispatchEvent(new CustomEvent("error",{detail:{message:"Composition timeline not found after 8s"}})))},200)}_injectRuntime(){this._runtimeInjected=!0;try{const e=this.iframe.contentDocument;if(!e)return;const t=e.createElement("script");t.src=Q,t.onload=()=>{},t.onerror=()=>{},(e.head||e.documentElement).appendChild(t)}catch{}}_updateScale(){const e=this.getBoundingClientRect();if(e.width===0||e.height===0)return;const t=Math.min(e.width/this._compositionWidth,e.height/this._compositionHeight);this.iframe.style.width=`${this._compositionWidth}px`,this.iframe.style.height=`${this._compositionHeight}px`,this.iframe.style.transform=`translate(-50%, -50%) scale(${t})`}_setupControls(){if(this.controlsApi)return;const e={onPlay:()=>this.play(),onPause:()=>this.pause(),onSeek:i=>this.seek(i*this._duration),onSpeedChange:i=>{this.playbackRate=i}},t=this.getAttribute("speed-presets"),r=t?t.split(",").map(Number).filter(i=>!isNaN(i)&&i>0):void 0;this.controlsApi=W(this.shadow,e,{speedPresets:r})}_setupPoster(){var t;const e=this.getAttribute("poster");if(!e){(t=this.posterEl)==null||t.remove(),this.posterEl=null;return}this.posterEl||(this.posterEl=document.createElement("img"),this.posterEl.className="hfp-poster",this.shadow.appendChild(this.posterEl)),this.posterEl.src=e}_playParentMedia(){for(const e of this._parentMedia)e.el.src&&e.el.play().catch(t=>this._reportPlaybackError(t))}_reportPlaybackError(e){this._playbackErrorPosted||(this._playbackErrorPosted=!0,this.dispatchEvent(new CustomEvent("playbackerror",{detail:{source:"parent-proxy",error:e}})))}_pauseParentMedia(){for(const e of this._parentMedia)e.el.pause()}_mirrorParentMediaTime(e,t){const r=(t==null?void 0:t.force)===!0,i=x.MIRROR_REQUIRED_CONSECUTIVE_DRIFT_SAMPLES,s=x.MIRROR_DRIFT_THRESHOLD_SECONDS;for(const n of this._parentMedia){const o=e-n.start;if(o<0||o>=n.duration){n.driftSamples=0;continue}Math.abs(n.el.currentTime-o)>s?(n.driftSamples+=1,(r||n.driftSamples>=i)&&(n.el.currentTime=o,n.driftSamples=0)):n.driftSamples=0}}_promoteToParentProxy(){this._audioOwner!=="parent"&&(this._audioOwner="parent",this._sendControl("set-media-output-muted",{muted:!0}),this._mirrorParentMediaTime(this._currentTime,{force:!0}),this._paused||this._playParentMedia(),this.dispatchEvent(new CustomEvent("audioownershipchange",{detail:{owner:"parent",reason:"autoplay-blocked"}})))}_createParentMedia(e,t,r,i){if(this._parentMedia.some(o=>o.el.src===e))return null;const s=t==="video"?document.createElement("video"):new Audio;s.preload="auto",s.src=e,s.load(),s.muted=this.muted,this.playbackRate!==1&&(s.playbackRate=this.playbackRate);const n={el:s,start:r,duration:i,driftSamples:0};return this._parentMedia.push(n),n}_setupParentAudioFromUrl(e){this._createParentMedia(e,"audio",0,1/0)}_setupParentMedia(){try{const e=this.iframe.contentDocument;if(!e)return;const t=e.querySelectorAll("audio[data-start], video[data-start]");for(const r of t)this._adoptIframeMedia(r);this._observeDynamicMedia(e)}catch{}}_adoptIframeMedia(e){var f;const t=e.getAttribute("src")||((f=e.querySelector("source"))==null?void 0:f.getAttribute("src"));if(!t)return;const r=new URL(t,e.ownerDocument.baseURI).href,i=parseFloat(e.getAttribute("data-start")||"0"),s=parseFloat(e.getAttribute("data-duration")||"Infinity"),n=e.tagName==="VIDEO"?"video":"audio",o=this._createParentMedia(r,n,i,s);o&&this._audioOwner==="parent"&&(this._mirrorParentMediaTime(this._currentTime,{force:!0}),!this._paused&&o.el.src&&o.el.play().catch(u=>this._reportPlaybackError(u)))}_observeDynamicMedia(e){if(this._teardownMediaObserver(),typeof MutationObserver>"u"||!e.body)return;const t=new MutationObserver(i=>{var s,n,o,f;for(const u of i){for(const h of u.addedNodes){if(!(h instanceof Element))continue;const m=[];(s=h.matches)!=null&&s.call(h,"audio[data-start], video[data-start]")&&m.push(h);const g=(n=h.querySelectorAll)==null?void 0:n.call(h,"audio[data-start], video[data-start]");if(g)for(const b of g)m.push(b);for(const b of m)this._adoptIframeMedia(b)}for(const h of u.removedNodes){if(!(h instanceof Element))continue;const m=[];(o=h.matches)!=null&&o.call(h,"audio[data-start], video[data-start]")&&m.push(h);const g=(f=h.querySelectorAll)==null?void 0:f.call(h,"audio[data-start], video[data-start]");if(g)for(const b of g)m.push(b);for(const b of m)this._detachIframeMedia(b)}}}),r=e.querySelectorAll("[data-composition-id]");if(r.length>0)for(const i of r)t.observe(i,{childList:!0,subtree:!0});else t.observe(e.body,{childList:!0,subtree:!0});this._mediaObserver=t}_teardownMediaObserver(){var e;(e=this._mediaObserver)==null||e.disconnect(),this._mediaObserver=void 0}_detachIframeMedia(e){var n;const t=e.getAttribute("src")||((n=e.querySelector("source"))==null?void 0:n.getAttribute("src"));if(!t)return;const r=new URL(t,e.ownerDocument.baseURI).href,i=this._parentMedia.findIndex(o=>o.el.src===r);if(i===-1)return;const s=this._parentMedia[i];s.el.pause(),s.el.src="",this._parentMedia.splice(i,1)}_hidePoster(){var e;(e=this.posterEl)==null||e.remove(),this.posterEl=null}};c(x,"MIRROR_DRIFT_THRESHOLD_SECONDS",.05),c(x,"MIRROR_REQUIRED_CONSECUTIVE_DRIFT_SAMPLES",2);let M=x;customElements.get("hyperframes-player")||customElements.define("hyperframes-player",M);export{M as HyperframesPlayer,B as SPEED_PRESETS,C as formatSpeed,D as formatTime};
|