three-vr-player 0.7.0 → 0.9.0
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/Player.d.ts +4 -0
- package/dist/VideoSource-BXMPMJzW.js +722 -0
- package/dist/VideoSource-BXMPMJzW.js.map +1 -0
- package/dist/core/StereoScene.d.ts +50 -0
- package/dist/core/VRControls.d.ts +30 -1
- package/dist/core/projections.d.ts +1 -1
- package/dist/core/vr-panel-layout.d.ts +2 -1
- package/dist/core.js +1 -1
- package/dist/three-vr-player.js +42 -34
- package/dist/three-vr-player.js.map +1 -1
- package/dist/three-vr-player.standalone.js +176 -157
- package/dist/three-vr-player.standalone.js.map +1 -1
- package/dist/types.d.ts +6 -1
- package/package.json +3 -2
- package/dist/VideoSource-Cx7XPpvZ.js +0 -528
- package/dist/VideoSource-Cx7XPpvZ.js.map +0 -1
package/dist/three-vr-player.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as X, f as J, V as Z, S as tt, L as et, a as st, b as it } from "./VideoSource-
|
|
2
|
-
import { M as dt, c as ht, d as ut, i as vt } from "./VideoSource-
|
|
1
|
+
import { P as X, f as J, V as Z, S as tt, L as et, a as st, b as it } from "./VideoSource-BXMPMJzW.js";
|
|
2
|
+
import { M as dt, c as ht, d as ut, i as vt } from "./VideoSource-BXMPMJzW.js";
|
|
3
3
|
function o(v, t = {}, e = []) {
|
|
4
4
|
const s = document.createElement(v), { class: p, ...c } = t;
|
|
5
5
|
p && (s.className = p), Object.assign(s, c);
|
|
@@ -9,27 +9,27 @@ function o(v, t = {}, e = []) {
|
|
|
9
9
|
class ot {
|
|
10
10
|
constructor(t, e) {
|
|
11
11
|
this.nodes = [], this.disposers = [];
|
|
12
|
-
const s = e.video, p = o("button", { class: "tvp-btn tvp-play", title: "Play/Pause", textContent: "▶" }), c = o("input", { class: "tvp-seek", type: "range", min: "0", max: "1000", value: "0" }), h = o("span", { class: "tvp-time", textContent: "0:00 / 0:00" }), n = o("button", { class: "tvp-btn tvp-mute", title: "Volume", textContent: "🔊" }), m = o("input", { class: "tvp-volume", type: "range", min: "0", max: "1", step: "0.01", value: "1" }), g = o("div", { class: "tvp-volpopup", hidden: !0 }, [m]),
|
|
12
|
+
const s = e.video, p = o("button", { class: "tvp-btn tvp-play", title: "Play/Pause", textContent: "▶" }), c = o("input", { class: "tvp-seek", type: "range", min: "0", max: "1000", value: "0" }), h = o("span", { class: "tvp-time", textContent: "0:00 / 0:00" }), n = o("button", { class: "tvp-btn tvp-mute", title: "Volume", textContent: "🔊" }), m = o("input", { class: "tvp-volume", type: "range", min: "0", max: "1", step: "0.01", value: "1" }), g = o("div", { class: "tvp-volpopup", hidden: !0 }, [m]), Y = o("span", { class: "tvp-volwrap" }, [n, g]), y = o("button", { class: "tvp-btn tvp-vrbtn", title: "Enter VR", textContent: "🥽", hidden: !0 }), k = o("button", { class: "tvp-btn tvp-projbtn", title: "Projection", textContent: "🌐" }), d = o("div", { class: "tvp-projmenu", hidden: !0 });
|
|
13
13
|
for (const i of X) {
|
|
14
14
|
const r = o("button", { textContent: i.label });
|
|
15
15
|
r.dataset.mode = i.value, d.append(r);
|
|
16
16
|
}
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const H = o("span", { class: "tvp-projwrap" }, [k, d]), j = o("button", { class: "tvp-btn tvp-settingsbtn", title: "Settings", textContent: "⚙" }), M = o("button", { class: "tvp-btn tvp-fullscreen", title: "Fullscreen", textContent: "⛶" }), C = o("footer", { class: "tvp-controls" }, [p, c, h,
|
|
20
|
-
o("label", { class: "row" }, [
|
|
21
|
-
o("label", {}, [W("Field of view (zoom): ",
|
|
22
|
-
o("label", {}, [W("Supersampling: ", I, "× (sharpness)"),
|
|
17
|
+
const O = o("button", { textContent: "Off (native player)" });
|
|
18
|
+
O.dataset.mode = "off", d.append(o("hr", { class: "tvp-sep" }), O);
|
|
19
|
+
const H = o("span", { class: "tvp-projwrap" }, [k, d]), j = o("button", { class: "tvp-btn tvp-settingsbtn", title: "Settings", textContent: "⚙" }), M = o("button", { class: "tvp-btn tvp-fullscreen", title: "Fullscreen", textContent: "⛶" }), C = o("footer", { class: "tvp-controls" }, [p, c, h, Y, y, H, j, M]), R = o("input", { type: "checkbox", checked: e.initial.swapEyes }), w = o("input", { type: "range", min: "30", max: "100", step: "1", value: String(e.initial.fov) }), T = o("span", { textContent: String(e.initial.fov) }), F = o("input", { type: "range", min: "1", max: "2", step: "0.25", value: String(e.initial.supersampling) }), I = o("span", { textContent: String(e.initial.supersampling) }), L = o("input", { type: "checkbox", checked: e.proxy.enabled }), V = o("input", { type: "text", value: e.proxy.url, placeholder: "http://localhost:8888", spellcheck: !1 }), A = o("input", { type: "password", value: e.proxy.apiPassword, placeholder: "API password" }), b = o("section", { class: "tvp-settings" }, [
|
|
20
|
+
o("label", { class: "row" }, [R, "Swap eyes (if depth looks wrong)"]),
|
|
21
|
+
o("label", {}, [W("Field of view (zoom): ", T, "°"), w]),
|
|
22
|
+
o("label", {}, [W("Supersampling: ", I, "× (sharpness)"), F]),
|
|
23
23
|
o("hr", { class: "tvp-sep" }),
|
|
24
24
|
o("label", { class: "row" }, [L, "Use CORS proxy"]),
|
|
25
25
|
o("label", {}, ["Proxy URL", V]),
|
|
26
|
-
o("label", {}, ["API password",
|
|
26
|
+
o("label", {}, ["API password", A])
|
|
27
27
|
]), S = o("div", { class: "tvp-toast" });
|
|
28
28
|
this.nodes.push(C, b, S);
|
|
29
29
|
for (const i of this.nodes) t.append(i);
|
|
30
30
|
const a = (i, r, l, u) => {
|
|
31
31
|
i.addEventListener(r, l, u), this.disposers.push(() => i.removeEventListener(r, l, u));
|
|
32
|
-
}, B = (i) => c.style.setProperty("--seek", `${i}%`),
|
|
32
|
+
}, B = (i) => c.style.setProperty("--seek", `${i}%`), P = () => {
|
|
33
33
|
g.hidden = !0, d.hidden = !0, b.classList.remove("open");
|
|
34
34
|
};
|
|
35
35
|
let D = 0;
|
|
@@ -65,7 +65,7 @@ class ot {
|
|
|
65
65
|
B(Number(c.value) / 10), s.duration && (s.currentTime = Number(c.value) / 1e3 * s.duration);
|
|
66
66
|
}), f(n, () => {
|
|
67
67
|
const i = g.hidden;
|
|
68
|
-
|
|
68
|
+
P(), g.hidden = !i;
|
|
69
69
|
}), a(m, "input", () => {
|
|
70
70
|
s.volume = Number(m.value), s.muted = s.volume === 0, n.textContent = s.muted ? "🔇" : "🔊";
|
|
71
71
|
});
|
|
@@ -79,42 +79,42 @@ class ot {
|
|
|
79
79
|
};
|
|
80
80
|
f(k, () => {
|
|
81
81
|
const i = d.hidden;
|
|
82
|
-
|
|
82
|
+
P(), d.hidden = !i;
|
|
83
83
|
}), f(d, (i) => {
|
|
84
84
|
const r = i.target.closest("button[data-mode]");
|
|
85
85
|
r && (e.setProjection(r.dataset.mode), U(), d.hidden = !0);
|
|
86
86
|
}), U(), f(j, () => {
|
|
87
87
|
const i = !b.classList.contains("open");
|
|
88
|
-
|
|
89
|
-
}), a(
|
|
88
|
+
P(), b.classList.toggle("open", i);
|
|
89
|
+
}), a(R, "change", () => e.setSwapEyes(R.checked)), a(w, "input", () => {
|
|
90
90
|
const i = Number(w.value);
|
|
91
|
-
|
|
92
|
-
}), a(
|
|
93
|
-
const i = Number(
|
|
91
|
+
T.textContent = String(i), e.setFov(i);
|
|
92
|
+
}), a(F, "input", () => {
|
|
93
|
+
const i = Number(F.value);
|
|
94
94
|
I.textContent = String(i), e.setSupersampling(i);
|
|
95
95
|
});
|
|
96
|
-
const
|
|
97
|
-
a(L, "change",
|
|
96
|
+
const N = () => e.setProxy({ url: V.value.trim(), apiPassword: A.value, enabled: L.checked });
|
|
97
|
+
a(L, "change", N), a(V, "change", N), a(A, "change", N), a(e.surface, "wheel", (i) => {
|
|
98
98
|
i.preventDefault();
|
|
99
99
|
const r = Math.max(30, Math.min(100, Number(w.value) + Math.sign(i.deltaY) * 3));
|
|
100
|
-
w.value = String(r),
|
|
100
|
+
w.value = String(r), T.textContent = String(r), e.setFov(r);
|
|
101
101
|
}, { passive: !1 }), f(M, () => {
|
|
102
102
|
var r, l;
|
|
103
103
|
const i = e.fullscreenTarget;
|
|
104
104
|
document.fullscreenElement ? (l = document.exitFullscreen) == null || l.call(document) : (r = i.requestFullscreen) == null || r.call(i);
|
|
105
105
|
}), a(document, "pointerdown", (i) => {
|
|
106
106
|
const r = i.composedPath(), l = (u) => r.includes(u);
|
|
107
|
-
[g, n, d, k, b, j].some(l) ||
|
|
107
|
+
[g, n, d, k, b, j].some(l) || P();
|
|
108
108
|
});
|
|
109
|
-
let
|
|
109
|
+
let E = 0;
|
|
110
110
|
const Q = () => !g.hidden || !d.hidden || b.classList.contains("open"), $ = () => {
|
|
111
111
|
Q() || C.classList.add("tvp-hidden");
|
|
112
|
-
},
|
|
113
|
-
C.classList.remove("tvp-hidden"), clearTimeout(
|
|
112
|
+
}, z = () => {
|
|
113
|
+
C.classList.remove("tvp-hidden"), clearTimeout(E), E = window.setTimeout($, 5e3);
|
|
114
114
|
};
|
|
115
|
-
a(e.fullscreenTarget, "pointermove",
|
|
116
|
-
clearTimeout(
|
|
117
|
-
}), this.disposers.push(() => clearTimeout(
|
|
115
|
+
a(e.fullscreenTarget, "pointermove", z), a(e.fullscreenTarget, "pointerdown", z), a(e.fullscreenTarget, "pointerleave", () => {
|
|
116
|
+
clearTimeout(E), $();
|
|
117
|
+
}), this.disposers.push(() => clearTimeout(E)), z(), e.vrSupported().then((i) => {
|
|
118
118
|
y.hidden = !i;
|
|
119
119
|
}), f(y, () => {
|
|
120
120
|
if (e.isPresenting()) {
|
|
@@ -135,7 +135,7 @@ function W(v, t, e) {
|
|
|
135
135
|
const s = document.createDocumentFragment();
|
|
136
136
|
return s.append(v, t, e), s;
|
|
137
137
|
}
|
|
138
|
-
const
|
|
138
|
+
const _ = ":host,:host *,.tvp,.tvp *{box-sizing:border-box}.tvp-canvas{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;display:block;touch-action:none;cursor:grab}.tvp-canvas:active{cursor:grabbing}.tvp-video{display:none}.tvp-controls{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;gap:10px;padding:12px;background:linear-gradient(transparent,#000c);z-index:5;font:14px system-ui,Segoe UI,Roboto,sans-serif;color:#e8eaed;transition:opacity .3s}.tvp-controls.tvp-hidden{opacity:0;pointer-events:none}.tvp-btn{padding:4px;border:0;background:none;color:#e8eaed;cursor:pointer;font-size:22px;line-height:1}.tvp-btn:hover{opacity:.7}.tvp-seek{flex:1;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:14px;background:transparent;cursor:pointer;margin:0}.tvp-seek::-webkit-slider-runnable-track{height:4px;border-radius:2px;background:linear-gradient(to right,#4f8cff var(--seek,0%),#3a4150 var(--seek,0%))}.tvp-seek::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;margin-top:-4px;width:12px;height:12px;border-radius:50%;background:#fff;cursor:pointer}.tvp-seek::-moz-range-track{height:4px;border-radius:2px;background:#3a4150}.tvp-seek::-moz-range-progress{height:4px;border-radius:2px;background:#4f8cff}.tvp-seek::-moz-range-thumb{width:12px;height:12px;border:0;border-radius:50%;background:#fff;cursor:pointer}.tvp-time{font-variant-numeric:tabular-nums;min-width:96px;text-align:center;color:#cfd6e2}.tvp-volwrap,.tvp-projwrap{position:relative;display:inline-flex}.tvp-volpopup{position:absolute;bottom:calc(100% + 10px);left:50%;transform:translate(-50%);width:40px;height:132px;background:#121418eb;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid #2a2f3a;border-radius:10px;z-index:8;box-shadow:0 8px 24px #0009}.tvp-volpopup[hidden]{display:none}.tvp-volume{position:absolute;top:50%;left:50%;width:104px;height:14px;margin:0;transform:translate(-50%,-50%) rotate(-90deg);-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;cursor:pointer}.tvp-volume::-webkit-slider-runnable-track{height:4px;border-radius:2px;background:#3a4150}.tvp-volume::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;margin-top:-4px;width:12px;height:12px;border-radius:50%;background:#fff;cursor:pointer}.tvp-volume::-moz-range-track{height:4px;border-radius:2px;background:#3a4150}.tvp-volume::-moz-range-thumb{width:12px;height:12px;border:0;border-radius:50%;background:#fff;cursor:pointer}.tvp-projmenu{position:absolute;bottom:calc(100% + 8px);right:0;min-width:210px;background:#121418eb;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid #2a2f3a;border-radius:10px;padding:6px;display:flex;flex-direction:column;gap:2px;z-index:8;box-shadow:0 8px 24px #0009}.tvp-projmenu[hidden]{display:none}.tvp-projmenu button{text-align:left;background:transparent;border:0;color:#e8eaed;padding:8px 10px;border-radius:7px;cursor:pointer;font:inherit;white-space:nowrap}.tvp-projmenu button:hover{background:#252b39}.tvp-projmenu button.active{background:#4f8cff;color:#fff}.tvp-btn.active{color:#4f8cff}.tvp-settings{position:absolute;bottom:62px;right:10px;width:300px;max-width:calc(100% - 20px);max-height:70%;overflow-y:auto;background:#121418eb;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid #2a2f3a;border-radius:12px;padding:14px;display:none;flex-direction:column;gap:12px;z-index:6;font:14px system-ui,Segoe UI,Roboto,sans-serif;color:#e8eaed}.tvp-settings.open{display:flex}.tvp-settings label{display:flex;flex-direction:column;gap:4px;font-size:12px;color:#aab2c0}.tvp-settings label.row{flex-direction:row;align-items:center;gap:8px;color:#e8eaed;font-size:13px}.tvp-settings input[type=range]{width:100%;accent-color:#4f8cff}.tvp-settings input[type=text],.tvp-settings input[type=password]{width:100%;padding:7px 9px;border-radius:7px;border:1px solid #333;background:#151821;color:#e8eaed;font:inherit}.tvp-sep{width:100%;border:0;border-top:1px solid #2a2f3a;margin:2px 0}.tvp-toast{position:absolute;left:50%;bottom:74px;transform:translate(-50%);max-width:80%;padding:10px 16px;border-radius:10px;background:#1b1f2aed;border:1px solid #2a2f3a;color:#e8eaed;opacity:0;pointer-events:none;transition:opacity .2s;z-index:7;font:13px system-ui}.tvp-toast.show{opacity:1}", q = "three-vr-player:settings";
|
|
139
139
|
class nt {
|
|
140
140
|
constructor(t, e = {}) {
|
|
141
141
|
var c, h;
|
|
@@ -150,11 +150,11 @@ class nt {
|
|
|
150
150
|
let p;
|
|
151
151
|
if (e.shadowDom !== !1) {
|
|
152
152
|
const n = this.wrap.attachShadow({ mode: "open" }), m = document.createElement("style");
|
|
153
|
-
m.textContent =
|
|
153
|
+
m.textContent = _, n.appendChild(m), p = n;
|
|
154
154
|
} else {
|
|
155
155
|
if (!document.getElementById("tvp-styles")) {
|
|
156
156
|
const n = document.createElement("style");
|
|
157
|
-
n.id = "tvp-styles", n.textContent =
|
|
157
|
+
n.id = "tvp-styles", n.textContent = _, document.head.appendChild(n);
|
|
158
158
|
}
|
|
159
159
|
p = this.wrap;
|
|
160
160
|
}
|
|
@@ -195,10 +195,14 @@ class nt {
|
|
|
195
195
|
vrSupported() {
|
|
196
196
|
return this.opts.vrButton === !1 || !navigator.xr ? Promise.resolve(!1) : navigator.xr.isSessionSupported("immersive-vr").catch(() => !1);
|
|
197
197
|
}
|
|
198
|
+
/** Whether immersive-ar (passthrough) is available — used for alpha/fisheye content. */
|
|
199
|
+
arSupported() {
|
|
200
|
+
return navigator.xr ? navigator.xr.isSessionSupported("immersive-ar").catch(() => !1) : Promise.resolve(!1);
|
|
201
|
+
}
|
|
198
202
|
async load(t, e = {}) {
|
|
199
203
|
this.currentSrc = t;
|
|
200
204
|
const s = e.projection ?? (this.opts.autoDetect !== !1 ? st(t) : null);
|
|
201
|
-
s && this.applyProjectionGeometry(s), this.displayMode !== "off" && (this.displayMode = this.view.projection);
|
|
205
|
+
s && this.applyProjectionGeometry(s), this.scene.setAlphaMatte(this.opts.alpha ?? /_alpha/i.test(t)), this.displayMode !== "off" && (this.displayMode = this.view.projection);
|
|
202
206
|
const { url: p, format: c } = it(t, this.useProxy ? this.proxyConfig : void 0), h = this.opts.crossOrigin === void 0 ? "anonymous" : this.opts.crossOrigin;
|
|
203
207
|
this.loading = !0;
|
|
204
208
|
try {
|
|
@@ -269,6 +273,10 @@ class nt {
|
|
|
269
273
|
async enterVR() {
|
|
270
274
|
await this.scene.enterVR();
|
|
271
275
|
}
|
|
276
|
+
/** Enter immersive AR (passthrough) — for alpha/fisheye content. */
|
|
277
|
+
async enterAR() {
|
|
278
|
+
await this.scene.enterAR();
|
|
279
|
+
}
|
|
272
280
|
exitVR() {
|
|
273
281
|
this.scene.exitVR();
|
|
274
282
|
}
|
|
@@ -290,13 +298,13 @@ class nt {
|
|
|
290
298
|
persist() {
|
|
291
299
|
if (this.opts.persistSettings)
|
|
292
300
|
try {
|
|
293
|
-
localStorage.setItem(
|
|
301
|
+
localStorage.setItem(q, JSON.stringify(this.view));
|
|
294
302
|
} catch {
|
|
295
303
|
}
|
|
296
304
|
}
|
|
297
305
|
loadSettings() {
|
|
298
306
|
try {
|
|
299
|
-
const t = localStorage.getItem(
|
|
307
|
+
const t = localStorage.getItem(q);
|
|
300
308
|
return t ? JSON.parse(t) : null;
|
|
301
309
|
} catch {
|
|
302
310
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"three-vr-player.js","sources":["../src/ui/ControlsUI.ts","../src/Player.ts","../src/webcomponent.ts","../src/index.ts"],"sourcesContent":["import type { Projection } from '../types.js';\r\nimport { PROJECTIONS } from '../core/projections.js';\r\nimport { formatTime } from './format.js';\r\n\r\n/** What the ControlsUI needs from the Player to drive playback + view. */\r\nexport interface PlayerBridge {\r\n video: HTMLVideoElement;\r\n surface: HTMLElement; // canvas — for wheel-zoom\r\n fullscreenTarget: HTMLElement;\r\n vrSupported(): Promise<boolean>;\r\n enterVR(): Promise<void>;\r\n exitVR(): void;\r\n isPresenting(): boolean;\r\n onVrChange(cb: (presenting: boolean) => void): void;\r\n getProjection(): Projection | 'off';\r\n setProjection(p: Projection | 'off'): void;\r\n setSwapEyes(v: boolean): void;\r\n setFov(deg: number): void;\r\n setSupersampling(x: number): void;\r\n initial: { swapEyes: boolean; fov: number; supersampling: number };\r\n proxy: { url: string; apiPassword: string; enabled: boolean };\r\n setProxy(p: { url: string; apiPassword: string; enabled: boolean }): void;\r\n}\r\n\r\ntype Props = Record<string, unknown> & { class?: string };\r\nfunction h<K extends keyof HTMLElementTagNameMap>(tag: K, props: Props = {}, children: (Node | string)[] = []): HTMLElementTagNameMap[K] {\r\n const el = document.createElement(tag);\r\n const { class: cls, ...rest } = props;\r\n if (cls) el.className = cls;\r\n Object.assign(el, rest);\r\n for (const c of children) el.append(c);\r\n return el;\r\n}\r\n\r\n/** Builds the controls bar + settings/menus inside `root` and wires them to `bridge`. */\r\nexport class ControlsUI {\r\n private readonly nodes: HTMLElement[] = [];\r\n private readonly disposers: (() => void)[] = [];\r\n\r\n constructor(root: ParentNode, bridge: PlayerBridge) {\r\n const v = bridge.video;\r\n\r\n // --- playback ---\r\n const play = h('button', { class: 'tvp-btn tvp-play', title: 'Play/Pause', textContent: '▶' });\r\n const seek = h('input', { class: 'tvp-seek', type: 'range', min: '0', max: '1000', value: '0' });\r\n const time = h('span', { class: 'tvp-time', textContent: '0:00 / 0:00' });\r\n\r\n // --- volume ---\r\n const mute = h('button', { class: 'tvp-btn tvp-mute', title: 'Volume', textContent: '🔊' });\r\n const volume = h('input', { class: 'tvp-volume', type: 'range', min: '0', max: '1', step: '0.01', value: '1' });\r\n const volPopup = h('div', { class: 'tvp-volpopup', hidden: true }, [volume]);\r\n const volWrap = h('span', { class: 'tvp-volwrap' }, [mute, volPopup]);\r\n\r\n // --- VR ---\r\n const vrBtn = h('button', { class: 'tvp-btn tvp-vrbtn', title: 'Enter VR', textContent: '🥽', hidden: true });\r\n\r\n // --- projection menu ---\r\n const projBtn = h('button', { class: 'tvp-btn tvp-projbtn', title: 'Projection', textContent: '🌐' });\r\n const projMenu = h('div', { class: 'tvp-projmenu', hidden: true });\r\n for (const p of PROJECTIONS) {\r\n const b = h('button', { textContent: p.label });\r\n b.dataset.mode = p.value;\r\n projMenu.append(b);\r\n }\r\n const offBtn = h('button', { textContent: 'Off (native player)' });\r\n offBtn.dataset.mode = 'off';\r\n projMenu.append(h('hr', { class: 'tvp-sep' }), offBtn);\r\n const projWrap = h('span', { class: 'tvp-projwrap' }, [projBtn, projMenu]);\r\n\r\n // --- settings ---\r\n const settingsBtn = h('button', { class: 'tvp-btn tvp-settingsbtn', title: 'Settings', textContent: '⚙' });\r\n const fullscreen = h('button', { class: 'tvp-btn tvp-fullscreen', title: 'Fullscreen', textContent: '⛶' });\r\n\r\n const controls = h('footer', { class: 'tvp-controls' }, [play, seek, time, volWrap, vrBtn, projWrap, settingsBtn, fullscreen]);\r\n\r\n const swapCb = h('input', { type: 'checkbox', checked: bridge.initial.swapEyes });\r\n const fovRange = h('input', { type: 'range', min: '30', max: '100', step: '1', value: String(bridge.initial.fov) });\r\n const fovVal = h('span', { textContent: String(bridge.initial.fov) });\r\n const ssRange = h('input', { type: 'range', min: '1', max: '2', step: '0.25', value: String(bridge.initial.supersampling) });\r\n const ssVal = h('span', { textContent: String(bridge.initial.supersampling) });\r\n const useProxyCb = h('input', { type: 'checkbox', checked: bridge.proxy.enabled });\r\n const proxyUrlIn = h('input', { type: 'text', value: bridge.proxy.url, placeholder: 'http://localhost:8888', spellcheck: false });\r\n const proxyPwIn = h('input', { type: 'password', value: bridge.proxy.apiPassword, placeholder: 'API password' });\r\n const settings = h('section', { class: 'tvp-settings' }, [\r\n h('label', { class: 'row' }, [swapCb, 'Swap eyes (if depth looks wrong)']),\r\n h('label', {}, [makeText('Field of view (zoom): ', fovVal, '°'), fovRange]),\r\n h('label', {}, [makeText('Supersampling: ', ssVal, '× (sharpness)'), ssRange]),\r\n h('hr', { class: 'tvp-sep' }),\r\n h('label', { class: 'row' }, [useProxyCb, 'Use CORS proxy']),\r\n h('label', {}, ['Proxy URL', proxyUrlIn]),\r\n h('label', {}, ['API password', proxyPwIn]),\r\n ]);\r\n\r\n const toast = h('div', { class: 'tvp-toast' });\r\n\r\n this.nodes.push(controls, settings, toast);\r\n for (const n of this.nodes) root.append(n);\r\n\r\n // ---- wiring ----\r\n const on = <T extends EventTarget>(t: T, ev: string, fn: (e: any) => void, opts?: AddEventListenerOptions) => {\r\n t.addEventListener(ev, fn as EventListener, opts);\r\n this.disposers.push(() => t.removeEventListener(ev, fn as EventListener, opts));\r\n };\r\n const setSeekFill = (pct: number) => seek.style.setProperty('--seek', `${pct}%`);\r\n // Only one popup (volume / projection / settings) open at a time.\r\n const closeMenus = () => { volPopup.hidden = true; projMenu.hidden = true; settings.classList.remove('open'); };\r\n let toastTimer = 0;\r\n const showToast = (msg: string) => {\r\n toast.textContent = msg;\r\n toast.classList.add('show');\r\n clearTimeout(toastTimer);\r\n toastTimer = window.setTimeout(() => toast.classList.remove('show'), 4500);\r\n };\r\n\r\n // Fire on a real pointer tap. The Meta Quest controller ray often fails to\r\n // synthesize `click` on <button> (tiny ray movement between press/release exceeds\r\n // the click threshold), while pointerup always fires. We trigger on pointerup and\r\n // keep `click` for keyboard/assistive tech, deduped so each activation fires once.\r\n // (pointerup carries transient activation too, so WebXR requestSession still works.)\r\n const onTap = (el: HTMLElement, fn: (e: Event) => void) => {\r\n let downOn = false;\r\n let firedAt = -1e9;\r\n const run = (e: Event) => { firedAt = e.timeStamp; fn(e); };\r\n on(el, 'pointerdown', () => { downOn = true; });\r\n on(el, 'pointercancel', () => { downOn = false; });\r\n on(el, 'pointerup', (e: Event) => { if (downOn) { downOn = false; run(e); } });\r\n on(el, 'click', (e: Event) => { if (e.timeStamp - firedAt > 700) run(e); });\r\n };\r\n\r\n onTap(play, () => { v.paused ? void v.play() : v.pause(); });\r\n on(v, 'play', () => { play.textContent = '⏸'; });\r\n on(v, 'pause', () => { play.textContent = '▶'; });\r\n\r\n on(v, 'timeupdate', () => {\r\n if (v.duration) {\r\n const pct = (v.currentTime / v.duration) * 100;\r\n seek.value = String(pct * 10);\r\n setSeekFill(pct);\r\n time.textContent = `${formatTime(v.currentTime)} / ${formatTime(v.duration)}`;\r\n }\r\n });\r\n on(seek, 'input', () => {\r\n setSeekFill(Number(seek.value) / 10);\r\n if (v.duration) v.currentTime = (Number(seek.value) / 1000) * v.duration;\r\n });\r\n\r\n onTap(mute, () => { const open = volPopup.hidden; closeMenus(); volPopup.hidden = !open; });\r\n on(volume, 'input', () => { v.volume = Number(volume.value); v.muted = v.volume === 0; mute.textContent = v.muted ? '🔇' : '🔊'; });\r\n\r\n const updateProjection = () => {\r\n const mode = bridge.getProjection();\r\n let label = 'Projection';\r\n projMenu.querySelectorAll('button').forEach((b) => {\r\n const on2 = b.dataset.mode === mode;\r\n b.classList.toggle('active', on2);\r\n if (on2) label = `Projection: ${b.textContent}`;\r\n });\r\n projBtn.title = label;\r\n };\r\n onTap(projBtn, () => { const open = projMenu.hidden; closeMenus(); projMenu.hidden = !open; });\r\n onTap(projMenu, (e: Event) => {\r\n const b = (e.target as HTMLElement).closest('button[data-mode]') as HTMLElement | null;\r\n if (b) { bridge.setProjection(b.dataset.mode as Projection | 'off'); updateProjection(); projMenu.hidden = true; }\r\n });\r\n updateProjection();\r\n\r\n onTap(settingsBtn, () => { const open = !settings.classList.contains('open'); closeMenus(); settings.classList.toggle('open', open); });\r\n on(swapCb, 'change', () => bridge.setSwapEyes(swapCb.checked));\r\n on(fovRange, 'input', () => { const d = Number(fovRange.value); fovVal.textContent = String(d); bridge.setFov(d); });\r\n on(ssRange, 'input', () => { const x = Number(ssRange.value); ssVal.textContent = String(x); bridge.setSupersampling(x); });\r\n const applyProxy = () => bridge.setProxy({ url: proxyUrlIn.value.trim(), apiPassword: proxyPwIn.value, enabled: useProxyCb.checked });\r\n on(useProxyCb, 'change', applyProxy);\r\n on(proxyUrlIn, 'change', applyProxy);\r\n on(proxyPwIn, 'change', applyProxy);\r\n on(bridge.surface, 'wheel', (e: WheelEvent) => {\r\n e.preventDefault();\r\n const next = Math.max(30, Math.min(100, Number(fovRange.value) + Math.sign(e.deltaY) * 3));\r\n fovRange.value = String(next); fovVal.textContent = String(next); bridge.setFov(next);\r\n }, { passive: false });\r\n\r\n onTap(fullscreen, () => {\r\n const t = bridge.fullscreenTarget;\r\n if (!document.fullscreenElement) void t.requestFullscreen?.();\r\n else void document.exitFullscreen?.();\r\n });\r\n\r\n // outside-tap closes any open popup (pointerdown fires reliably on Quest; click may not)\r\n on(document, 'pointerdown', (e: Event) => {\r\n const path = (e as Event & { composedPath(): EventTarget[] }).composedPath();\r\n const inside = (el: Node) => path.includes(el);\r\n if (![volPopup, mute, projMenu, projBtn, settings, settingsBtn].some(inside)) closeMenus();\r\n });\r\n\r\n // Auto-hide the control bar after 5s of inactivity; show on movement over the player.\r\n let hideTimer = 0;\r\n const popupOpen = () => !volPopup.hidden || !projMenu.hidden || settings.classList.contains('open');\r\n const hideBar = () => { if (!popupOpen()) controls.classList.add('tvp-hidden'); };\r\n const showBar = () => { controls.classList.remove('tvp-hidden'); clearTimeout(hideTimer); hideTimer = window.setTimeout(hideBar, 5000); };\r\n on(bridge.fullscreenTarget, 'pointermove', showBar);\r\n on(bridge.fullscreenTarget, 'pointerdown', showBar);\r\n on(bridge.fullscreenTarget, 'pointerleave', () => { clearTimeout(hideTimer); hideBar(); });\r\n this.disposers.push(() => clearTimeout(hideTimer));\r\n showBar();\r\n\r\n // VR button only when an immersive-VR device is available\r\n void bridge.vrSupported().then((ok) => { vrBtn.hidden = !ok; });\r\n onTap(vrBtn, () => {\r\n if (bridge.isPresenting()) { bridge.exitVR(); return; }\r\n // requestSession is the first thing off the tap so it keeps the user gesture;\r\n // any rejection is surfaced instead of silently swallowed.\r\n bridge.enterVR().catch((err: unknown) => showToast(err instanceof Error ? err.message : 'Could not enter VR.'));\r\n });\r\n bridge.onVrChange((presenting) => { vrBtn.classList.toggle('active', presenting); vrBtn.title = presenting ? 'Exit VR' : 'Enter VR'; });\r\n }\r\n\r\n dispose() {\r\n for (const d of this.disposers) d();\r\n for (const n of this.nodes) n.remove();\r\n }\r\n}\r\n\r\nfunction makeText(prefix: string, valueSpan: HTMLElement, suffix: string): DocumentFragment {\r\n const frag = document.createDocumentFragment();\r\n frag.append(prefix, valueSpan, suffix);\r\n return frag;\r\n}\r\n","import { StereoScene } from './core/StereoScene.js';\r\nimport { LookControls } from './core/LookControls.js';\r\nimport { VideoSource } from './core/VideoSource.js';\r\nimport { buildProxyUrl, type ProxyConfig } from './core/proxy.js';\r\nimport { detectProjection } from './core/projections.js';\r\nimport { ControlsUI } from './ui/ControlsUI.js';\r\nimport css from './ui/controls.css?inline';\r\nimport type { PlayerOptions, PlayerEvent, Projection } from './types.js';\r\n\r\ntype ViewSettings = { projection: Projection; swapEyes: boolean; fov: number; supersampling: number };\r\nconst STORE_KEY = 'three-vr-player:settings';\r\n\r\n/**\r\n * A drop-in 3D/VR video player. Mounts a canvas + controls (into a Shadow DOM by\r\n * default) inside `container`, composing the headless core.\r\n */\r\nexport class Player {\r\n readonly video: HTMLVideoElement;\r\n\r\n private readonly opts: PlayerOptions;\r\n private readonly wrap: HTMLElement;\r\n private readonly canvas: HTMLCanvasElement;\r\n private readonly scene: StereoScene;\r\n private readonly look: LookControls;\r\n private readonly source = new VideoSource();\r\n private readonly ui?: ControlsUI;\r\n private readonly listeners = new Map<PlayerEvent, Set<(p?: unknown) => void>>();\r\n private view: ViewSettings;\r\n private readyEmitted = false;\r\n private native = false;\r\n private tainted = false; // current video loaded via CORS-fallback (crossOrigin removed)\r\n private displayMode: Projection | 'off';\r\n private loading = false;\r\n private proxyConfig?: ProxyConfig;\r\n private useProxy = false;\r\n private currentSrc?: string;\r\n\r\n constructor(container: HTMLElement, options: PlayerOptions = {}) {\r\n this.opts = options;\r\n this.proxyConfig = options.proxy;\r\n this.useProxy = !!options.proxy;\r\n const stored = options.persistSettings ? this.loadSettings() : null;\r\n this.view = {\r\n projection: options.projection ?? stored?.projection ?? '180-sbs',\r\n swapEyes: options.swapEyes ?? stored?.swapEyes ?? false,\r\n fov: options.fov ?? stored?.fov ?? 70,\r\n supersampling: options.supersampling ?? stored?.supersampling ?? 1.5,\r\n };\r\n this.displayMode = this.view.projection;\r\n\r\n this.wrap = document.createElement('div');\r\n this.wrap.className = 'tvp';\r\n this.wrap.style.cssText = 'position:relative;width:100%;height:100%;overflow:hidden;';\r\n container.appendChild(this.wrap);\r\n\r\n let root: ParentNode;\r\n if (options.shadowDom !== false) {\r\n const shadow = this.wrap.attachShadow({ mode: 'open' });\r\n const style = document.createElement('style'); style.textContent = css; shadow.appendChild(style);\r\n root = shadow;\r\n } else {\r\n if (!document.getElementById('tvp-styles')) {\r\n const style = document.createElement('style'); style.id = 'tvp-styles'; style.textContent = css; document.head.appendChild(style);\r\n }\r\n root = this.wrap;\r\n }\r\n\r\n this.canvas = document.createElement('canvas'); this.canvas.className = 'tvp-canvas';\r\n this.video = document.createElement('video'); this.video.className = 'tvp-video'; this.video.playsInline = true;\r\n if (options.crossOrigin !== null) this.video.crossOrigin = options.crossOrigin ?? 'anonymous';\r\n root.append(this.canvas, this.video);\r\n\r\n this.scene = new StereoScene({\r\n canvas: this.canvas, video: this.video,\r\n projection: this.view.projection, swapEyes: this.view.swapEyes,\r\n fov: this.view.fov, supersampling: this.view.supersampling,\r\n });\r\n if (options.title) this.scene.setVRTitle(options.title);\r\n this.look = new LookControls(this.scene.camera, this.canvas, { isPresenting: () => this.scene.renderer.xr.isPresenting });\r\n this.scene.onFrame(() => this.look.update());\r\n this.look.setEnabled(!this.scene.isFlat());\r\n\r\n if (options.controls !== false) {\r\n this.ui = new ControlsUI(root, {\r\n video: this.video,\r\n surface: this.canvas,\r\n fullscreenTarget: this.wrap,\r\n vrSupported: () => this.vrSupported(),\r\n enterVR: () => this.enterVR(),\r\n exitVR: () => this.scene.exitVR(),\r\n isPresenting: () => this.scene.renderer.xr.isPresenting,\r\n onVrChange: (cb) => { this.on('enterxr', () => cb(true)); this.on('exitxr', () => cb(false)); },\r\n getProjection: () => this.displayMode,\r\n setProjection: (p) => this.setProjection(p),\r\n setSwapEyes: (v) => this.setSwapEyes(v),\r\n setFov: (d) => this.setFov(d),\r\n setSupersampling: (x) => this.setSupersampling(x),\r\n initial: { swapEyes: this.view.swapEyes, fov: this.view.fov, supersampling: this.view.supersampling },\r\n proxy: { url: this.proxyConfig?.url ?? '', apiPassword: this.proxyConfig?.apiPassword ?? '', enabled: this.useProxy },\r\n setProxy: (p) => this.setProxy(p),\r\n });\r\n }\r\n\r\n this.video.addEventListener('play', () => this.emit('play'));\r\n this.video.addEventListener('pause', () => this.emit('pause'));\r\n this.video.addEventListener('ended', () => this.emit('ended'));\r\n this.video.addEventListener('timeupdate', () => this.emit('timeupdate', this.video.currentTime));\r\n this.video.addEventListener('error', () => { if (!this.loading) this.emit('error', this.video.error); });\r\n this.video.addEventListener('loadedmetadata', () => { if (!this.readyEmitted) { this.readyEmitted = true; this.emit('ready'); } });\r\n this.scene.renderer.xr.addEventListener('sessionstart', () => this.emit('enterxr'));\r\n this.scene.renderer.xr.addEventListener('sessionend', () => this.emit('exitxr'));\r\n // Arm the headset/browser's own \"Enter VR\" affordance when immersive VR is available.\r\n void this.vrSupported().then((ok) => { if (ok) this.scene.offerVR(); });\r\n\r\n if (options.src) void this.load(options.src, { projection: options.projection });\r\n }\r\n\r\n private vrSupported(): Promise<boolean> {\r\n if (this.opts.vrButton === false || !navigator.xr) return Promise.resolve(false);\r\n return navigator.xr.isSessionSupported('immersive-vr').catch(() => false);\r\n }\r\n\r\n async load(src: string, o: { projection?: Projection } = {}): Promise<void> {\r\n this.currentSrc = src;\r\n const proj = o.projection ?? (this.opts.autoDetect !== false ? detectProjection(src) : null);\r\n if (proj) this.applyProjectionGeometry(proj);\r\n if (this.displayMode !== 'off') this.displayMode = this.view.projection;\r\n const { url, format } = buildProxyUrl(src, this.useProxy ? this.proxyConfig : undefined);\r\n const primaryCO = this.opts.crossOrigin === undefined ? 'anonymous' : this.opts.crossOrigin;\r\n this.loading = true;\r\n try {\r\n await this.source.attach(this.video, { url, format }, { crossOrigin: primaryCO });\r\n this.tainted = false;\r\n this.applyDisplay();\r\n await this.video.play().catch(() => { /* autoplay may be blocked until a user gesture */ });\r\n } catch (err) {\r\n // A cross-origin progressive source that isn't CORS-clean (and isn't proxied) can't be a\r\n // WebGL texture. Retry without crossOrigin and show plain 2D <video> playback if allowed.\r\n if (this.opts.nativeFallback !== false && format === 'progressive' && primaryCO !== null) {\r\n try {\r\n this.tainted = true;\r\n this.setNativeFallback(true); // stop WebGL rendering before the tainted video loads\r\n await this.source.attach(this.video, { url, format }, { crossOrigin: null });\r\n await this.video.play().catch(() => {});\r\n this.emit('fallback');\r\n return;\r\n } catch (err2) {\r\n this.tainted = false;\r\n this.setNativeFallback(false);\r\n this.emit('error', err2);\r\n throw err2;\r\n }\r\n }\r\n this.setNativeFallback(false);\r\n this.emit('error', err);\r\n throw err;\r\n } finally {\r\n this.loading = false;\r\n }\r\n }\r\n\r\n /** Swap between WebGL (3D) rendering and plain 2D `<video>` playback. */\r\n private setNativeFallback(on: boolean) {\r\n if (on === this.native) return;\r\n this.native = on;\r\n if (on) {\r\n this.scene.pauseRendering();\r\n this.canvas.style.display = 'none';\r\n Object.assign(this.video.style, {\r\n display: 'block', position: 'absolute', inset: '0',\r\n width: '100%', height: '100%', objectFit: 'contain', background: '#000', zIndex: '1',\r\n });\r\n } else {\r\n this.canvas.style.display = '';\r\n this.video.style.cssText = '';\r\n this.scene.resumeRendering();\r\n }\r\n }\r\n\r\n async play() { await this.video.play(); }\r\n pause() { this.video.pause(); }\r\n /** Set the display mode: a geometry projection (WebGL 3D) or 'off' for plain 2D `<video>`. */\r\n setProjection(p: Projection | 'off') {\r\n if (p === 'off') {\r\n this.displayMode = 'off';\r\n this.setNativeFallback(true);\r\n this.emit('projectionchange', p);\r\n return;\r\n }\r\n this.displayMode = p;\r\n this.applyProjectionGeometry(p);\r\n // A CORS-tainted (native-fallback) video can't be a WebGL texture — reload to re-attempt 3D.\r\n if (this.tainted && this.currentSrc) void this.load(this.currentSrc);\r\n else this.setNativeFallback(false);\r\n this.emit('projectionchange', p);\r\n }\r\n private applyProjectionGeometry(p: Projection) {\r\n this.scene.setProjection(p);\r\n this.look.setEnabled(!this.scene.isFlat());\r\n this.look.reset();\r\n this.view.projection = p; this.persist();\r\n }\r\n private applyDisplay() { this.setNativeFallback(this.displayMode === 'off'); }\r\n setSwapEyes(v: boolean) { this.scene.setSwapEyes(v); this.view.swapEyes = v; this.persist(); }\r\n setFov(deg: number) { this.scene.setFov(deg); this.view.fov = deg; this.persist(); }\r\n setSupersampling(x: number) { this.scene.setSupersampling(x); this.view.supersampling = x; this.persist(); }\r\n /** Update the CORS proxy config / toggle it, and reload the current source if any. */\r\n setProxy(p: { url: string; apiPassword?: string; enabled: boolean }) {\r\n this.proxyConfig = p.url ? { url: p.url, apiPassword: p.apiPassword || undefined } : undefined;\r\n this.useProxy = p.enabled;\r\n if (this.currentSrc) void this.load(this.currentSrc);\r\n }\r\n\r\n /** Enter immersive VR. Rejects if the WebXR session request fails (e.g. no headset,\r\n * or a non-secure origin) — the built-in controls surface the reason as a toast. */\r\n async enterVR() { await this.scene.enterVR(); }\r\n exitVR() { this.scene.exitVR(); }\r\n\r\n get three() { return { renderer: this.scene.renderer, scene: this.scene.scene, camera: this.scene.camera }; }\r\n\r\n on(e: PlayerEvent, cb: (p?: unknown) => void) {\r\n let s = this.listeners.get(e); if (!s) { s = new Set(); this.listeners.set(e, s); } s.add(cb); return this;\r\n }\r\n off(e: PlayerEvent, cb: (p?: unknown) => void) { this.listeners.get(e)?.delete(cb); return this; }\r\n private emit(e: PlayerEvent, p?: unknown) { this.listeners.get(e)?.forEach((cb) => cb(p)); }\r\n\r\n private persist() {\r\n if (!this.opts.persistSettings) return;\r\n try { localStorage.setItem(STORE_KEY, JSON.stringify(this.view)); } catch { /* private mode */ }\r\n }\r\n private loadSettings(): Partial<ViewSettings> | null {\r\n try { const raw = localStorage.getItem(STORE_KEY); return raw ? JSON.parse(raw) as Partial<ViewSettings> : null; }\r\n catch { return null; }\r\n }\r\n\r\n dispose() {\r\n this.ui?.dispose(); this.look.dispose(); this.source.dispose(); this.scene.dispose();\r\n this.video.remove(); this.canvas.remove(); this.wrap.remove(); this.listeners.clear();\r\n }\r\n}\r\n","import { Player } from './Player.js';\r\nimport type { Projection } from './types.js';\r\n\r\n/**\r\n * `<three-video src=\"…\" projection=\"180-sbs\" controls>` — a framework-agnostic\r\n * custom element wrapping {@link Player}. Give it a size via CSS.\r\n */\r\nexport class ThreeVideoElement extends HTMLElement {\r\n private player?: Player;\r\n\r\n static get observedAttributes() { return ['src', 'projection']; }\r\n\r\n connectedCallback() {\r\n if (this.player) return;\r\n if (!this.style.display) this.style.display = 'block';\r\n this.player = new Player(this, {\r\n src: this.getAttribute('src') ?? undefined,\r\n projection: (this.getAttribute('projection') as Projection) ?? undefined,\r\n controls: this.hasAttribute('controls'),\r\n swapEyes: this.hasAttribute('swap-eyes'),\r\n autoDetect: this.getAttribute('auto-detect') !== 'false',\r\n fov: this.numAttr('fov'),\r\n supersampling: this.numAttr('supersampling'),\r\n proxy: this.getAttribute('proxy-url')\r\n ? { url: this.getAttribute('proxy-url')!, apiPassword: this.getAttribute('proxy-password') ?? undefined }\r\n : undefined,\r\n });\r\n }\r\n\r\n attributeChangedCallback(name: string, _old: string | null, value: string | null) {\r\n if (!this.player || value == null) return;\r\n if (name === 'src') void this.player.load(value);\r\n if (name === 'projection') this.player.setProjection(value as Projection);\r\n }\r\n\r\n disconnectedCallback() { this.player?.dispose(); this.player = undefined; }\r\n\r\n private numAttr(n: string): number | undefined {\r\n const v = this.getAttribute(n);\r\n return v == null ? undefined : Number(v);\r\n }\r\n\r\n /** The underlying Player instance (for programmatic control). */\r\n get api(): Player | undefined { return this.player; }\r\n}\r\n\r\nexport function registerWebComponent(tag = 'three-video') {\r\n if (typeof customElements !== 'undefined' && !customElements.get(tag)) {\r\n customElements.define(tag, ThreeVideoElement);\r\n }\r\n}\r\n","export { Player } from './Player.js';\r\nexport type { PlayerOptions, PlayerEvent, Projection } from './types.js';\r\nexport { ThreeVideoElement, registerWebComponent } from './webcomponent.js';\r\nexport * from './core/index.js';\r\n\r\nimport { registerWebComponent } from './webcomponent.js';\r\n// Auto-register <three-video> when the main entry is imported.\r\nregisterWebComponent();\r\n"],"names":["h","tag","props","children","el","cls","rest","c","ControlsUI","root","bridge","v","play","seek","time","mute","volume","volPopup","volWrap","vrBtn","projBtn","projMenu","p","PROJECTIONS","b","offBtn","projWrap","settingsBtn","fullscreen","controls","swapCb","fovRange","fovVal","ssRange","ssVal","useProxyCb","proxyUrlIn","proxyPwIn","settings","makeText","toast","n","on","t","ev","fn","opts","setSeekFill","pct","closeMenus","toastTimer","showToast","msg","onTap","downOn","firedAt","run","e","formatTime","open","updateProjection","mode","label","on2","d","x","applyProxy","next","_b","_a","path","inside","hideTimer","popupOpen","hideBar","showBar","ok","err","presenting","prefix","valueSpan","suffix","frag","STORE_KEY","Player","container","options","VideoSource","stored","shadow","style","css","StereoScene","LookControls","cb","src","o","proj","detectProjection","url","format","buildProxyUrl","primaryCO","err2","deg","raw","ThreeVideoElement","name","_old","value","registerWebComponent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"three-vr-player.js","sources":["../src/ui/ControlsUI.ts","../src/Player.ts","../src/webcomponent.ts","../src/index.ts"],"sourcesContent":["import type { Projection } from '../types.js';\r\nimport { PROJECTIONS } from '../core/projections.js';\r\nimport { formatTime } from './format.js';\r\n\r\n/** What the ControlsUI needs from the Player to drive playback + view. */\r\nexport interface PlayerBridge {\r\n video: HTMLVideoElement;\r\n surface: HTMLElement; // canvas — for wheel-zoom\r\n fullscreenTarget: HTMLElement;\r\n vrSupported(): Promise<boolean>;\r\n enterVR(): Promise<void>;\r\n exitVR(): void;\r\n isPresenting(): boolean;\r\n onVrChange(cb: (presenting: boolean) => void): void;\r\n getProjection(): Projection | 'off';\r\n setProjection(p: Projection | 'off'): void;\r\n setSwapEyes(v: boolean): void;\r\n setFov(deg: number): void;\r\n setSupersampling(x: number): void;\r\n initial: { swapEyes: boolean; fov: number; supersampling: number };\r\n proxy: { url: string; apiPassword: string; enabled: boolean };\r\n setProxy(p: { url: string; apiPassword: string; enabled: boolean }): void;\r\n}\r\n\r\ntype Props = Record<string, unknown> & { class?: string };\r\nfunction h<K extends keyof HTMLElementTagNameMap>(tag: K, props: Props = {}, children: (Node | string)[] = []): HTMLElementTagNameMap[K] {\r\n const el = document.createElement(tag);\r\n const { class: cls, ...rest } = props;\r\n if (cls) el.className = cls;\r\n Object.assign(el, rest);\r\n for (const c of children) el.append(c);\r\n return el;\r\n}\r\n\r\n/** Builds the controls bar + settings/menus inside `root` and wires them to `bridge`. */\r\nexport class ControlsUI {\r\n private readonly nodes: HTMLElement[] = [];\r\n private readonly disposers: (() => void)[] = [];\r\n\r\n constructor(root: ParentNode, bridge: PlayerBridge) {\r\n const v = bridge.video;\r\n\r\n // --- playback ---\r\n const play = h('button', { class: 'tvp-btn tvp-play', title: 'Play/Pause', textContent: '▶' });\r\n const seek = h('input', { class: 'tvp-seek', type: 'range', min: '0', max: '1000', value: '0' });\r\n const time = h('span', { class: 'tvp-time', textContent: '0:00 / 0:00' });\r\n\r\n // --- volume ---\r\n const mute = h('button', { class: 'tvp-btn tvp-mute', title: 'Volume', textContent: '🔊' });\r\n const volume = h('input', { class: 'tvp-volume', type: 'range', min: '0', max: '1', step: '0.01', value: '1' });\r\n const volPopup = h('div', { class: 'tvp-volpopup', hidden: true }, [volume]);\r\n const volWrap = h('span', { class: 'tvp-volwrap' }, [mute, volPopup]);\r\n\r\n // --- VR ---\r\n const vrBtn = h('button', { class: 'tvp-btn tvp-vrbtn', title: 'Enter VR', textContent: '🥽', hidden: true });\r\n\r\n // --- projection menu ---\r\n const projBtn = h('button', { class: 'tvp-btn tvp-projbtn', title: 'Projection', textContent: '🌐' });\r\n const projMenu = h('div', { class: 'tvp-projmenu', hidden: true });\r\n for (const p of PROJECTIONS) {\r\n const b = h('button', { textContent: p.label });\r\n b.dataset.mode = p.value;\r\n projMenu.append(b);\r\n }\r\n const offBtn = h('button', { textContent: 'Off (native player)' });\r\n offBtn.dataset.mode = 'off';\r\n projMenu.append(h('hr', { class: 'tvp-sep' }), offBtn);\r\n const projWrap = h('span', { class: 'tvp-projwrap' }, [projBtn, projMenu]);\r\n\r\n // --- settings ---\r\n const settingsBtn = h('button', { class: 'tvp-btn tvp-settingsbtn', title: 'Settings', textContent: '⚙' });\r\n const fullscreen = h('button', { class: 'tvp-btn tvp-fullscreen', title: 'Fullscreen', textContent: '⛶' });\r\n\r\n const controls = h('footer', { class: 'tvp-controls' }, [play, seek, time, volWrap, vrBtn, projWrap, settingsBtn, fullscreen]);\r\n\r\n const swapCb = h('input', { type: 'checkbox', checked: bridge.initial.swapEyes });\r\n const fovRange = h('input', { type: 'range', min: '30', max: '100', step: '1', value: String(bridge.initial.fov) });\r\n const fovVal = h('span', { textContent: String(bridge.initial.fov) });\r\n const ssRange = h('input', { type: 'range', min: '1', max: '2', step: '0.25', value: String(bridge.initial.supersampling) });\r\n const ssVal = h('span', { textContent: String(bridge.initial.supersampling) });\r\n const useProxyCb = h('input', { type: 'checkbox', checked: bridge.proxy.enabled });\r\n const proxyUrlIn = h('input', { type: 'text', value: bridge.proxy.url, placeholder: 'http://localhost:8888', spellcheck: false });\r\n const proxyPwIn = h('input', { type: 'password', value: bridge.proxy.apiPassword, placeholder: 'API password' });\r\n const settings = h('section', { class: 'tvp-settings' }, [\r\n h('label', { class: 'row' }, [swapCb, 'Swap eyes (if depth looks wrong)']),\r\n h('label', {}, [makeText('Field of view (zoom): ', fovVal, '°'), fovRange]),\r\n h('label', {}, [makeText('Supersampling: ', ssVal, '× (sharpness)'), ssRange]),\r\n h('hr', { class: 'tvp-sep' }),\r\n h('label', { class: 'row' }, [useProxyCb, 'Use CORS proxy']),\r\n h('label', {}, ['Proxy URL', proxyUrlIn]),\r\n h('label', {}, ['API password', proxyPwIn]),\r\n ]);\r\n\r\n const toast = h('div', { class: 'tvp-toast' });\r\n\r\n this.nodes.push(controls, settings, toast);\r\n for (const n of this.nodes) root.append(n);\r\n\r\n // ---- wiring ----\r\n const on = <T extends EventTarget>(t: T, ev: string, fn: (e: any) => void, opts?: AddEventListenerOptions) => {\r\n t.addEventListener(ev, fn as EventListener, opts);\r\n this.disposers.push(() => t.removeEventListener(ev, fn as EventListener, opts));\r\n };\r\n const setSeekFill = (pct: number) => seek.style.setProperty('--seek', `${pct}%`);\r\n // Only one popup (volume / projection / settings) open at a time.\r\n const closeMenus = () => { volPopup.hidden = true; projMenu.hidden = true; settings.classList.remove('open'); };\r\n let toastTimer = 0;\r\n const showToast = (msg: string) => {\r\n toast.textContent = msg;\r\n toast.classList.add('show');\r\n clearTimeout(toastTimer);\r\n toastTimer = window.setTimeout(() => toast.classList.remove('show'), 4500);\r\n };\r\n\r\n // Fire on a real pointer tap. The Meta Quest controller ray often fails to\r\n // synthesize `click` on <button> (tiny ray movement between press/release exceeds\r\n // the click threshold), while pointerup always fires. We trigger on pointerup and\r\n // keep `click` for keyboard/assistive tech, deduped so each activation fires once.\r\n // (pointerup carries transient activation too, so WebXR requestSession still works.)\r\n const onTap = (el: HTMLElement, fn: (e: Event) => void) => {\r\n let downOn = false;\r\n let firedAt = -1e9;\r\n const run = (e: Event) => { firedAt = e.timeStamp; fn(e); };\r\n on(el, 'pointerdown', () => { downOn = true; });\r\n on(el, 'pointercancel', () => { downOn = false; });\r\n on(el, 'pointerup', (e: Event) => { if (downOn) { downOn = false; run(e); } });\r\n on(el, 'click', (e: Event) => { if (e.timeStamp - firedAt > 700) run(e); });\r\n };\r\n\r\n onTap(play, () => { v.paused ? void v.play() : v.pause(); });\r\n on(v, 'play', () => { play.textContent = '⏸'; });\r\n on(v, 'pause', () => { play.textContent = '▶'; });\r\n\r\n on(v, 'timeupdate', () => {\r\n if (v.duration) {\r\n const pct = (v.currentTime / v.duration) * 100;\r\n seek.value = String(pct * 10);\r\n setSeekFill(pct);\r\n time.textContent = `${formatTime(v.currentTime)} / ${formatTime(v.duration)}`;\r\n }\r\n });\r\n on(seek, 'input', () => {\r\n setSeekFill(Number(seek.value) / 10);\r\n if (v.duration) v.currentTime = (Number(seek.value) / 1000) * v.duration;\r\n });\r\n\r\n onTap(mute, () => { const open = volPopup.hidden; closeMenus(); volPopup.hidden = !open; });\r\n on(volume, 'input', () => { v.volume = Number(volume.value); v.muted = v.volume === 0; mute.textContent = v.muted ? '🔇' : '🔊'; });\r\n\r\n const updateProjection = () => {\r\n const mode = bridge.getProjection();\r\n let label = 'Projection';\r\n projMenu.querySelectorAll('button').forEach((b) => {\r\n const on2 = b.dataset.mode === mode;\r\n b.classList.toggle('active', on2);\r\n if (on2) label = `Projection: ${b.textContent}`;\r\n });\r\n projBtn.title = label;\r\n };\r\n onTap(projBtn, () => { const open = projMenu.hidden; closeMenus(); projMenu.hidden = !open; });\r\n onTap(projMenu, (e: Event) => {\r\n const b = (e.target as HTMLElement).closest('button[data-mode]') as HTMLElement | null;\r\n if (b) { bridge.setProjection(b.dataset.mode as Projection | 'off'); updateProjection(); projMenu.hidden = true; }\r\n });\r\n updateProjection();\r\n\r\n onTap(settingsBtn, () => { const open = !settings.classList.contains('open'); closeMenus(); settings.classList.toggle('open', open); });\r\n on(swapCb, 'change', () => bridge.setSwapEyes(swapCb.checked));\r\n on(fovRange, 'input', () => { const d = Number(fovRange.value); fovVal.textContent = String(d); bridge.setFov(d); });\r\n on(ssRange, 'input', () => { const x = Number(ssRange.value); ssVal.textContent = String(x); bridge.setSupersampling(x); });\r\n const applyProxy = () => bridge.setProxy({ url: proxyUrlIn.value.trim(), apiPassword: proxyPwIn.value, enabled: useProxyCb.checked });\r\n on(useProxyCb, 'change', applyProxy);\r\n on(proxyUrlIn, 'change', applyProxy);\r\n on(proxyPwIn, 'change', applyProxy);\r\n on(bridge.surface, 'wheel', (e: WheelEvent) => {\r\n e.preventDefault();\r\n const next = Math.max(30, Math.min(100, Number(fovRange.value) + Math.sign(e.deltaY) * 3));\r\n fovRange.value = String(next); fovVal.textContent = String(next); bridge.setFov(next);\r\n }, { passive: false });\r\n\r\n onTap(fullscreen, () => {\r\n const t = bridge.fullscreenTarget;\r\n if (!document.fullscreenElement) void t.requestFullscreen?.();\r\n else void document.exitFullscreen?.();\r\n });\r\n\r\n // outside-tap closes any open popup (pointerdown fires reliably on Quest; click may not)\r\n on(document, 'pointerdown', (e: Event) => {\r\n const path = (e as Event & { composedPath(): EventTarget[] }).composedPath();\r\n const inside = (el: Node) => path.includes(el);\r\n if (![volPopup, mute, projMenu, projBtn, settings, settingsBtn].some(inside)) closeMenus();\r\n });\r\n\r\n // Auto-hide the control bar after 5s of inactivity; show on movement over the player.\r\n let hideTimer = 0;\r\n const popupOpen = () => !volPopup.hidden || !projMenu.hidden || settings.classList.contains('open');\r\n const hideBar = () => { if (!popupOpen()) controls.classList.add('tvp-hidden'); };\r\n const showBar = () => { controls.classList.remove('tvp-hidden'); clearTimeout(hideTimer); hideTimer = window.setTimeout(hideBar, 5000); };\r\n on(bridge.fullscreenTarget, 'pointermove', showBar);\r\n on(bridge.fullscreenTarget, 'pointerdown', showBar);\r\n on(bridge.fullscreenTarget, 'pointerleave', () => { clearTimeout(hideTimer); hideBar(); });\r\n this.disposers.push(() => clearTimeout(hideTimer));\r\n showBar();\r\n\r\n // VR button only when an immersive-VR device is available\r\n void bridge.vrSupported().then((ok) => { vrBtn.hidden = !ok; });\r\n onTap(vrBtn, () => {\r\n if (bridge.isPresenting()) { bridge.exitVR(); return; }\r\n // requestSession is the first thing off the tap so it keeps the user gesture;\r\n // any rejection is surfaced instead of silently swallowed.\r\n bridge.enterVR().catch((err: unknown) => showToast(err instanceof Error ? err.message : 'Could not enter VR.'));\r\n });\r\n bridge.onVrChange((presenting) => { vrBtn.classList.toggle('active', presenting); vrBtn.title = presenting ? 'Exit VR' : 'Enter VR'; });\r\n }\r\n\r\n dispose() {\r\n for (const d of this.disposers) d();\r\n for (const n of this.nodes) n.remove();\r\n }\r\n}\r\n\r\nfunction makeText(prefix: string, valueSpan: HTMLElement, suffix: string): DocumentFragment {\r\n const frag = document.createDocumentFragment();\r\n frag.append(prefix, valueSpan, suffix);\r\n return frag;\r\n}\r\n","import { StereoScene } from './core/StereoScene.js';\r\nimport { LookControls } from './core/LookControls.js';\r\nimport { VideoSource } from './core/VideoSource.js';\r\nimport { buildProxyUrl, type ProxyConfig } from './core/proxy.js';\r\nimport { detectProjection } from './core/projections.js';\r\nimport { ControlsUI } from './ui/ControlsUI.js';\r\nimport css from './ui/controls.css?inline';\r\nimport type { PlayerOptions, PlayerEvent, Projection } from './types.js';\r\n\r\ntype ViewSettings = { projection: Projection; swapEyes: boolean; fov: number; supersampling: number };\r\nconst STORE_KEY = 'three-vr-player:settings';\r\n\r\n/**\r\n * A drop-in 3D/VR video player. Mounts a canvas + controls (into a Shadow DOM by\r\n * default) inside `container`, composing the headless core.\r\n */\r\nexport class Player {\r\n readonly video: HTMLVideoElement;\r\n\r\n private readonly opts: PlayerOptions;\r\n private readonly wrap: HTMLElement;\r\n private readonly canvas: HTMLCanvasElement;\r\n private readonly scene: StereoScene;\r\n private readonly look: LookControls;\r\n private readonly source = new VideoSource();\r\n private readonly ui?: ControlsUI;\r\n private readonly listeners = new Map<PlayerEvent, Set<(p?: unknown) => void>>();\r\n private view: ViewSettings;\r\n private readyEmitted = false;\r\n private native = false;\r\n private tainted = false; // current video loaded via CORS-fallback (crossOrigin removed)\r\n private displayMode: Projection | 'off';\r\n private loading = false;\r\n private proxyConfig?: ProxyConfig;\r\n private useProxy = false;\r\n private currentSrc?: string;\r\n\r\n constructor(container: HTMLElement, options: PlayerOptions = {}) {\r\n this.opts = options;\r\n this.proxyConfig = options.proxy;\r\n this.useProxy = !!options.proxy;\r\n const stored = options.persistSettings ? this.loadSettings() : null;\r\n this.view = {\r\n projection: options.projection ?? stored?.projection ?? '180-sbs',\r\n swapEyes: options.swapEyes ?? stored?.swapEyes ?? false,\r\n fov: options.fov ?? stored?.fov ?? 70,\r\n supersampling: options.supersampling ?? stored?.supersampling ?? 1.5,\r\n };\r\n this.displayMode = this.view.projection;\r\n\r\n this.wrap = document.createElement('div');\r\n this.wrap.className = 'tvp';\r\n this.wrap.style.cssText = 'position:relative;width:100%;height:100%;overflow:hidden;';\r\n container.appendChild(this.wrap);\r\n\r\n let root: ParentNode;\r\n if (options.shadowDom !== false) {\r\n const shadow = this.wrap.attachShadow({ mode: 'open' });\r\n const style = document.createElement('style'); style.textContent = css; shadow.appendChild(style);\r\n root = shadow;\r\n } else {\r\n if (!document.getElementById('tvp-styles')) {\r\n const style = document.createElement('style'); style.id = 'tvp-styles'; style.textContent = css; document.head.appendChild(style);\r\n }\r\n root = this.wrap;\r\n }\r\n\r\n this.canvas = document.createElement('canvas'); this.canvas.className = 'tvp-canvas';\r\n this.video = document.createElement('video'); this.video.className = 'tvp-video'; this.video.playsInline = true;\r\n if (options.crossOrigin !== null) this.video.crossOrigin = options.crossOrigin ?? 'anonymous';\r\n root.append(this.canvas, this.video);\r\n\r\n this.scene = new StereoScene({\r\n canvas: this.canvas, video: this.video,\r\n projection: this.view.projection, swapEyes: this.view.swapEyes,\r\n fov: this.view.fov, supersampling: this.view.supersampling,\r\n });\r\n if (options.title) this.scene.setVRTitle(options.title);\r\n this.look = new LookControls(this.scene.camera, this.canvas, { isPresenting: () => this.scene.renderer.xr.isPresenting });\r\n this.scene.onFrame(() => this.look.update());\r\n this.look.setEnabled(!this.scene.isFlat());\r\n\r\n if (options.controls !== false) {\r\n this.ui = new ControlsUI(root, {\r\n video: this.video,\r\n surface: this.canvas,\r\n fullscreenTarget: this.wrap,\r\n vrSupported: () => this.vrSupported(),\r\n enterVR: () => this.enterVR(),\r\n exitVR: () => this.scene.exitVR(),\r\n isPresenting: () => this.scene.renderer.xr.isPresenting,\r\n onVrChange: (cb) => { this.on('enterxr', () => cb(true)); this.on('exitxr', () => cb(false)); },\r\n getProjection: () => this.displayMode,\r\n setProjection: (p) => this.setProjection(p),\r\n setSwapEyes: (v) => this.setSwapEyes(v),\r\n setFov: (d) => this.setFov(d),\r\n setSupersampling: (x) => this.setSupersampling(x),\r\n initial: { swapEyes: this.view.swapEyes, fov: this.view.fov, supersampling: this.view.supersampling },\r\n proxy: { url: this.proxyConfig?.url ?? '', apiPassword: this.proxyConfig?.apiPassword ?? '', enabled: this.useProxy },\r\n setProxy: (p) => this.setProxy(p),\r\n });\r\n }\r\n\r\n this.video.addEventListener('play', () => this.emit('play'));\r\n this.video.addEventListener('pause', () => this.emit('pause'));\r\n this.video.addEventListener('ended', () => this.emit('ended'));\r\n this.video.addEventListener('timeupdate', () => this.emit('timeupdate', this.video.currentTime));\r\n this.video.addEventListener('error', () => { if (!this.loading) this.emit('error', this.video.error); });\r\n this.video.addEventListener('loadedmetadata', () => { if (!this.readyEmitted) { this.readyEmitted = true; this.emit('ready'); } });\r\n this.scene.renderer.xr.addEventListener('sessionstart', () => this.emit('enterxr'));\r\n this.scene.renderer.xr.addEventListener('sessionend', () => this.emit('exitxr'));\r\n // Arm the headset/browser's own \"Enter VR\" affordance when immersive VR is available.\r\n void this.vrSupported().then((ok) => { if (ok) this.scene.offerVR(); });\r\n\r\n if (options.src) void this.load(options.src, { projection: options.projection });\r\n }\r\n\r\n private vrSupported(): Promise<boolean> {\r\n if (this.opts.vrButton === false || !navigator.xr) return Promise.resolve(false);\r\n return navigator.xr.isSessionSupported('immersive-vr').catch(() => false);\r\n }\r\n\r\n /** Whether immersive-ar (passthrough) is available — used for alpha/fisheye content. */\r\n arSupported(): Promise<boolean> {\r\n if (!navigator.xr) return Promise.resolve(false);\r\n return navigator.xr.isSessionSupported('immersive-ar').catch(() => false);\r\n }\r\n\r\n async load(src: string, o: { projection?: Projection } = {}): Promise<void> {\r\n this.currentSrc = src;\r\n const proj = o.projection ?? (this.opts.autoDetect !== false ? detectProjection(src) : null);\r\n if (proj) this.applyProjectionGeometry(proj);\r\n // Packed alpha matte (fisheye passthrough): explicit option, else DeoVR's `_ALPHA` filename marker.\r\n this.scene.setAlphaMatte(this.opts.alpha ?? /_alpha/i.test(src));\r\n if (this.displayMode !== 'off') this.displayMode = this.view.projection;\r\n const { url, format } = buildProxyUrl(src, this.useProxy ? this.proxyConfig : undefined);\r\n const primaryCO = this.opts.crossOrigin === undefined ? 'anonymous' : this.opts.crossOrigin;\r\n this.loading = true;\r\n try {\r\n await this.source.attach(this.video, { url, format }, { crossOrigin: primaryCO });\r\n this.tainted = false;\r\n this.applyDisplay();\r\n await this.video.play().catch(() => { /* autoplay may be blocked until a user gesture */ });\r\n } catch (err) {\r\n // A cross-origin progressive source that isn't CORS-clean (and isn't proxied) can't be a\r\n // WebGL texture. Retry without crossOrigin and show plain 2D <video> playback if allowed.\r\n if (this.opts.nativeFallback !== false && format === 'progressive' && primaryCO !== null) {\r\n try {\r\n this.tainted = true;\r\n this.setNativeFallback(true); // stop WebGL rendering before the tainted video loads\r\n await this.source.attach(this.video, { url, format }, { crossOrigin: null });\r\n await this.video.play().catch(() => {});\r\n this.emit('fallback');\r\n return;\r\n } catch (err2) {\r\n this.tainted = false;\r\n this.setNativeFallback(false);\r\n this.emit('error', err2);\r\n throw err2;\r\n }\r\n }\r\n this.setNativeFallback(false);\r\n this.emit('error', err);\r\n throw err;\r\n } finally {\r\n this.loading = false;\r\n }\r\n }\r\n\r\n /** Swap between WebGL (3D) rendering and plain 2D `<video>` playback. */\r\n private setNativeFallback(on: boolean) {\r\n if (on === this.native) return;\r\n this.native = on;\r\n if (on) {\r\n this.scene.pauseRendering();\r\n this.canvas.style.display = 'none';\r\n Object.assign(this.video.style, {\r\n display: 'block', position: 'absolute', inset: '0',\r\n width: '100%', height: '100%', objectFit: 'contain', background: '#000', zIndex: '1',\r\n });\r\n } else {\r\n this.canvas.style.display = '';\r\n this.video.style.cssText = '';\r\n this.scene.resumeRendering();\r\n }\r\n }\r\n\r\n async play() { await this.video.play(); }\r\n pause() { this.video.pause(); }\r\n /** Set the display mode: a geometry projection (WebGL 3D) or 'off' for plain 2D `<video>`. */\r\n setProjection(p: Projection | 'off') {\r\n if (p === 'off') {\r\n this.displayMode = 'off';\r\n this.setNativeFallback(true);\r\n this.emit('projectionchange', p);\r\n return;\r\n }\r\n this.displayMode = p;\r\n this.applyProjectionGeometry(p);\r\n // A CORS-tainted (native-fallback) video can't be a WebGL texture — reload to re-attempt 3D.\r\n if (this.tainted && this.currentSrc) void this.load(this.currentSrc);\r\n else this.setNativeFallback(false);\r\n this.emit('projectionchange', p);\r\n }\r\n private applyProjectionGeometry(p: Projection) {\r\n this.scene.setProjection(p);\r\n this.look.setEnabled(!this.scene.isFlat());\r\n this.look.reset();\r\n this.view.projection = p; this.persist();\r\n }\r\n private applyDisplay() { this.setNativeFallback(this.displayMode === 'off'); }\r\n setSwapEyes(v: boolean) { this.scene.setSwapEyes(v); this.view.swapEyes = v; this.persist(); }\r\n setFov(deg: number) { this.scene.setFov(deg); this.view.fov = deg; this.persist(); }\r\n setSupersampling(x: number) { this.scene.setSupersampling(x); this.view.supersampling = x; this.persist(); }\r\n /** Update the CORS proxy config / toggle it, and reload the current source if any. */\r\n setProxy(p: { url: string; apiPassword?: string; enabled: boolean }) {\r\n this.proxyConfig = p.url ? { url: p.url, apiPassword: p.apiPassword || undefined } : undefined;\r\n this.useProxy = p.enabled;\r\n if (this.currentSrc) void this.load(this.currentSrc);\r\n }\r\n\r\n /** Enter immersive VR. Rejects if the WebXR session request fails (e.g. no headset,\r\n * or a non-secure origin) — the built-in controls surface the reason as a toast. */\r\n async enterVR() { await this.scene.enterVR(); }\r\n /** Enter immersive AR (passthrough) — for alpha/fisheye content. */\r\n async enterAR() { await this.scene.enterAR(); }\r\n exitVR() { this.scene.exitVR(); }\r\n\r\n get three() { return { renderer: this.scene.renderer, scene: this.scene.scene, camera: this.scene.camera }; }\r\n\r\n on(e: PlayerEvent, cb: (p?: unknown) => void) {\r\n let s = this.listeners.get(e); if (!s) { s = new Set(); this.listeners.set(e, s); } s.add(cb); return this;\r\n }\r\n off(e: PlayerEvent, cb: (p?: unknown) => void) { this.listeners.get(e)?.delete(cb); return this; }\r\n private emit(e: PlayerEvent, p?: unknown) { this.listeners.get(e)?.forEach((cb) => cb(p)); }\r\n\r\n private persist() {\r\n if (!this.opts.persistSettings) return;\r\n try { localStorage.setItem(STORE_KEY, JSON.stringify(this.view)); } catch { /* private mode */ }\r\n }\r\n private loadSettings(): Partial<ViewSettings> | null {\r\n try { const raw = localStorage.getItem(STORE_KEY); return raw ? JSON.parse(raw) as Partial<ViewSettings> : null; }\r\n catch { return null; }\r\n }\r\n\r\n dispose() {\r\n this.ui?.dispose(); this.look.dispose(); this.source.dispose(); this.scene.dispose();\r\n this.video.remove(); this.canvas.remove(); this.wrap.remove(); this.listeners.clear();\r\n }\r\n}\r\n","import { Player } from './Player.js';\r\nimport type { Projection } from './types.js';\r\n\r\n/**\r\n * `<three-video src=\"…\" projection=\"180-sbs\" controls>` — a framework-agnostic\r\n * custom element wrapping {@link Player}. Give it a size via CSS.\r\n */\r\nexport class ThreeVideoElement extends HTMLElement {\r\n private player?: Player;\r\n\r\n static get observedAttributes() { return ['src', 'projection']; }\r\n\r\n connectedCallback() {\r\n if (this.player) return;\r\n if (!this.style.display) this.style.display = 'block';\r\n this.player = new Player(this, {\r\n src: this.getAttribute('src') ?? undefined,\r\n projection: (this.getAttribute('projection') as Projection) ?? undefined,\r\n controls: this.hasAttribute('controls'),\r\n swapEyes: this.hasAttribute('swap-eyes'),\r\n autoDetect: this.getAttribute('auto-detect') !== 'false',\r\n fov: this.numAttr('fov'),\r\n supersampling: this.numAttr('supersampling'),\r\n proxy: this.getAttribute('proxy-url')\r\n ? { url: this.getAttribute('proxy-url')!, apiPassword: this.getAttribute('proxy-password') ?? undefined }\r\n : undefined,\r\n });\r\n }\r\n\r\n attributeChangedCallback(name: string, _old: string | null, value: string | null) {\r\n if (!this.player || value == null) return;\r\n if (name === 'src') void this.player.load(value);\r\n if (name === 'projection') this.player.setProjection(value as Projection);\r\n }\r\n\r\n disconnectedCallback() { this.player?.dispose(); this.player = undefined; }\r\n\r\n private numAttr(n: string): number | undefined {\r\n const v = this.getAttribute(n);\r\n return v == null ? undefined : Number(v);\r\n }\r\n\r\n /** The underlying Player instance (for programmatic control). */\r\n get api(): Player | undefined { return this.player; }\r\n}\r\n\r\nexport function registerWebComponent(tag = 'three-video') {\r\n if (typeof customElements !== 'undefined' && !customElements.get(tag)) {\r\n customElements.define(tag, ThreeVideoElement);\r\n }\r\n}\r\n","export { Player } from './Player.js';\r\nexport type { PlayerOptions, PlayerEvent, Projection } from './types.js';\r\nexport { ThreeVideoElement, registerWebComponent } from './webcomponent.js';\r\nexport * from './core/index.js';\r\n\r\nimport { registerWebComponent } from './webcomponent.js';\r\n// Auto-register <three-video> when the main entry is imported.\r\nregisterWebComponent();\r\n"],"names":["h","tag","props","children","el","cls","rest","c","ControlsUI","root","bridge","v","play","seek","time","mute","volume","volPopup","volWrap","vrBtn","projBtn","projMenu","p","PROJECTIONS","b","offBtn","projWrap","settingsBtn","fullscreen","controls","swapCb","fovRange","fovVal","ssRange","ssVal","useProxyCb","proxyUrlIn","proxyPwIn","settings","makeText","toast","n","on","t","ev","fn","opts","setSeekFill","pct","closeMenus","toastTimer","showToast","msg","onTap","downOn","firedAt","run","e","formatTime","open","updateProjection","mode","label","on2","d","x","applyProxy","next","_b","_a","path","inside","hideTimer","popupOpen","hideBar","showBar","ok","err","presenting","prefix","valueSpan","suffix","frag","STORE_KEY","Player","container","options","VideoSource","stored","shadow","style","css","StereoScene","LookControls","cb","src","o","proj","detectProjection","url","format","buildProxyUrl","primaryCO","err2","deg","raw","ThreeVideoElement","name","_old","value","registerWebComponent"],"mappings":"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"}
|