hyperframes 0.6.0-alpha.1 → 0.6.0-alpha.10

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.
@@ -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-D04_ZoMm.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-UWFaHilT.css">
7
+ <script type="module" crossorigin src="/assets/index-B-16fRnH.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-14zH9lqh.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
@@ -7,7 +7,8 @@
7
7
  | Skill | Command | When to use |
8
8
  | -------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------- |
9
9
  | **hyperframes** | `/hyperframes` | Creating or editing HTML compositions, captions, TTS, audio-reactive animation, marker highlights |
10
- | **hyperframes-cli** | `/hyperframes-cli` | CLI commands: init, lint, preview, render, transcribe, tts |
10
+ | **hyperframes-cli** | `/hyperframes-cli` | Dev-loop CLI: init, lint, inspect, preview, render, doctor |
11
+ | **hyperframes-media** | `/hyperframes-media` | Asset preprocessing: tts (Kokoro), transcribe (Whisper), remove-background (u2net) |
11
12
  | **hyperframes-registry** | `/hyperframes-registry` | Installing blocks and components via `hyperframes add` |
12
13
  | **website-to-hyperframes** | `/website-to-hyperframes` | Capturing a URL and turning it into a video — full website-to-video pipeline |
13
14
  | **tailwind** | `/tailwind` | Tailwind v4 browser-runtime styles for projects created with `hyperframes init --tailwind` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyperframes",
3
- "version": "0.6.0-alpha.1",
3
+ "version": "0.6.0-alpha.10",
4
4
  "description": "HyperFrames CLI — create, preview, and render HTML video compositions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,75 +0,0 @@
