@vizor-vr/player 0.2.0 → 0.2.1
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 +4 -0
- package/dist/__tests__/autoplay.test.d.ts +2 -0
- package/dist/__tests__/autoplay.test.d.ts.map +1 -0
- package/dist/__tests__/chapter-logic.test.d.ts +2 -0
- package/dist/__tests__/chapter-logic.test.d.ts.map +1 -0
- package/dist/__tests__/chapter-manager.test.d.ts +2 -0
- package/dist/__tests__/chapter-manager.test.d.ts.map +1 -0
- package/dist/__tests__/chapter-menu.test.d.ts +2 -0
- package/dist/__tests__/chapter-menu.test.d.ts.map +1 -0
- package/dist/__tests__/dom-drm.test.d.ts +2 -0
- package/dist/__tests__/dom-drm.test.d.ts.map +1 -0
- package/dist/__tests__/drm-gate.test.d.ts +2 -0
- package/dist/__tests__/drm-gate.test.d.ts.map +1 -0
- package/dist/__tests__/fairplay.test.d.ts +2 -0
- package/dist/__tests__/fairplay.test.d.ts.map +1 -0
- package/dist/__tests__/hub-controller.test.d.ts +2 -0
- package/dist/__tests__/hub-controller.test.d.ts.map +1 -0
- package/dist/__tests__/hub-layout.test.d.ts +2 -0
- package/dist/__tests__/hub-layout.test.d.ts.map +1 -0
- package/dist/__tests__/hub-model.test.d.ts +2 -0
- package/dist/__tests__/hub-model.test.d.ts.map +1 -0
- package/dist/__tests__/hub-panel-renderer.test.d.ts +2 -0
- package/dist/__tests__/hub-panel-renderer.test.d.ts.map +1 -0
- package/dist/__tests__/lens-angle.test.d.ts +2 -0
- package/dist/__tests__/lens-angle.test.d.ts.map +1 -0
- package/dist/__tests__/media-element-drm-gate.test.d.ts +2 -0
- package/dist/__tests__/media-element-drm-gate.test.d.ts.map +1 -0
- package/dist/__tests__/media-element-gating.test.d.ts +2 -0
- package/dist/__tests__/media-element-gating.test.d.ts.map +1 -0
- package/dist/__tests__/player-version-lock.test.d.ts +2 -0
- package/dist/__tests__/player-version-lock.test.d.ts.map +1 -0
- package/dist/__tests__/source-manager-drm.test.d.ts +2 -0
- package/dist/__tests__/source-manager-drm.test.d.ts.map +1 -0
- package/dist/__tests__/vz-chapter.test.d.ts +2 -0
- package/dist/__tests__/vz-chapter.test.d.ts.map +1 -0
- package/dist/__tests__/vz-cinema-gating.test.d.ts +2 -0
- package/dist/__tests__/vz-cinema-gating.test.d.ts.map +1 -0
- package/dist/__tests__/vz-hub-item.test.d.ts +2 -0
- package/dist/__tests__/vz-hub-item.test.d.ts.map +1 -0
- package/dist/__tests__/vz-tour-gating.test.d.ts +2 -0
- package/dist/__tests__/vz-tour-gating.test.d.ts.map +1 -0
- package/dist/__tests__/watch-time.test.d.ts +2 -0
- package/dist/__tests__/watch-time.test.d.ts.map +1 -0
- package/dist/analytics/index.d.ts.map +1 -1
- package/dist/annotations/annotation-popup.d.ts.map +1 -1
- package/dist/{annotations-C0ugfCn4.js → annotations-Du6ZWrqC.js} +82 -13
- package/dist/annotations-Du6ZWrqC.js.map +1 -0
- package/dist/captions/caption-renderer.d.ts.map +1 -1
- package/dist/{captions-BP0H2E03.js → captions-YvnHAwLY.js} +4 -4
- package/dist/captions-YvnHAwLY.js.map +1 -0
- package/dist/chapters/chapter-logic.d.ts +47 -0
- package/dist/chapters/chapter-logic.d.ts.map +1 -0
- package/dist/chapters/chapter-manager.d.ts +42 -0
- package/dist/chapters/chapter-manager.d.ts.map +1 -0
- package/dist/chapters/chapter-menu.d.ts +24 -0
- package/dist/chapters/chapter-menu.d.ts.map +1 -0
- package/dist/{collab-BXPomrS0.js → collab-BLpllHtb.js} +20 -14
- package/dist/collab-BLpllHtb.js.map +1 -0
- package/dist/collaborative/chat-button.d.ts.map +1 -1
- package/dist/collaborative/voice-button.d.ts.map +1 -1
- package/dist/controls/cc-button.d.ts.map +1 -1
- package/dist/controls/compass.d.ts.map +1 -1
- package/dist/controls/controls-overlay.d.ts.map +1 -1
- package/dist/controls/fullscreen-button.d.ts.map +1 -1
- package/dist/controls/icons.d.ts +1 -0
- package/dist/controls/icons.d.ts.map +1 -1
- package/dist/controls/live-indicator.d.ts.map +1 -1
- package/dist/controls/play-button.d.ts.map +1 -1
- package/dist/controls/playlist-controls.d.ts.map +1 -1
- package/dist/controls/quality-menu.d.ts.map +1 -1
- package/dist/controls/seek-bar.d.ts +9 -0
- package/dist/controls/seek-bar.d.ts.map +1 -1
- package/dist/controls/volume-control.d.ts.map +1 -1
- package/dist/controls/vr-button.d.ts.map +1 -1
- package/dist/core/base-element.d.ts +8 -0
- package/dist/core/base-element.d.ts.map +1 -1
- package/dist/core/media-element.d.ts +70 -1
- package/dist/core/media-element.d.ts.map +1 -1
- package/dist/{dash-adapter-tid9ZyhO.js → dash-adapter-BMpHWcBA.js} +9 -2
- package/dist/dash-adapter-BMpHWcBA.js.map +1 -0
- package/dist/delivery/__tests__/delivery-client.test.d.ts +2 -0
- package/dist/delivery/__tests__/delivery-client.test.d.ts.map +1 -0
- package/dist/delivery/__tests__/delivery-hydrate.test.d.ts +2 -0
- package/dist/delivery/__tests__/delivery-hydrate.test.d.ts.map +1 -0
- package/dist/delivery/delivery-client.d.ts +27 -0
- package/dist/delivery/delivery-client.d.ts.map +1 -0
- package/dist/delivery/delivery-hydrate.d.ts +18 -0
- package/dist/delivery/delivery-hydrate.d.ts.map +1 -0
- package/dist/delivery/dom-drm.d.ts +9 -0
- package/dist/delivery/dom-drm.d.ts.map +1 -0
- package/dist/elements/vz-chapter.d.ts +27 -0
- package/dist/elements/vz-chapter.d.ts.map +1 -0
- package/dist/elements/vz-cinema.d.ts +20 -0
- package/dist/elements/vz-cinema.d.ts.map +1 -1
- package/dist/elements/vz-hub-item.d.ts +23 -0
- package/dist/elements/vz-hub-item.d.ts.map +1 -0
- package/dist/elements/vz-hub.d.ts +57 -0
- package/dist/elements/vz-hub.d.ts.map +1 -0
- package/dist/elements/vz-playlist.d.ts +14 -0
- package/dist/elements/vz-playlist.d.ts.map +1 -1
- package/dist/elements/vz-tour.d.ts +16 -0
- package/dist/elements/vz-tour.d.ts.map +1 -1
- package/dist/hls-adapter-C_a65zia.js +161 -0
- package/dist/hls-adapter-C_a65zia.js.map +1 -0
- package/dist/hub/hub-controller.d.ts +31 -0
- package/dist/hub/hub-controller.d.ts.map +1 -0
- package/dist/hub/hub-layout.d.ts +23 -0
- package/dist/hub/hub-layout.d.ts.map +1 -0
- package/dist/hub/hub-model.d.ts +27 -0
- package/dist/hub/hub-model.d.ts.map +1 -0
- package/dist/hub/hub-panel-manager.d.ts +16 -0
- package/dist/hub/hub-panel-manager.d.ts.map +1 -0
- package/dist/hub/hub-panel-renderer.d.ts +26 -0
- package/dist/hub/hub-panel-renderer.d.ts.map +1 -0
- package/dist/license/__tests__/cache.test.d.ts +2 -0
- package/dist/license/__tests__/cache.test.d.ts.map +1 -0
- package/dist/license/__tests__/feature-gate.test.d.ts +2 -0
- package/dist/license/__tests__/feature-gate.test.d.ts.map +1 -0
- package/dist/license/__tests__/format-gate.test.d.ts +2 -0
- package/dist/license/__tests__/format-gate.test.d.ts.map +1 -0
- package/dist/license/__tests__/license-checker.test.d.ts.map +1 -0
- package/dist/license/__tests__/master-key.test.d.ts.map +1 -0
- package/dist/license/__tests__/verify-no-ed25519.test.d.ts +2 -0
- package/dist/license/__tests__/verify-no-ed25519.test.d.ts.map +1 -0
- package/dist/license/__tests__/verify.test.d.ts +2 -0
- package/dist/license/__tests__/verify.test.d.ts.map +1 -0
- package/dist/license/cache.d.ts +4 -0
- package/dist/license/cache.d.ts.map +1 -0
- package/dist/license/drm-gate.d.ts +15 -0
- package/dist/license/drm-gate.d.ts.map +1 -0
- package/dist/license/feature-gate.d.ts +27 -0
- package/dist/license/feature-gate.d.ts.map +1 -0
- package/dist/license/format-gate.d.ts +23 -0
- package/dist/license/format-gate.d.ts.map +1 -0
- package/dist/license/license-checker.d.ts.map +1 -1
- package/dist/license/master-key.d.ts +11 -7
- package/dist/license/master-key.d.ts.map +1 -1
- package/dist/license/trusted-key.d.ts +7 -0
- package/dist/license/trusted-key.d.ts.map +1 -0
- package/dist/license/verify.d.ts +7 -0
- package/dist/license/verify.d.ts.map +1 -0
- package/dist/{register-CwnmiGEs.js → register-BmZt_300.js} +1482 -163
- package/dist/register-BmZt_300.js.map +1 -0
- package/dist/register.d.ts.map +1 -1
- package/dist/register.js +1 -1
- package/dist/renderer/camera-controller.d.ts +1 -1
- package/dist/renderer/camera-controller.d.ts.map +1 -1
- package/dist/renderer/projections/fisheye-projection.d.ts +4 -0
- package/dist/renderer/projections/fisheye-projection.d.ts.map +1 -1
- package/dist/renderer/projections/spherical-projection.d.ts +26 -0
- package/dist/renderer/projections/spherical-projection.d.ts.map +1 -0
- package/dist/renderer/renderer.d.ts.map +1 -1
- package/dist/renderer/shaders/fisheye.glsl.d.ts +10 -1
- package/dist/renderer/shaders/fisheye.glsl.d.ts.map +1 -1
- package/dist/sri.json +8 -8
- package/dist/streaming/dash-adapter.d.ts +2 -2
- package/dist/streaming/dash-adapter.d.ts.map +1 -1
- package/dist/streaming/fairplay.d.ts +21 -0
- package/dist/streaming/fairplay.d.ts.map +1 -0
- package/dist/streaming/hls-adapter.d.ts +2 -2
- package/dist/streaming/hls-adapter.d.ts.map +1 -1
- package/dist/streaming/progressive-adapter.d.ts +2 -2
- package/dist/streaming/progressive-adapter.d.ts.map +1 -1
- package/dist/streaming/source-manager.d.ts +3 -1
- package/dist/streaming/source-manager.d.ts.map +1 -1
- package/dist/streaming/types.d.ts +9 -3
- package/dist/streaming/types.d.ts.map +1 -1
- package/dist/styles/controls.d.ts +1 -1
- package/dist/styles/controls.d.ts.map +1 -1
- package/dist/utils/static-html.d.ts +12 -0
- package/dist/utils/static-html.d.ts.map +1 -0
- package/dist/vizor.js +4 -4
- package/package.json +8 -5
- package/dist/__tests__/license-checker.test.d.ts.map +0 -1
- package/dist/__tests__/master-key.test.d.ts.map +0 -1
- package/dist/annotations-C0ugfCn4.js.map +0 -1
- package/dist/captions-BP0H2E03.js.map +0 -1
- package/dist/collab-BXPomrS0.js.map +0 -1
- package/dist/dash-adapter-tid9ZyhO.js.map +0 -1
- package/dist/hls-adapter-BivH46L_.js +0 -97
- package/dist/hls-adapter-BivH46L_.js.map +0 -1
- package/dist/register-CwnmiGEs.js.map +0 -1
- /package/dist/{__tests__ → license/__tests__}/license-checker.test.d.ts +0 -0
- /package/dist/{__tests__ → license/__tests__}/master-key.test.d.ts +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, DOM-free chapter helpers. Extracted so the seek-bar marker math and the
|
|
3
|
+
* active-chapter tracking that drives `vz-chapter-change` can be unit-tested
|
|
4
|
+
* without a renderer or a real media element.
|
|
5
|
+
*/
|
|
6
|
+
export interface PlayerChapter {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
/** Start offset in seconds. Chapters are contiguous (end = next start). */
|
|
10
|
+
startTime: number;
|
|
11
|
+
sortOrder: number;
|
|
12
|
+
}
|
|
13
|
+
export interface ChapterMarker {
|
|
14
|
+
id: string;
|
|
15
|
+
title: string;
|
|
16
|
+
startTime: number;
|
|
17
|
+
/** Fractional position along the seek bar in [0, 1]. */
|
|
18
|
+
position: number;
|
|
19
|
+
}
|
|
20
|
+
/** A chapter as parsed from the DOM/delivery, before ids/order are normalized. */
|
|
21
|
+
export interface RawChapter {
|
|
22
|
+
id?: string | null;
|
|
23
|
+
title: string;
|
|
24
|
+
startTime: number;
|
|
25
|
+
sortOrder?: number | null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Turn raw parsed chapters (from `<vz-chapter>` children or a delivery config)
|
|
29
|
+
* into a sorted, fully-populated list: sort by startTime, then fill any missing
|
|
30
|
+
* id with a stable `chapter-<n>` index and default sortOrder from position.
|
|
31
|
+
*/
|
|
32
|
+
export declare function normalizeChapters(raw: RawChapter[]): PlayerChapter[];
|
|
33
|
+
/** Return a new array sorted by startTime ascending (input untouched). */
|
|
34
|
+
export declare function sortChapters(chapters: PlayerChapter[]): PlayerChapter[];
|
|
35
|
+
/**
|
|
36
|
+
* The chapter active at `currentTime`: the last chapter whose startTime is at or
|
|
37
|
+
* before it (chapters are contiguous). Returns null when the time precedes the
|
|
38
|
+
* first chapter or the list is empty. Accepts unsorted input.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveActiveChapter(chapters: PlayerChapter[], currentTime: number): PlayerChapter | null;
|
|
41
|
+
/**
|
|
42
|
+
* Map each chapter to a fractional seek-bar position (startTime / duration),
|
|
43
|
+
* clamped to [0, 1] and sorted by startTime. Returns [] until the duration is
|
|
44
|
+
* known (0 or negative), so callers can re-run when `duration` resolves.
|
|
45
|
+
*/
|
|
46
|
+
export declare function chapterMarkerPositions(chapters: PlayerChapter[], duration: number): ChapterMarker[];
|
|
47
|
+
//# sourceMappingURL=chapter-logic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapter-logic.d.ts","sourceRoot":"","sources":["../../src/chapters/chapter-logic.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,aAAa,EAAE,CAWpE;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EAAE,EACzB,WAAW,EAAE,MAAM,GAClB,aAAa,GAAG,IAAI,CAOtB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,aAAa,EAAE,EACzB,QAAQ,EAAE,MAAM,GACf,aAAa,EAAE,CAQjB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { PlayerState } from '../core/player-state.js';
|
|
2
|
+
import type { VzEventEmitter } from '../core/event-emitter.js';
|
|
3
|
+
import { type PlayerChapter, type ChapterMarker } from './chapter-logic.js';
|
|
4
|
+
/** Minimal structural view of SeekBar the manager needs (keeps it testable). */
|
|
5
|
+
export interface ChapterSeekBar {
|
|
6
|
+
setChapterMarkers(markers: ChapterMarker[]): void;
|
|
7
|
+
}
|
|
8
|
+
/** Minimal structural view of ControlsOverlay the manager needs. */
|
|
9
|
+
export interface ChapterControlsOverlay {
|
|
10
|
+
addControl(el: HTMLElement, section: 'left' | 'center' | 'right' | 'seek'): void;
|
|
11
|
+
}
|
|
12
|
+
export interface ChapterManagerOptions {
|
|
13
|
+
chapters: PlayerChapter[];
|
|
14
|
+
state: PlayerState;
|
|
15
|
+
events: VzEventEmitter;
|
|
16
|
+
/** Seek callback (media element's seek). */
|
|
17
|
+
seek: (time: number) => void;
|
|
18
|
+
seekBar?: ChapterSeekBar | null;
|
|
19
|
+
controlsOverlay?: ChapterControlsOverlay | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Wires manual chapters into a media element: renders seek-bar tick markers
|
|
23
|
+
* (reactive to duration), adds a chapter menu to the controls bar, and tracks
|
|
24
|
+
* the active chapter from `currentTime`, firing `vz-chapter-change` on each
|
|
25
|
+
* boundary crossing. Created only when the tier includes chapters (the gate
|
|
26
|
+
* lives in the media element's onLicenseResolved).
|
|
27
|
+
*/
|
|
28
|
+
export declare class ChapterManager {
|
|
29
|
+
private chapters;
|
|
30
|
+
private state;
|
|
31
|
+
private events;
|
|
32
|
+
private seek;
|
|
33
|
+
private seekBar;
|
|
34
|
+
private menu;
|
|
35
|
+
private activeId;
|
|
36
|
+
private unsubscribes;
|
|
37
|
+
constructor(opts: ChapterManagerOptions);
|
|
38
|
+
private renderMarkers;
|
|
39
|
+
private updateActive;
|
|
40
|
+
dispose(): void;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=chapter-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapter-manager.d.ts","sourceRoot":"","sources":["../../src/chapters/chapter-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAG5B,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,iBAAiB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;CACnD;AAED,oEAAoE;AACpE,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;CAClF;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,4CAA4C;IAC5C,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,eAAe,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;CACjD;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,YAAY,CAAyB;gBAEjC,IAAI,EAAE,qBAAqB;IAmBvC,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,YAAY;IAepB,OAAO,IAAI,IAAI;CAMhB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PlayerChapter } from './chapter-logic.js';
|
|
2
|
+
/**
|
|
3
|
+
* Chapters button + dropdown list. Mirrors the CcButton/QualityMenu pattern: a
|
|
4
|
+
* button in the controls bar toggles a dropdown of chapters (timestamp + title).
|
|
5
|
+
* Selecting a chapter seeks to its start. Titles render as inert text — they are
|
|
6
|
+
* author/delivery-supplied and only length-validated server-side.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ChapterMenu {
|
|
9
|
+
private container;
|
|
10
|
+
private btn;
|
|
11
|
+
private dropdown;
|
|
12
|
+
private chapters;
|
|
13
|
+
private onSelect;
|
|
14
|
+
private activeId;
|
|
15
|
+
private isOpen;
|
|
16
|
+
private unsubscribes;
|
|
17
|
+
constructor(chapters: PlayerChapter[], onSelect: (startTime: number) => void);
|
|
18
|
+
getElement(): HTMLDivElement;
|
|
19
|
+
/** Highlight the chapter with the given id (or clear when null). */
|
|
20
|
+
setActive(id: string | null): void;
|
|
21
|
+
dispose(): void;
|
|
22
|
+
private renderOptions;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=chapter-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapter-menu.d.ts","sourceRoot":"","sources":["../../src/chapters/chapter-menu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAexD;;;;;GAKG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAyB;gBAEjC,QAAQ,EAAE,aAAa,EAAE,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI;IAqC5E,UAAU,IAAI,cAAc;IAI5B,oEAAoE;IACpE,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAQlC,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,aAAa;CA6BtB"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { C as CanvasTexture, L as LinearFilter, S as SpriteMaterial, a as Sprite } from "./three-Bci7aSeI.js";
|
|
2
|
-
import { C as COLLAB_GAZE_LERP_FACTOR, l as latLonToSpherical, a as COLLAB_GAZE_INTERVAL, b as COLLAB_GAZE_THRESHOLD } from "./annotations-
|
|
2
|
+
import { C as COLLAB_GAZE_LERP_FACTOR, l as latLonToSpherical, a as COLLAB_GAZE_INTERVAL, b as COLLAB_GAZE_THRESHOLD } from "./annotations-Du6ZWrqC.js";
|
|
3
|
+
function setStaticHtml(el, constantHtml) {
|
|
4
|
+
el.innerHTML = constantHtml;
|
|
5
|
+
}
|
|
3
6
|
const ICON_PLAY = `<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>`;
|
|
4
7
|
const ICON_PAUSE = `<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>`;
|
|
5
8
|
const ICON_VOLUME_HIGH = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" fill="currentColor" stroke="none"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/></svg>`;
|
|
@@ -14,6 +17,7 @@ const ICON_PLAYLIST_NEXT = `<svg viewBox="0 0 24 24" fill="none" stroke="current
|
|
|
14
17
|
const ICON_PLAYLIST_PREV = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="19 20 9 12 19 4 19 20" fill="currentColor"/><line x1="5" y1="19" x2="5" y2="5"/></svg>`;
|
|
15
18
|
const ICON_LIVE_DOT = `<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="6" fill="currentColor"/></svg>`;
|
|
16
19
|
const ICON_CC = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2" ry="2"/><path d="M7 10.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5"/><path d="M7 13.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5"/><path d="M14 10.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5"/><path d="M14 13.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5"/></svg>`;
|
|
20
|
+
const ICON_CHAPTERS = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>`;
|
|
17
21
|
const ICON_CHAT = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>`;
|
|
18
22
|
const ICON_MIC = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>`;
|
|
19
23
|
const ICON_MIC_MUTED = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="1" y1="1" x2="23" y2="23"/><path d="M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6"/><path d="M17 16.95A7 7 0 0 1 5 12v-2m14 0v2c0 .64-.09 1.26-.26 1.85"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>`;
|
|
@@ -589,7 +593,7 @@ class ChatPanel {
|
|
|
589
593
|
});
|
|
590
594
|
const sendBtn = document.createElement("button");
|
|
591
595
|
sendBtn.className = "vz-chat-send";
|
|
592
|
-
sendBtn.
|
|
596
|
+
sendBtn.textContent = "➤";
|
|
593
597
|
sendBtn.addEventListener("click", () => this.handleSend());
|
|
594
598
|
inputRow.appendChild(this.inputEl);
|
|
595
599
|
inputRow.appendChild(sendBtn);
|
|
@@ -693,7 +697,7 @@ class ChatButton {
|
|
|
693
697
|
this.container.style.display = "inline-flex";
|
|
694
698
|
const btn = document.createElement("button");
|
|
695
699
|
btn.className = "vz-btn vz-chat-btn";
|
|
696
|
-
btn
|
|
700
|
+
setStaticHtml(btn, ICON_CHAT);
|
|
697
701
|
btn.title = "Chat (T)";
|
|
698
702
|
btn.addEventListener("click", (e) => {
|
|
699
703
|
e.stopPropagation();
|
|
@@ -895,7 +899,7 @@ class VoiceButton {
|
|
|
895
899
|
this.container.style.display = "inline-flex";
|
|
896
900
|
this.btn = document.createElement("button");
|
|
897
901
|
this.btn.className = "vz-btn vz-voice-btn";
|
|
898
|
-
this.btn
|
|
902
|
+
setStaticHtml(this.btn, ICON_MIC);
|
|
899
903
|
this.btn.title = "Voice Chat (V)";
|
|
900
904
|
this.btn.style.opacity = "0.5";
|
|
901
905
|
this.btn.addEventListener("click", (e) => {
|
|
@@ -913,17 +917,17 @@ class VoiceButton {
|
|
|
913
917
|
const state = this.voiceManager.getState();
|
|
914
918
|
switch (state) {
|
|
915
919
|
case "inactive":
|
|
916
|
-
this.btn
|
|
920
|
+
setStaticHtml(this.btn, ICON_MIC);
|
|
917
921
|
this.btn.style.opacity = "0.5";
|
|
918
922
|
this.btn.title = "Start Voice Chat (V)";
|
|
919
923
|
break;
|
|
920
924
|
case "active":
|
|
921
|
-
this.btn
|
|
925
|
+
setStaticHtml(this.btn, ICON_MIC);
|
|
922
926
|
this.btn.style.opacity = "1";
|
|
923
927
|
this.btn.title = "Mute (V)";
|
|
924
928
|
break;
|
|
925
929
|
case "muted":
|
|
926
|
-
this.btn
|
|
930
|
+
setStaticHtml(this.btn, ICON_MIC_MUTED);
|
|
927
931
|
this.btn.style.opacity = "1";
|
|
928
932
|
this.btn.title = "Unmute (V)";
|
|
929
933
|
break;
|
|
@@ -962,17 +966,19 @@ export {
|
|
|
962
966
|
GazeSender as c,
|
|
963
967
|
VoiceManager as d,
|
|
964
968
|
ICON_PAUSE as e,
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
969
|
+
ICON_VOLUME_MUTED as f,
|
|
970
|
+
ICON_VOLUME_HIGH as g,
|
|
971
|
+
ICON_VOLUME_LOW as h,
|
|
968
972
|
ICON_FULLSCREEN as i,
|
|
969
973
|
ICON_FULLSCREEN_EXIT as j,
|
|
970
974
|
ICON_VR as k,
|
|
971
975
|
ICON_COMPASS as l,
|
|
972
976
|
ICON_SETTINGS as m,
|
|
973
977
|
ICON_LIVE_DOT as n,
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
978
|
+
ICON_CHAPTERS as o,
|
|
979
|
+
ICON_CC as p,
|
|
980
|
+
ICON_PLAYLIST_PREV as q,
|
|
981
|
+
ICON_PLAYLIST_NEXT as r,
|
|
982
|
+
setStaticHtml as s
|
|
977
983
|
};
|
|
978
|
-
//# sourceMappingURL=collab-
|
|
984
|
+
//# sourceMappingURL=collab-BLpllHtb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collab-BLpllHtb.js","sources":["../src/utils/static-html.ts","../src/controls/icons.ts","../src/collaborative/collab-client.ts","../src/collaborative/gaze-cursor-manager.ts","../src/collaborative/gaze-sender.ts","../src/collaborative/chat-panel.ts","../src/collaborative/chat-button.ts","../src/collaborative/voice-manager.ts","../src/collaborative/voice-button.ts"],"sourcesContent":["/**\n * The player's single audited raw-`innerHTML` sink for compile-time-constant\n * markup: control icons from `controls/icons.ts` and fixed scaffolding like\n * the loading spinner. Callers MUST pass only module-level string constants —\n * never user input, server responses, media metadata, or anything derived\n * from them. Dynamic content goes through `sanitize.ts` (DOMPurify) instead.\n *\n * Centralizing the sink lets the semgrep `no-raw-innerhtml` rule run at ERROR\n * with exactly one suppression in shipped player code.\n */\nexport function setStaticHtml(el: Element, constantHtml: string): void {\n // nosemgrep: no-raw-innerhtml\n el.innerHTML = constantHtml;\n}\n","/**\n * SVG icon strings for controls.\n * Uses stroke-based icons with 1.5px weight for a refined, Vimeo-inspired look.\n * Play/pause remain filled for quick recognition.\n */\n\nexport const ICON_PLAY = `<svg viewBox=\"0 0 24 24\"><path d=\"M8 5v14l11-7z\"/></svg>`;\n\nexport const ICON_PAUSE = `<svg viewBox=\"0 0 24 24\"><path d=\"M6 19h4V5H6v14zm8-14v14h4V5h-4z\"/></svg>`;\n\nexport const ICON_VOLUME_HIGH = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" fill=\"currentColor\" stroke=\"none\"/><path d=\"M19.07 4.93a10 10 0 0 1 0 14.14\"/><path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/></svg>`;\n\nexport const ICON_VOLUME_LOW = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" fill=\"currentColor\" stroke=\"none\"/><path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/></svg>`;\n\nexport const ICON_VOLUME_MUTED = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" fill=\"currentColor\" stroke=\"none\"/><line x1=\"23\" y1=\"9\" x2=\"17\" y2=\"15\"/><line x1=\"17\" y1=\"9\" x2=\"23\" y2=\"15\"/></svg>`;\n\nexport const ICON_FULLSCREEN = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>`;\n\nexport const ICON_FULLSCREEN_EXIT = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" y1=\"10\" x2=\"21\" y2=\"3\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>`;\n\nexport const ICON_VR = `<svg viewBox=\"0 0 24 24\"><path d=\"M20.74 6H3.21C2.55 6 2 6.57 2 7.28v10.44c0 .7.55 1.28 1.23 1.28h4.79c.52 0 .96-.3 1.19-.77l1.58-3.15c.28-.58.84-.94 1.43-.94h1.56c.59 0 1.15.36 1.43.94l1.58 3.15c.23.47.67.77 1.19.77h4.79c.68 0 1.23-.57 1.23-1.28V7.28C22 6.57 21.43 6 20.74 6zM7.5 14.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5zm9 0c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z\"/></svg>`;\n\nexport const ICON_COMPASS = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><polygon points=\"16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76\" fill=\"currentColor\"/></svg>`;\n\nexport const ICON_SETTINGS = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"/></svg>`;\n\n// Playlist & Live icons (for future steps)\nexport const ICON_PLAYLIST_NEXT = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"5 4 15 12 5 20 5 4\" fill=\"currentColor\"/><line x1=\"19\" y1=\"5\" x2=\"19\" y2=\"19\"/></svg>`;\n\nexport const ICON_PLAYLIST_PREV = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"19 20 9 12 19 4 19 20\" fill=\"currentColor\"/><line x1=\"5\" y1=\"19\" x2=\"5\" y2=\"5\"/></svg>`;\n\nexport const ICON_LIVE_DOT = `<svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"6\" fill=\"currentColor\"/></svg>`;\n\nexport const ICON_CC = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" ry=\"2\"/><path d=\"M7 10.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5\"/><path d=\"M7 13.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5\"/><path d=\"M14 10.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5\"/><path d=\"M14 13.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5\"/></svg>`;\n\nexport const ICON_CHAPTERS = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"8\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"8\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"8\" y1=\"18\" x2=\"21\" y2=\"18\"/><line x1=\"3\" y1=\"6\" x2=\"3.01\" y2=\"6\"/><line x1=\"3\" y1=\"12\" x2=\"3.01\" y2=\"12\"/><line x1=\"3\" y1=\"18\" x2=\"3.01\" y2=\"18\"/></svg>`;\n\nexport const ICON_CHAT = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>`;\n\nexport const ICON_MIC = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"/><path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"/><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"/></svg>`;\n\nexport const ICON_MIC_MUTED = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"/><path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\"/><path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2c0 .64-.09 1.26-.26 1.85\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"/><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"/></svg>`;\n","import type { PlayerState } from '../core/player-state.js';\nimport type { ClientMessage, ServerMessage, CollabParticipant } from '@vizor-vr/shared';\n\n/** Drift threshold in seconds — viewer only seeks if drift exceeds this */\nconst DRIFT_THRESHOLD = 1.0;\n\n/** Reconnect delay in milliseconds */\nconst RECONNECT_DELAY = 3000;\n\n/** Throttle interval for playback_state messages (ms) */\nconst PLAYBACK_THROTTLE = 250;\n\nexport interface CollabClientOptions {\n serverUrl: string;\n roomCode: string;\n role: 'host' | 'viewer';\n userId: string;\n displayName: string;\n state: PlayerState;\n /** The media element for play/pause/seek control */\n mediaElement: {\n play(): void | Promise<void>;\n pause(): void;\n seek(time: number): void;\n currentTime: number;\n };\n /** Optional callback when participants change */\n onParticipantsChange?: (users: CollabParticipant[]) => void;\n /** Callback when a peer's gaze position is received */\n onPeerGaze?: (userId: string, lat: number, lon: number) => void;\n /** Callback when a user joins the room */\n onUserJoined?: (user: CollabParticipant) => void;\n /** Callback when a user leaves the room */\n onUserLeft?: (userId: string) => void;\n /** Callback when a chat message is received */\n onChatMessage?: (userId: string, displayName: string, text: string, timestamp: number) => void;\n /** Callback when a voice signal (SDP/ICE) is received from a peer */\n onVoiceSignal?: (fromUserId: string, sdp?: string, candidate?: string) => void;\n /** Room password (host sets, viewers must match) */\n password?: string;\n}\n\n/**\n * Browser-side WebSocket client for collaborative viewing.\n *\n * - Host: subscribes to local state changes → sends playback_state/seek to server\n * - Viewer: receives sync messages → applies play/pause/seek locally\n * - Auto-reconnects on unexpected close\n */\nexport class CollaborativeClient {\n private ws: WebSocket | null = null;\n private options: CollabClientOptions;\n private unsubscribes: Array<() => void> = [];\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private disposed = false;\n private lastPlaybackSend = 0;\n private connected = false;\n\n constructor(options: CollabClientOptions) {\n this.options = options;\n }\n\n /** Connect to the collaborative server */\n connect(): void {\n if (this.disposed) return;\n\n try {\n this.ws = new WebSocket(this.options.serverUrl);\n } catch {\n this.scheduleReconnect();\n return;\n }\n\n this.ws.onopen = () => {\n this.connected = true;\n // Send join message\n this.send({\n type: 'join',\n roomCode: this.options.roomCode,\n userId: this.options.userId,\n displayName: this.options.displayName,\n password: this.options.password,\n });\n\n // If host, subscribe to state changes to broadcast\n if (this.options.role === 'host') {\n this.subscribeHostState();\n }\n };\n\n this.ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data as string) as ServerMessage;\n this.handleMessage(msg);\n } catch {\n // Ignore invalid messages\n }\n };\n\n this.ws.onclose = () => {\n this.connected = false;\n this.cleanupSubscriptions();\n if (!this.disposed) {\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = () => {\n // onclose will fire after onerror\n };\n }\n\n /** Whether the client is currently connected */\n isConnected(): boolean {\n return this.connected;\n }\n\n /** Gracefully disconnect and clean up */\n dispose(): void {\n this.disposed = true;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n this.cleanupSubscriptions();\n\n if (this.ws) {\n // Send leave before closing\n if (this.ws.readyState === WebSocket.OPEN) {\n this.send({ type: 'leave' });\n }\n this.ws.close();\n this.ws = null;\n }\n\n this.connected = false;\n }\n\n // --- Private ---\n\n private handleMessage(msg: ServerMessage): void {\n switch (msg.type) {\n case 'room_state':\n this.handleRoomState(msg.users, msg.playing, msg.currentTime);\n break;\n\n case 'sync':\n this.handleSync(msg.playing, msg.currentTime);\n break;\n\n case 'user_joined':\n this.options.onUserJoined?.(msg.user);\n this.options.onParticipantsChange?.([]); // Signal change; full list comes with room_state\n break;\n\n case 'user_left':\n this.options.onUserLeft?.(msg.userId);\n this.options.onParticipantsChange?.([]); // Signal change\n break;\n\n case 'error':\n console.warn(`[Vizor Collab] Server error: ${msg.code} — ${msg.message}`);\n break;\n\n case 'peer_gaze':\n this.options.onPeerGaze?.(msg.userId, msg.lat, msg.lon);\n break;\n\n case 'chat_message':\n this.options.onChatMessage?.(msg.userId, msg.displayName, msg.text, msg.timestamp);\n break;\n\n case 'voice_signal':\n this.options.onVoiceSignal?.(msg.fromUserId, msg.sdp, msg.candidate);\n break;\n }\n }\n\n private handleRoomState(\n users: CollabParticipant[],\n playing: boolean,\n currentTime: number,\n ): void {\n this.options.onParticipantsChange?.(users);\n\n // Viewer: sync to room state on join\n if (this.options.role === 'viewer') {\n this.applySync(playing, currentTime);\n }\n }\n\n private handleSync(playing: boolean, currentTime: number): void {\n // Only viewers apply sync\n if (this.options.role !== 'viewer') return;\n this.applySync(playing, currentTime);\n }\n\n private applySync(playing: boolean, currentTime: number): void {\n const { state, mediaElement } = this.options;\n const localTime = mediaElement.currentTime;\n const drift = Math.abs(currentTime - localTime);\n\n // Seek if drift exceeds threshold\n if (drift > DRIFT_THRESHOLD) {\n mediaElement.seek(currentTime);\n }\n\n // Sync play/pause\n const localPlaying = state.get('playing');\n if (playing && !localPlaying) {\n Promise.resolve(mediaElement.play()).catch(() => {});\n } else if (!playing && localPlaying) {\n mediaElement.pause();\n }\n }\n\n /** Host: subscribe to local state changes and broadcast them */\n private subscribeHostState(): void {\n const { state } = this.options;\n\n // Subscribe to playing state changes (play/pause)\n const unsubPlaying = state.subscribe('playing', (playing) => {\n this.sendPlaybackState(playing, state.get('currentTime'));\n });\n this.unsubscribes.push(unsubPlaying);\n\n // Subscribe to seeking (user seeks)\n const unsubSeeking = state.subscribe('seeking', (seeking, prevSeeking) => {\n // Send seek when seeking ends (user released seek bar)\n if (!seeking && prevSeeking) {\n this.send({\n type: 'seek',\n currentTime: state.get('currentTime'),\n });\n }\n });\n this.unsubscribes.push(unsubSeeking);\n }\n\n /** Throttled playback state sender */\n private sendPlaybackState(playing: boolean, currentTime: number): void {\n const now = Date.now();\n if (now - this.lastPlaybackSend < PLAYBACK_THROTTLE) return;\n this.lastPlaybackSend = now;\n\n this.send({\n type: 'playback_state',\n playing,\n currentTime,\n timestamp: now,\n });\n }\n\n /** Send a chat message */\n sendChat(text: string): void {\n this.send({ type: 'chat', text });\n }\n\n /** Send a voice signal (SDP offer/answer or ICE candidate) to a specific peer */\n sendVoiceSignal(targetUserId: string, sdp?: string, candidate?: string): void {\n this.send({ type: 'voice_signal', targetUserId, sdp, candidate });\n }\n\n /** Send a message to the server */\n send(msg: ClientMessage): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(msg));\n }\n }\n\n private scheduleReconnect(): void {\n if (this.disposed || this.reconnectTimer) return;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, RECONNECT_DELAY);\n }\n\n /** Register a cleanup function to run on dispose */\n addCleanup(fn: () => void): void {\n this.unsubscribes.push(fn);\n }\n\n private cleanupSubscriptions(): void {\n for (const unsub of this.unsubscribes) unsub();\n this.unsubscribes = [];\n }\n}\n","import {\n Sprite,\n SpriteMaterial,\n CanvasTexture,\n LinearFilter,\n} from 'three';\nimport type { Scene } from 'three';\nimport { latLonToSpherical, COLLAB_GAZE_LERP_FACTOR } from '@vizor-vr/shared';\n\n/** Tracked state for a single peer's gaze cursor */\ninterface PeerCursor {\n sprite: Sprite;\n nameLabel: Sprite;\n targetLat: number;\n targetLon: number;\n currentLat: number;\n currentLon: number;\n displayName: string;\n color: string;\n}\n\n/** Color palette for peer cursors — assigned by join order */\nconst PEER_COLORS = [\n '#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8',\n '#F7DC6F', '#BB8FCE', '#85C1E9', '#F1948A', '#82E0AA',\n];\n\n/** Distance from center for cursor sprites (in front of sphere at 200) */\nconst CURSOR_DISTANCE = 195;\nconst CURSOR_SCALE = 6;\nconst LABEL_SCALE_X = 14;\nconst LABEL_SCALE_Y = 5;\nconst CURSOR_CANVAS_SIZE = 64;\nconst LABEL_CANVAS_WIDTH = 256;\nconst LABEL_CANVAS_HEIGHT = 64;\n\n/**\n * Manages 3D sprite cursors for all remote peers.\n * Each peer gets a colored dot on the sphere at their camera orientation.\n * Positions are smoothly interpolated each frame via lerp.\n */\nexport class GazeCursorManager {\n private scene: Scene;\n private cursors = new Map<string, PeerCursor>();\n private colorIndex = 0;\n\n constructor(scene: Scene) {\n this.scene = scene;\n }\n\n /** Add a cursor for a new peer */\n addPeer(userId: string, displayName: string): void {\n if (this.cursors.has(userId)) return;\n\n const color = PEER_COLORS[this.colorIndex % PEER_COLORS.length]!;\n this.colorIndex++;\n\n const sprite = this.createCursorSprite(color);\n const nameLabel = this.createLabelSprite(displayName, color);\n nameLabel.visible = true;\n\n this.scene.add(sprite);\n this.scene.add(nameLabel);\n\n this.cursors.set(userId, {\n sprite,\n nameLabel,\n targetLat: 0,\n targetLon: 0,\n currentLat: 0,\n currentLon: 0,\n displayName,\n color: color,\n });\n }\n\n /** Remove a peer's cursor */\n removePeer(userId: string): void {\n const cursor = this.cursors.get(userId);\n if (!cursor) return;\n\n this.scene.remove(cursor.sprite);\n this.scene.remove(cursor.nameLabel);\n cursor.sprite.material.map?.dispose();\n cursor.sprite.material.dispose();\n cursor.nameLabel.material.map?.dispose();\n cursor.nameLabel.material.dispose();\n this.cursors.delete(userId);\n }\n\n /** Update the target gaze position for a peer */\n updateGaze(userId: string, lat: number, lon: number): void {\n const cursor = this.cursors.get(userId);\n if (!cursor) return;\n cursor.targetLat = lat;\n cursor.targetLon = lon;\n }\n\n /** Called each animation frame. Lerps all cursors toward their target positions. */\n update(): void {\n for (const [, cursor] of this.cursors) {\n cursor.currentLat += (cursor.targetLat - cursor.currentLat) * COLLAB_GAZE_LERP_FACTOR;\n cursor.currentLon += (cursor.targetLon - cursor.currentLon) * COLLAB_GAZE_LERP_FACTOR;\n\n const { phi, theta } = latLonToSpherical(cursor.currentLat, cursor.currentLon);\n const x = CURSOR_DISTANCE * Math.sin(phi) * Math.cos(theta);\n const y = CURSOR_DISTANCE * Math.cos(phi);\n const z = CURSOR_DISTANCE * Math.sin(phi) * Math.sin(theta);\n\n cursor.sprite.position.set(x, y, z);\n\n // Name label sits above the cursor\n cursor.nameLabel.position.set(x, y + CURSOR_SCALE * 0.8, z);\n }\n }\n\n /** Get the number of tracked peers */\n getPeerCount(): number {\n return this.cursors.size;\n }\n\n /** Clean up all cursors */\n dispose(): void {\n for (const [userId] of this.cursors) {\n this.removePeer(userId);\n }\n }\n\n /** Create a colored circle sprite for the cursor dot */\n private createCursorSprite(color: string): Sprite {\n const canvas = document.createElement('canvas');\n canvas.width = CURSOR_CANVAS_SIZE;\n canvas.height = CURSOR_CANVAS_SIZE;\n const ctx = canvas.getContext('2d')!;\n\n const cx = CURSOR_CANVAS_SIZE / 2;\n const cy = CURSOR_CANVAS_SIZE / 2;\n const radius = CURSOR_CANVAS_SIZE / 2 - 4;\n\n // Colored circle\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.arc(cx, cy, radius, 0, Math.PI * 2);\n ctx.fill();\n\n // White ring border\n ctx.strokeStyle = '#ffffff';\n ctx.lineWidth = 3;\n ctx.stroke();\n\n const texture = new CanvasTexture(canvas);\n texture.minFilter = LinearFilter;\n texture.magFilter = LinearFilter;\n\n const material = new SpriteMaterial({\n map: texture,\n sizeAttenuation: true,\n depthTest: false,\n transparent: true,\n });\n\n const sprite = new Sprite(material);\n sprite.scale.set(CURSOR_SCALE, CURSOR_SCALE, 1);\n return sprite;\n }\n\n /** Create a text label sprite showing the peer's display name */\n private createLabelSprite(name: string, color: string): Sprite {\n const canvas = document.createElement('canvas');\n canvas.width = LABEL_CANVAS_WIDTH;\n canvas.height = LABEL_CANVAS_HEIGHT;\n const ctx = canvas.getContext('2d')!;\n\n // Semi-transparent background bar\n const padding = 10;\n ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';\n ctx.beginPath();\n ctx.roundRect(padding, padding, LABEL_CANVAS_WIDTH - padding * 2, LABEL_CANVAS_HEIGHT - padding * 2, 8);\n ctx.fill();\n\n // Name text\n ctx.fillStyle = color;\n ctx.font = 'bold 24px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(name, LABEL_CANVAS_WIDTH / 2, LABEL_CANVAS_HEIGHT / 2);\n\n const texture = new CanvasTexture(canvas);\n texture.minFilter = LinearFilter;\n texture.magFilter = LinearFilter;\n\n const material = new SpriteMaterial({\n map: texture,\n sizeAttenuation: true,\n depthTest: false,\n transparent: true,\n });\n\n const sprite = new Sprite(material);\n sprite.scale.set(LABEL_SCALE_X, LABEL_SCALE_Y, 1);\n return sprite;\n }\n}\n","import type { ClientMessage } from '@vizor-vr/shared';\nimport { COLLAB_GAZE_INTERVAL, COLLAB_GAZE_THRESHOLD } from '@vizor-vr/shared';\n\n/** Orientation provider callback (matches CameraController.getOrientation) */\nexport interface OrientationProvider {\n getOrientation(): { lat: number; lon: number; fov: number };\n}\n\n/**\n * Samples local camera orientation at ~5Hz and sends throttled `gaze` messages.\n * Only sends when orientation changes by more than COLLAB_GAZE_THRESHOLD degrees.\n */\nexport class GazeSender {\n private timer: ReturnType<typeof setInterval> | null = null;\n private lastSentLat = NaN;\n private lastSentLon = NaN;\n private orientationProvider: OrientationProvider;\n private sendFn: (msg: ClientMessage) => void;\n\n constructor(orientationProvider: OrientationProvider, sendFn: (msg: ClientMessage) => void) {\n this.orientationProvider = orientationProvider;\n this.sendFn = sendFn;\n }\n\n /** Start sampling and sending gaze messages */\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(() => this.sample(), COLLAB_GAZE_INTERVAL);\n }\n\n /** Stop sampling */\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n /** Clean up */\n dispose(): void {\n this.stop();\n }\n\n private sample(): void {\n const { lat, lon } = this.orientationProvider.getOrientation();\n const dLat = Math.abs(lat - this.lastSentLat);\n const dLon = Math.abs(lon - this.lastSentLon);\n\n if (dLat > COLLAB_GAZE_THRESHOLD || dLon > COLLAB_GAZE_THRESHOLD || isNaN(this.lastSentLat)) {\n this.lastSentLat = lat;\n this.lastSentLon = lon;\n this.sendFn({ type: 'gaze', lat, lon });\n }\n }\n}\n","/** A single chat message displayed in the panel */\nexport interface ChatMessage {\n userId: string;\n displayName: string;\n text: string;\n timestamp: number;\n isLocal: boolean;\n}\n\n/** Color palette matching gaze cursor colors */\nconst PEER_COLORS = [\n '#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8',\n '#F7DC6F', '#BB8FCE', '#85C1E9', '#F1948A', '#82E0AA',\n];\n\nconst CHAT_CSS = `\n.vz-chat-panel {\n position: absolute;\n right: 0;\n top: 0;\n bottom: 0;\n width: 300px;\n max-width: 70%;\n background: rgba(15, 15, 25, 0.95);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n z-index: 25;\n display: flex;\n flex-direction: column;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n.vz-chat-panel.open {\n transform: translateX(0);\n}\n.vz-chat-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n flex-shrink: 0;\n}\n.vz-chat-title {\n color: #fff;\n font-size: 14px;\n font-weight: 600;\n}\n.vz-chat-close {\n background: none;\n border: none;\n color: rgba(255, 255, 255, 0.6);\n font-size: 18px;\n cursor: pointer;\n padding: 0 4px;\n line-height: 1;\n}\n.vz-chat-close:hover {\n color: #fff;\n}\n.vz-chat-messages {\n flex: 1;\n overflow-y: auto;\n padding: 8px 12px;\n scrollbar-width: thin;\n scrollbar-color: rgba(255,255,255,0.2) transparent;\n}\n.vz-chat-messages::-webkit-scrollbar {\n width: 4px;\n}\n.vz-chat-messages::-webkit-scrollbar-thumb {\n background: rgba(255,255,255,0.2);\n border-radius: 2px;\n}\n.vz-chat-message {\n margin: 4px 0;\n padding: 4px 0;\n}\n.vz-chat-msg-header {\n display: flex;\n align-items: baseline;\n gap: 6px;\n}\n.vz-chat-msg-name {\n font-weight: 600;\n font-size: 12px;\n}\n.vz-chat-msg-time {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n}\n.vz-chat-msg-text {\n font-size: 13px;\n color: rgba(255, 255, 255, 0.9);\n word-break: break-word;\n margin-top: 2px;\n line-height: 1.4;\n}\n.vz-chat-input-row {\n display: flex;\n gap: 6px;\n padding: 8px 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n flex-shrink: 0;\n}\n.vz-chat-input {\n flex: 1;\n height: 32px;\n border-radius: 6px;\n border: none;\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n padding: 0 10px;\n font-size: 13px;\n outline: none;\n}\n.vz-chat-input::placeholder {\n color: rgba(255, 255, 255, 0.3);\n}\n.vz-chat-input:focus {\n background: rgba(255, 255, 255, 0.15);\n}\n.vz-chat-send {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n border: none;\n background: var(--vz-primary, #f43f5e);\n color: #fff;\n font-size: 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.vz-chat-send:hover {\n opacity: 0.85;\n}\n.vz-chat-empty {\n color: rgba(255, 255, 255, 0.3);\n font-size: 13px;\n text-align: center;\n padding: 24px 16px;\n}\n`;\n\n/**\n * Side panel overlay for collaborative chat.\n * Slides in from the right with frosted glass styling.\n */\nexport class ChatPanel {\n private panel: HTMLDivElement;\n private messagesEl: HTMLDivElement;\n private inputEl: HTMLInputElement;\n private emptyEl: HTMLDivElement;\n private styleEl: HTMLStyleElement;\n private isOpen = false;\n private messages: ChatMessage[] = [];\n private colorMap = new Map<string, string>();\n private colorIndex = 0;\n private onSend: (text: string) => void;\n private shadowRoot: ShadowRoot;\n\n constructor(shadowRoot: ShadowRoot, onSend: (text: string) => void) {\n this.shadowRoot = shadowRoot;\n this.onSend = onSend;\n\n // Inject CSS\n this.styleEl = document.createElement('style');\n this.styleEl.textContent = CHAT_CSS;\n shadowRoot.appendChild(this.styleEl);\n\n // Build panel DOM\n this.panel = document.createElement('div');\n this.panel.className = 'vz-chat-panel';\n\n // Header\n const header = document.createElement('div');\n header.className = 'vz-chat-header';\n const title = document.createElement('span');\n title.className = 'vz-chat-title';\n title.textContent = 'Chat';\n const closeBtn = document.createElement('button');\n closeBtn.className = 'vz-chat-close';\n closeBtn.textContent = '\\u2715';\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(title);\n header.appendChild(closeBtn);\n this.panel.appendChild(header);\n\n // Messages area\n this.messagesEl = document.createElement('div');\n this.messagesEl.className = 'vz-chat-messages';\n this.emptyEl = document.createElement('div');\n this.emptyEl.className = 'vz-chat-empty';\n this.emptyEl.textContent = 'No messages yet';\n this.messagesEl.appendChild(this.emptyEl);\n this.panel.appendChild(this.messagesEl);\n\n // Input row\n const inputRow = document.createElement('div');\n inputRow.className = 'vz-chat-input-row';\n this.inputEl = document.createElement('input');\n this.inputEl.className = 'vz-chat-input';\n this.inputEl.type = 'text';\n this.inputEl.placeholder = 'Type a message...';\n this.inputEl.maxLength = 500;\n this.inputEl.addEventListener('keydown', (e) => {\n e.stopPropagation(); // Prevent keyboard shortcuts from firing\n if (e.key === 'Enter') {\n this.handleSend();\n }\n });\n const sendBtn = document.createElement('button');\n sendBtn.className = 'vz-chat-send';\n sendBtn.textContent = '\\u27A4'; // Right arrow\n sendBtn.addEventListener('click', () => this.handleSend());\n inputRow.appendChild(this.inputEl);\n inputRow.appendChild(sendBtn);\n this.panel.appendChild(inputRow);\n\n shadowRoot.appendChild(this.panel);\n }\n\n /** Add a chat message to the panel */\n addMessage(msg: ChatMessage): void {\n this.messages.push(msg);\n if (this.emptyEl.parentNode) {\n this.emptyEl.remove();\n }\n this.renderMessage(msg);\n this.scrollToBottom();\n }\n\n /** Toggle panel open/closed */\n toggle(): void {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /** Open the panel */\n open(): void {\n this.isOpen = true;\n this.panel.classList.add('open');\n this.inputEl.focus();\n }\n\n /** Close the panel */\n close(): void {\n this.isOpen = false;\n this.panel.classList.remove('open');\n }\n\n /** Whether the panel is currently visible */\n isVisible(): boolean {\n return this.isOpen;\n }\n\n /** Get message count */\n getMessageCount(): number {\n return this.messages.length;\n }\n\n /** Clean up */\n dispose(): void {\n this.panel.remove();\n this.styleEl.remove();\n }\n\n private handleSend(): void {\n const text = this.inputEl.value.trim();\n if (!text) return;\n this.inputEl.value = '';\n this.onSend(text);\n }\n\n private renderMessage(msg: ChatMessage): void {\n const el = document.createElement('div');\n el.className = 'vz-chat-message';\n\n const headerEl = document.createElement('div');\n headerEl.className = 'vz-chat-msg-header';\n\n const nameEl = document.createElement('span');\n nameEl.className = 'vz-chat-msg-name';\n nameEl.style.color = this.getColorForUser(msg.userId);\n nameEl.textContent = msg.isLocal ? 'You' : msg.displayName;\n\n const timeEl = document.createElement('span');\n timeEl.className = 'vz-chat-msg-time';\n timeEl.textContent = this.formatTime(msg.timestamp);\n\n headerEl.appendChild(nameEl);\n headerEl.appendChild(timeEl);\n\n const textEl = document.createElement('div');\n textEl.className = 'vz-chat-msg-text';\n textEl.textContent = msg.text; // textContent auto-escapes HTML\n\n el.appendChild(headerEl);\n el.appendChild(textEl);\n this.messagesEl.appendChild(el);\n }\n\n private scrollToBottom(): void {\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight;\n }\n\n private getColorForUser(userId: string): string {\n if (!this.colorMap.has(userId)) {\n this.colorMap.set(userId, PEER_COLORS[this.colorIndex % PEER_COLORS.length]!);\n this.colorIndex++;\n }\n return this.colorMap.get(userId)!;\n }\n\n private formatTime(ts: number): string {\n const d = new Date(ts);\n const h = d.getHours().toString().padStart(2, '0');\n const m = d.getMinutes().toString().padStart(2, '0');\n return `${h}:${m}`;\n }\n}\n","import { ICON_CHAT } from '../controls/icons.js';\nimport { setStaticHtml } from '../utils/static-html.js';\nimport type { ChatPanel } from './chat-panel.js';\n\n/**\n * Chat toggle button with unread message badge.\n * Placed in the controls bar right section.\n */\nexport class ChatButton {\n private container: HTMLDivElement;\n private badge: HTMLSpanElement;\n private unreadCount = 0;\n private chatPanel: ChatPanel;\n\n constructor(chatPanel: ChatPanel) {\n this.chatPanel = chatPanel;\n\n this.container = document.createElement('div');\n this.container.style.position = 'relative';\n this.container.style.display = 'inline-flex';\n\n const btn = document.createElement('button');\n btn.className = 'vz-btn vz-chat-btn';\n setStaticHtml(btn, ICON_CHAT);\n btn.title = 'Chat (T)';\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.chatPanel.toggle();\n if (this.chatPanel.isVisible()) {\n this.resetUnread();\n }\n });\n\n this.badge = document.createElement('span');\n this.badge.className = 'vz-chat-badge';\n this.badge.style.display = 'none';\n\n this.container.appendChild(btn);\n this.container.appendChild(this.badge);\n }\n\n /** Increment unread count and show badge */\n incrementUnread(): void {\n this.unreadCount++;\n this.updateBadge();\n }\n\n /** Reset unread count and hide badge */\n resetUnread(): void {\n this.unreadCount = 0;\n this.updateBadge();\n }\n\n /** Get the DOM element to insert into controls */\n getElement(): HTMLDivElement {\n return this.container;\n }\n\n /** Clean up */\n dispose(): void {\n this.container.remove();\n }\n\n private updateBadge(): void {\n if (this.unreadCount > 0) {\n this.badge.textContent = this.unreadCount > 99 ? '99+' : String(this.unreadCount);\n this.badge.style.display = 'flex';\n } else {\n this.badge.textContent = '';\n this.badge.style.display = 'none';\n }\n }\n}\n","/** STUN servers for ICE connectivity */\nconst STUN_SERVERS: RTCIceServer[] = [\n { urls: 'stun:stun.l.google.com:19302' },\n { urls: 'stun:stun1.l.google.com:19302' },\n];\n\n/** State of the voice manager */\nexport type VoiceState = 'inactive' | 'active' | 'muted';\n\n/** Per-peer connection info */\ninterface PeerConnection {\n pc: RTCPeerConnection;\n audioEl: HTMLAudioElement;\n}\n\n/**\n * WebRTC mesh voice manager.\n *\n * Handles microphone capture, peer-to-peer audio connections,\n * and SDP/ICE signaling relay. Mesh topology — each participant\n * connects directly to every other participant (suitable for <8 peers).\n */\nexport class VoiceManager {\n private localStream: MediaStream | null = null;\n private peers = new Map<string, PeerConnection>();\n private state: VoiceState = 'inactive';\n private sendSignal: (targetUserId: string, sdp?: string, candidate?: string) => void;\n\n constructor(\n sendSignal: (targetUserId: string, sdp?: string, candidate?: string) => void,\n ) {\n this.sendSignal = sendSignal;\n }\n\n /** Get current voice state */\n getState(): VoiceState {\n return this.state;\n }\n\n /** Start voice — request microphone and begin connections */\n async start(): Promise<void> {\n if (this.state !== 'inactive') return;\n\n try {\n this.localStream = await navigator.mediaDevices.getUserMedia({ audio: true });\n this.state = 'active';\n } catch (err) {\n console.warn('[Vizor Voice] getUserMedia failed:', err);\n throw err;\n }\n }\n\n /** Toggle mute on/off */\n toggleMute(): void {\n if (!this.localStream) return;\n\n if (this.state === 'active') {\n this.localStream.getAudioTracks().forEach((t) => (t.enabled = false));\n this.state = 'muted';\n } else if (this.state === 'muted') {\n this.localStream.getAudioTracks().forEach((t) => (t.enabled = true));\n this.state = 'active';\n }\n }\n\n /** Whether voice is currently active (active or muted) */\n isActive(): boolean {\n return this.state !== 'inactive';\n }\n\n /** Whether mic is currently muted */\n isMuted(): boolean {\n return this.state === 'muted';\n }\n\n /**\n * Initiate a WebRTC connection to a peer (caller side).\n * Creates an offer and sends it via signaling.\n */\n async connectToPeer(peerId: string): Promise<void> {\n if (!this.localStream || this.peers.has(peerId)) return;\n\n const pc = this.createPeerConnection(peerId);\n\n // Add local audio tracks\n this.localStream.getTracks().forEach((track) => {\n pc.addTrack(track, this.localStream!);\n });\n\n // Create and send SDP offer\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n\n this.sendSignal(peerId, JSON.stringify(offer));\n }\n\n /**\n * Handle an incoming voice signal (SDP offer/answer or ICE candidate).\n */\n async handleSignal(fromUserId: string, sdp?: string, candidate?: string): Promise<void> {\n if (!this.localStream) return;\n\n if (sdp) {\n const desc = JSON.parse(sdp) as RTCSessionDescriptionInit;\n\n if (desc.type === 'offer') {\n // Incoming offer — create answer\n const pc = this.createPeerConnection(fromUserId);\n\n // Add local tracks\n this.localStream.getTracks().forEach((track) => {\n pc.addTrack(track, this.localStream!);\n });\n\n await pc.setRemoteDescription(new RTCSessionDescription(desc));\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n\n this.sendSignal(fromUserId, JSON.stringify(answer));\n } else if (desc.type === 'answer') {\n // Answer to our offer\n const peerConn = this.peers.get(fromUserId);\n if (peerConn) {\n await peerConn.pc.setRemoteDescription(new RTCSessionDescription(desc));\n }\n }\n } else if (candidate) {\n // ICE candidate\n const peerConn = this.peers.get(fromUserId);\n if (peerConn) {\n const iceCandidate = new RTCIceCandidate(JSON.parse(candidate));\n await peerConn.pc.addIceCandidate(iceCandidate);\n }\n }\n }\n\n /** Remove a peer connection (when peer leaves) */\n removePeer(peerId: string): void {\n const peerConn = this.peers.get(peerId);\n if (!peerConn) return;\n\n peerConn.pc.close();\n peerConn.audioEl.srcObject = null;\n peerConn.audioEl.remove();\n this.peers.delete(peerId);\n }\n\n /** Stop voice — release microphone and close all connections */\n stop(): void {\n // Close all peer connections\n this.peers.forEach((peerConn, peerId) => {\n peerConn.pc.close();\n peerConn.audioEl.srcObject = null;\n peerConn.audioEl.remove();\n });\n this.peers.clear();\n\n // Release local microphone\n if (this.localStream) {\n this.localStream.getTracks().forEach((t) => t.stop());\n this.localStream = null;\n }\n\n this.state = 'inactive';\n }\n\n /** Get the number of active peer connections */\n getPeerCount(): number {\n return this.peers.size;\n }\n\n /** Clean up everything */\n dispose(): void {\n this.stop();\n }\n\n // --- Private ---\n\n private createPeerConnection(peerId: string): RTCPeerConnection {\n // If a connection already exists, close it first\n if (this.peers.has(peerId)) {\n this.removePeer(peerId);\n }\n\n const pc = new RTCPeerConnection({ iceServers: STUN_SERVERS });\n\n // Create audio element for remote stream\n const audioEl = document.createElement('audio');\n audioEl.autoplay = true;\n\n // Handle incoming remote track\n pc.ontrack = (event) => {\n audioEl.srcObject = event.streams[0] ?? new MediaStream([event.track]);\n };\n\n // Relay ICE candidates to the peer\n pc.onicecandidate = (event) => {\n if (event.candidate) {\n this.sendSignal(peerId, undefined, JSON.stringify(event.candidate));\n }\n };\n\n // Clean up on connection failure\n pc.onconnectionstatechange = () => {\n if (pc.connectionState === 'failed' || pc.connectionState === 'disconnected') {\n this.removePeer(peerId);\n }\n };\n\n this.peers.set(peerId, { pc, audioEl });\n return pc;\n }\n}\n","import { ICON_MIC, ICON_MIC_MUTED } from '../controls/icons.js';\nimport { setStaticHtml } from '../utils/static-html.js';\nimport type { VoiceManager } from './voice-manager.js';\n\n/**\n * Microphone toggle button for collaborative voice chat.\n *\n * First click starts voice (requests microphone).\n * Subsequent clicks toggle mute.\n * Shows mic icon (active) or mic-muted icon (muted).\n */\nexport class VoiceButton {\n private container: HTMLDivElement;\n private btn: HTMLButtonElement;\n private voiceManager: VoiceManager;\n private onVoiceStarted?: () => void;\n\n constructor(\n voiceManager: VoiceManager,\n onVoiceStarted?: () => void,\n ) {\n this.voiceManager = voiceManager;\n this.onVoiceStarted = onVoiceStarted;\n\n this.container = document.createElement('div');\n this.container.style.position = 'relative';\n this.container.style.display = 'inline-flex';\n\n this.btn = document.createElement('button');\n this.btn.className = 'vz-btn vz-voice-btn';\n setStaticHtml(this.btn, ICON_MIC);\n this.btn.title = 'Voice Chat (V)';\n this.btn.style.opacity = '0.5'; // Dimmed when inactive\n this.btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.handleClick();\n });\n\n this.container.appendChild(this.btn);\n }\n\n /** Get the DOM element to insert into controls */\n getElement(): HTMLDivElement {\n return this.container;\n }\n\n /** Update button icon based on current voice state */\n updateState(): void {\n const state = this.voiceManager.getState();\n switch (state) {\n case 'inactive':\n setStaticHtml(this.btn, ICON_MIC);\n this.btn.style.opacity = '0.5';\n this.btn.title = 'Start Voice Chat (V)';\n break;\n case 'active':\n setStaticHtml(this.btn, ICON_MIC);\n this.btn.style.opacity = '1';\n this.btn.title = 'Mute (V)';\n break;\n case 'muted':\n setStaticHtml(this.btn, ICON_MIC_MUTED);\n this.btn.style.opacity = '1';\n this.btn.title = 'Unmute (V)';\n break;\n }\n }\n\n /** Handle toggle via keyboard shortcut */\n toggle(): void {\n this.handleClick();\n }\n\n /** Clean up */\n dispose(): void {\n this.container.remove();\n }\n\n // --- Private ---\n\n private handleClick(): void {\n if (!this.voiceManager.isActive()) {\n // First click — start voice\n this.voiceManager.start().then(() => {\n this.updateState();\n this.onVoiceStarted?.();\n }).catch((err) => {\n console.warn('[Vizor Voice] Failed to start:', err);\n });\n } else {\n // Toggle mute\n this.voiceManager.toggleMute();\n this.updateState();\n }\n }\n}\n"],"names":["PEER_COLORS"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-button.d.ts","sourceRoot":"","sources":["../../src/collaborative/chat-button.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat-button.d.ts","sourceRoot":"","sources":["../../src/collaborative/chat-button.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,SAAS,CAAY;gBAEjB,SAAS,EAAE,SAAS;IA2BhC,4CAA4C;IAC5C,eAAe,IAAI,IAAI;IAKvB,wCAAwC;IACxC,WAAW,IAAI,IAAI;IAKnB,kDAAkD;IAClD,UAAU,IAAI,cAAc;IAI5B,eAAe;IACf,OAAO,IAAI,IAAI;IAIf,OAAO,CAAC,WAAW;CASpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-button.d.ts","sourceRoot":"","sources":["../../src/collaborative/voice-button.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"voice-button.d.ts","sourceRoot":"","sources":["../../src/collaborative/voice-button.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,cAAc,CAAC,CAAa;gBAGlC,YAAY,EAAE,YAAY,EAC1B,cAAc,CAAC,EAAE,MAAM,IAAI;IAsB7B,kDAAkD;IAClD,UAAU,IAAI,cAAc;IAI5B,sDAAsD;IACtD,WAAW,IAAI,IAAI;IAqBnB,0CAA0C;IAC1C,MAAM,IAAI,IAAI;IAId,eAAe;IACf,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,WAAW;CAepB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cc-button.d.ts","sourceRoot":"","sources":["../../src/controls/cc-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"cc-button.d.ts","sourceRoot":"","sources":["../../src/controls/cc-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGvE;;;;;GAKG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,MAAM,CAAS;gBAEX,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe;IAuChE,UAAU,IAAI,cAAc;IAI5B,oEAAoE;IACpE,gBAAgB,IAAI,IAAI;IAKxB,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,aAAa;CA0CtB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compass.d.ts","sourceRoot":"","sources":["../../src/controls/compass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"compass.d.ts","sourceRoot":"","sources":["../../src/controls/compass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAG1D;;;;GAIG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAyB;gBAEjC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU;IAoBpD,UAAU,IAAI,iBAAiB;IAI/B,OAAO,IAAI,IAAI;CAGhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controls-overlay.d.ts","sourceRoot":"","sources":["../../src/controls/controls-overlay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"controls-overlay.d.ts","sourceRoot":"","sources":["../../src/controls/controls-overlay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAK/D;;;;;;;;;;;GAWG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,QAAQ,CAAyB;gBAGvC,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,cAAc;IAkGzB,kDAAkD;IAClD,IAAI,IAAI,IAAI;IAMZ,oBAAoB;IACpB,IAAI,IAAI,IAAI;IAMZ,2CAA2C;IAC3C,UAAU,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI;IAiBhF;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAWhE,8CAA8C;IAC9C,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,YAAY;CAIrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fullscreen-button.d.ts","sourceRoot":"","sources":["../../src/controls/fullscreen-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"fullscreen-button.d.ts","sourceRoot":"","sources":["../../src/controls/fullscreen-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAI3D,UAAU,gBAAgB;IACxB,gBAAgB,IAAI,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAyB;gBAEjC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB;IAiB9D,UAAU,IAAI,iBAAiB;IAI/B,OAAO,IAAI,IAAI;CAGhB"}
|
package/dist/controls/icons.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare const ICON_PLAYLIST_NEXT = "<svg viewBox=\"0 0 24 24\" fill=\"non
|
|
|
17
17
|
export declare const ICON_PLAYLIST_PREV = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"19 20 9 12 19 4 19 20\" fill=\"currentColor\"/><line x1=\"5\" y1=\"19\" x2=\"5\" y2=\"5\"/></svg>";
|
|
18
18
|
export declare const ICON_LIVE_DOT = "<svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"6\" fill=\"currentColor\"/></svg>";
|
|
19
19
|
export declare const ICON_CC = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" ry=\"2\"/><path d=\"M7 10.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5\"/><path d=\"M7 13.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5\"/><path d=\"M14 10.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5\"/><path d=\"M14 13.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5\"/></svg>";
|
|
20
|
+
export declare const ICON_CHAPTERS = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"8\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"8\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"8\" y1=\"18\" x2=\"21\" y2=\"18\"/><line x1=\"3\" y1=\"6\" x2=\"3.01\" y2=\"6\"/><line x1=\"3\" y1=\"12\" x2=\"3.01\" y2=\"12\"/><line x1=\"3\" y1=\"18\" x2=\"3.01\" y2=\"18\"/></svg>";
|
|
20
21
|
export declare const ICON_CHAT = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>";
|
|
21
22
|
export declare const ICON_MIC = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"/><path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"/><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"/></svg>";
|
|
22
23
|
export declare const ICON_MIC_MUTED = "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"/><path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\"/><path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2c0 .64-.09 1.26-.26 1.85\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"/><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"/></svg>";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/controls/icons.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,SAAS,iEAA6D,CAAC;AAEpF,eAAO,MAAM,UAAU,mFAA+E,CAAC;AAEvG,eAAO,MAAM,gBAAgB,wUAAkT,CAAC;AAEhV,eAAO,MAAM,eAAe,2RAAuQ,CAAC;AAEpS,eAAO,MAAM,iBAAiB,6UAA2S,CAAC;AAE1U,eAAO,MAAM,eAAe,0TAA0R,CAAC;AAEvT,eAAO,MAAM,oBAAoB,8TAA8R,CAAC;AAEhU,eAAO,MAAM,OAAO,6cAAyc,CAAC;AAE9d,eAAO,MAAM,YAAY,4RAAsQ,CAAC;AAEhS,eAAO,MAAM,aAAa,65BAAy4B,CAAC;AAGp6B,eAAO,MAAM,kBAAkB,gQAAwO,CAAC;AAExQ,eAAO,MAAM,kBAAkB,iQAAyO,CAAC;AAEzQ,eAAO,MAAM,aAAa,iGAAuF,CAAC;AAElH,eAAO,MAAM,OAAO,gcAAga,CAAC;AAErb,eAAO,MAAM,SAAS,+NAAiN,CAAC;AAExO,eAAO,MAAM,QAAQ,2VAA2T,CAAC;AAEjV,eAAO,MAAM,cAAc,0aAAkY,CAAC"}
|
|
1
|
+
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/controls/icons.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,SAAS,iEAA6D,CAAC;AAEpF,eAAO,MAAM,UAAU,mFAA+E,CAAC;AAEvG,eAAO,MAAM,gBAAgB,wUAAkT,CAAC;AAEhV,eAAO,MAAM,eAAe,2RAAuQ,CAAC;AAEpS,eAAO,MAAM,iBAAiB,6UAA2S,CAAC;AAE1U,eAAO,MAAM,eAAe,0TAA0R,CAAC;AAEvT,eAAO,MAAM,oBAAoB,8TAA8R,CAAC;AAEhU,eAAO,MAAM,OAAO,6cAAyc,CAAC;AAE9d,eAAO,MAAM,YAAY,4RAAsQ,CAAC;AAEhS,eAAO,MAAM,aAAa,65BAAy4B,CAAC;AAGp6B,eAAO,MAAM,kBAAkB,gQAAwO,CAAC;AAExQ,eAAO,MAAM,kBAAkB,iQAAyO,CAAC;AAEzQ,eAAO,MAAM,aAAa,iGAAuF,CAAC;AAElH,eAAO,MAAM,OAAO,gcAAga,CAAC;AAErb,eAAO,MAAM,aAAa,0aAA8W,CAAC;AAEzY,eAAO,MAAM,SAAS,+NAAiN,CAAC;AAExO,eAAO,MAAM,QAAQ,2VAA2T,CAAC;AAEjV,eAAO,MAAM,cAAc,0aAAkY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-indicator.d.ts","sourceRoot":"","sources":["../../src/controls/live-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"live-indicator.d.ts","sourceRoot":"","sources":["../../src/controls/live-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAI3D;;;;GAIG;AACH,qBAAa,aAAa;IAMQ,OAAO,CAAC,YAAY;IALpD,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,YAAY,CAAyB;gBAEjC,KAAK,EAAE,WAAW,EAAU,YAAY,EAAE,MAAM,IAAI;IA6ChE,UAAU,IAAI,cAAc;IAI5B,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"play-button.d.ts","sourceRoot":"","sources":["../../src/controls/play-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"play-button.d.ts","sourceRoot":"","sources":["../../src/controls/play-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,YAAY,CAAyB;gBAEjC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW;IA8CtF,UAAU,IAAI,iBAAiB;IAI/B,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playlist-controls.d.ts","sourceRoot":"","sources":["../../src/controls/playlist-controls.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"playlist-controls.d.ts","sourceRoot":"","sources":["../../src/controls/playlist-controls.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,aAAa,CAAqB;gBAGxC,YAAY,EAAE,WAAW,EACzB,aAAa,EAAE,WAAW,GAAG,IAAI,EACjC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,IAAI,EAClB,MAAM,EAAE,MAAM,IAAI,EAClB,aAAa,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI;IA8DpC,iCAAiC;IACjC,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAItD,+BAA+B;IAC/B,OAAO,IAAI,IAAI;CAMhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quality-menu.d.ts","sourceRoot":"","sources":["../../src/controls/quality-menu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"quality-menu.d.ts","sourceRoot":"","sources":["../../src/controls/quality-menu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAGpE;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,MAAM,CAAS;gBAEX,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa;IA4C5D,UAAU,IAAI,cAAc;IAI5B,OAAO,IAAI,IAAI;IAIf,OAAO,CAAC,aAAa;CAsCtB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PlayerState } from '../core/player-state.js';
|
|
2
2
|
import type { VzMediaElement } from '../core/media-element.js';
|
|
3
|
+
import type { ChapterMarker } from '../chapters/chapter-logic.js';
|
|
3
4
|
/**
|
|
4
5
|
* Seek bar with played/buffered progress, time display, and hover tooltip.
|
|
5
6
|
*/
|
|
@@ -12,9 +13,17 @@ export declare class SeekBar {
|
|
|
12
13
|
private tooltip;
|
|
13
14
|
private input;
|
|
14
15
|
private track;
|
|
16
|
+
private chapterLayer;
|
|
15
17
|
private unsubscribes;
|
|
16
18
|
constructor(state: PlayerState, mediaElement: VzMediaElement);
|
|
17
19
|
getElement(): HTMLDivElement;
|
|
20
|
+
/**
|
|
21
|
+
* Render chapter tick markers on the seek track. Markers are purely visual
|
|
22
|
+
* (pointer-events: none) so they never interfere with the range input; the
|
|
23
|
+
* native `title` shows the chapter label on hover. Re-render on duration
|
|
24
|
+
* change by calling again; pass [] to clear.
|
|
25
|
+
*/
|
|
26
|
+
setChapterMarkers(markers: ChapterMarker[]): void;
|
|
18
27
|
getTimeDisplay(): HTMLSpanElement;
|
|
19
28
|
dispose(): void;
|
|
20
29
|
private updateProgress;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seek-bar.d.ts","sourceRoot":"","sources":["../../src/controls/seek-bar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"seek-bar.d.ts","sourceRoot":"","sources":["../../src/controls/seek-bar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE;;GAEG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,YAAY,CAAyB;gBAEjC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc;IA6F5D,UAAU,IAAI,cAAc;IAI5B;;;;;OAKG;IACH,iBAAiB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI;IAgBjD,cAAc,IAAI,eAAe;IAIjC,OAAO,IAAI,IAAI;IAIf,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,UAAU;CAWnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"volume-control.d.ts","sourceRoot":"","sources":["../../src/controls/volume-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"volume-control.d.ts","sourceRoot":"","sources":["../../src/controls/volume-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,YAAY,CAAyB;gBAEjC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc;IAgE5D,UAAU,IAAI,cAAc;IAI5B,OAAO,IAAI,IAAI;CAGhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vr-button.d.ts","sourceRoot":"","sources":["../../src/controls/vr-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"vr-button.d.ts","sourceRoot":"","sources":["../../src/controls/vr-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAI3D;;;;GAIG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAyB;gBAEjC,KAAK,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM,IAAI;IA6BvD,UAAU,IAAI,iBAAiB;IAI/B,OAAO,IAAI,IAAI;CAGhB"}
|
|
@@ -25,6 +25,14 @@ export declare abstract class VzBaseElement extends HTMLElementBase {
|
|
|
25
25
|
private watermarkEl;
|
|
26
26
|
constructor();
|
|
27
27
|
connectedCallback(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Optional async hook run after config/styles are resolved but BEFORE
|
|
30
|
+
* onConnected(). Return a promise to defer onConnected() until it settles
|
|
31
|
+
* (e.g. to inject fetched DOM children); return void (default) to keep the
|
|
32
|
+
* connect path synchronous. Subclasses override.
|
|
33
|
+
*/
|
|
34
|
+
protected beforeConnect(): Promise<void> | void;
|
|
35
|
+
private finishConnect;
|
|
28
36
|
disconnectedCallback(): void;
|
|
29
37
|
attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null): void;
|
|
30
38
|
/** Get the resolved player configuration */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-element.d.ts","sourceRoot":"","sources":["../../src/core/base-element.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAY,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"base-element.d.ts","sourceRoot":"","sources":["../../src/core/base-element.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAY,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AA8EpD;;;;;;;;;;GAUG;AACH,8BAAsB,aAAc,SAAQ,eAAe;IACzD,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;IAED,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC;IAC7B,SAAS,CAAC,KAAK,EAAE,WAAW,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC;IACjC,SAAS,CAAC,MAAM,EAAG,YAAY,CAAC;IAChC,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAQ;IAC/C,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,UAAU,CAAsC;IACxD,OAAO,CAAC,WAAW,CAA4B;;IAS/C,iBAAiB,IAAI,IAAI;IAiCzB;;;;;OAKG;IACH,SAAS,CAAC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI/C,OAAO,CAAC,aAAa;IASrB,oBAAoB,IAAI,IAAI;IAS5B,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAQ1F,4CAA4C;IAC5C,SAAS,IAAI,QAAQ,CAAC,YAAY,CAAC;IAInC,mCAAmC;IACnC,QAAQ,IAAI,WAAW;IAIvB,4DAA4D;IAC5D,UAAU,IAAI,QAAQ,CAAC,aAAa,CAAC,GAAG,IAAI;IAI5C,2DAA2D;IAC3D,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,YAAY,GAAG,OAAO;IAO1D,SAAS,CAAC,QAAQ,CAAC,WAAW,IAAI,IAAI;IACtC,SAAS,CAAC,QAAQ,CAAC,cAAc,IAAI,IAAI;IACzC,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CACnC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,IAAI;IACP,SAAS,CAAC,QAAQ,CAAC,QAAQ,IAAI,IAAI;IAEnC,kFAAkF;IAClF,SAAS,CAAC,iBAAiB,IAAI,IAAI;IAMnC,8CAA8C;YAChC,iBAAiB;IA0D/B,kEAAkE;IAClE,OAAO,CAAC,WAAW;IAmCnB,4DAA4D;IAC5D,OAAO,CAAC,WAAW;IA4BnB,iDAAiD;IACjD,OAAO,CAAC,gBAAgB;CAyCzB"}
|