@ct-player/embed 1.1.11 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1908,6 +1908,40 @@ interface StreamingRecordingInfo {
1908
1908
  /** Creation timestamp (ISO 8601) */
1909
1909
  createdAt: string;
1910
1910
  }
1911
+ /**
1912
+ * Video quality level information
1913
+ */
1914
+ interface VideoQuality {
1915
+ /** Quality name (low, medium, high) */
1916
+ name: string;
1917
+ /** Bitrate in bits per second */
1918
+ bitrate: number;
1919
+ /** Video width in pixels */
1920
+ width: number;
1921
+ /** Video height in pixels */
1922
+ height: number;
1923
+ /** URL to the quality-specific playlist */
1924
+ playlistUrl?: string;
1925
+ }
1926
+ /**
1927
+ * Video streaming configuration (webcam overlay)
1928
+ */
1929
+ interface StreamingVideoConfig {
1930
+ /** Video type (always 'hls' for adaptive streaming) */
1931
+ type: 'hls';
1932
+ /** URL to the HLS master playlist */
1933
+ masterPlaylistUrl: string;
1934
+ /** Available quality levels */
1935
+ qualities: VideoQuality[];
1936
+ /** Video duration in seconds */
1937
+ duration: number;
1938
+ /** Video width in pixels */
1939
+ width: number;
1940
+ /** Video height in pixels */
1941
+ height: number;
1942
+ /** Video codec */
1943
+ codec: string;
1944
+ }
1911
1945
  /**
1912
1946
  * Audio streaming configuration
1913
1947
  */