1
- # Text-to-Speech
2
-
3
- Generate speech audio locally using Kokoro-82M (no API key, runs on CPU).
4
-
5
- ## Voice Selection
6
-
7
- Match voice to content. Default is `af_heart`.
8
-
9
- | Content type | Voice | Why |
10
- | ------------- | --------------------- | -------------------------- |
11
- | Product demo | `af_heart`/`af_nova` | Warm, professional |
12
- | Tutorial | `am_adam`/`bf_emma` | Neutral, easy to follow |
13
- | Marketing | `af_sky`/`am_michael` | Energetic or authoritative |
14
- | Documentation | `bf_emma`/`bm_george` | Clear British English |
15
- | Casual | `af_heart`/`af_sky` | Approachable, natural |
16
-
17
- Run `npx hyperframes tts --list` for all 54 voices (8 languages).
18
-
19
- ## Multilingual Phonemization
20
-
21
- Kokoro voice IDs encode language in the first letter: `a`=American English, `b`=British English, `e`=Spanish, `f`=French, `h`=Hindi, `i`=Italian, `j`=Japanese, `p`=Brazilian Portuguese, `z`=Mandarin. The CLI auto-detects the phonemizer locale from that prefix — you don't need to pass `--lang` when the voice matches the text.
22
-
23
- ```bash
24
- npx hyperframes tts "La reunión empieza a las nueve" --voice ef_dora --output es.wav
25
- npx hyperframes tts "今日はいい天気ですね" --voice jf_alpha --output ja.wav
26
- ```
27
-
28
- Use `--lang` only to override auto-detection (e.g. stylized accents):
29
-
30
- ```bash
31
- npx hyperframes tts "Hello there" --voice af_heart --lang fr-fr --output accented.wav
32
- ```
33
-
34
- Valid `--lang` codes: `en-us`, `en-gb`, `es`, `fr-fr`, `hi`, `it`, `pt-br`, `ja`, `zh`.
35
-
36
- Non-English phonemization requires `espeak-ng` installed system-wide (`brew install espeak-ng` on macOS, `apt-get install espeak-ng` on Debian/Ubuntu).
37
-
38
- ## Speed Tuning
39
-
40
- - **0.7-0.8** — Tutorial, complex content
41
- - **1.0** — Natural pace (default)
42
- - **1.1-1.2** — Intros, upbeat content
43
- - **1.5+** — Rarely appropriate
44
-
45
- ## Usage
46
-
47
- ```bash
48
- npx hyperframes tts "Your script here" --voice af_nova --output narration.wav
49
- npx hyperframes tts script.txt --voice bf_emma --output narration.wav
50
- ```
51
-
52
- In compositions:
53
-
54
- ```html
55
- <audio
56
- id="narration"
57
- data-start="0"
58
- data-duration="auto"
59
- data-track-index="2"
60
- src="narration.wav"
61
- data-volume="1"
62
- ></audio>
63
- ```
64
-
65
- ## TTS + Captions Workflow
66
-
67
- ```bash
68
- npx hyperframes tts script.txt --voice af_heart --output narration.wav
69
- npx hyperframes transcribe narration.wav # → transcript.json with word-level timestamps
70
- ```
71
-
72
- ## Requirements
73
-
74
- - Python 3.8+ with `kokoro-onnx` and `soundfile`
75
- - Model downloads on first use (~311 MB + ~27 MB voices, cached in `~/.cache/hyperframes/tts/`)
@@ -1,198 +0,0 @@
1
- var D=Object.defineProperty;var F=(d,b,e)=>b in d?D(d,b,{enumerable:!0,configurable:!0,writable:!0,value:e}):d[b]=e;var p=(d,b,e)=>F(d,typeof b!="symbol"?b+"":b,e);const N=`
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
- /* ── Theming via CSS custom properties ──
35
- *
36
- * Override from outside the shadow DOM:
37
- * hyperframes-player {
38
- * --hfp-controls-bg: linear-gradient(transparent, rgba(0,0,0,0.9));
39
- * --hfp-accent: #ff6b6b;
40
- * --hfp-font: "Inter", sans-serif;
41
- * }
42
- */
43
-
44
- .hfp-controls {
45
- position: absolute;
46
- bottom: 0;
47
- left: 0;
48
- right: 0;
49
- display: flex;
50
- align-items: center;
51
- gap: var(--hfp-controls-gap, 12px);
52
- padding: var(--hfp-controls-padding, 8px 16px);
53
- background: var(--hfp-controls-bg, linear-gradient(transparent, rgba(0, 0, 0, 0.7)));
54
- color: var(--hfp-color, #fff);
55
- font-family: var(--hfp-font, system-ui, -apple-system, sans-serif);
56
- font-size: var(--hfp-font-size, 13px);
57
- z-index: 10;
58
- pointer-events: auto;
59
- opacity: 1;
60
- transition: opacity 0.3s ease;
61
- user-select: none;
62
- }
63
-
64
- .hfp-controls.hfp-hidden {
65
- opacity: 0;
66
- pointer-events: none;
67
- }
68
-
69
- .hfp-play-btn {
70
- background: none;
71
- border: none;
72
- color: var(--hfp-color, #fff);
73
- cursor: pointer;
74
- padding: 8px;
75
- display: flex;
76
- align-items: center;
77
- justify-content: center;
78
- width: 40px;
79
- height: 40px;
80
- flex-shrink: 0;
81
- z-index: 10;
82
- }
83
-
84
- .hfp-play-btn:hover {
85
- opacity: 0.8;
86
- }
87
-
88
- .hfp-play-btn svg,
89
- .hfp-play-btn svg * {
90
- pointer-events: none;
91
- }
92
-
93
- .hfp-scrubber {
94
- flex: 1;
95
- height: var(--hfp-scrubber-height, 4px);
96
- background: var(--hfp-scrubber-bg, rgba(255, 255, 255, 0.3));
97
- border-radius: var(--hfp-scrubber-radius, 2px);
98
- cursor: pointer;
99
- position: relative;
100
- }
101
-
102
- .hfp-scrubber:hover {
103
- height: var(--hfp-scrubber-height-hover, 6px);
104
- }
105
-
106
- .hfp-progress {
107
- position: absolute;
108
- top: 0;
109
- left: 0;
110
- height: 100%;
111
- background: var(--hfp-accent, #fff);
112
- border-radius: var(--hfp-scrubber-radius, 2px);
113
- pointer-events: none;
114
- }
115
-
116
- .hfp-time {
117
- flex-shrink: 0;
118
- font-variant-numeric: tabular-nums;
119
- opacity: 0.9;
120
- }
121
-
122
- .hfp-speed-wrap {
123
- position: relative;
124
- flex-shrink: 0;
125
- }
126
-
127
- .hfp-speed-btn {
128
- background: var(--hfp-speed-btn-bg, rgba(255, 255, 255, 0.15));
129
- border: none;
130
- border-radius: var(--hfp-speed-btn-radius, 4px);
131
- color: var(--hfp-color, #fff);
132
- cursor: pointer;
133
- font-family: var(--hfp-font, system-ui, -apple-system, sans-serif);
134
- font-size: 12px;
135
- font-variant-numeric: tabular-nums;
136
- font-weight: 600;
137
- padding: 4px 8px;
138
- min-width: 40px;
139
- text-align: center;
140
- transition: background 0.15s ease;
141
- }
142
-
143
- .hfp-speed-btn:hover {
144
- background: var(--hfp-speed-btn-bg-hover, rgba(255, 255, 255, 0.3));
145
- }
146
-
147
- .hfp-speed-menu {
148
- position: absolute;
149
- bottom: calc(100% + 8px);
150
- right: 0;
151
- background: var(--hfp-menu-bg, rgba(20, 20, 20, 0.95));
152
- backdrop-filter: blur(12px);
153
- -webkit-backdrop-filter: blur(12px);
154
- border: 1px solid var(--hfp-menu-border, rgba(255, 255, 255, 0.1));
155
- border-radius: var(--hfp-menu-radius, 8px);
156
- padding: 4px;
157
- display: flex;
158
- flex-direction: column;
159
- gap: 2px;
160
- min-width: 80px;
161
- opacity: 0;
162
- visibility: hidden;
163
- transform: translateY(4px);
164
- transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
165
- box-shadow: var(--hfp-menu-shadow, 0 8px 24px rgba(0, 0, 0, 0.4));
166
- }
167
-
168
- .hfp-speed-menu.hfp-open {
169
- opacity: 1;
170
- visibility: visible;
171
- transform: translateY(0);
172
- }
173
-
174
- .hfp-speed-option {
175
- background: none;
176
- border: none;
177
- border-radius: 4px;
178
- color: var(--hfp-menu-color, rgba(255, 255, 255, 0.7));
179
- cursor: pointer;
180
- font-family: var(--hfp-font, system-ui, -apple-system, sans-serif);
181
- font-size: 13px;
182
- font-variant-numeric: tabular-nums;
183
- padding: 6px 12px;
184
- text-align: left;
185
- transition: background 0.1s ease, color 0.1s ease;
186
- white-space: nowrap;
187
- }
188
-
189
- .hfp-speed-option:hover {
190
- background: var(--hfp-menu-hover-bg, rgba(255, 255, 255, 0.1));
191
- color: var(--hfp-color, #fff);
192
- }
193
-
194
- .hfp-speed-option.hfp-active {
195
- color: var(--hfp-accent, #fff);
196
- font-weight: 600;
197
- }
198
- `,O='<svg width="24" height="24" viewBox="0 0 18 18" fill="currentColor"><polygon points="4,2 16,9 4,16"/></svg>',U='<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>',j=[.25,.5,1,1.5,2,4];function k(d){return Number.isInteger(d)?`${d}x`:`${d}x`}function R(d){if(!Number.isFinite(d)||d<0)return"0:00";const b=Math.floor(d),e=Math.floor(b/60),t=b%60;return`${e}:${t.toString().padStart(2,"0")}`}function z(d,b,e={}){const t=e.speedPresets??j,s=document.createElement("div");s.className="hfp-controls",s.addEventListener("click",o=>{o.stopPropagation()});const i=document.createElement("button");i.className="hfp-play-btn",i.type="button",i.innerHTML=O,i.setAttribute("aria-label","Play");const r=document.createElement("div");r.className="hfp-scrubber";const n=document.createElement("div");n.className="hfp-progress",n.style.width="0%",r.appendChild(n);const c=document.createElement("span");c.className="hfp-time",c.textContent="0:00 / 0:00";const _=document.createElement("div");_.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 a=document.createElement("div");a.className="hfp-speed-menu",a.setAttribute("role","menu");for(const o of t){const h=document.createElement("button");h.className="hfp-speed-option",h.type="button",h.setAttribute("role","menuitem"),h.dataset.speed=String(o),h.textContent=k(o),o===1&&h.classList.add("hfp-active"),a.appendChild(h)}_.appendChild(a),_.appendChild(u),s.appendChild(i),s.appendChild(r),s.appendChild(c),s.appendChild(_),d.appendChild(s);let l=!1,f=null;t.indexOf(1),i.addEventListener("click",o=>{o.stopPropagation(),l?b.onPause():b.onPlay()});const m=o=>{for(const h of a.querySelectorAll(".hfp-speed-option"))h.classList.toggle("hfp-active",h.dataset.speed===String(o))};u.addEventListener("click",o=>{o.stopPropagation();const h=a.classList.toggle("hfp-open");u.setAttribute("aria-expanded",String(h))}),a.addEventListener("click",o=>{o.stopPropagation();const h=o.target.closest(".hfp-speed-option");if(!h)return;const y=parseFloat(h.dataset.speed);t.indexOf(y),u.textContent=k(y),m(y),a.classList.remove("hfp-open"),u.setAttribute("aria-expanded","false"),b.onSpeedChange(y)});const v=()=>{a.classList.remove("hfp-open"),u.setAttribute("aria-expanded","false")};document.addEventListener("click",v);const E=o=>{const h=r.getBoundingClientRect(),y=Math.max(0,Math.min(1,(o-h.left)/h.width));b.onSeek(y)};let g=!1;r.addEventListener("mousedown",o=>{o.stopPropagation(),g=!0,E(o.clientX)});const A=o=>{g&&E(o.clientX)},P=()=>{g=!1};document.addEventListener("mousemove",A),document.addEventListener("mouseup",P),r.addEventListener("touchstart",o=>{g=!0;const h=o.touches[0];h&&E(h.clientX)},{passive:!0});const C=o=>{if(g){const h=o.touches[0];h&&E(h.clientX)}},I=()=>{g=!1};document.addEventListener("touchmove",C,{passive:!0}),document.addEventListener("touchend",I);const T=()=>{f&&clearTimeout(f),f=setTimeout(()=>{l&&s.classList.add("hfp-hidden")},3e3)},L=d instanceof ShadowRoot?d.host:d;return L.addEventListener("mousemove",()=>{s.classList.remove("hfp-hidden"),T()}),L.addEventListener("mouseleave",()=>{l&&s.classList.add("hfp-hidden")}),{updateTime(o,h){const y=h>0?o/h*100:0;n.style.width=`${y}%`,c.textContent=`${R(o)} / ${R(h)}`},updatePlaying(o){l=o,i.innerHTML=o?U:O,i.setAttribute("aria-label",o?"Pause":"Play"),o?T():s.classList.remove("hfp-hidden")},updateSpeed(o){t.indexOf(o),u.textContent=k(o),m(o)},show(){s.style.display=""},hide(){s.style.display="none"},destroy(){document.removeEventListener("mousemove",A),document.removeEventListener("mouseup",P),document.removeEventListener("touchmove",C),document.removeEventListener("touchend",I),document.removeEventListener("click",v),f&&clearTimeout(f)}}}function H(d){return d.hasRuntime||d.runtimeInjected?!1:!!(d.hasNestedCompositions||d.hasTimelines&&d.attempts>=5)}let M=null;function q(){if(M)return M;if(typeof CSSStyleSheet>"u")return null;try{const d=new CSSStyleSheet;return d.replaceSync(N),M=d,d}catch{return null}}const S=30,W="https://cdn.jsdelivr.net/npm/@hyperframes/core/dist/hyperframe.runtime.iife.js",w=class w extends HTMLElement{constructor(){super();p(this,"shadow");p(this,"container");p(this,"iframe");p(this,"posterEl",null);p(this,"controlsApi",null);p(this,"resizeObserver");p(this,"_ready",!1);p(this,"_duration",0);p(this,"_currentTime",0);p(this,"_paused",!0);p(this,"_compositionWidth",1920);p(this,"_compositionHeight",1080);p(this,"_probeInterval",null);p(this,"_lastUpdateMs",0);p(this,"_parentMedia",[]);p(this,"_audioOwner","runtime");p(this,"_mediaObserver");p(this,"_playbackErrorPosted",!1);p(this,"_runtimeInjected",!1);this.shadow=this.attachShadow({mode:"open"});const e=q();if(e)this.shadow.adoptedStyleSheets=[e];else{const t=document.createElement("style");t.textContent=N,this.shadow.appendChild(t)}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),this.addEventListener("click",t=>{this._isControlsClick(t)||(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"]}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.getAttribute("srcdoc")),this.hasAttribute("src")&&(this.iframe.src=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._teardownMediaObserver(),(e=this.controlsApi)==null||e.destroy();for(const t of this._parentMedia)t.el.pause(),t.el.src="";this._parentMedia=[]}attributeChangedCallback(e,t,s){var i,r;switch(e){case"src":s&&(this._ready=!1,this.iframe.src=s);break;case"srcdoc":this._ready=!1,s!==null?this.iframe.srcdoc=s:this.iframe.removeAttribute("srcdoc");break;case"width":this._compositionWidth=parseInt(s||"1920",10),this._updateScale();break;case"height":this._compositionHeight=parseInt(s||"1080",10),this._updateScale();break;case"controls":s!==null?this._setupControls():((i=this.controlsApi)==null||i.destroy(),this.controlsApi=null);break;case"poster":this._setupPoster();break;case"playback-rate":{const n=parseFloat(s||"1");for(const c of this._parentMedia)c.el.playbackRate=n;this._sendControl("set-playback-rate",{playbackRate:n}),(r=this.controlsApi)==null||r.updateSpeed(n),this.dispatchEvent(new Event("ratechange"));break}case"muted":for(const n of this._parentMedia)n.el.muted=s!==null;this._sendControl("set-muted",{muted:s!==null});break;case"audio-src":s&&this._setupParentAudioFromUrl(s);break}}get iframeElement(){return this.iframe}play(){var e;this._hidePoster(),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,s;if(!this._trySyncSeek(e)){const i=Math.round(e*S);this._sendControl("seek",{frame:i})}if(this._currentTime=e,this._audioOwner==="parent")for(const i of this._parentMedia){const r=e-i.start;r>=0&&r<i.duration&&(i.el.currentTime=r)}this._paused=!0,(t=this.controlsApi)==null||t.updatePlaying(!1),(s=this.controlsApi)==null||s.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 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 s;try{(s=this.iframe.contentWindow)==null||s.postMessage({source:"hf-parent",type:"control",action:e,...t},"*")}catch{}}_trySyncSeek(e){try{const t=this.iframe.contentWindow,s=t==null?void 0:t.__player,i=s==null?void 0:s.seek;return typeof i!="function"?!1:(i.call(s,e),!0)}catch{return!1}}_isControlsClick(e){return e.composedPath().some(t=>t instanceof HTMLElement&&t.classList.contains("hfp-controls"))}_onMessage(e){var s,i,r,n;if(e.source!==this.iframe.contentWindow)return;const t=e.data;if(!(!t||t.source!=="hf-preview")){if(t.type==="state"){this._currentTime=(t.frame??0)/S;const c=!this._paused,_=!t.isPlaying,u=this._duration>0&&this._currentTime>=this._duration&&(c||t.isPlaying);if(u&&this.loop){this._audioOwner==="parent"&&this._pauseParentMedia(),this._paused=_,this.seek(0),this.play();return}this._paused=_,this._audioOwner==="parent"&&(c&&this._paused?this._pauseParentMedia():!c&&!this._paused&&this._playParentMedia(),this._mirrorParentMediaTime(this._currentTime));const a=performance.now();(a-this._lastUpdateMs>100||this._paused!==c)&&(this._lastUpdateMs=a,(s=this.controlsApi)==null||s.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,(r=this.controlsApi)==null||r.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/S,(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;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 s,i;e++;try{const r=this.iframe.contentWindow;if(!r)return;const n=!!(r.__hf||r.__player),c=!!(r.__timelines&&Object.keys(r.__timelines).length>0),_=!!((s=this.iframe.contentDocument)!=null&&s.querySelector("[data-composition-src]"));if(H({hasRuntime:n,hasTimelines:c,hasNestedCompositions:_,runtimeInjected:this._runtimeInjected,attempts:e})){this._injectRuntime();return}if(this._runtimeInjected&&!n)return;const a=(()=>{var l,f;if(r.__player&&typeof r.__player.getDuration=="function")return r.__player;if(r.__timelines){const m=Object.keys(r.__timelines);if(m.length>0){const v=(f=(l=this.iframe.contentDocument)==null?void 0:l.querySelector("[data-composition-id]"))==null?void 0:f.getAttribute("data-composition-id"),E=v&&v in r.__timelines?v:m[m.length-1],g=r.__timelines[E];return{getDuration:()=>g.duration()}}}return null})();if(a&&a.getDuration()>0){clearInterval(this._probeInterval),this._duration=a.getDuration(),this._ready=!0,(i=this.controlsApi)==null||i.updateTime(0,this._duration),this.dispatchEvent(new CustomEvent("ready",{detail:{duration:this._duration}}));const l=this.iframe.contentDocument,f=l==null?void 0:l.querySelector("[data-composition-id]");if(f){const m=parseInt(f.getAttribute("data-width")||"0",10),v=parseInt(f.getAttribute("data-height")||"0",10);m>0&&v>0&&(this._compositionWidth=m,this._compositionHeight=v,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=W,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"),s=t?t.split(",").map(Number).filter(i=>!isNaN(i)&&i>0):void 0;this.controlsApi=z(this.shadow,e,{speedPresets:s})}_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 s=(t==null?void 0:t.force)===!0,i=w.MIRROR_REQUIRED_CONSECUTIVE_DRIFT_SAMPLES,r=w.MIRROR_DRIFT_THRESHOLD_SECONDS;for(const n of this._parentMedia){const c=e-n.start;if(c<0||c>=n.duration){n.driftSamples=0;continue}Math.abs(n.el.currentTime-c)>r?(n.driftSamples+=1,(s||n.driftSamples>=i)&&(n.el.currentTime=c,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,s,i){if(this._parentMedia.some(c=>c.el.src===e))return null;const r=t==="video"?document.createElement("video"):new Audio;r.preload="auto",r.src=e,r.load(),r.muted=this.muted,this.playbackRate!==1&&(r.playbackRate=this.playbackRate);const n={el:r,start:s,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 s of t)this._adoptIframeMedia(s);this._observeDynamicMedia(e)}catch{}}_adoptIframeMedia(e){var _;const t=e.getAttribute("src")||((_=e.querySelector("source"))==null?void 0:_.getAttribute("src"));if(!t)return;const s=new URL(t,e.ownerDocument.baseURI).href,i=parseFloat(e.getAttribute("data-start")||"0"),r=parseFloat(e.getAttribute("data-duration")||"Infinity"),n=e.tagName==="VIDEO"?"video":"audio",c=this._createParentMedia(s,n,i,r);c&&this._audioOwner==="parent"&&(this._mirrorParentMediaTime(this._currentTime,{force:!0}),!this._paused&&c.el.src&&c.el.play().catch(u=>this._reportPlaybackError(u)))}_observeDynamicMedia(e){if(this._teardownMediaObserver(),typeof MutationObserver>"u"||!e.body)return;const t=new MutationObserver(i=>{var r,n,c,_;for(const u of i){for(const a of u.addedNodes){if(!(a instanceof Element))continue;const l=[];(r=a.matches)!=null&&r.call(a,"audio[data-start], video[data-start]")&&l.push(a);const f=(n=a.querySelectorAll)==null?void 0:n.call(a,"audio[data-start], video[data-start]");if(f)for(const m of f)l.push(m);for(const m of l)this._adoptIframeMedia(m)}for(const a of u.removedNodes){if(!(a instanceof Element))continue;const l=[];(c=a.matches)!=null&&c.call(a,"audio[data-start], video[data-start]")&&l.push(a);const f=(_=a.querySelectorAll)==null?void 0:_.call(a,"audio[data-start], video[data-start]");if(f)for(const m of f)l.push(m);for(const m of l)this._detachIframeMedia(m)}}}),s=e.querySelectorAll("[data-composition-id]");if(s.length>0)for(const i of s)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 s=new URL(t,e.ownerDocument.baseURI).href,i=this._parentMedia.findIndex(c=>c.el.src===s);if(i===-1)return;const r=this._parentMedia[i];r.el.pause(),r.el.src="",this._parentMedia.splice(i,1)}_hidePoster(){var e;(e=this.posterEl)==null||e.remove(),this.posterEl=null}};p(w,"MIRROR_DRIFT_THRESHOLD_SECONDS",.05),p(w,"MIRROR_REQUIRED_CONSECUTIVE_DRIFT_SAMPLES",2);let x=w;customElements.get("hyperframes-player")||customElements.define("hyperframes-player",x);export{x as HyperframesPlayer,j as SPEED_PRESETS,k as formatSpeed,R as formatTime};