three-vr-player 0.4.0 → 0.5.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/README.md +3 -0
- package/dist/Player.d.ts +6 -1
- package/dist/{VideoSource-CJGIX8gL.js → VideoSource-BGaVaGUn.js} +2 -2
- package/dist/VideoSource-BGaVaGUn.js.map +1 -0
- package/dist/core.js +1 -1
- package/dist/three-vr-player.js +80 -67
- package/dist/three-vr-player.js.map +1 -1
- package/dist/three-vr-player.standalone.js +17 -17
- package/dist/three-vr-player.standalone.js.map +1 -1
- package/dist/ui/ControlsUI.d.ts +2 -2
- package/package.json +1 -1
- package/dist/VideoSource-CJGIX8gL.js.map +0 -1
package/README.md
CHANGED
|
@@ -62,6 +62,9 @@ menu in the controls, or set it programmatically:
|
|
|
62
62
|
| `flat-sbs-full` | flat screen | left/right (full-width per eye) |
|
|
63
63
|
| `flat-sbs-half` | flat screen | left/right (half-width per eye) |
|
|
64
64
|
|
|
65
|
+
Pick **Off (native player)** in the menu — or call `setProjection('off')` — to disable
|
|
66
|
+
reprojection and play the raw **2D `<video>`** (the same view as the CORS fallback).
|
|
67
|
+
|
|
65
68
|
## Options
|
|
66
69
|
|
|
67
70
|
```ts
|
package/dist/Player.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export declare class Player {
|
|
|
17
17
|
private view;
|
|
18
18
|
private readyEmitted;
|
|
19
19
|
private native;
|
|
20
|
+
private tainted;
|
|
21
|
+
private displayMode;
|
|
20
22
|
private loading;
|
|
21
23
|
private proxyConfig?;
|
|
22
24
|
private useProxy;
|
|
@@ -30,7 +32,10 @@ export declare class Player {
|
|
|
30
32
|
private setNativeFallback;
|
|
31
33
|
play(): Promise<void>;
|
|
32
34
|
pause(): void;
|
|
33
|
-
|
|
35
|
+
/** Set the display mode: a geometry projection (WebGL 3D) or 'off' for plain 2D `<video>`. */
|
|
36
|
+
setProjection(p: Projection | 'off'): void;
|
|
37
|
+
private applyProjectionGeometry;
|
|
38
|
+
private applyDisplay;
|
|
34
39
|
setSwapEyes(v: boolean): void;
|
|
35
40
|
setFov(deg: number): void;
|
|
36
41
|
setSupersampling(x: number): void;
|
|
@@ -38,7 +38,7 @@ const h = {
|
|
|
38
38
|
{ value: "360-mono", label: "360° Mono" },
|
|
39
39
|
{ value: "360-sbs", label: "360° SBS" },
|
|
40
40
|
{ value: "360-tb", label: "360° Top-Bottom" },
|
|
41
|
-
{ value: "flat-2d", label: "Flat 2D
|
|
41
|
+
{ value: "flat-2d", label: "Flat 2D" },
|
|
42
42
|
{ value: "flat-sbs-full", label: "Flat 3D — Full SBS" },
|
|
43
43
|
{ value: "flat-sbs-half", label: "Flat 3D — Half SBS" }
|
|
44
44
|
];
|
|
@@ -245,4 +245,4 @@ export {
|
|
|
245
245
|
M as d,
|
|
246
246
|
R as i
|
|
247
247
|
};
|
|
248
|
-
//# sourceMappingURL=VideoSource-
|
|
248
|
+
//# sourceMappingURL=VideoSource-BGaVaGUn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoSource-BGaVaGUn.js","sources":["../src/core/proxy.ts","../src/core/projections.ts","../src/core/StereoScene.ts","../src/core/LookControls.ts","../src/core/VideoSource.ts"],"sourcesContent":["export type StreamFormat = 'hls' | 'dash' | 'progressive';\r\n\r\nexport interface ProxyConfig {\r\n url: string;\r\n apiPassword?: string;\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/** Detect streaming format from a URL by extension. */\r\nexport function detectFormat(rawUrl: string): StreamFormat {\r\n let pathname = rawUrl;\r\n try { pathname = new URL(rawUrl).pathname; } catch { /* relative/opaque: use raw */ }\r\n const lower = pathname.toLowerCase();\r\n if (lower.endsWith('.m3u8')) return 'hls';\r\n if (lower.endsWith('.mpd')) return 'dash';\r\n return 'progressive';\r\n}\r\n\r\nconst ENDPOINTS: Record<StreamFormat, string> = {\r\n progressive: '/proxy/stream',\r\n hls: '/proxy/hls/manifest.m3u8',\r\n dash: '/proxy/mpd/manifest.m3u8',\r\n};\r\n\r\n/**\r\n * Build the URL the `<video>`/hls.js should load. When `proxy` is omitted the raw\r\n * URL is returned (it must then be CORS-clean to be used as a WebGL texture).\r\n */\r\nexport function buildProxyUrl(rawUrl: string, proxy?: ProxyConfig): { url: string; format: StreamFormat } {\r\n const format = detectFormat(rawUrl);\r\n if (!proxy || !proxy.url) return { url: rawUrl, format };\r\n const base = proxy.url.replace(/\\/+$/, '');\r\n const params = new URLSearchParams();\r\n params.set('d', rawUrl);\r\n if (proxy.apiPassword) params.set('api_password', proxy.apiPassword);\r\n for (const [name, value] of Object.entries(proxy.headers ?? {})) {\r\n if (value != null && value !== '') params.set(`h_${name}`, value);\r\n }\r\n return { url: `${base}${ENDPOINTS[format]}?${params.toString()}`, format };\r\n}\r\n","import type { Projection } from '../types.js';\r\n\r\nexport type Split = 'mono' | 'sbs' | 'tb';\r\nexport type GeomKind = 'sphere180' | 'sphere360' | 'plane';\r\n\r\nexport interface ModeConfig {\r\n geom: GeomKind;\r\n split: Split;\r\n stereo: boolean;\r\n flat?: boolean;\r\n /** plane only: 'full' = displayW/H, 'per-eye' = (W/2)/H */\r\n aspect?: 'full' | 'per-eye';\r\n}\r\n\r\nexport const MODES: Record<Projection, ModeConfig> = {\r\n '180-sbs': { geom: 'sphere180', split: 'sbs', stereo: true },\r\n '180-mono': { geom: 'sphere180', split: 'mono', stereo: false },\r\n '360-mono': { geom: 'sphere360', split: 'mono', stereo: false },\r\n '360-sbs': { geom: 'sphere360', split: 'sbs', stereo: true },\r\n '360-tb': { geom: 'sphere360', split: 'tb', stereo: true },\r\n 'flat-2d': { geom: 'plane', split: 'mono', stereo: false, flat: true, aspect: 'full' },\r\n 'flat-sbs-full': { geom: 'plane', split: 'sbs', stereo: true, flat: true, aspect: 'per-eye' },\r\n 'flat-sbs-half': { geom: 'plane', split: 'sbs', stereo: true, flat: true, aspect: 'full' },\r\n};\r\n\r\nexport const PROJECTIONS: { value: Projection; label: string }[] = [\r\n { value: '180-sbs', label: '180° SBS (VR180)' },\r\n { value: '180-mono', label: '180° Mono' },\r\n { value: '360-mono', label: '360° Mono' },\r\n { value: '360-sbs', label: '360° SBS' },\r\n { value: '360-tb', label: '360° Top-Bottom' },\r\n { value: 'flat-2d', label: 'Flat 2D' },\r\n { value: 'flat-sbs-full', label: 'Flat 3D — Full SBS' },\r\n { value: 'flat-sbs-half', label: 'Flat 3D — Half SBS' },\r\n];\r\n\r\nexport function isFlatMode(p: Projection): boolean {\r\n return !!MODES[p]?.flat;\r\n}\r\n\r\n/** Guess a projection from a URL / filename; null when nothing recognizable. */\r\nexport function detectProjection(url: string): Projection | null {\r\n const s = String(url).toLowerCase();\r\n const tb = /(^|[^a-z])(tb|ou|top.?bottom|over.?under)([^a-z]|$)/.test(s);\r\n const sbs = /(sbs|side.?by.?side)/.test(s);\r\n if (s.includes('360')) {\r\n if (tb) return '360-tb';\r\n if (sbs) return '360-sbs';\r\n return '360-mono';\r\n }\r\n if (s.includes('180') || s.includes('vr180')) {\r\n return s.includes('mono') ? '180-mono' : '180-sbs';\r\n }\r\n if (sbs) return s.includes('half') ? 'flat-sbs-half' : 'flat-sbs-full';\r\n return null;\r\n}\r\n","import * as THREE from 'three';\r\nimport { VRButton } from 'three/examples/jsm/webxr/VRButton.js';\r\nimport type { Projection } from '../types.js';\r\nimport { MODES } from './projections.js';\r\n\r\n/**\r\n * Maps a video onto the geometry for a chosen projection (inside-out 180/360\r\n * sphere or a flat screen plane) and packs stereo eyes via UV split + WebXR\r\n * layers. Sizes to its canvas's container (not the window), for embedding.\r\n */\r\nexport class StereoScene {\r\n readonly renderer: THREE.WebGLRenderer;\r\n readonly scene = new THREE.Scene();\r\n readonly camera: THREE.PerspectiveCamera;\r\n readonly vrButton: HTMLElement;\r\n readonly maxAnisotropy: number;\r\n\r\n private readonly canvas: HTMLCanvasElement;\r\n private readonly video: HTMLVideoElement;\r\n private readonly texture: THREE.VideoTexture;\r\n private readonly meshes: THREE.Mesh[] = [];\r\n private readonly frameCbs: (() => void)[] = [];\r\n private readonly animate = () => {\r\n for (const cb of this.frameCbs) cb();\r\n this.renderer.render(this.scene, this.camera);\r\n };\r\n private readonly ro: ResizeObserver;\r\n private currentMode: Projection;\r\n private currentSwap: boolean;\r\n\r\n constructor(opts: {\r\n canvas: HTMLCanvasElement; video: HTMLVideoElement;\r\n projection?: Projection; swapEyes?: boolean; fov?: number; supersampling?: number;\r\n }) {\r\n const { canvas, video, projection = '180-sbs', swapEyes = false, fov = 70, supersampling = 1.5 } = opts;\r\n this.canvas = canvas;\r\n this.video = video;\r\n this.currentMode = MODES[projection] ? projection : '180-sbs';\r\n this.currentSwap = swapEyes;\r\n\r\n this.renderer = new THREE.WebGLRenderer({ canvas, antialias: true });\r\n this.renderer.setPixelRatio(this.pixelRatioFor(supersampling));\r\n this.renderer.setSize(this.w(), this.h(), false);\r\n this.renderer.xr.enabled = true;\r\n\r\n this.camera = new THREE.PerspectiveCamera(fov, this.w() / this.h(), 0.1, 1000);\r\n this.camera.position.set(0, 0, 0);\r\n this.camera.layers.enable(1); // desktop shows Layer 1 (left eye) for stereo modes\r\n\r\n this.maxAnisotropy = this.renderer.capabilities.getMaxAnisotropy();\r\n this.texture = new THREE.VideoTexture(video);\r\n this.texture.colorSpace = THREE.SRGBColorSpace;\r\n this.texture.minFilter = THREE.LinearFilter;\r\n this.texture.magFilter = THREE.LinearFilter;\r\n this.texture.anisotropy = this.maxAnisotropy;\r\n\r\n this.applyProjection(this.currentMode, this.currentSwap);\r\n video.addEventListener('loadedmetadata', () => {\r\n if (MODES[this.currentMode].flat) this.applyProjection(this.currentMode, this.currentSwap);\r\n });\r\n\r\n this.renderer.setAnimationLoop(this.animate);\r\n this.vrButton = VRButton.createButton(this.renderer);\r\n\r\n this.ro = new ResizeObserver(() => this.resize());\r\n this.ro.observe(canvas);\r\n }\r\n\r\n private w() { return this.canvas.clientWidth || 1; }\r\n private h() { return this.canvas.clientHeight || 1; }\r\n private pixelRatioFor(ss: number) { return Math.min(window.devicePixelRatio * ss, 4); }\r\n\r\n private planeAspect(mode: Projection) {\r\n const vw = this.video.videoWidth, vh = this.video.videoHeight;\r\n if (!vw || !vh) return 16 / 9;\r\n return MODES[mode].aspect === 'per-eye' ? (vw / 2) / vh : vw / vh;\r\n }\r\n\r\n private buildGeometry(mode: Projection): THREE.BufferGeometry {\r\n const kind = MODES[mode].geom;\r\n if (kind === 'sphere180') { const g = new THREE.SphereGeometry(500, 60, 40, -Math.PI, Math.PI, 0, Math.PI); g.scale(-1, 1, 1); return g; }\r\n if (kind === 'sphere360') { const g = new THREE.SphereGeometry(500, 60, 40); g.scale(-1, 1, 1); return g; }\r\n const h = 2.4, w = h * this.planeAspect(mode);\r\n const g = new THREE.PlaneGeometry(w, h); g.translate(0, 0, -2); return g;\r\n }\r\n\r\n private splitUV(geo: THREE.BufferGeometry, split: string, eye: 'left' | 'right') {\r\n if (split === 'mono') return;\r\n const uv = geo.attributes.uv.array as Float32Array;\r\n for (let i = 0; i < uv.length; i += 2) {\r\n if (split === 'sbs') uv[i] = uv[i] * 0.5 + (eye === 'right' ? 0.5 : 0);\r\n else if (split === 'tb') uv[i + 1] = uv[i + 1] * 0.5 + (eye === 'left' ? 0.5 : 0); // top = left\r\n }\r\n geo.attributes.uv.needsUpdate = true;\r\n }\r\n\r\n private clearMeshes() {\r\n for (const m of this.meshes) { this.scene.remove(m); m.geometry.dispose(); (m.material as THREE.Material).dispose(); }\r\n this.meshes.length = 0;\r\n }\r\n\r\n private applyProjection(mode: Projection, swap: boolean) {\r\n if (!MODES[mode]) mode = '180-sbs';\r\n this.clearMeshes();\r\n const cfg = MODES[mode];\r\n if (!cfg.stereo) {\r\n const m = new THREE.Mesh(this.buildGeometry(mode), new THREE.MeshBasicMaterial({ map: this.texture }));\r\n m.layers.set(0); // mono: desktop + both XR eyes\r\n this.scene.add(m); this.meshes.push(m);\r\n } else {\r\n const gL = this.buildGeometry(mode); this.splitUV(gL, cfg.split, 'left');\r\n const gR = this.buildGeometry(mode); this.splitUV(gR, cfg.split, 'right');\r\n const mL = new THREE.Mesh(gL, new THREE.MeshBasicMaterial({ map: this.texture }));\r\n const mR = new THREE.Mesh(gR, new THREE.MeshBasicMaterial({ map: this.texture }));\r\n mL.layers.set(swap ? 2 : 1); mR.layers.set(swap ? 1 : 2);\r\n this.scene.add(mL, mR); this.meshes.push(mL, mR);\r\n }\r\n this.currentMode = mode; this.currentSwap = swap;\r\n }\r\n\r\n setProjection(p: Projection) { this.applyProjection(p, this.currentSwap); }\r\n setSwapEyes(v: boolean) { this.applyProjection(this.currentMode, v); }\r\n setFov(deg: number) { this.camera.fov = deg; this.camera.updateProjectionMatrix(); }\r\n setSupersampling(ss: number) { this.renderer.setPixelRatio(this.pixelRatioFor(ss)); this.renderer.setSize(this.w(), this.h(), false); }\r\n getProjection() { return this.currentMode; }\r\n isFlat() { return !!MODES[this.currentMode].flat; }\r\n onFrame(cb: () => void) { this.frameCbs.push(cb); }\r\n pauseRendering() { this.renderer.setAnimationLoop(null); }\r\n resumeRendering() { this.renderer.setAnimationLoop(this.animate); }\r\n\r\n resize = () => {\r\n const w = this.w(), h = this.h();\r\n this.camera.aspect = w / h;\r\n this.camera.updateProjectionMatrix();\r\n this.renderer.setSize(w, h, false);\r\n };\r\n\r\n dispose() {\r\n this.ro.disconnect();\r\n this.renderer.setAnimationLoop(null);\r\n this.texture.dispose();\r\n this.clearMeshes();\r\n this.renderer.dispose();\r\n }\r\n}\r\n","import type { Camera } from 'three';\r\n\r\nconst DEG = Math.PI / 180;\r\n\r\n/** Clamp look angles (degrees) to keep the view inside the front hemisphere. */\r\nexport function clampAngles(lon: number, lat: number): { lon: number; lat: number } {\r\n return {\r\n lon: Math.max(-90, Math.min(90, lon)),\r\n lat: Math.max(-85, Math.min(85, lat)),\r\n };\r\n}\r\n\r\n/**\r\n * Pointer/touch drag → camera yaw/pitch, clamped to the front hemisphere.\r\n * Disabled while an XR session drives the head pose, and for flat-screen modes.\r\n */\r\nexport class LookControls {\r\n private lon = 0;\r\n private lat = 0;\r\n private dragging = false;\r\n private px = 0;\r\n private py = 0;\r\n private enabled = true;\r\n private readonly isPresenting: () => boolean;\r\n\r\n constructor(\r\n private readonly camera: Camera,\r\n private readonly dom: HTMLElement,\r\n opts: { isPresenting?: () => boolean } = {},\r\n ) {\r\n this.isPresenting = opts.isPresenting ?? (() => false);\r\n this.dom.addEventListener('pointerdown', this.onDown);\r\n this.dom.addEventListener('pointermove', this.onMove);\r\n this.dom.addEventListener('pointerup', this.onUp);\r\n this.dom.addEventListener('pointercancel', this.onUp);\r\n }\r\n\r\n private capture(fn: 'setPointerCapture' | 'releasePointerCapture', id: number) {\r\n try { this.dom[fn]?.(id); } catch { /* pointer not active */ }\r\n }\r\n\r\n private onDown = (e: PointerEvent) => {\r\n if (!this.enabled) return;\r\n this.dragging = true;\r\n this.px = e.clientX;\r\n this.py = e.clientY;\r\n this.capture('setPointerCapture', e.pointerId);\r\n };\r\n\r\n private onMove = (e: PointerEvent) => {\r\n if (!this.dragging) return;\r\n const dx = e.clientX - this.px;\r\n const dy = e.clientY - this.py;\r\n this.px = e.clientX;\r\n this.py = e.clientY;\r\n ({ lon: this.lon, lat: this.lat } = clampAngles(this.lon - dx * 0.15, this.lat + dy * 0.15));\r\n };\r\n\r\n private onUp = (e: PointerEvent) => {\r\n this.dragging = false;\r\n this.capture('releasePointerCapture', e.pointerId);\r\n };\r\n\r\n update() {\r\n if (this.isPresenting() || !this.enabled) return;\r\n const phi = (90 - this.lat) * DEG;\r\n const theta = this.lon * DEG;\r\n this.camera.lookAt(\r\n Math.sin(phi) * Math.sin(theta),\r\n Math.cos(phi),\r\n -Math.sin(phi) * Math.cos(theta),\r\n );\r\n }\r\n\r\n reset() { this.lon = 0; this.lat = 0; }\r\n\r\n setEnabled(v: boolean) {\r\n this.enabled = v;\r\n if (!v) { this.lon = 0; this.lat = 0; this.camera.lookAt(0, 0, -1); }\r\n }\r\n\r\n getAngles() { return { lon: this.lon, lat: this.lat }; }\r\n\r\n dispose() {\r\n this.dom.removeEventListener('pointerdown', this.onDown);\r\n this.dom.removeEventListener('pointermove', this.onMove);\r\n this.dom.removeEventListener('pointerup', this.onUp);\r\n this.dom.removeEventListener('pointercancel', this.onUp);\r\n }\r\n}\r\n","import type Hls from 'hls.js';\r\nimport type { StreamFormat } from './proxy.js';\r\n\r\n/**\r\n * Attaches a source to a `<video>`. Progressive files go straight on `video.src`;\r\n * HLS/DASH-as-HLS go through hls.js — which is imported dynamically, so consumers\r\n * who never play HLS don't pay for it (and it's an optional dependency).\r\n */\r\nexport class VideoSource {\r\n private hls: Hls | null = null;\r\n\r\n async attach(\r\n video: HTMLVideoElement,\r\n source: { url: string; format: StreamFormat },\r\n opts: { crossOrigin?: string | null } = {},\r\n ): Promise<void> {\r\n this.dispose();\r\n const co = opts.crossOrigin === undefined ? 'anonymous' : opts.crossOrigin;\r\n if (co === null) video.removeAttribute('crossorigin');\r\n else video.crossOrigin = co;\r\n video.playsInline = true;\r\n\r\n const { url, format } = source;\r\n const isHlsLike = format === 'hls' || format === 'dash';\r\n const nativeHls = video.canPlayType('application/vnd.apple.mpegurl') !== '';\r\n\r\n return new Promise<void>((resolve, reject) => {\r\n const cleanup = () => {\r\n video.removeEventListener('loadedmetadata', onLoaded);\r\n video.removeEventListener('error', onError);\r\n };\r\n const onLoaded = () => { cleanup(); resolve(); };\r\n const onError = () => {\r\n cleanup();\r\n const code = video.error ? video.error.code : 'unknown';\r\n reject(new Error(`Video failed to load (media error ${code}). Is the source reachable and CORS-clean?`));\r\n };\r\n video.addEventListener('loadedmetadata', onLoaded);\r\n video.addEventListener('error', onError);\r\n\r\n if (isHlsLike && !nativeHls) {\r\n import('hls.js').then(({ default: HlsCtor }) => {\r\n if (!HlsCtor.isSupported()) {\r\n cleanup();\r\n reject(new Error('HLS/DASH stream needs hls.js, which is unsupported in this browser.'));\r\n return;\r\n }\r\n this.hls = new HlsCtor({ enableWorker: true });\r\n this.hls.on(HlsCtor.Events.ERROR, (_e, data) => {\r\n if (data.fatal) { cleanup(); this.dispose(); reject(new Error(`HLS fatal error: ${data.type} / ${data.details}`)); }\r\n });\r\n this.hls.loadSource(url);\r\n this.hls.attachMedia(video);\r\n }).catch(() => {\r\n cleanup();\r\n reject(new Error('This looks like an HLS/DASH stream but hls.js could not be loaded. Install \"hls.js\".'));\r\n });\r\n } else {\r\n video.src = url;\r\n video.load();\r\n }\r\n });\r\n }\r\n\r\n dispose() {\r\n if (this.hls) { this.hls.destroy(); this.hls = null; }\r\n }\r\n}\r\n"],"names":["detectFormat","rawUrl","pathname","lower","ENDPOINTS","buildProxyUrl","proxy","format","base","params","name","value","MODES","PROJECTIONS","isFlatMode","p","_a","detectProjection","url","s","tb","sbs","StereoScene","opts","THREE","cb","w","h","canvas","video","projection","swapEyes","fov","supersampling","VRButton","ss","mode","vw","vh","kind","g","geo","split","eye","uv","m","swap","cfg","gL","gR","mL","mR","v","deg","DEG","clampAngles","lon","lat","LookControls","camera","dom","e","dx","dy","fn","id","_b","phi","theta","VideoSource","source","co","isHlsLike","nativeHls","resolve","reject","cleanup","onLoaded","onError","code","HlsCtor","_e","data"],"mappings":"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"}
|
package/dist/core.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as o, M as s, P as t, S as r, V as c, b as d, c as l, d as S, a as i, i as n } from "./VideoSource-
|
|
1
|
+
import { L as o, M as s, P as t, S as r, V as c, b as d, c as l, d as S, a as i, i as n } from "./VideoSource-BGaVaGUn.js";
|
|
2
2
|
export {
|
|
3
3
|
o as LookControls,
|
|
4
4
|
s as MODES,
|
package/dist/three-vr-player.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { P as Y, V as _, S as H, L as K, a as
|
|
2
|
-
import { M as
|
|
3
|
-
function
|
|
1
|
+
import { P as Y, V as _, S as H, L as K, a as Q, b as X } from "./VideoSource-BGaVaGUn.js";
|
|
2
|
+
import { M as rt, c as at, d as pt, i as lt } from "./VideoSource-BGaVaGUn.js";
|
|
3
|
+
function $(l) {
|
|
4
4
|
if (!Number.isFinite(l) || l < 0) return "0:00";
|
|
5
5
|
const t = Math.floor(l % 60), e = Math.floor(l / 60 % 60), s = Math.floor(l / 3600), p = String(t).padStart(2, "0");
|
|
6
6
|
return s > 0 ? `${s}:${String(e).padStart(2, "0")}:${p}` : `${e}:${p}`;
|
|
@@ -11,29 +11,31 @@ function o(l, t = {}, e = []) {
|
|
|
11
11
|
for (const u of e) s.append(u);
|
|
12
12
|
return s;
|
|
13
13
|
}
|
|
14
|
-
class
|
|
14
|
+
class Z {
|
|
15
15
|
constructor(t, e) {
|
|
16
16
|
this.nodes = [], this.disposers = [];
|
|
17
|
-
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" }), u = o("span", { class: "tvp-time", textContent: "0:00 / 0:00" }), r = o("button", { class: "tvp-btn tvp-mute", title: "Volume", textContent: "🔊" }), v = o("input", { class: "tvp-volume", type: "range", min: "0", max: "1", step: "0.01", value: "1" }), f = o("div", { class: "tvp-volpopup", hidden: !0 }, [v]),
|
|
17
|
+
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" }), u = o("span", { class: "tvp-time", textContent: "0:00 / 0:00" }), r = o("button", { class: "tvp-btn tvp-mute", title: "Volume", textContent: "🔊" }), v = o("input", { class: "tvp-volume", type: "range", min: "0", max: "1", step: "0.01", value: "1" }), f = o("div", { class: "tvp-volpopup", hidden: !0 }, [v]), G = o("span", { class: "tvp-volwrap" }, [r, f]), z = o("span", { class: "tvp-vrslot" }), b = o("button", { class: "tvp-btn tvp-projbtn", title: "Projection", textContent: "🌐" }), d = o("div", { class: "tvp-projmenu", hidden: !0 });
|
|
18
18
|
for (const i of Y) {
|
|
19
19
|
const n = o("button", { textContent: i.label });
|
|
20
|
-
n.dataset.mode = i.value,
|
|
20
|
+
n.dataset.mode = i.value, d.append(n);
|
|
21
21
|
}
|
|
22
|
-
const
|
|
22
|
+
const M = o("button", { textContent: "Off (native player)" });
|
|
23
|
+
M.dataset.mode = "off", d.append(o("hr", { class: "tvp-sep" }), M);
|
|
24
|
+
const J = o("span", { class: "tvp-projwrap" }, [b, d]), k = o("button", { class: "tvp-btn tvp-settingsbtn", title: "Settings", textContent: "⚙" }), O = o("button", { class: "tvp-btn tvp-fullscreen", title: "Fullscreen", textContent: "⛶" }), S = o("footer", { class: "tvp-controls" }, [p, c, u, G, z, J, k, O]), P = o("input", { type: "checkbox", checked: e.initial.swapEyes }), x = o("input", { type: "range", min: "30", max: "100", step: "1", value: String(e.initial.fov) }), j = o("span", { textContent: String(e.initial.fov) }), E = o("input", { type: "range", min: "1", max: "2", step: "0.25", value: String(e.initial.supersampling) }), A = o("span", { textContent: String(e.initial.supersampling) }), C = o("input", { type: "checkbox", checked: e.proxy.enabled }), F = o("input", { type: "text", value: e.proxy.url, placeholder: "http://localhost:8888", spellcheck: !1 }), N = o("input", { type: "password", value: e.proxy.apiPassword, placeholder: "API password" }), g = o("section", { class: "tvp-settings" }, [
|
|
23
25
|
o("label", { class: "row" }, [P, "Swap eyes (if depth looks wrong)"]),
|
|
24
|
-
o("label", {}, [
|
|
25
|
-
o("label", {}, [
|
|
26
|
+
o("label", {}, [D("Field of view (zoom): ", j, "°"), x]),
|
|
27
|
+
o("label", {}, [D("Supersampling: ", A, "× (sharpness)"), E]),
|
|
26
28
|
o("hr", { class: "tvp-sep" }),
|
|
27
29
|
o("label", { class: "row" }, [C, "Use CORS proxy"]),
|
|
28
30
|
o("label", {}, ["Proxy URL", F]),
|
|
29
|
-
o("label", {}, ["API password",
|
|
31
|
+
o("label", {}, ["API password", N])
|
|
30
32
|
]), W = o("div", { class: "tvp-toast" });
|
|
31
33
|
this.nodes.push(S, g, W);
|
|
32
34
|
for (const i of this.nodes) t.append(i);
|
|
33
|
-
const a = (i, n,
|
|
34
|
-
i.addEventListener(n,
|
|
35
|
+
const a = (i, n, h, m) => {
|
|
36
|
+
i.addEventListener(n, h, m), this.disposers.push(() => i.removeEventListener(n, h, m));
|
|
35
37
|
}, I = (i) => c.style.setProperty("--seek", `${i}%`), y = () => {
|
|
36
|
-
f.hidden = !0,
|
|
38
|
+
f.hidden = !0, d.hidden = !0, g.classList.remove("open");
|
|
37
39
|
};
|
|
38
40
|
a(p, "click", () => {
|
|
39
41
|
s.paused ? s.play() : s.pause();
|
|
@@ -44,7 +46,7 @@ class X {
|
|
|
44
46
|
}), a(s, "timeupdate", () => {
|
|
45
47
|
if (s.duration) {
|
|
46
48
|
const i = s.currentTime / s.duration * 100;
|
|
47
|
-
c.value = String(i * 10), I(i), u.textContent = `${
|
|
49
|
+
c.value = String(i * 10), I(i), u.textContent = `${$(s.currentTime)} / ${$(s.duration)}`;
|
|
48
50
|
}
|
|
49
51
|
}), a(c, "input", () => {
|
|
50
52
|
I(Number(c.value) / 10), s.duration && (s.currentTime = Number(c.value) / 1e3 * s.duration);
|
|
@@ -55,55 +57,55 @@ class X {
|
|
|
55
57
|
}), a(v, "input", () => {
|
|
56
58
|
s.volume = Number(v.value), s.muted = s.volume === 0, r.textContent = s.muted ? "🔇" : "🔊";
|
|
57
59
|
});
|
|
58
|
-
const
|
|
60
|
+
const B = () => {
|
|
59
61
|
const i = e.getProjection();
|
|
60
62
|
let n = "Projection";
|
|
61
|
-
|
|
62
|
-
const m =
|
|
63
|
-
|
|
63
|
+
d.querySelectorAll("button").forEach((h) => {
|
|
64
|
+
const m = h.dataset.mode === i;
|
|
65
|
+
h.classList.toggle("active", m), m && (n = `Projection: ${h.textContent}`);
|
|
64
66
|
}), b.title = n;
|
|
65
67
|
};
|
|
66
68
|
a(b, "click", (i) => {
|
|
67
69
|
i.stopPropagation();
|
|
68
|
-
const n =
|
|
69
|
-
y(),
|
|
70
|
-
}), a(
|
|
70
|
+
const n = d.hidden;
|
|
71
|
+
y(), d.hidden = !n;
|
|
72
|
+
}), a(d, "click", (i) => {
|
|
71
73
|
const n = i.target.closest("button[data-mode]");
|
|
72
|
-
n && (e.setProjection(n.dataset.mode),
|
|
73
|
-
}),
|
|
74
|
+
n && (e.setProjection(n.dataset.mode), B(), d.hidden = !0);
|
|
75
|
+
}), B(), a(k, "click", (i) => {
|
|
74
76
|
i.stopPropagation();
|
|
75
77
|
const n = !g.classList.contains("open");
|
|
76
78
|
y(), g.classList.toggle("open", n);
|
|
77
79
|
}), a(P, "change", () => e.setSwapEyes(P.checked)), a(x, "input", () => {
|
|
78
80
|
const i = Number(x.value);
|
|
79
|
-
|
|
80
|
-
}), a(
|
|
81
|
-
const i = Number(
|
|
81
|
+
j.textContent = String(i), e.setFov(i);
|
|
82
|
+
}), a(E, "input", () => {
|
|
83
|
+
const i = Number(E.value);
|
|
82
84
|
A.textContent = String(i), e.setSupersampling(i);
|
|
83
85
|
});
|
|
84
|
-
const
|
|
85
|
-
a(C, "change",
|
|
86
|
+
const T = () => e.setProxy({ url: F.value.trim(), apiPassword: N.value, enabled: C.checked });
|
|
87
|
+
a(C, "change", T), a(F, "change", T), a(N, "change", T), a(e.surface, "wheel", (i) => {
|
|
86
88
|
i.preventDefault();
|
|
87
89
|
const n = Math.max(30, Math.min(100, Number(x.value) + Math.sign(i.deltaY) * 3));
|
|
88
|
-
x.value = String(n),
|
|
90
|
+
x.value = String(n), j.textContent = String(n), e.setFov(n);
|
|
89
91
|
}, { passive: !1 }), a(O, "click", () => {
|
|
90
|
-
var n,
|
|
92
|
+
var n, h;
|
|
91
93
|
const i = e.fullscreenTarget;
|
|
92
|
-
document.fullscreenElement ? (
|
|
94
|
+
document.fullscreenElement ? (h = document.exitFullscreen) == null || h.call(document) : (n = i.requestFullscreen) == null || n.call(i);
|
|
93
95
|
}), a(document, "click", (i) => {
|
|
94
|
-
const n = i.composedPath(),
|
|
95
|
-
[f, r,
|
|
96
|
+
const n = i.composedPath(), h = (m) => n.includes(m);
|
|
97
|
+
[f, r, d, b, g, k].some(h) || y();
|
|
96
98
|
});
|
|
97
99
|
let w = 0;
|
|
98
|
-
const q = () => !f.hidden || !
|
|
100
|
+
const q = () => !f.hidden || !d.hidden || g.classList.contains("open"), R = () => {
|
|
99
101
|
q() || S.classList.add("tvp-hidden");
|
|
100
|
-
},
|
|
101
|
-
S.classList.remove("tvp-hidden"), clearTimeout(w), w = window.setTimeout(
|
|
102
|
+
}, L = () => {
|
|
103
|
+
S.classList.remove("tvp-hidden"), clearTimeout(w), w = window.setTimeout(R, 5e3);
|
|
102
104
|
};
|
|
103
|
-
a(e.fullscreenTarget, "pointermove",
|
|
104
|
-
clearTimeout(w),
|
|
105
|
-
}), this.disposers.push(() => clearTimeout(w)),
|
|
106
|
-
i && (Object.assign(e.vrButton.style, { position: "static", left: "auto", bottom: "auto", transform: "none", margin: "0" }),
|
|
105
|
+
a(e.fullscreenTarget, "pointermove", L), a(e.fullscreenTarget, "pointerdown", L), a(e.fullscreenTarget, "pointerleave", () => {
|
|
106
|
+
clearTimeout(w), R();
|
|
107
|
+
}), this.disposers.push(() => clearTimeout(w)), L(), e.vrSupported().then((i) => {
|
|
108
|
+
i && (Object.assign(e.vrButton.style, { position: "static", left: "auto", bottom: "auto", transform: "none", margin: "0" }), z.append(e.vrButton));
|
|
107
109
|
});
|
|
108
110
|
}
|
|
109
111
|
dispose() {
|
|
@@ -111,22 +113,22 @@ class X {
|
|
|
111
113
|
for (const t of this.nodes) t.remove();
|
|
112
114
|
}
|
|
113
115
|
}
|
|
114
|
-
function
|
|
116
|
+
function D(l, t, e) {
|
|
115
117
|
const s = document.createDocumentFragment();
|
|
116
118
|
return s.append(l, t, e), s;
|
|
117
119
|
}
|
|
118
120
|
const U = ":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-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}", V = "three-vr-player:settings";
|
|
119
|
-
class
|
|
121
|
+
class tt {
|
|
120
122
|
constructor(t, e = {}) {
|
|
121
123
|
var c, u;
|
|
122
|
-
this.source = new _(), this.listeners = /* @__PURE__ */ new Map(), this.readyEmitted = !1, this.native = !1, this.loading = !1, this.useProxy = !1, this.opts = e, this.proxyConfig = e.proxy, this.useProxy = !!e.proxy;
|
|
124
|
+
this.source = new _(), this.listeners = /* @__PURE__ */ new Map(), this.readyEmitted = !1, this.native = !1, this.tainted = !1, this.loading = !1, this.useProxy = !1, this.opts = e, this.proxyConfig = e.proxy, this.useProxy = !!e.proxy;
|
|
123
125
|
const s = e.persistSettings ? this.loadSettings() : null;
|
|
124
126
|
this.view = {
|
|
125
127
|
projection: e.projection ?? (s == null ? void 0 : s.projection) ?? "180-sbs",
|
|
126
128
|
swapEyes: e.swapEyes ?? (s == null ? void 0 : s.swapEyes) ?? !1,
|
|
127
129
|
fov: e.fov ?? (s == null ? void 0 : s.fov) ?? 70,
|
|
128
130
|
supersampling: e.supersampling ?? (s == null ? void 0 : s.supersampling) ?? 1.5
|
|
129
|
-
}, 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);
|
|
131
|
+
}, this.displayMode = this.view.projection, 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);
|
|
130
132
|
let p;
|
|
131
133
|
if (e.shadowDom !== !1) {
|
|
132
134
|
const r = this.wrap.attachShadow({ mode: "open" }), v = document.createElement("style");
|
|
@@ -145,13 +147,13 @@ class Z {
|
|
|
145
147
|
swapEyes: this.view.swapEyes,
|
|
146
148
|
fov: this.view.fov,
|
|
147
149
|
supersampling: this.view.supersampling
|
|
148
|
-
}), this.look = new K(this.scene.camera, this.canvas, { isPresenting: () => this.scene.renderer.xr.isPresenting }), this.scene.onFrame(() => this.look.update()), this.look.setEnabled(!this.scene.isFlat()), e.controls !== !1 && (this.ui = new
|
|
150
|
+
}), this.look = new K(this.scene.camera, this.canvas, { isPresenting: () => this.scene.renderer.xr.isPresenting }), this.scene.onFrame(() => this.look.update()), this.look.setEnabled(!this.scene.isFlat()), e.controls !== !1 && (this.ui = new Z(p, {
|
|
149
151
|
video: this.video,
|
|
150
152
|
surface: this.canvas,
|
|
151
153
|
fullscreenTarget: this.wrap,
|
|
152
154
|
vrButton: this.scene.vrButton,
|
|
153
155
|
vrSupported: () => this.vrSupported(),
|
|
154
|
-
getProjection: () => this.
|
|
156
|
+
getProjection: () => this.displayMode,
|
|
155
157
|
setProjection: (r) => this.setProjection(r),
|
|
156
158
|
setSwapEyes: (r) => this.setSwapEyes(r),
|
|
157
159
|
setFov: (r) => this.setFov(r),
|
|
@@ -170,21 +172,21 @@ class Z {
|
|
|
170
172
|
}
|
|
171
173
|
async load(t, e = {}) {
|
|
172
174
|
this.currentSrc = t;
|
|
173
|
-
const s = e.projection ?? (this.opts.autoDetect !== !1 ?
|
|
174
|
-
s && this.
|
|
175
|
-
const { url: p, format: c } =
|
|
175
|
+
const s = e.projection ?? (this.opts.autoDetect !== !1 ? Q(t) : null);
|
|
176
|
+
s && this.applyProjectionGeometry(s), this.displayMode !== "off" && (this.displayMode = this.view.projection);
|
|
177
|
+
const { url: p, format: c } = X(t, this.useProxy ? this.proxyConfig : void 0), u = this.opts.crossOrigin === void 0 ? "anonymous" : this.opts.crossOrigin;
|
|
176
178
|
this.loading = !0;
|
|
177
179
|
try {
|
|
178
|
-
await this.source.attach(this.video, { url: p, format: c }, { crossOrigin: u }), this.
|
|
180
|
+
await this.source.attach(this.video, { url: p, format: c }, { crossOrigin: u }), this.tainted = !1, this.applyDisplay(), await this.video.play().catch(() => {
|
|
179
181
|
});
|
|
180
182
|
} catch (r) {
|
|
181
183
|
if (this.opts.nativeFallback !== !1 && c === "progressive" && u !== null)
|
|
182
184
|
try {
|
|
183
|
-
this.setNativeFallback(!0), await this.source.attach(this.video, { url: p, format: c }, { crossOrigin: null }), await this.video.play().catch(() => {
|
|
185
|
+
this.tainted = !0, this.setNativeFallback(!0), await this.source.attach(this.video, { url: p, format: c }, { crossOrigin: null }), await this.video.play().catch(() => {
|
|
184
186
|
}), this.emit("fallback");
|
|
185
187
|
return;
|
|
186
188
|
} catch (v) {
|
|
187
|
-
throw this.setNativeFallback(!1), this.emit("error", v), v;
|
|
189
|
+
throw this.tainted = !1, this.setNativeFallback(!1), this.emit("error", v), v;
|
|
188
190
|
}
|
|
189
191
|
throw this.setNativeFallback(!1), this.emit("error", r), r;
|
|
190
192
|
} finally {
|
|
@@ -210,8 +212,19 @@ class Z {
|
|
|
210
212
|
pause() {
|
|
211
213
|
this.video.pause();
|
|
212
214
|
}
|
|
215
|
+
/** Set the display mode: a geometry projection (WebGL 3D) or 'off' for plain 2D `<video>`. */
|
|
213
216
|
setProjection(t) {
|
|
214
|
-
|
|
217
|
+
if (t === "off") {
|
|
218
|
+
this.displayMode = "off", this.setNativeFallback(!0), this.emit("projectionchange", t);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
this.displayMode = t, this.applyProjectionGeometry(t), this.tainted && this.currentSrc ? this.load(this.currentSrc) : this.setNativeFallback(!1), this.emit("projectionchange", t);
|
|
222
|
+
}
|
|
223
|
+
applyProjectionGeometry(t) {
|
|
224
|
+
this.scene.setProjection(t), this.look.setEnabled(!this.scene.isFlat()), this.look.reset(), this.view.projection = t, this.persist();
|
|
225
|
+
}
|
|
226
|
+
applyDisplay() {
|
|
227
|
+
this.setNativeFallback(this.displayMode === "off");
|
|
215
228
|
}
|
|
216
229
|
setSwapEyes(t) {
|
|
217
230
|
this.scene.setSwapEyes(t), this.view.swapEyes = t, this.persist();
|
|
@@ -266,12 +279,12 @@ class Z {
|
|
|
266
279
|
(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();
|
|
267
280
|
}
|
|
268
281
|
}
|
|
269
|
-
class
|
|
282
|
+
class et extends HTMLElement {
|
|
270
283
|
static get observedAttributes() {
|
|
271
284
|
return ["src", "projection"];
|
|
272
285
|
}
|
|
273
286
|
connectedCallback() {
|
|
274
|
-
this.player || (this.style.display || (this.style.display = "block"), this.player = new
|
|
287
|
+
this.player || (this.style.display || (this.style.display = "block"), this.player = new tt(this, {
|
|
275
288
|
src: this.getAttribute("src") ?? void 0,
|
|
276
289
|
projection: this.getAttribute("projection") ?? void 0,
|
|
277
290
|
controls: this.hasAttribute("controls"),
|
|
@@ -298,23 +311,23 @@ class tt extends HTMLElement {
|
|
|
298
311
|
return this.player;
|
|
299
312
|
}
|
|
300
313
|
}
|
|
301
|
-
function
|
|
302
|
-
typeof customElements < "u" && !customElements.get(l) && customElements.define(l,
|
|
314
|
+
function st(l = "three-video") {
|
|
315
|
+
typeof customElements < "u" && !customElements.get(l) && customElements.define(l, et);
|
|
303
316
|
}
|
|
304
|
-
|
|
317
|
+
st();
|
|
305
318
|
export {
|
|
306
319
|
K as LookControls,
|
|
307
|
-
|
|
320
|
+
rt as MODES,
|
|
308
321
|
Y as PROJECTIONS,
|
|
309
|
-
|
|
322
|
+
tt as Player,
|
|
310
323
|
H as StereoScene,
|
|
311
|
-
|
|
324
|
+
et as ThreeVideoElement,
|
|
312
325
|
_ as VideoSource,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
326
|
+
X as buildProxyUrl,
|
|
327
|
+
at as clampAngles,
|
|
328
|
+
pt as detectFormat,
|
|
329
|
+
Q as detectProjection,
|
|
330
|
+
lt as isFlatMode,
|
|
331
|
+
st as registerWebComponent
|
|
319
332
|
};
|
|
320
333
|
//# sourceMappingURL=three-vr-player.js.map
|