@@ -1960,6 +1994,8 @@ interface StreamingManifest {
1960
1994
  recording: StreamingRecordingInfo;
1961
1995
  /** Audio streaming configuration */
1962
1996
  audio: StreamingAudioConfig;
1997
+ /** Video streaming configuration (present when webcam was recorded) */
1998
+ video?: StreamingVideoConfig;
1963
1999
  /** Events streaming configuration */
1964
2000
  events: StreamingEventsConfig;
1965
2001
  /** Streaming playback hints */
@@ -2038,8 +2074,10 @@ interface RemoteStreamingPlaybackState {
2038
2074
  isPlaying: boolean;
2039
2075
  /** Current playback speed */
2040
2076
  speed: number;
2041
- /** Whether the player is ready */
2077
+ /** Whether the player is ready (UI can render — audio+events loaded) */
2042
2078
  isReady: boolean;
2079
+ /** Whether ALL sources are loaded and synced (audio+video+events) */
2080
+ allSourcesReady: boolean;
2043
2081
  /** Whether currently buffering */
2044
2082
  isBuffering: boolean;
2045
2083
  /** Buffer health information */
@@ -2065,6 +2103,10 @@ interface RemoteStreamingPlaybackControls {
2065
2103
  setSpeed(speed: number): void;
2066
2104
  /** Get the audio element for custom controls */
2067
2105
  getAudioElement(): HTMLAudioElement | null;
2106
+ /** Get the video element for webcam overlay (null if no video) */
2107
+ getVideoElement(): HTMLVideoElement | null;
2108
+ /** Attach HLS video player to a video element (from WebcamOverlay onVideoRef) */
2109
+ initVideoHls(videoElement: HTMLVideoElement | null): void;
2068
2110
  }
2069
2111
  /**
2070
2112
  * HLS player configuration
@@ -2453,6 +2495,7 @@ interface PlaybackControls {
2453
2495
  setVolume(volume: number): void;
2454
2496
  setMuted(muted: boolean): void;
2455
2497
  setAudioElement(audio: HTMLAudioElement | null): void;
2498
+ setVideoElement(video: HTMLVideoElement | null): void;
2456
2499
  enterInteractiveMode(): void;
2457
2500
  exitInteractiveMode(): void;
2458
2501
  setInteractiveCode(code: string): void;
@@ -2717,16 +2760,77 @@ declare function useAudioElement(src: string | null): {
2717
2760
  error: Error | null;
2718
2761
  duration: number;
2719
2762
  };
2720
- /** @deprecated Use AudioSyncState instead */
2721
- type VideoSyncState = AudioSyncState;
2722
- /** @deprecated Use AudioSyncControls instead */
2723
- type VideoSyncControls = AudioSyncControls;
2724
- /** @deprecated Use UseAudioSyncOptions instead */
2725
- type UseVideoSyncOptions = UseAudioSyncOptions;
2726
- /** @deprecated Use useAudioSync instead */
2727
- declare const useVideoSync: typeof useAudioSync;
2728
- /** @deprecated Use useAudioElement instead */
2729
- declare const useVideoElement: typeof useAudioElement;
2763
+
2764
+ /**
2765
+ * useVideoSync Hook
2766
+ *
2767
+ * Synchronizes video playback with event state.
2768
+ * Handles video/event drift and maintains sync within tolerance.
2769
+ *
2770
+ * @packageDocumentation
2771
+ */
2772
+ /**
2773
+ * Video sync state
2774
+ */
2775
+ interface VideoSyncState {
2776
+ /** Current video time in ms */
2777
+ videoTime: number;
2778
+ /** Current event time in ms */
2779
+ eventTime: number;
2780
+ /** Drift between video and events (ms) */
2781
+ drift: number;
2782
+ /** Is sync healthy (within tolerance) */
2783
+ isSynced: boolean;
2784
+ /** Is video loaded */
2785
+ isVideoReady: boolean;
2786
+ }
2787
+ /**
2788
+ * Video sync controls
2789
+ */
2790
+ interface VideoSyncControls {
2791
+ /** Sync events to video time */
2792
+ syncToVideo(): void;
2793
+ /** Sync video to event time */
2794
+ syncVideoTo(timeMs: number): void;
2795
+ /** Force resync */
2796
+ forceResync(): void;
2797
+ }
2798
+ /**
2799
+ * Options for useVideoSync hook
2800
+ */
2801
+ interface UseVideoSyncOptions {
2802
+ /** Reference to video element */
2803
+ videoRef: React.RefObject<HTMLVideoElement>;
2804
+ /** Current event time */
2805
+ eventTime: number;
2806
+ /** Is currently playing */
2807
+ isPlaying: boolean;
2808
+ /** Playback speed */
2809
+ speed: number;
2810
+ /** Maximum allowed drift in ms before resync (default: 500ms) */
2811
+ driftTolerance?: number;
2812
+ /** Callback when video time updates */
2813
+ onVideoTimeUpdate?: (timeMs: number) => void;
2814
+ /** Callback when sync is lost */
2815
+ onSyncLost?: (drift: number) => void;
2816
+ /** Callback when sync is restored */
2817
+ onSyncRestored?: () => void;
2818
+ }
2819
+ /**
2820
+ * Hook for synchronizing video playback with event state
2821
+ */
2822
+ declare function useVideoSync(options: UseVideoSyncOptions): VideoSyncState & {
2823
+ controls: VideoSyncControls;
2824
+ };
2825
+ /**
2826
+ * Hook for managing video element lifecycle
2827
+ */
2828
+ declare function useVideoElement(src: string | null): {
2829
+ videoRef: react.MutableRefObject<HTMLVideoElement | null>;
2830
+ isLoaded: boolean;
2831
+ error: Error | null;
2832
+ duration: number;
2833
+ };
2730
2834
 
2731
2835
  /**
2732
2836
  * HLS Loader Utility
@@ -2757,6 +2861,29 @@ interface HLSPlayerInstance {
2757
2861
  /** Remove event listener */
2758
2862
  off: (event: string, callback: (...args: unknown[]) => void) => void;
2759
2863
  }
2864
+ /**
2865
+ * HLS video player instance (mirrors HLSPlayerInstance but for video elements)
2866
+ */
2867
+ interface HLSVideoPlayerInstance {
2868
+ /** The HLS.js instance (null if using native HLS) */
2869
+ hls: Hls | null;
2870
+ /** The video element */
2871
+ videoElement: HTMLVideoElement;
2872
+ /** Whether this is using native HLS (Safari) */
2873
+ isNative: boolean;
2874
+ /** Destroy and cleanup */
2875
+ destroy: () => void;
2876
+ /** Get current quality levels */
2877
+ getQualityLevels: () => HLSQualityLevel[];
2878
+ /** Set quality level (-1 for auto) */
2879
+ setQualityLevel: (index: number) => void;
2880
+ /** Get current quality level */
2881
+ getCurrentQualityLevel: () => number;
2882
+ /** Add event listener for HLS events */
2883
+ on: (event: string, callback: (...args: unknown[]) => void) => void;
2884
+ /** Remove event listener */
2885
+ off: (event: string, callback: (...args: unknown[]) => void) => void;
2886
+ }
2760
2887
  interface HLSEvents {
2761
2888
  /** Manifest has been parsed and is ready */
2762
2889
  MANIFEST_PARSED: 'hlsManifestParsed';
@@ -2795,7 +2922,7 @@ declare function createHlsPlayer(audioElement: HTMLAudioElement, masterPlaylistU
2795
2922
  /**
2796
2923
  * Destroy an HLS player instance safely
2797
2924
  */
2798
- declare function destroyHlsPlayer(player: HLSPlayerInstance | null): void;
2925
+ declare function destroyHlsPlayer(player: HLSPlayerInstance | HLSVideoPlayerInstance | null): void;
2799
2926
 
2800
2927
  interface Marker$1 {
2801
2928
  time: number;
@@ -2908,11 +3035,11 @@ declare function Timeline({ currentTime, duration, markers, chunks, buffered, on
2908
3035
  /**
2909
3036
  * Overlay position presets
2910
3037
  */
2911
- type OverlayPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'custom';
3038
+ type OverlayPosition$1 = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'custom';
2912
3039
  /**
2913
3040
  * Custom position
2914
3041
  */
2915
- interface CustomPosition {
3042
+ interface CustomPosition$1 {
2916
3043
  x: number;
2917
3044
  y: number;
2918
3045
  }
@@ -2929,9 +3056,9 @@ interface AudioOverlayProps {
2929
3056
  /** Playback rate */
2930
3057
  playbackRate?: number;
2931
3058
  /** Overlay position preset */
2932
- position?: OverlayPosition;
3059
+ position?: OverlayPosition$1;
2933
3060
  /** Custom position (when position='custom') */
2934
- customPosition?: CustomPosition;
3061
+ customPosition?: CustomPosition$1;
2935
3062
  /** Whether to show the overlay */
2936
3063
  visible?: boolean;
2937
3064
  /** Enable dragging */
@@ -2941,7 +3068,7 @@ interface AudioOverlayProps {
2941
3068
  /** Opacity (0-1) */
2942
3069
  opacity?: number;
2943
3070
  /** On position change callback */
2944
- onPositionChange?: (position: CustomPosition) => void;
3071
+ onPositionChange?: (position: CustomPosition$1) => void;
2945
3072
  /** Callback to pass audio element reference for sync */
2946
3073
  onAudioRef?: (audio: HTMLAudioElement | null) => void;
2947
3074
  /** Whether audio is muted */
@@ -2960,4 +3087,90 @@ interface AudioOverlayProps {
2960
3087
  */
2961
3088
  declare function AudioOverlay({ src, currentTime: _currentTime, isPlaying: _isPlaying, playbackRate: _playbackRate, position, customPosition, visible, draggable, showControls, opacity, onPositionChange, onAudioRef, muted: _muted, volume: _volume, syncTolerance: _syncTolerance, }: AudioOverlayProps): JSX.Element | null;
2962
3089
 
2963
- export { AudioOverlay, type AudioOverlayProps, type AudioQuality, type AudioSyncControls, type AudioSyncState, type BackendAdapter, type BufferHealth, type CTEvent, type CTManifest, type CTMarker, type CTReadOptions, type CTRecording, CoursePlayer, type CoursePlayerProps, type CoursePlayerRef, type CursorPosition, type CustomPosition, DocumentPanel, type DocumentPanelProps, FileExplorer, type FileExplorerProps, type FileSystemSnapshot, type HLSPlayerInstance, HLS_EVENTS, IDEPanel, type IDEPanelProps, type InternalEvent, type InternalRecording, type OverlayPosition, type PanelMode, type PlaybackControls$1 as PlaybackControls, type PlaybackEngineConfig, type PlaybackHookState, type PlaybackState, PlayerControls, type PlayerControlsProps$1 as PlayerControlsProps, type PlayerProps, type PlayerRef, type RecordingMarker, type RemoteBufferHealth, type RemoteStreamingMetrics, type RemoteStreamingPlaybackControls, type RemoteStreamingPlaybackState, type SpeedSelectorProps, type StreamingAudioConfig, type StreamingConfig, StreamingCoursePlayer, type StreamingCoursePlayerProps, type StreamingCoursePlayerRef, type StreamingEventsConfig, type StreamingManifest, type StreamingMetrics, type StreamingPlaybackControls, type StreamingPlaybackState, type StreamingRecordingInfo, Terminal, type TerminalLineData, type TerminalProps, Timeline, type TimelineProps$1 as TimelineProps, ToolSidebar, type ToolSidebarProps, type ToolType, type UseAudioSyncOptions, type UsePlaybackEngineResult, type UsePlaybackOptions, type UseRemoteStreamingPlaybackOptions, type UseVideoSyncOptions, type ValidationResult$1 as ValidationResult, type VideoSyncControls, type VideoSyncState, type VolumeControlProps, AudioOverlay as WebcamOverlay, type AudioOverlayProps as WebcamOverlayProps, WhiteboardPanel, type WhiteboardPanelProps, type WriteCTOptions, canPlayHls, createEmptyRecording, createHlsPlayer, destroyHlsPlayer, hasNativeHlsSupport, isHlsSupported, readCTFile, readCTManifest, useAudioElement, useAudioSync, useInteractiveMode, usePlayback, usePlayback as usePlaybackEngine, useRemoteStreamingPlayback, useStreamingPlayback, useVideoElement, useVideoSync, validateCTFile, writeCTFile };
3090
+ /**
3091
+ * WebcamOverlay Component
3092
+ *
3093
+ * Circular webcam video overlay with draggable positioning,
3094
+ * resize handles, and video sync. Matches frontend styling.
3095
+ *
3096
+ * @packageDocumentation
3097
+ */
3098
+ /**
3099
+ * Overlay position presets
3100
+ */
3101
+ type OverlayPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'custom';
3102
+ /**
3103
+ * Overlay size presets
3104
+ */
3105
+ type OverlaySize = 'small' | 'medium' | 'large' | 'custom';
3106
+ /**
3107
+ * Custom position
3108
+ */
3109
+ interface CustomPosition {
3110
+ x: number;
3111
+ y: number;
3112
+ }
3113
+ /**
3114
+ * Custom size
3115
+ */
3116
+ interface CustomSize {
3117
+ width: number;
3118
+ height: number;
3119
+ }
3120
+ /**
3121
+ * Props for WebcamOverlay component
3122
+ */
3123
+ interface WebcamOverlayProps {
3124
+ /** Video source URL */
3125
+ src: string | null;
3126
+ /** Current time to sync to (ms) */
3127
+ currentTime: number;
3128
+ /** Whether video should be playing */
3129
+ isPlaying: boolean;
3130
+ /** Playback rate */
3131
+ playbackRate?: number;
3132
+ /** Overlay position preset */
3133
+ position?: OverlayPosition;
3134
+ /** Custom position (when position='custom') */
3135
+ customPosition?: CustomPosition;
3136
+ /** Size preset */
3137
+ size?: OverlaySize;
3138
+ /** Custom size (when size='custom') */
3139
+ customSize?: CustomSize;
3140
+ /** Whether to show the overlay */
3141
+ visible?: boolean;
3142
+ /** Enable dragging */
3143
+ draggable?: boolean;
3144
+ /** Enable resize */
3145
+ resizable?: boolean;
3146
+ /** Show controls on hover */
3147
+ showControls?: boolean;
3148
+ /** Border radius (default is circular) */
3149
+ borderRadius?: number | 'circle';
3150
+ /** Opacity (0-1) */
3151
+ opacity?: number;
3152
+ /** On position change callback */
3153
+ onPositionChange?: (position: CustomPosition) => void;
3154
+ /** On size change callback */
3155
+ onSizeChange?: (size: CustomSize) => void;
3156
+ /** On visibility toggle callback */
3157
+ onVisibilityToggle?: () => void;
3158
+ /** Callback to pass video element reference for sync */
3159
+ onVideoRef?: (video: HTMLVideoElement | null) => void;
3160
+ /** Whether audio is muted */
3161
+ muted?: boolean;
3162
+ /** Volume level (0-1) */
3163
+ volume?: number;
3164
+ /** Sync tolerance in ms */
3165
+ syncTolerance?: number;
3166
+ }
3167
+ /**
3168
+ * Webcam overlay for instructor video
3169
+ *
3170
+ * NOTE: Video playback is now controlled entirely by parent (usePlayback).
3171
+ * Props like currentTime, isPlaying, playbackRate, muted, volume, syncTolerance
3172
+ * are kept for backward compatibility but are no longer used.
3173
+ */
3174
+ declare function WebcamOverlay({ src, currentTime: _currentTime, isPlaying: _isPlaying, playbackRate: _playbackRate, position, customPosition, size, customSize, visible, draggable, resizable, showControls, borderRadius, opacity, onPositionChange, onSizeChange: _onSizeChange, onVisibilityToggle: _onVisibilityToggle, onVideoRef, muted: _muted, volume: _volume, syncTolerance: _syncTolerance, }: WebcamOverlayProps): JSX.Element | null;
3175
+
3176
+ export { AudioOverlay, type AudioOverlayProps, type AudioQuality, type AudioSyncControls, type AudioSyncState, type BackendAdapter, type BufferHealth, type CTEvent, type CTManifest, type CTMarker, type CTReadOptions, type CTRecording, CoursePlayer, type CoursePlayerProps, type CoursePlayerRef, type CursorPosition, type CustomPosition$1 as CustomPosition, DocumentPanel, type DocumentPanelProps, FileExplorer, type FileExplorerProps, type FileSystemSnapshot, type HLSPlayerInstance, HLS_EVENTS, IDEPanel, type IDEPanelProps, type InternalEvent, type InternalRecording, type OverlayPosition$1 as OverlayPosition, type PanelMode, type PlaybackControls$1 as PlaybackControls, type PlaybackEngineConfig, type PlaybackHookState, type PlaybackState, PlayerControls, type PlayerControlsProps$1 as PlayerControlsProps, type PlayerProps, type PlayerRef, type RecordingMarker, type RemoteBufferHealth, type RemoteStreamingMetrics, type RemoteStreamingPlaybackControls, type RemoteStreamingPlaybackState, type SpeedSelectorProps, type StreamingAudioConfig, type StreamingConfig, StreamingCoursePlayer, type StreamingCoursePlayerProps, type StreamingCoursePlayerRef, type StreamingEventsConfig, type StreamingManifest, type StreamingMetrics, type StreamingPlaybackControls, type StreamingPlaybackState, type StreamingRecordingInfo, Terminal, type TerminalLineData, type TerminalProps, Timeline, type TimelineProps$1 as TimelineProps, ToolSidebar, type ToolSidebarProps, type ToolType, type UseAudioSyncOptions, type UsePlaybackEngineResult, type UsePlaybackOptions, type UseRemoteStreamingPlaybackOptions, type UseVideoSyncOptions, type ValidationResult$1 as ValidationResult, type VideoSyncControls, type VideoSyncState, type VolumeControlProps, WebcamOverlay, type WebcamOverlayProps, WhiteboardPanel, type WhiteboardPanelProps, type WriteCTOptions, canPlayHls, createEmptyRecording, createHlsPlayer, destroyHlsPlayer, hasNativeHlsSupport, isHlsSupported, readCTFile, readCTManifest, useAudioElement, useAudioSync, useInteractiveMode, usePlayback, usePlayback as usePlaybackEngine, useRemoteStreamingPlayback, useStreamingPlayback, useVideoElement, useVideoSync, validateCTFile, writeCTFile };
package/dist/index.d.ts CHANGED
@@ -1908,6 +1908,40 @@ interface StreamingRecordingInfo {
1908
1908
  /** Creation timestamp (ISO 8601) */
1909
1909
  createdAt: string;
1910
1910
  }
1911
+ /**
1912
+ * Video quality level information
1913
+ */
1914
+ interface VideoQuality {
1915
+ /** Quality name (low, medium, high) */
1916
+ name: string;
1917
+ /** Bitrate in bits per second */
1918
+ bitrate: number;
1919
+ /** Video width in pixels */
1920
+ width: number;
1921
+ /** Video height in pixels */
1922
+ height: number;
1923
+ /** URL to the quality-specific playlist */
1924
+ playlistUrl?: string;
1925
+ }
1926
+ /**
1927
+ * Video streaming configuration (webcam overlay)
1928
+ */
1929
+ interface StreamingVideoConfig {
1930
+ /** Video type (always 'hls' for adaptive streaming) */
1931
+ type: 'hls';
1932
+ /** URL to the HLS master playlist */
1933
+ masterPlaylistUrl: string;
1934
+ /** Available quality levels */
1935
+ qualities: VideoQuality[];
1936
+ /** Video duration in seconds */
1937
+ duration: number;
1938
+ /** Video width in pixels */
1939
+ width: number;
1940
+ /** Video height in pixels */
1941
+ height: number;
1942
+ /** Video codec */
1943
+ codec: string;
1944
+ }
1911
1945
  /**
1912
1946
  * Audio streaming configuration
1913
1947
  */
@@ -1960,6 +1994,8 @@ interface StreamingManifest {
1960
1994
  recording: StreamingRecordingInfo;
1961
1995
  /** Audio streaming configuration */
1962
1996
  audio: StreamingAudioConfig;
1997
+ /** Video streaming configuration (present when webcam was recorded) */
1998
+ video?: StreamingVideoConfig;
1963
1999
  /** Events streaming configuration */
1964
2000
  events: StreamingEventsConfig;
1965
2001
  /** Streaming playback hints */
@@ -2038,8 +2074,10 @@ interface RemoteStreamingPlaybackState {
2038
2074
  isPlaying: boolean;
2039
2075
  /** Current playback speed */
2040
2076
  speed: number;
2041
- /** Whether the player is ready */
2077
+ /** Whether the player is ready (UI can render — audio+events loaded) */
2042
2078
  isReady: boolean;
2079
+ /** Whether ALL sources are loaded and synced (audio+video+events) */
2080
+ allSourcesReady: boolean;
2043
2081
  /** Whether currently buffering */
2044
2082
  isBuffering: boolean;
2045
2083
  /** Buffer health information */
@@ -2065,6 +2103,10 @@ interface RemoteStreamingPlaybackControls {
2065
2103
  setSpeed(speed: number): void;
2066
2104
  /** Get the audio element for custom controls */
2067
2105
  getAudioElement(): HTMLAudioElement | null;
2106
+ /** Get the video element for webcam overlay (null if no video) */
2107
+ getVideoElement(): HTMLVideoElement | null;
2108
+ /** Attach HLS video player to a video element (from WebcamOverlay onVideoRef) */
2109
+ initVideoHls(videoElement: HTMLVideoElement | null): void;
2068
2110
  }
2069
2111
  /**
2070
2112
  * HLS player configuration
@@ -2453,6 +2495,7 @@ interface PlaybackControls {
2453
2495
  setVolume(volume: number): void;
2454
2496
  setMuted(muted: boolean): void;
2455
2497
  setAudioElement(audio: HTMLAudioElement | null): void;
2498
+ setVideoElement(video: HTMLVideoElement | null): void;
2456
2499
  enterInteractiveMode(): void;
2457
2500
  exitInteractiveMode(): void;
2458
2501
  setInteractiveCode(code: string): void;
@@ -2717,16 +2760,77 @@ declare function useAudioElement(src: string | null): {
2717
2760
  error: Error | null;
2718
2761
  duration: number;
2719
2762
  };
2720
- /** @deprecated Use AudioSyncState instead */
2721
- type VideoSyncState = AudioSyncState;
2722
- /** @deprecated Use AudioSyncControls instead */
2723
- type VideoSyncControls = AudioSyncControls;
2724
- /** @deprecated Use UseAudioSyncOptions instead */
2725
- type UseVideoSyncOptions = UseAudioSyncOptions;
2726
- /** @deprecated Use useAudioSync instead */
2727
- declare const useVideoSync: typeof useAudioSync;
2728
- /** @deprecated Use useAudioElement instead */
2729
- declare const useVideoElement: typeof useAudioElement;
2763
+
2764
+ /**
2765
+ * useVideoSync Hook
2766
+ *
2767
+ * Synchronizes video playback with event state.
2768
+ * Handles video/event drift and maintains sync within tolerance.
2769
+ *
2770
+ * @packageDocumentation
2771
+ */
2772
+ /**
2773
+ * Video sync state
2774
+ */
2775
+ interface VideoSyncState {
2776
+ /** Current video time in ms */
2777
+ videoTime: number;
2778
+ /** Current event time in ms */
2779
+ eventTime: number;
2780
+ /** Drift between video and events (ms) */
2781
+ drift: number;
2782
+ /** Is sync healthy (within tolerance) */
2783
+ isSynced: boolean;
2784
+ /** Is video loaded */
2785
+ isVideoReady: boolean;
2786
+ }
2787
+ /**
2788
+ * Video sync controls
2789
+ */
2790
+ interface VideoSyncControls {
2791
+ /** Sync events to video time */
2792
+ syncToVideo(): void;
2793
+ /** Sync video to event time */
2794
+ syncVideoTo(timeMs: number): void;
2795
+ /** Force resync */
2796
+ forceResync(): void;
2797
+ }
2798
+ /**
2799
+ * Options for useVideoSync hook
2800
+ */
2801
+ interface UseVideoSyncOptions {
2802
+ /** Reference to video element */
2803
+ videoRef: React.RefObject<HTMLVideoElement>;
2804
+ /** Current event time */
2805
+ eventTime: number;
2806
+ /** Is currently playing */
2807
+ isPlaying: boolean;
2808
+ /** Playback speed */
2809
+ speed: number;
2810
+ /** Maximum allowed drift in ms before resync (default: 500ms) */
2811
+ driftTolerance?: number;
2812
+ /** Callback when video time updates */
2813
+ onVideoTimeUpdate?: (timeMs: number) => void;
2814
+ /** Callback when sync is lost */
2815
+ onSyncLost?: (drift: number) => void;
2816
+ /** Callback when sync is restored */
2817
+ onSyncRestored?: () => void;
2818
+ }
2819
+ /**
2820
+ * Hook for synchronizing video playback with event state
2821
+ */
2822
+ declare function useVideoSync(options: UseVideoSyncOptions): VideoSyncState & {
2823
+ controls: VideoSyncControls;
2824
+ };
2825
+ /**
2826
+ * Hook for managing video element lifecycle
2827
+ */
2828
+ declare function useVideoElement(src: string | null): {
2829
+ videoRef: react.MutableRefObject<HTMLVideoElement | null>;
2830
+ isLoaded: boolean;
2831
+ error: Error | null;
2832
+ duration: number;
2833
+ };
2730
2834
 
2731
2835
  /**
2732
2836
  * HLS Loader Utility
@@ -2757,6 +2861,29 @@ interface HLSPlayerInstance {
2757
2861
  /** Remove event listener */
2758
2862
  off: (event: string, callback: (...args: unknown[]) => void) => void;
2759
2863
  }
2864
+ /**
2865
+ * HLS video player instance (mirrors HLSPlayerInstance but for video elements)
2866
+ */
2867
+ interface HLSVideoPlayerInstance {
2868
+ /** The HLS.js instance (null if using native HLS) */
2869
+ hls: Hls | null;
2870
+ /** The video element */
2871
+ videoElement: HTMLVideoElement;
2872
+ /** Whether this is using native HLS (Safari) */
2873
+ isNative: boolean;
2874
+ /** Destroy and cleanup */
2875
+ destroy: () => void;
2876
+ /** Get current quality levels */
2877
+ getQualityLevels: () => HLSQualityLevel[];
2878
+ /** Set quality level (-1 for auto) */
2879
+ setQualityLevel: (index: number) => void;
2880
+ /** Get current quality level */
2881
+ getCurrentQualityLevel: () => number;
2882
+ /** Add event listener for HLS events */
2883
+ on: (event: string, callback: (...args: unknown[]) => void) => void;
2884
+ /** Remove event listener */
2885
+ off: (event: string, callback: (...args: unknown[]) => void) => void;
2886
+ }
2760
2887
  interface HLSEvents {
2761
2888
  /** Manifest has been parsed and is ready */
2762
2889
  MANIFEST_PARSED: 'hlsManifestParsed';
@@ -2795,7 +2922,7 @@ declare function createHlsPlayer(audioElement: HTMLAudioElement, masterPlaylistU
2795
2922
  /**
2796
2923
  * Destroy an HLS player instance safely
2797
2924
  */
2798
- declare function destroyHlsPlayer(player: HLSPlayerInstance | null): void;
2925
+ declare function destroyHlsPlayer(player: HLSPlayerInstance | HLSVideoPlayerInstance | null): void;
2799
2926
 
2800
2927
  interface Marker$1 {
2801
2928
  time: number;
@@ -2908,11 +3035,11 @@ declare function Timeline({ currentTime, duration, markers, chunks, buffered, on
2908
3035
  /**
2909
3036
  * Overlay position presets
2910
3037
  */
2911
- type OverlayPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'custom';
3038
+ type OverlayPosition$1 = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'custom';
2912
3039
  /**
2913
3040
  * Custom position
2914
3041
  */
2915
- interface CustomPosition {
3042
+ interface CustomPosition$1 {
2916
3043
  x: number;
2917
3044
  y: number;
2918
3045
  }
@@ -2929,9 +3056,9 @@ interface AudioOverlayProps {
2929
3056
  /** Playback rate */
2930
3057
  playbackRate?: number;
2931
3058
  /** Overlay position preset */
2932
- position?: OverlayPosition;
3059
+ position?: OverlayPosition$1;
2933
3060
  /** Custom position (when position='custom') */
2934
- customPosition?: CustomPosition;
3061
+ customPosition?: CustomPosition$1;
2935
3062
  /** Whether to show the overlay */
2936
3063
  visible?: boolean;
2937
3064
  /** Enable dragging */
@@ -2941,7 +3068,7 @@ interface AudioOverlayProps {
2941
3068
  /** Opacity (0-1) */
2942
3069
  opacity?: number;
2943
3070
  /** On position change callback */
2944
- onPositionChange?: (position: CustomPosition) => void;
3071
+ onPositionChange?: (position: CustomPosition$1) => void;
2945
3072
  /** Callback to pass audio element reference for sync */
2946
3073
  onAudioRef?: (audio: HTMLAudioElement | null) => void;
2947
3074
  /** Whether audio is muted */
@@ -2960,4 +3087,90 @@ interface AudioOverlayProps {
2960
3087
  */
2961
3088
  declare function AudioOverlay({ src, currentTime: _currentTime, isPlaying: _isPlaying, playbackRate: _playbackRate, position, customPosition, visible, draggable, showControls, opacity, onPositionChange, onAudioRef, muted: _muted, volume: _volume, syncTolerance: _syncTolerance, }: AudioOverlayProps): JSX.Element | null;
2962
3089
 
2963
- export { AudioOverlay, type AudioOverlayProps, type AudioQuality, type AudioSyncControls, type AudioSyncState, type BackendAdapter, type BufferHealth, type CTEvent, type CTManifest, type CTMarker, type CTReadOptions, type CTRecording, CoursePlayer, type CoursePlayerProps, type CoursePlayerRef, type CursorPosition, type CustomPosition, DocumentPanel, type DocumentPanelProps, FileExplorer, type FileExplorerProps, type FileSystemSnapshot, type HLSPlayerInstance, HLS_EVENTS, IDEPanel, type IDEPanelProps, type InternalEvent, type InternalRecording, type OverlayPosition, type PanelMode, type PlaybackControls$1 as PlaybackControls, type PlaybackEngineConfig, type PlaybackHookState, type PlaybackState, PlayerControls, type PlayerControlsProps$1 as PlayerControlsProps, type PlayerProps, type PlayerRef, type RecordingMarker, type RemoteBufferHealth, type RemoteStreamingMetrics, type RemoteStreamingPlaybackControls, type RemoteStreamingPlaybackState, type SpeedSelectorProps, type StreamingAudioConfig, type StreamingConfig, StreamingCoursePlayer, type StreamingCoursePlayerProps, type StreamingCoursePlayerRef, type StreamingEventsConfig, type StreamingManifest, type StreamingMetrics, type StreamingPlaybackControls, type StreamingPlaybackState, type StreamingRecordingInfo, Terminal, type TerminalLineData, type TerminalProps, Timeline, type TimelineProps$1 as TimelineProps, ToolSidebar, type ToolSidebarProps, type ToolType, type UseAudioSyncOptions, type UsePlaybackEngineResult, type UsePlaybackOptions, type UseRemoteStreamingPlaybackOptions, type UseVideoSyncOptions, type ValidationResult$1 as ValidationResult, type VideoSyncControls, type VideoSyncState, type VolumeControlProps, AudioOverlay as WebcamOverlay, type AudioOverlayProps as WebcamOverlayProps, WhiteboardPanel, type WhiteboardPanelProps, type WriteCTOptions, canPlayHls, createEmptyRecording, createHlsPlayer, destroyHlsPlayer, hasNativeHlsSupport, isHlsSupported, readCTFile, readCTManifest, useAudioElement, useAudioSync, useInteractiveMode, usePlayback, usePlayback as usePlaybackEngine, useRemoteStreamingPlayback, useStreamingPlayback, useVideoElement, useVideoSync, validateCTFile, writeCTFile };
3090
+ /**
3091
+ * WebcamOverlay Component
3092
+ *
3093
+ * Circular webcam video overlay with draggable positioning,
3094
+ * resize handles, and video sync. Matches frontend styling.
3095
+ *
3096
+ * @packageDocumentation
3097
+ */
3098
+ /**
3099
+ * Overlay position presets
3100
+ */
3101
+ type OverlayPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'custom';
3102
+ /**
3103
+ * Overlay size presets
3104
+ */
3105
+ type OverlaySize = 'small' | 'medium' | 'large' | 'custom';
3106
+ /**
3107
+ * Custom position
3108
+ */
3109
+ interface CustomPosition {
3110
+ x: number;
3111
+ y: number;
3112
+ }
3113
+ /**
3114
+ * Custom size
3115
+ */
3116
+ interface CustomSize {
3117
+ width: number;
3118
+ height: number;
3119
+ }
3120
+ /**
3121
+ * Props for WebcamOverlay component
3122
+ */
3123
+ interface WebcamOverlayProps {
3124
+ /** Video source URL */
3125
+ src: string | null;
3126
+ /** Current time to sync to (ms) */
3127
+ currentTime: number;
3128
+ /** Whether video should be playing */
3129
+ isPlaying: boolean;
3130
+ /** Playback rate */
3131
+ playbackRate?: number;
3132
+ /** Overlay position preset */
3133
+ position?: OverlayPosition;
3134
+ /** Custom position (when position='custom') */
3135
+ customPosition?: CustomPosition;
3136
+ /** Size preset */
3137
+ size?: OverlaySize;
3138
+ /** Custom size (when size='custom') */
3139
+ customSize?: CustomSize;
3140
+ /** Whether to show the overlay */
3141
+ visible?: boolean;
3142
+ /** Enable dragging */
3143
+ draggable?: boolean;
3144
+ /** Enable resize */
3145
+ resizable?: boolean;
3146
+ /** Show controls on hover */
3147
+ showControls?: boolean;
3148
+ /** Border radius (default is circular) */
3149
+ borderRadius?: number | 'circle';
3150
+ /** Opacity (0-1) */
3151
+ opacity?: number;
3152
+ /** On position change callback */
3153
+ onPositionChange?: (position: CustomPosition) => void;
3154
+ /** On size change callback */
3155
+ onSizeChange?: (size: CustomSize) => void;
3156
+ /** On visibility toggle callback */
3157
+ onVisibilityToggle?: () => void;
3158
+ /** Callback to pass video element reference for sync */
3159
+ onVideoRef?: (video: HTMLVideoElement | null) => void;
3160
+ /** Whether audio is muted */
3161
+ muted?: boolean;
3162
+ /** Volume level (0-1) */
3163
+ volume?: number;
3164
+ /** Sync tolerance in ms */
3165
+ syncTolerance?: number;
3166
+ }
3167
+ /**
3168
+ * Webcam overlay for instructor video
3169
+ *
3170
+ * NOTE: Video playback is now controlled entirely by parent (usePlayback).
3171
+ * Props like currentTime, isPlaying, playbackRate, muted, volume, syncTolerance
3172
+ * are kept for backward compatibility but are no longer used.
3173
+ */
3174
+ declare function WebcamOverlay({ src, currentTime: _currentTime, isPlaying: _isPlaying, playbackRate: _playbackRate, position, customPosition, size, customSize, visible, draggable, resizable, showControls, borderRadius, opacity, onPositionChange, onSizeChange: _onSizeChange, onVisibilityToggle: _onVisibilityToggle, onVideoRef, muted: _muted, volume: _volume, syncTolerance: _syncTolerance, }: WebcamOverlayProps): JSX.Element | null;
3175
+
3176
+ export { AudioOverlay, type AudioOverlayProps, type AudioQuality, type AudioSyncControls, type AudioSyncState, type BackendAdapter, type BufferHealth, type CTEvent, type CTManifest, type CTMarker, type CTReadOptions, type CTRecording, CoursePlayer, type CoursePlayerProps, type CoursePlayerRef, type CursorPosition, type CustomPosition$1 as CustomPosition, DocumentPanel, type DocumentPanelProps, FileExplorer, type FileExplorerProps, type FileSystemSnapshot, type HLSPlayerInstance, HLS_EVENTS, IDEPanel, type IDEPanelProps, type InternalEvent, type InternalRecording, type OverlayPosition$1 as OverlayPosition, type PanelMode, type PlaybackControls$1 as PlaybackControls, type PlaybackEngineConfig, type PlaybackHookState, type PlaybackState, PlayerControls, type PlayerControlsProps$1 as PlayerControlsProps, type PlayerProps, type PlayerRef, type RecordingMarker, type RemoteBufferHealth, type RemoteStreamingMetrics, type RemoteStreamingPlaybackControls, type RemoteStreamingPlaybackState, type SpeedSelectorProps, type StreamingAudioConfig, type StreamingConfig, StreamingCoursePlayer, type StreamingCoursePlayerProps, type StreamingCoursePlayerRef, type StreamingEventsConfig, type StreamingManifest, type StreamingMetrics, type StreamingPlaybackControls, type StreamingPlaybackState, type StreamingRecordingInfo, Terminal, type TerminalLineData, type TerminalProps, Timeline, type TimelineProps$1 as TimelineProps, ToolSidebar, type ToolSidebarProps, type ToolType, type UseAudioSyncOptions, type UsePlaybackEngineResult, type UsePlaybackOptions, type UseRemoteStreamingPlaybackOptions, type UseVideoSyncOptions, type ValidationResult$1 as ValidationResult, type VideoSyncControls, type VideoSyncState, type VolumeControlProps, WebcamOverlay, type WebcamOverlayProps, WhiteboardPanel, type WhiteboardPanelProps, type WriteCTOptions, canPlayHls, createEmptyRecording, createHlsPlayer, destroyHlsPlayer, hasNativeHlsSupport, isHlsSupported, readCTFile, readCTManifest, useAudioElement, useAudioSync, useInteractiveMode, usePlayback, usePlayback as usePlaybackEngine, useRemoteStreamingPlayback, useStreamingPlayback, useVideoElement, useVideoSync, validateCTFile, writeCTFile };