three-vr-player 0.1.0 → 0.3.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.
@@ -1,220 +1,260 @@
1
- import { P as $, V as I, S as R, L as V, a as D, b as U } from "./VideoSource-pc2RM7bl.js";
2
- import { M as G, c as Q, d as X, i as Z } from "./VideoSource-pc2RM7bl.js";
3
- function F(c) {
4
- if (!Number.isFinite(c) || c < 0) return "0:00";
5
- const e = Math.floor(c % 60), s = Math.floor(c / 60 % 60), t = Math.floor(c / 3600), a = String(e).padStart(2, "0");
6
- return t > 0 ? `${t}:${String(s).padStart(2, "0")}:${a}` : `${s}:${a}`;
1
+ import { P as V, V as D, S as J, L as W, a as q, b as Y } from "./VideoSource-CJGIX8gL.js";
2
+ import { M as tt, c as et, d as st, i as it } from "./VideoSource-CJGIX8gL.js";
3
+ function L(l) {
4
+ if (!Number.isFinite(l) || l < 0) return "0:00";
5
+ const t = Math.floor(l % 60), s = Math.floor(l / 60 % 60), e = Math.floor(l / 3600), a = String(t).padStart(2, "0");
6
+ return e > 0 ? `${e}:${String(s).padStart(2, "0")}:${a}` : `${s}:${a}`;
7
7
  }
8
- function n(c, e = {}, s = []) {
9
- const t = document.createElement(c), { class: a, ...o } = e;
10
- a && (t.className = a), Object.assign(t, o);
11
- for (const l of s) t.append(l);
12
- return t;
8
+ function o(l, t = {}, s = []) {
9
+ const e = document.createElement(l), { class: a, ...c } = t;
10
+ a && (e.className = a), Object.assign(e, c);
11
+ for (const d of s) e.append(d);
12
+ return e;
13
13
  }
14
- class J {
15
- constructor(e, s) {
14
+ class _ {
15
+ constructor(t, s) {
16
16
  this.nodes = [], this.disposers = [];
17
- const t = s.video, a = n("button", { class: "tvp-btn tvp-play", title: "Play/Pause", textContent: "▶" }), o = n("input", { class: "tvp-seek", type: "range", min: "0", max: "1000", value: "0" }), l = n("span", { class: "tvp-time", textContent: "0:00 / 0:00" }), f = n("button", { class: "tvp-btn tvp-mute", title: "Volume", textContent: "🔊" }), b = n("input", { class: "tvp-volume", type: "range", min: "0", max: "1", step: "0.01", value: "1" }), h = n("div", { class: "tvp-volpopup", hidden: !0 }, [b]), T = n("span", { class: "tvp-volwrap" }, [f, h]), k = n("span", { class: "tvp-vrslot" }), g = n("button", { class: "tvp-btn tvp-projbtn", title: "Projection", textContent: "🌐" }), d = n("div", { class: "tvp-projmenu", hidden: !0 });
18
- for (const i of $) {
19
- const r = n("button", { textContent: i.label });
20
- r.dataset.mode = i.value, d.append(r);
17
+ const e = s.video, a = 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" }), d = o("span", { class: "tvp-time", textContent: "0:00 / 0:00" }), n = o("button", { class: "tvp-btn tvp-mute", title: "Volume", textContent: "🔊" }), h = o("input", { class: "tvp-volume", type: "range", min: "0", max: "1", step: "0.01", value: "1" }), m = o("div", { class: "tvp-volpopup", hidden: !0 }, [h]), R = o("span", { class: "tvp-volwrap" }, [n, m]), j = o("span", { class: "tvp-vrslot" }), x = o("button", { class: "tvp-btn tvp-projbtn", title: "Projection", textContent: "🌐" }), u = o("div", { class: "tvp-projmenu", hidden: !0 });
18
+ for (const i of V) {
19
+ const r = o("button", { textContent: i.label });
20
+ r.dataset.mode = i.value, u.append(r);
21
21
  }
22
- const M = n("span", { class: "tvp-projwrap" }, [g, d]), S = n("button", { class: "tvp-btn tvp-settingsbtn", title: "Settings", textContent: "⚙" }), E = n("button", { class: "tvp-btn tvp-fullscreen", title: "Fullscreen", textContent: "⛶" }), O = n("footer", { class: "tvp-controls" }, [a, o, l, T, k, M, S, E]), x = n("input", { type: "checkbox", checked: s.initial.swapEyes }), v = n("input", { type: "range", min: "30", max: "100", step: "1", value: String(s.initial.fov) }), w = n("span", { textContent: String(s.initial.fov) }), y = n("input", { type: "range", min: "1", max: "2", step: "0.25", value: String(s.initial.supersampling) }), j = n("span", { textContent: String(s.initial.supersampling) }), C = n("section", { class: "tvp-settings" }, [
23
- n("label", { class: "row" }, [x, "Swap eyes (if depth looks wrong)"]),
24
- n("label", {}, [A("Field of view (zoom): ", w, "°"), v]),
25
- n("label", {}, [A("Supersampling: ", j, "× (sharpness)"), y])
26
- ]), B = n("div", { class: "tvp-toast" });
27
- this.nodes.push(O, C, B);
28
- for (const i of this.nodes) e.append(i);
29
- const p = (i, r, u, m) => {
30
- i.addEventListener(r, u, m), this.disposers.push(() => i.removeEventListener(r, u, m));
31
- }, P = (i) => o.style.setProperty("--seek", `${i}%`);
22
+ const B = o("span", { class: "tvp-projwrap" }, [x, u]), C = o("button", { class: "tvp-btn tvp-settingsbtn", title: "Settings", textContent: "⚙" }), F = o("button", { class: "tvp-btn tvp-fullscreen", title: "Fullscreen", textContent: "⛶" }), $ = o("footer", { class: "tvp-controls" }, [a, c, d, R, j, B, C, F]), b = o("input", { type: "checkbox", checked: s.initial.swapEyes }), f = o("input", { type: "range", min: "30", max: "100", step: "1", value: String(s.initial.fov) }), y = o("span", { textContent: String(s.initial.fov) }), w = o("input", { type: "range", min: "1", max: "2", step: "0.25", value: String(s.initial.supersampling) }), z = o("span", { textContent: String(s.initial.supersampling) }), k = o("input", { type: "checkbox", checked: s.proxy.enabled }), S = o("input", { type: "text", value: s.proxy.url, placeholder: "http://localhost:8888", spellcheck: !1 }), P = o("input", { type: "password", value: s.proxy.apiPassword, placeholder: "API password" }), N = o("section", { class: "tvp-settings" }, [
23
+ o("label", { class: "row" }, [b, "Swap eyes (if depth looks wrong)"]),
24
+ o("label", {}, [T("Field of view (zoom): ", y, "°"), f]),
25
+ o("label", {}, [T("Supersampling: ", z, "× (sharpness)"), w]),
26
+ o("hr", { class: "tvp-sep" }),
27
+ o("label", { class: "row" }, [k, "Use CORS proxy"]),
28
+ o("label", {}, ["Proxy URL", S]),
29
+ o("label", {}, ["API password", P])
30
+ ]), U = o("div", { class: "tvp-toast" });
31
+ this.nodes.push($, N, U);
32
+ for (const i of this.nodes) t.append(i);
33
+ const p = (i, r, v, g) => {
34
+ i.addEventListener(r, v, g), this.disposers.push(() => i.removeEventListener(r, v, g));
35
+ }, O = (i) => c.style.setProperty("--seek", `${i}%`);
32
36
  p(a, "click", () => {
33
- t.paused ? t.play() : t.pause();
34
- }), p(t, "play", () => {
37
+ e.paused ? e.play() : e.pause();
38
+ }), p(e, "play", () => {
35
39
  a.textContent = "⏸";
36
- }), p(t, "pause", () => {
40
+ }), p(e, "pause", () => {
37
41
  a.textContent = "▶";
38
- }), p(t, "timeupdate", () => {
39
- if (t.duration) {
40
- const i = t.currentTime / t.duration * 100;
41
- o.value = String(i * 10), P(i), l.textContent = `${F(t.currentTime)} / ${F(t.duration)}`;
42
+ }), p(e, "timeupdate", () => {
43
+ if (e.duration) {
44
+ const i = e.currentTime / e.duration * 100;
45
+ c.value = String(i * 10), O(i), d.textContent = `${L(e.currentTime)} / ${L(e.duration)}`;
42
46
  }
43
- }), p(o, "input", () => {
44
- P(Number(o.value) / 10), t.duration && (t.currentTime = Number(o.value) / 1e3 * t.duration);
45
- }), p(f, "click", (i) => {
46
- i.stopPropagation(), h.hidden = !h.hidden;
47
- }), p(b, "input", () => {
48
- t.volume = Number(b.value), t.muted = t.volume === 0, f.textContent = t.muted ? "🔇" : "🔊";
47
+ }), p(c, "input", () => {
48
+ O(Number(c.value) / 10), e.duration && (e.currentTime = Number(c.value) / 1e3 * e.duration);
49
+ }), p(n, "click", (i) => {
50
+ i.stopPropagation(), m.hidden = !m.hidden;
51
+ }), p(h, "input", () => {
52
+ e.volume = Number(h.value), e.muted = e.volume === 0, n.textContent = e.muted ? "🔇" : "🔊";
49
53
  });
50
- const z = () => {
54
+ const A = () => {
51
55
  const i = s.getProjection();
52
56
  let r = "Projection";
53
- d.querySelectorAll("button").forEach((u) => {
54
- const m = u.dataset.mode === i;
55
- u.classList.toggle("active", m), m && (r = `Projection: ${u.textContent}`);
56
- }), g.title = r;
57
+ u.querySelectorAll("button").forEach((v) => {
58
+ const g = v.dataset.mode === i;
59
+ v.classList.toggle("active", g), g && (r = `Projection: ${v.textContent}`);
60
+ }), x.title = r;
57
61
  };
58
- p(g, "click", (i) => {
59
- i.stopPropagation(), d.hidden = !d.hidden;
60
- }), p(d, "click", (i) => {
62
+ p(x, "click", (i) => {
63
+ i.stopPropagation(), u.hidden = !u.hidden;
64
+ }), p(u, "click", (i) => {
61
65
  const r = i.target.closest("button[data-mode]");
62
- r && (s.setProjection(r.dataset.mode), z(), d.hidden = !0);
63
- }), z(), p(S, "click", (i) => {
64
- i.stopPropagation(), C.classList.toggle("open");
65
- }), p(x, "change", () => s.setSwapEyes(x.checked)), p(v, "input", () => {
66
- const i = Number(v.value);
67
- w.textContent = String(i), s.setFov(i);
68
- }), p(y, "input", () => {
69
- const i = Number(y.value);
70
- j.textContent = String(i), s.setSupersampling(i);
71
- }), p(s.surface, "wheel", (i) => {
66
+ r && (s.setProjection(r.dataset.mode), A(), u.hidden = !0);
67
+ }), A(), p(C, "click", (i) => {
68
+ i.stopPropagation(), N.classList.toggle("open");
69
+ }), p(b, "change", () => s.setSwapEyes(b.checked)), p(f, "input", () => {
70
+ const i = Number(f.value);
71
+ y.textContent = String(i), s.setFov(i);
72
+ }), p(w, "input", () => {
73
+ const i = Number(w.value);
74
+ z.textContent = String(i), s.setSupersampling(i);
75
+ });
76
+ const E = () => s.setProxy({ url: S.value.trim(), apiPassword: P.value, enabled: k.checked });
77
+ p(k, "change", E), p(S, "change", E), p(P, "change", E), p(s.surface, "wheel", (i) => {
72
78
  i.preventDefault();
73
- const r = Math.max(30, Math.min(100, Number(v.value) + Math.sign(i.deltaY) * 3));
74
- v.value = String(r), w.textContent = String(r), s.setFov(r);
75
- }, { passive: !1 }), p(E, "click", () => {
76
- var r, u;
79
+ const r = Math.max(30, Math.min(100, Number(f.value) + Math.sign(i.deltaY) * 3));
80
+ f.value = String(r), y.textContent = String(r), s.setFov(r);
81
+ }, { passive: !1 }), p(F, "click", () => {
82
+ var r, v;
77
83
  const i = s.fullscreenTarget;
78
- document.fullscreenElement ? (u = document.exitFullscreen) == null || u.call(document) : (r = i.requestFullscreen) == null || r.call(i);
84
+ document.fullscreenElement ? (v = document.exitFullscreen) == null || v.call(document) : (r = i.requestFullscreen) == null || r.call(i);
79
85
  }), p(document, "click", (i) => {
80
86
  const r = i.composedPath();
81
- !h.hidden && !r.includes(h) && !r.includes(f) && (h.hidden = !0), !d.hidden && !r.includes(d) && !r.includes(g) && (d.hidden = !0);
87
+ !m.hidden && !r.includes(m) && !r.includes(n) && (m.hidden = !0), !u.hidden && !r.includes(u) && !r.includes(x) && (u.hidden = !0);
82
88
  }), s.vrSupported().then((i) => {
83
- i && (Object.assign(s.vrButton.style, { position: "static", left: "auto", bottom: "auto", transform: "none", margin: "0" }), k.append(s.vrButton));
89
+ i && (Object.assign(s.vrButton.style, { position: "static", left: "auto", bottom: "auto", transform: "none", margin: "0" }), j.append(s.vrButton));
84
90
  });
85
91
  }
86
92
  dispose() {
87
- for (const e of this.disposers) e();
88
- for (const e of this.nodes) e.remove();
93
+ for (const t of this.disposers) t();
94
+ for (const t of this.nodes) t.remove();
89
95
  }
90
96
  }
91
- function A(c, e, s) {
92
- const t = document.createDocumentFragment();
93
- return t.append(c, e, s), t;
97
+ function T(l, t, s) {
98
+ const e = document.createDocumentFragment();
99
+ return e.append(l, t, s), e;
94
100
  }
95
- const L = ":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}.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-vrslot button{position:static!important}.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-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}", N = "three-vr-player:settings";
96
- class W {
97
- constructor(e, s = {}) {
98
- this.source = new I(), this.listeners = /* @__PURE__ */ new Map(), this.readyEmitted = !1, this.opts = s;
99
- const t = s.persistSettings ? this.loadSettings() : null;
101
+ const I = ":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}.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-vrslot button{position:static!important}.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}", M = "three-vr-player:settings";
102
+ class H {
103
+ constructor(t, s = {}) {
104
+ var c, d;
105
+ this.source = new D(), this.listeners = /* @__PURE__ */ new Map(), this.readyEmitted = !1, this.native = !1, this.loading = !1, this.useProxy = !1, this.opts = s, this.proxyConfig = s.proxy, this.useProxy = !!s.proxy;
106
+ const e = s.persistSettings ? this.loadSettings() : null;
100
107
  this.view = {
101
- projection: s.projection ?? (t == null ? void 0 : t.projection) ?? "180-sbs",
102
- swapEyes: s.swapEyes ?? (t == null ? void 0 : t.swapEyes) ?? !1,
103
- fov: s.fov ?? (t == null ? void 0 : t.fov) ?? 70,
104
- supersampling: s.supersampling ?? (t == null ? void 0 : t.supersampling) ?? 1.5
105
- }, this.wrap = document.createElement("div"), this.wrap.className = "tvp", this.wrap.style.cssText = "position:relative;width:100%;height:100%;overflow:hidden;", e.appendChild(this.wrap);
108
+ projection: s.projection ?? (e == null ? void 0 : e.projection) ?? "180-sbs",
109
+ swapEyes: s.swapEyes ?? (e == null ? void 0 : e.swapEyes) ?? !1,
110
+ fov: s.fov ?? (e == null ? void 0 : e.fov) ?? 70,
111
+ supersampling: s.supersampling ?? (e == null ? void 0 : e.supersampling) ?? 1.5
112
+ }, this.wrap = document.createElement("div"), this.wrap.className = "tvp", this.wrap.style.cssText = "position:relative;width:100%;height:100%;overflow:hidden;", t.appendChild(this.wrap);
106
113
  let a;
107
114
  if (s.shadowDom !== !1) {
108
- const o = this.wrap.attachShadow({ mode: "open" }), l = document.createElement("style");
109
- l.textContent = L, o.appendChild(l), a = o;
115
+ const n = this.wrap.attachShadow({ mode: "open" }), h = document.createElement("style");
116
+ h.textContent = I, n.appendChild(h), a = n;
110
117
  } else {
111
118
  if (!document.getElementById("tvp-styles")) {
112
- const o = document.createElement("style");
113
- o.id = "tvp-styles", o.textContent = L, document.head.appendChild(o);
119
+ const n = document.createElement("style");
120
+ n.id = "tvp-styles", n.textContent = I, document.head.appendChild(n);
114
121
  }
115
122
  a = this.wrap;
116
123
  }
117
- this.canvas = document.createElement("canvas"), this.canvas.className = "tvp-canvas", this.video = document.createElement("video"), this.video.className = "tvp-video", this.video.playsInline = !0, s.crossOrigin !== null && (this.video.crossOrigin = s.crossOrigin ?? "anonymous"), a.append(this.canvas, this.video), this.scene = new R({
124
+ this.canvas = document.createElement("canvas"), this.canvas.className = "tvp-canvas", this.video = document.createElement("video"), this.video.className = "tvp-video", this.video.playsInline = !0, s.crossOrigin !== null && (this.video.crossOrigin = s.crossOrigin ?? "anonymous"), a.append(this.canvas, this.video), this.scene = new J({
118
125
  canvas: this.canvas,
119
126
  video: this.video,
120
127
  projection: this.view.projection,
121
128
  swapEyes: this.view.swapEyes,
122
129
  fov: this.view.fov,
123
130
  supersampling: this.view.supersampling
124
- }), this.look = new V(this.scene.camera, this.canvas, { isPresenting: () => this.scene.renderer.xr.isPresenting }), this.scene.onFrame(() => this.look.update()), this.look.setEnabled(!this.scene.isFlat()), s.controls !== !1 && (this.ui = new J(a, {
131
+ }), this.look = new W(this.scene.camera, this.canvas, { isPresenting: () => this.scene.renderer.xr.isPresenting }), this.scene.onFrame(() => this.look.update()), this.look.setEnabled(!this.scene.isFlat()), s.controls !== !1 && (this.ui = new _(a, {
125
132
  video: this.video,
126
133
  surface: this.canvas,
127
134
  fullscreenTarget: this.wrap,
128
135
  vrButton: this.scene.vrButton,
129
136
  vrSupported: () => this.vrSupported(),
130
137
  getProjection: () => this.scene.getProjection(),
131
- setProjection: (o) => this.setProjection(o),
132
- setSwapEyes: (o) => this.setSwapEyes(o),
133
- setFov: (o) => this.setFov(o),
134
- setSupersampling: (o) => this.setSupersampling(o),
135
- initial: { swapEyes: this.view.swapEyes, fov: this.view.fov, supersampling: this.view.supersampling }
136
- })), this.video.addEventListener("play", () => this.emit("play")), this.video.addEventListener("pause", () => this.emit("pause")), this.video.addEventListener("ended", () => this.emit("ended")), this.video.addEventListener("timeupdate", () => this.emit("timeupdate", this.video.currentTime)), this.video.addEventListener("error", () => this.emit("error", this.video.error)), this.video.addEventListener("loadedmetadata", () => {
138
+ setProjection: (n) => this.setProjection(n),
139
+ setSwapEyes: (n) => this.setSwapEyes(n),
140
+ setFov: (n) => this.setFov(n),
141
+ setSupersampling: (n) => this.setSupersampling(n),
142
+ initial: { swapEyes: this.view.swapEyes, fov: this.view.fov, supersampling: this.view.supersampling },
143
+ proxy: { url: ((c = this.proxyConfig) == null ? void 0 : c.url) ?? "", apiPassword: ((d = this.proxyConfig) == null ? void 0 : d.apiPassword) ?? "", enabled: this.useProxy },
144
+ setProxy: (n) => this.setProxy(n)
145
+ })), this.video.addEventListener("play", () => this.emit("play")), this.video.addEventListener("pause", () => this.emit("pause")), this.video.addEventListener("ended", () => this.emit("ended")), this.video.addEventListener("timeupdate", () => this.emit("timeupdate", this.video.currentTime)), this.video.addEventListener("error", () => {
146
+ this.loading || this.emit("error", this.video.error);
147
+ }), this.video.addEventListener("loadedmetadata", () => {
137
148
  this.readyEmitted || (this.readyEmitted = !0, this.emit("ready"));
138
149
  }), this.scene.renderer.xr.addEventListener("sessionstart", () => this.emit("enterxr")), this.scene.renderer.xr.addEventListener("sessionend", () => this.emit("exitxr")), s.src && this.load(s.src, { projection: s.projection });
139
150
  }
140
151
  vrSupported() {
141
152
  return this.opts.vrButton === !1 || !navigator.xr ? Promise.resolve(!1) : navigator.xr.isSessionSupported("immersive-vr").catch(() => !1);
142
153
  }
143
- async load(e, s = {}) {
144
- const t = s.projection ?? (this.opts.autoDetect !== !1 ? D(e) : null);
145
- t && this.setProjection(t);
146
- const { url: a, format: o } = U(e, this.opts.proxy);
154
+ async load(t, s = {}) {
155
+ this.currentSrc = t;
156
+ const e = s.projection ?? (this.opts.autoDetect !== !1 ? q(t) : null);
157
+ e && this.setProjection(e);
158
+ const { url: a, format: c } = Y(t, this.useProxy ? this.proxyConfig : void 0), d = this.opts.crossOrigin === void 0 ? "anonymous" : this.opts.crossOrigin;
159
+ this.loading = !0;
147
160
  try {
148
- await this.source.attach(this.video, { url: a, format: o }), await this.video.play().catch(() => {
161
+ await this.source.attach(this.video, { url: a, format: c }, { crossOrigin: d }), this.setNativeFallback(!1), await this.video.play().catch(() => {
149
162
  });
150
- } catch (l) {
151
- throw this.emit("error", l), l;
163
+ } catch (n) {
164
+ if (this.opts.nativeFallback !== !1 && c === "progressive" && d !== null)
165
+ try {
166
+ this.setNativeFallback(!0), await this.source.attach(this.video, { url: a, format: c }, { crossOrigin: null }), await this.video.play().catch(() => {
167
+ }), this.emit("fallback");
168
+ return;
169
+ } catch (h) {
170
+ throw this.setNativeFallback(!1), this.emit("error", h), h;
171
+ }
172
+ throw this.setNativeFallback(!1), this.emit("error", n), n;
173
+ } finally {
174
+ this.loading = !1;
152
175
  }
153
176
  }
177
+ /** Swap between WebGL (3D) rendering and plain 2D `<video>` playback. */
178
+ setNativeFallback(t) {
179
+ t !== this.native && (this.native = t, t ? (this.scene.pauseRendering(), this.canvas.style.display = "none", Object.assign(this.video.style, {
180
+ display: "block",
181
+ position: "absolute",
182
+ inset: "0",
183
+ width: "100%",
184
+ height: "100%",
185
+ objectFit: "contain",
186
+ background: "#000",
187
+ zIndex: "1"
188
+ })) : (this.canvas.style.display = "", this.video.style.cssText = "", this.scene.resumeRendering()));
189
+ }
154
190
  async play() {
155
191
  await this.video.play();
156
192
  }
157
193
  pause() {
158
194
  this.video.pause();
159
195
  }
160
- setProjection(e) {
161
- this.scene.setProjection(e), this.look.setEnabled(!this.scene.isFlat()), this.look.reset(), this.view.projection = e, this.persist(), this.emit("projectionchange", e);
196
+ setProjection(t) {
197
+ this.scene.setProjection(t), this.look.setEnabled(!this.scene.isFlat()), this.look.reset(), this.view.projection = t, this.persist(), this.emit("projectionchange", t);
198
+ }
199
+ setSwapEyes(t) {
200
+ this.scene.setSwapEyes(t), this.view.swapEyes = t, this.persist();
162
201
  }
163
- setSwapEyes(e) {
164
- this.scene.setSwapEyes(e), this.view.swapEyes = e, this.persist();
202
+ setFov(t) {
203
+ this.scene.setFov(t), this.view.fov = t, this.persist();
165
204
  }
166
- setFov(e) {
167
- this.scene.setFov(e), this.view.fov = e, this.persist();
205
+ setSupersampling(t) {
206
+ this.scene.setSupersampling(t), this.view.supersampling = t, this.persist();
168
207
  }
169
- setSupersampling(e) {
170
- this.scene.setSupersampling(e), this.view.supersampling = e, this.persist();
208
+ /** Update the CORS proxy config / toggle it, and reload the current source if any. */
209
+ setProxy(t) {
210
+ this.proxyConfig = t.url ? { url: t.url, apiPassword: t.apiPassword || void 0 } : void 0, this.useProxy = t.enabled, this.currentSrc && this.load(this.currentSrc);
171
211
  }
172
212
  async enterVR() {
173
213
  var s;
174
- const e = this.scene.vrButton;
175
- (s = e == null ? void 0 : e.click) == null || s.call(e);
214
+ const t = this.scene.vrButton;
215
+ (s = t == null ? void 0 : t.click) == null || s.call(t);
176
216
  }
177
217
  get three() {
178
218
  return { renderer: this.scene.renderer, scene: this.scene.scene, camera: this.scene.camera };
179
219
  }
180
- on(e, s) {
181
- let t = this.listeners.get(e);
182
- return t || (t = /* @__PURE__ */ new Set(), this.listeners.set(e, t)), t.add(s), this;
220
+ on(t, s) {
221
+ let e = this.listeners.get(t);
222
+ return e || (e = /* @__PURE__ */ new Set(), this.listeners.set(t, e)), e.add(s), this;
183
223
  }
184
- off(e, s) {
185
- var t;
186
- return (t = this.listeners.get(e)) == null || t.delete(s), this;
224
+ off(t, s) {
225
+ var e;
226
+ return (e = this.listeners.get(t)) == null || e.delete(s), this;
187
227
  }
188
- emit(e, s) {
189
- var t;
190
- (t = this.listeners.get(e)) == null || t.forEach((a) => a(s));
228
+ emit(t, s) {
229
+ var e;
230
+ (e = this.listeners.get(t)) == null || e.forEach((a) => a(s));
191
231
  }
192
232
  persist() {
193
233
  if (this.opts.persistSettings)
194
234
  try {
195
- localStorage.setItem(N, JSON.stringify(this.view));
235
+ localStorage.setItem(M, JSON.stringify(this.view));
196
236
  } catch {
197
237
  }
198
238
  }
199
239
  loadSettings() {
200
240
  try {
201
- const e = localStorage.getItem(N);
202
- return e ? JSON.parse(e) : null;
241
+ const t = localStorage.getItem(M);
242
+ return t ? JSON.parse(t) : null;
203
243
  } catch {
204
244
  return null;
205
245
  }
206
246
  }
207
247
  dispose() {
208
- var e;
209
- (e = this.ui) == null || e.dispose(), this.look.dispose(), this.source.dispose(), this.scene.dispose(), this.video.remove(), this.canvas.remove(), this.wrap.remove(), this.listeners.clear();
248
+ var t;
249
+ (t = this.ui) == null || t.dispose(), this.look.dispose(), this.source.dispose(), this.scene.dispose(), this.video.remove(), this.canvas.remove(), this.wrap.remove(), this.listeners.clear();
210
250
  }
211
251
  }
212
- class q extends HTMLElement {
252
+ class K extends HTMLElement {
213
253
  static get observedAttributes() {
214
254
  return ["src", "projection"];
215
255
  }
216
256
  connectedCallback() {
217
- this.player || (this.style.display || (this.style.display = "block"), this.player = new W(this, {
257
+ this.player || (this.style.display || (this.style.display = "block"), this.player = new H(this, {
218
258
  src: this.getAttribute("src") ?? void 0,
219
259
  projection: this.getAttribute("projection") ?? void 0,
220
260
  controls: this.hasAttribute("controls"),
@@ -225,15 +265,15 @@ class q extends HTMLElement {
225
265
  proxy: this.getAttribute("proxy-url") ? { url: this.getAttribute("proxy-url"), apiPassword: this.getAttribute("proxy-password") ?? void 0 } : void 0
226
266
  }));
227
267
  }
228
- attributeChangedCallback(e, s, t) {
229
- !this.player || t == null || (e === "src" && this.player.load(t), e === "projection" && this.player.setProjection(t));
268
+ attributeChangedCallback(t, s, e) {
269
+ !this.player || e == null || (t === "src" && this.player.load(e), t === "projection" && this.player.setProjection(e));
230
270
  }
231
271
  disconnectedCallback() {
232
- var e;
233
- (e = this.player) == null || e.dispose(), this.player = void 0;
272
+ var t;
273
+ (t = this.player) == null || t.dispose(), this.player = void 0;
234
274
  }
235
- numAttr(e) {
236
- const s = this.getAttribute(e);
275
+ numAttr(t) {
276
+ const s = this.getAttribute(t);
237
277
  return s == null ? void 0 : Number(s);
238
278
  }
239
279
  /** The underlying Player instance (for programmatic control). */
@@ -241,23 +281,23 @@ class q extends HTMLElement {
241
281
  return this.player;
242
282
  }
243
283
  }
244
- function Y(c = "three-video") {
245
- typeof customElements < "u" && !customElements.get(c) && customElements.define(c, q);
284
+ function G(l = "three-video") {
285
+ typeof customElements < "u" && !customElements.get(l) && customElements.define(l, K);
246
286
  }
247
- Y();
287
+ G();
248
288
  export {
249
- V as LookControls,
250
- G as MODES,
251
- $ as PROJECTIONS,
252
- W as Player,
253
- R as StereoScene,
254
- q as ThreeVideoElement,
255
- I as VideoSource,
256
- U as buildProxyUrl,
257
- Q as clampAngles,
258
- X as detectFormat,
259
- D as detectProjection,
260
- Z as isFlatMode,
261
- Y as registerWebComponent
289
+ W as LookControls,
290
+ tt as MODES,
291
+ V as PROJECTIONS,
292
+ H as Player,
293
+ J as StereoScene,
294
+ K as ThreeVideoElement,
295
+ D as VideoSource,
296
+ Y as buildProxyUrl,
297
+ et as clampAngles,
298
+ st as detectFormat,
299
+ q as detectProjection,
300
+ it as isFlatMode,
301
+ G as registerWebComponent
262
302
  };
263
303
  //# sourceMappingURL=three-vr-player.js.map