@ct-player/embed 1.0.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.
@@ -0,0 +1,2716 @@
1
+ import * as react from 'react';
2
+ import react__default from 'react';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import Hls from 'hls.js';
5
+
6
+ /**
7
+ * CT Format Event Types
8
+ *
9
+ * Defines all event types and their data structures for the .ct format.
10
+ */
11
+ /**
12
+ * All possible event types in the .ct format
13
+ */
14
+ type CTEventType = 'init' | 'code' | 'code_edit' | 'language' | 'terminal' | 'terminal_input' | 'stroke_start' | 'whiteboard_points' | 'stroke_end' | 'whiteboard_stroke' | 'whiteboard_clear' | 'whiteboard_undo' | 'whiteboard' | 'whiteboard_point' | 'excalidraw_scene' | 'excalidraw_clear' | 'document_load' | 'document_page' | 'document_zoom' | 'document_scroll' | 'document_clear' | 'file_create' | 'file_update' | 'file_delete' | 'file_rename' | 'file_switch' | 'file_select' | 'file_change' | 'file_creation_start' | 'file_creation_input' | 'file_creation_cancel' | 'cursor_move' | 'cursor_click' | 'cursor_enter' | 'cursor_leave' | 'tool_switch' | 'tool' | 'marker';
15
+ /**
16
+ * Base event structure with generic type parameter
17
+ */
18
+ interface CTEventBase<T extends CTEventType = CTEventType> {
19
+ /** Event type identifier */
20
+ type: T;
21
+ /** Time in milliseconds from recording start */
22
+ time: number;
23
+ /** Event-specific data payload */
24
+ data: CTEventDataMap[T];
25
+ }
26
+ /**
27
+ * Discriminated union of all event types.
28
+ * This enables proper type narrowing in switch statements.
29
+ */
30
+ type CTEvent = CTEventBase<'init'> | CTEventBase<'code'> | CTEventBase<'code_edit'> | CTEventBase<'language'> | CTEventBase<'terminal'> | CTEventBase<'terminal_input'> | CTEventBase<'stroke_start'> | CTEventBase<'whiteboard_points'> | CTEventBase<'stroke_end'> | CTEventBase<'whiteboard_stroke'> | CTEventBase<'whiteboard_clear'> | CTEventBase<'whiteboard_undo'> | CTEventBase<'whiteboard'> | CTEventBase<'whiteboard_point'> | CTEventBase<'excalidraw_scene'> | CTEventBase<'excalidraw_clear'> | CTEventBase<'document_load'> | CTEventBase<'document_page'> | CTEventBase<'document_zoom'> | CTEventBase<'document_scroll'> | CTEventBase<'document_clear'> | CTEventBase<'file_create'> | CTEventBase<'file_update'> | CTEventBase<'file_delete'> | CTEventBase<'file_rename'> | CTEventBase<'file_switch'> | CTEventBase<'file_select'> | CTEventBase<'file_change'> | CTEventBase<'file_creation_start'> | CTEventBase<'file_creation_input'> | CTEventBase<'file_creation_cancel'> | CTEventBase<'cursor_move'> | CTEventBase<'cursor_click'> | CTEventBase<'cursor_enter'> | CTEventBase<'cursor_leave'> | CTEventBase<'tool_switch'> | CTEventBase<'tool'> | CTEventBase<'marker'>;
31
+ /**
32
+ * Mapping of event types to their data structures
33
+ */
34
+ interface CTEventDataMap {
35
+ init: InitEventData;
36
+ code: CodeEventData;
37
+ code_edit: CodeEditEventData;
38
+ language: LanguageEventData;
39
+ terminal: TerminalEventData;
40
+ terminal_input: TerminalInputEventData;
41
+ stroke_start: StrokeStartEventData;
42
+ whiteboard_points: WhiteboardPointsEventData;
43
+ stroke_end: StrokeEndEventData;
44
+ whiteboard_stroke: WhiteboardStrokeEventData;
45
+ whiteboard_clear: WhiteboardClearEventData;
46
+ whiteboard_undo: WhiteboardUndoEventData;
47
+ excalidraw_scene: ExcalidrawSceneEventData;
48
+ excalidraw_clear: ExcalidrawClearEventData;
49
+ document_load: DocumentLoadEventData;
50
+ document_page: DocumentPageEventData;
51
+ document_zoom: DocumentZoomEventData;
52
+ document_scroll: DocumentScrollEventData;
53
+ document_clear: DocumentClearEventData;
54
+ file_create: FileCreateEventData;
55
+ file_update: FileUpdateEventData;
56
+ file_delete: FileDeleteEventData;
57
+ file_rename: FileRenameEventData;
58
+ file_switch: FileSwitchEventData;
59
+ file_creation_start: FileCreationStartEventData;
60
+ file_creation_input: FileCreationInputEventData;
61
+ file_creation_cancel: FileCreationCancelEventData;
62
+ cursor_move: CursorMoveEventData;
63
+ cursor_click: CursorClickEventData;
64
+ cursor_enter: CursorEnterEventData;
65
+ cursor_leave: CursorLeaveEventData;
66
+ tool_switch: ToolSwitchEventData;
67
+ marker: MarkerEventData;
68
+ tool: ToolEventData;
69
+ whiteboard: WhiteboardEventData;
70
+ whiteboard_point: WhiteboardPointEventData;
71
+ file_select: FileSelectEventData;
72
+ file_change: FileChangeEventData;
73
+ }
74
+ /**
75
+ * Tool types for tool switching
76
+ */
77
+ type Tool = 'code' | 'terminal' | 'whiteboard' | 'document';
78
+ /**
79
+ * Terminal line entry
80
+ */
81
+ interface TerminalLine$1 {
82
+ type: 'input' | 'output' | 'error' | 'system';
83
+ text: string;
84
+ }
85
+ /**
86
+ * 2D point with optional pressure
87
+ */
88
+ interface Point {
89
+ x: number;
90
+ y: number;
91
+ pressure?: number;
92
+ }
93
+ /**
94
+ * Drawing stroke
95
+ */
96
+ interface Stroke {
97
+ id: string;
98
+ color: string;
99
+ width: number;
100
+ opacity: number;
101
+ tool: StrokeTool;
102
+ points: Point[];
103
+ }
104
+ /**
105
+ * Stroke tool types
106
+ */
107
+ type StrokeTool = 'pen' | 'eraser' | 'highlighter';
108
+ /**
109
+ * Document reference data
110
+ */
111
+ interface DocumentData {
112
+ id: string;
113
+ name: string;
114
+ type: string;
115
+ data?: string;
116
+ assetRef?: string;
117
+ numPages: number;
118
+ }
119
+ /**
120
+ * Excalidraw element types we support
121
+ */
122
+ type ExcalidrawElementType = 'rectangle' | 'ellipse' | 'diamond' | 'line' | 'arrow' | 'freedraw' | 'text' | 'image' | 'frame' | 'group';
123
+ /**
124
+ * Excalidraw fill style
125
+ */
126
+ type ExcalidrawFillStyle = 'solid' | 'hachure' | 'cross-hatch' | 'none';
127
+ /**
128
+ * Excalidraw stroke style
129
+ */
130
+ type ExcalidrawStrokeStyle = 'solid' | 'dashed' | 'dotted';
131
+ /**
132
+ * Strongly typed Excalidraw element (v1.1.0+)
133
+ * This replaces the previous `unknown[]` for type safety
134
+ */
135
+ interface CTExcalidrawElement {
136
+ id: string;
137
+ type: ExcalidrawElementType | string;
138
+ x: number;
139
+ y: number;
140
+ width: number;
141
+ height: number;
142
+ angle: number;
143
+ strokeColor: string;
144
+ backgroundColor: string;
145
+ fillStyle: ExcalidrawFillStyle;
146
+ strokeWidth: number;
147
+ strokeStyle: ExcalidrawStrokeStyle;
148
+ roughness: number;
149
+ opacity: number;
150
+ points?: number[][];
151
+ text?: string;
152
+ fontSize?: number;
153
+ fontFamily?: number;
154
+ textAlign?: 'left' | 'center' | 'right';
155
+ groupIds?: string[];
156
+ frameId?: string | null;
157
+ isDeleted: boolean;
158
+ locked: boolean;
159
+ fileId?: string;
160
+ [key: string]: unknown;
161
+ }
162
+ /**
163
+ * Excalidraw app state we care about
164
+ */
165
+ interface CTExcalidrawAppState {
166
+ viewBackgroundColor: string;
167
+ zoom: {
168
+ value: number;
169
+ };
170
+ scrollX: number;
171
+ scrollY: number;
172
+ selectedElementIds?: Record<string, boolean>;
173
+ }
174
+ /**
175
+ * Excalidraw file (for images, etc.)
176
+ */
177
+ interface CTExcalidrawFile {
178
+ mimeType: string;
179
+ id: string;
180
+ dataURL?: string;
181
+ assetRef?: string;
182
+ }
183
+ /**
184
+ * Excalidraw scene structure (v1.1.0 with strong typing)
185
+ */
186
+ interface ExcalidrawScene {
187
+ elements: CTExcalidrawElement[];
188
+ appState?: CTExcalidrawAppState;
189
+ files?: Record<string, CTExcalidrawFile>;
190
+ /** Excalidraw library version for migrations (v1.1.0+) */
191
+ excalidrawVersion?: string;
192
+ /** Our schema version (v1.1.0+) */
193
+ ctSchemaVersion?: number;
194
+ }
195
+ /**
196
+ * Full state snapshot (used at recording start or after edits)
197
+ */
198
+ interface InitEventData {
199
+ code: string;
200
+ language: string;
201
+ terminal: TerminalLine$1[];
202
+ terminalInput: string;
203
+ strokes: Stroke[];
204
+ excalidrawScene?: ExcalidrawScene;
205
+ tool: Tool;
206
+ currentFile?: string;
207
+ fileSystem: Record<string, string>;
208
+ document?: DocumentData;
209
+ documentPage: number;
210
+ documentZoom: number;
211
+ documentScroll: {
212
+ x: number;
213
+ y: number;
214
+ };
215
+ }
216
+ /**
217
+ * Code content change
218
+ */
219
+ interface CodeEventData {
220
+ content: string;
221
+ language?: string;
222
+ cursorPosition?: {
223
+ line: number;
224
+ column: number;
225
+ };
226
+ }
227
+ /**
228
+ * Granular code edit event - for smooth typing playback
229
+ * Records individual text operations (insert/delete) at specific positions.
230
+ */
231
+ interface CodeEditEventData {
232
+ /** Type of edit operation */
233
+ operation: 'insert' | 'delete';
234
+ /** Start position of the edit */
235
+ position: {
236
+ line: number;
237
+ column: number;
238
+ /** Absolute character offset from start of file */
239
+ offset: number;
240
+ };
241
+ /** Text being inserted (for 'insert' operations) */
242
+ text?: string;
243
+ /** Number of characters deleted (for 'delete' operations) */
244
+ deleteCount?: number;
245
+ /** Direction of deletion: 'forward' (Delete key) or 'backward' (Backspace) */
246
+ deleteDirection?: 'forward' | 'backward';
247
+ /** Current cursor position after the edit */
248
+ cursorPosition?: {
249
+ line: number;
250
+ column: number;
251
+ };
252
+ }
253
+ /**
254
+ * Language change
255
+ */
256
+ interface LanguageEventData {
257
+ language: string;
258
+ }
259
+ /**
260
+ * Terminal output (batched) - v1.1.0 optimized format
261
+ */
262
+ interface TerminalBatchedOutput {
263
+ /** Full output text (may be multi-line) */
264
+ text: string;
265
+ /** Output stream */
266
+ stream: 'stdout' | 'stderr';
267
+ }
268
+ /**
269
+ * Terminal cursor position
270
+ */
271
+ interface TerminalCursorPosition {
272
+ row: number;
273
+ col: number;
274
+ }
275
+ /**
276
+ * Terminal output event
277
+ *
278
+ * v1.1.0 adds batched output support for efficiency.
279
+ * The `output` field is preferred over `lines` for new recordings.
280
+ */
281
+ interface TerminalEventData {
282
+ /** Legacy line-by-line format (v1.0.0) */
283
+ lines?: TerminalLine$1[];
284
+ /** Batched output format (v1.1.0+) - preferred */
285
+ output?: TerminalBatchedOutput | string;
286
+ /** Whether terminal was cleared */
287
+ cleared?: boolean;
288
+ /** Cursor position change (v1.1.0+) */
289
+ cursorPosition?: TerminalCursorPosition;
290
+ /** Legacy: append lines to existing (v1.0.0) */
291
+ addedLines?: boolean;
292
+ /** Legacy: command that was executed (v1.0.0) */
293
+ command?: string;
294
+ /** Legacy: whether terminal input was cleared (v1.0.0) */
295
+ inputCleared?: boolean;
296
+ }
297
+ /**
298
+ * Keystroke timing for realistic playback animation
299
+ */
300
+ interface TerminalKeystroke {
301
+ /** Character typed */
302
+ char: string;
303
+ /** Delay in ms since previous keystroke */
304
+ delay: number;
305
+ }
306
+ /**
307
+ * Terminal input event (user typing)
308
+ *
309
+ * v1.1.0 adds keystroke timing for realistic playback.
310
+ */
311
+ interface TerminalInputEventData {
312
+ /** Final input string (what was typed) */
313
+ input?: string;
314
+ /** Legacy: input value (v1.0.0) */
315
+ value?: string;
316
+ /** Keystroke timing for animation (v1.1.0+) */
317
+ keystrokes?: TerminalKeystroke[];
318
+ /** Whether Enter was pressed (command submitted) (v1.1.0+) */
319
+ submitted?: boolean;
320
+ }
321
+ /**
322
+ * Begin drawing stroke
323
+ */
324
+ interface StrokeStartEventData {
325
+ id: string;
326
+ color: string;
327
+ width: number;
328
+ opacity?: number;
329
+ tool: StrokeTool;
330
+ }
331
+ /**
332
+ * Batch of points in current stroke
333
+ */
334
+ interface WhiteboardPointsEventData {
335
+ strokeId: string;
336
+ points: Point[];
337
+ }
338
+ /**
339
+ * Finish stroke
340
+ */
341
+ interface StrokeEndEventData {
342
+ strokeId: string;
343
+ }
344
+ /**
345
+ * Complete stroke at once
346
+ */
347
+ interface WhiteboardStrokeEventData {
348
+ stroke: Stroke;
349
+ }
350
+ /**
351
+ * Clear entire whiteboard
352
+ */
353
+ interface WhiteboardClearEventData {
354
+ }
355
+ /**
356
+ * Undo last stroke
357
+ */
358
+ interface WhiteboardUndoEventData {
359
+ strokeId?: string;
360
+ }
361
+ /**
362
+ * Excalidraw full scene update
363
+ */
364
+ interface ExcalidrawSceneEventData {
365
+ elements: unknown[];
366
+ appState?: unknown;
367
+ files?: Record<string, unknown>;
368
+ }
369
+ /**
370
+ * Clear Excalidraw scene
371
+ */
372
+ interface ExcalidrawClearEventData {
373
+ }
374
+ /**
375
+ * Load document
376
+ */
377
+ interface DocumentLoadEventData {
378
+ id: string;
379
+ name: string;
380
+ type: string;
381
+ data?: string;
382
+ assetRef?: string;
383
+ numPages: number;
384
+ }
385
+ /**
386
+ * Document page change
387
+ */
388
+ interface DocumentPageEventData {
389
+ page: number;
390
+ }
391
+ /**
392
+ * Document zoom change
393
+ */
394
+ interface DocumentZoomEventData {
395
+ zoom: number;
396
+ }
397
+ /**
398
+ * Document scroll position
399
+ */
400
+ interface DocumentScrollEventData {
401
+ x: number;
402
+ y: number;
403
+ }
404
+ /**
405
+ * Remove document
406
+ */
407
+ interface DocumentClearEventData {
408
+ }
409
+ /**
410
+ * Create new file
411
+ */
412
+ interface FileCreateEventData {
413
+ path: string;
414
+ content: string;
415
+ language?: string;
416
+ }
417
+ /**
418
+ * Update file content
419
+ */
420
+ interface FileUpdateEventData {
421
+ path: string;
422
+ content: string;
423
+ }
424
+ /**
425
+ * Delete file
426
+ */
427
+ interface FileDeleteEventData {
428
+ path: string;
429
+ }
430
+ /**
431
+ * Rename file
432
+ */
433
+ interface FileRenameEventData {
434
+ oldPath: string;
435
+ newPath: string;
436
+ }
437
+ /**
438
+ * Switch active file
439
+ */
440
+ interface FileSwitchEventData {
441
+ path: string;
442
+ }
443
+ /**
444
+ * File/folder creation UI started - shows the inline input
445
+ */
446
+ interface FileCreationStartEventData {
447
+ /** Type of item being created */
448
+ type: 'file' | 'folder';
449
+ /** Parent folder path where the item is being created */
450
+ parentPath: string;
451
+ }
452
+ /**
453
+ * File/folder creation input changed - for typing animation
454
+ */
455
+ interface FileCreationInputEventData {
456
+ /** Current value of the input field */
457
+ value: string;
458
+ }
459
+ /**
460
+ * File/folder creation cancelled - hides the inline input
461
+ */
462
+ interface FileCreationCancelEventData {
463
+ /** Reason for cancellation (optional) */
464
+ reason?: 'escape' | 'blur' | 'other';
465
+ }
466
+ /**
467
+ * Cursor position update
468
+ */
469
+ interface CursorMoveEventData {
470
+ x: number;
471
+ y: number;
472
+ visible: boolean;
473
+ }
474
+ /**
475
+ * Click event
476
+ */
477
+ interface CursorClickEventData {
478
+ x: number;
479
+ y: number;
480
+ button: 'left' | 'right' | 'middle';
481
+ }
482
+ /**
483
+ * Cursor entered content area
484
+ */
485
+ interface CursorEnterEventData {
486
+ area: string;
487
+ }
488
+ /**
489
+ * Cursor left content area
490
+ */
491
+ interface CursorLeaveEventData {
492
+ area: string;
493
+ }
494
+ /**
495
+ * Switch active tool
496
+ */
497
+ interface ToolSwitchEventData {
498
+ tool: Tool;
499
+ }
500
+ /**
501
+ * Marker event (metadata only)
502
+ */
503
+ interface MarkerEventData {
504
+ id: string;
505
+ label: string;
506
+ type: 'chapter' | 'highlight' | 'quiz' | 'note';
507
+ }
508
+ /**
509
+ * Legacy tool event (same as tool_switch)
510
+ */
511
+ interface ToolEventData {
512
+ tool: Tool;
513
+ }
514
+ /**
515
+ * Legacy whiteboard full strokes replacement
516
+ */
517
+ interface WhiteboardEventData {
518
+ strokes: Stroke[];
519
+ }
520
+ /**
521
+ * Legacy single point add to current stroke
522
+ */
523
+ interface WhiteboardPointEventData {
524
+ point: Point;
525
+ }
526
+ /**
527
+ * Legacy file select event
528
+ */
529
+ interface FileSelectEventData {
530
+ path: string;
531
+ content?: string;
532
+ language?: string;
533
+ }
534
+ /**
535
+ * Legacy file change event
536
+ */
537
+ interface FileChangeEventData {
538
+ path: string;
539
+ content: string;
540
+ }
541
+
542
+ /**
543
+ * CT Format State Types
544
+ *
545
+ * Defines the playback state structure used by the state engine.
546
+ */
547
+
548
+ /**
549
+ * Complete playback state at any point in time
550
+ */
551
+ interface PlaybackState$1 {
552
+ /** Current code content */
553
+ code: string;
554
+ /** Current programming language */
555
+ language: string;
556
+ /** Terminal output history */
557
+ terminalLines: TerminalLine$1[];
558
+ /** Current terminal input buffer */
559
+ terminalInput: string;
560
+ /** Completed strokes on whiteboard (legacy) */
561
+ strokes: Stroke[];
562
+ /** Current Excalidraw scene (modern whiteboard) */
563
+ excalidrawScene: ExcalidrawScene | null;
564
+ /** Currently active tool */
565
+ activeTool: Tool;
566
+ /** Currently active file path */
567
+ currentFile: string | null;
568
+ /** Virtual file system (path → content) */
569
+ fileSystem: Record<string, string>;
570
+ /** Currently loaded document */
571
+ documentData: DocumentData | null;
572
+ /** Current document page number */
573
+ documentPage: number;
574
+ /** Current document zoom level */
575
+ documentZoom: number;
576
+ /** Current document scroll position */
577
+ documentScroll: {
578
+ x: number;
579
+ y: number;
580
+ };
581
+ /** Cursor position and visibility */
582
+ cursorPosition: {
583
+ x: number;
584
+ y: number;
585
+ visible: boolean;
586
+ };
587
+ /** File creation UI state - for showing inline input during playback */
588
+ fileCreation: FileCreationState | null;
589
+ }
590
+ /**
591
+ * State for file/folder creation UI display during playback
592
+ */
593
+ interface FileCreationState {
594
+ /** Type of item being created */
595
+ type: 'file' | 'folder';
596
+ /** Parent folder path */
597
+ parentPath: string;
598
+ /** Current input value (filename being typed) */
599
+ inputValue: string;
600
+ }
601
+
602
+ /**
603
+ * CT Format Chunked Events Types
604
+ *
605
+ * Defines types for the chunked events architecture in v1.1.0.
606
+ * Events are split into time-indexed chunks for:
607
+ * - Fast seeking (load only needed chunks)
608
+ * - Memory efficiency (unload distant chunks)
609
+ * - Progressive loading (start playback before full load)
610
+ */
611
+
612
+ /**
613
+ * A single chunk of events covering a time range
614
+ */
615
+ interface CTEventChunk {
616
+ /** Chunk identifier (0, 1, 2, ...) */
617
+ id: number;
618
+ /** First event time in this chunk (milliseconds) */
619
+ startTimeMs: number;
620
+ /** Last event time in this chunk (milliseconds) */
621
+ endTimeMs: number;
622
+ /** Events in this chunk */
623
+ events: CTEvent[];
624
+ /** Optional state snapshot at the start of this chunk for fast seeking */
625
+ snapshotAtStart?: PlaybackState$1;
626
+ }
627
+ /**
628
+ * Individual chunk metadata in the index
629
+ */
630
+ interface CTChunkInfo {
631
+ /** Chunk index (0, 1, 2, ...) */
632
+ id: number;
633
+ /** Filename (e.g., "chunk-000.json" or "chunk-000.json.gz") */
634
+ file: string;
635
+ /** First event time in this chunk (milliseconds) */
636
+ startTimeMs: number;
637
+ /** Last event time in this chunk (milliseconds) */
638
+ endTimeMs: number;
639
+ /** Number of events in this chunk */
640
+ eventCount: number;
641
+ /** SHA-256 checksum for integrity verification */
642
+ checksum: string;
643
+ /** File size in bytes (for progress reporting) */
644
+ sizeBytes: number;
645
+ /** Whether this chunk has a state snapshot at its start */
646
+ hasSnapshot: boolean;
647
+ }
648
+ /**
649
+ * State snapshot reference
650
+ */
651
+ interface CTStateSnapshotRef {
652
+ /** Chunk ID where snapshot is stored */
653
+ chunkId: number;
654
+ /** Snapshot timestamp (milliseconds) */
655
+ timeMs: number;
656
+ /** Snapshot file path (e.g., "snapshots/snap-003.json") */
657
+ file: string;
658
+ }
659
+ /**
660
+ * Event Chunk Index (events/index.json)
661
+ *
662
+ * This is the first file loaded when opening a .ct file.
663
+ * It tells the player which chunks exist and their time ranges.
664
+ */
665
+ interface CTEventChunkIndex {
666
+ /** Format version for the index itself */
667
+ formatVersion: string;
668
+ /** All chunks in this recording */
669
+ chunks: CTChunkInfo[];
670
+ /** State snapshots for fast seeking (every N chunks) */
671
+ snapshots?: CTStateSnapshotRef[];
672
+ /** Total event count across all chunks */
673
+ totalEventCount: number;
674
+ /** Total number of chunks */
675
+ totalChunks: number;
676
+ /** Total duration in milliseconds */
677
+ totalDuration: number;
678
+ /** Default chunk duration in milliseconds */
679
+ chunkDurationMs: number;
680
+ }
681
+ /**
682
+ * Chunk load result
683
+ */
684
+ interface ChunkLoadResult {
685
+ /** The loaded chunk (undefined if failed) */
686
+ chunk?: CTEventChunk;
687
+ /** Load time in milliseconds */
688
+ loadTimeMs: number;
689
+ /** Whether this was a cache hit */
690
+ fromCache: boolean;
691
+ /** Error message if load failed */
692
+ error?: string;
693
+ }
694
+ /** State snapshot stored at chunk boundary for fast seeking */
695
+ interface StateSnapshot {
696
+ /** Chunk ID where this snapshot applies */
697
+ chunkId: number;
698
+ /** Timestamp in milliseconds */
699
+ timeMs: number;
700
+ /** Complete playback state at this point */
701
+ state: PlaybackState$1;
702
+ }
703
+
704
+ /**
705
+ * CT Format Access Control Types
706
+ *
707
+ * Defines types for content protection, licensing, and DRM in v1.1.0.
708
+ * Supports multiple licensing models from free to enterprise.
709
+ */
710
+ /**
711
+ * License type for content access
712
+ */
713
+ type CTLicenseType = 'public' | 'unlisted' | 'private' | 'paid';
714
+ /**
715
+ * DRM provider options
716
+ */
717
+ type CTDRMProvider = 'widevine' | 'fairplay' | 'playready' | 'custom';
718
+ /**
719
+ * Watermark type
720
+ */
721
+ type CTWatermarkType = 'visible' | 'invisible' | 'both';
722
+ /**
723
+ * Encryption configuration for protected content
724
+ */
725
+ interface CTEncryptionConfig {
726
+ /** Encryption algorithm (only AES-256-GCM supported) */
727
+ algorithm: 'AES-256-GCM';
728
+ /** Key derivation function */
729
+ keyDerivation: 'PBKDF2';
730
+ /** Key identifier for key server */
731
+ keyId: string;
732
+ /** Whether event chunks are encrypted */
733
+ encryptedChunks: boolean;
734
+ /** Whether video/audio is encrypted */
735
+ encryptedMedia: boolean;
736
+ /** Initialization vector (base64 encoded) */
737
+ iv: string;
738
+ }
739
+ /**
740
+ * Access restrictions for content
741
+ */
742
+ interface CTAccessRestrictions {
743
+ /** ISO 8601 expiration date (for rentals) */
744
+ expiresAt?: string;
745
+ /** Maximum number of plays allowed */
746
+ maxPlays?: number;
747
+ /** Whether user can download for offline viewing */
748
+ allowDownload: boolean;
749
+ /** Whether content can be embedded on other sites */
750
+ allowEmbed: boolean;
751
+ /** Whitelist of allowed embedding domains */
752
+ allowedDomains?: string[];
753
+ /** Whether authentication is required */
754
+ requireAuth: boolean;
755
+ }
756
+ /**
757
+ * DRM configuration for premium content
758
+ */
759
+ interface CTDRMConfig {
760
+ /** DRM provider to use */
761
+ provider: CTDRMProvider;
762
+ /** License acquisition URL */
763
+ licenseServerUrl: string;
764
+ /** Certificate URL (required for FairPlay) */
765
+ certificateUrl?: string;
766
+ }
767
+ /**
768
+ * Watermark configuration for content tracing
769
+ */
770
+ interface CTWatermarkConfig {
771
+ /** Whether watermarking is enabled */
772
+ enabled: boolean;
773
+ /** Type of watermark */
774
+ type: CTWatermarkType;
775
+ /** Watermark template (e.g., "{userId} - {timestamp}") */
776
+ data: string;
777
+ }
778
+ /**
779
+ * Main Access Control Configuration
780
+ */
781
+ interface CTAccessControl {
782
+ /** License type */
783
+ license: CTLicenseType;
784
+ /** Encryption settings (for private/paid content) */
785
+ encryption?: CTEncryptionConfig;
786
+ /** Access restrictions */
787
+ restrictions?: CTAccessRestrictions;
788
+ /** DRM configuration (for premium content) */
789
+ drm?: CTDRMConfig;
790
+ /** Watermark configuration (for content tracing) */
791
+ watermark?: CTWatermarkConfig;
792
+ }
793
+
794
+ /**
795
+ * CT Format Streaming Types
796
+ *
797
+ * Defines types for streaming playback configuration in v1.1.0.
798
+ * Goal: Start playback within 2 seconds by loading minimal data first.
799
+ */
800
+ /**
801
+ * Priority loading configuration
802
+ */
803
+ interface CTStreamingPriority {
804
+ /** Files to load FIRST (before playback can start) */
805
+ critical: string[];
806
+ /** Files to load SECOND (for smooth early playback) */
807
+ high: string[];
808
+ /** Files to prefetch in background */
809
+ prefetch: string[];
810
+ }
811
+ /**
812
+ * Buffering strategy configuration
813
+ */
814
+ interface CTBufferStrategy {
815
+ /** Minimum buffer before play starts (ms, default: 5000) */
816
+ minBufferMs: number;
817
+ /** Maximum buffer to maintain (ms, default: 30000) */
818
+ maxBufferMs: number;
819
+ /** Number of chunks to prefetch ahead (default: 2) */
820
+ prefetchChunks: number;
821
+ }
822
+ /**
823
+ * Seek optimization configuration
824
+ */
825
+ interface CTSeekConfig {
826
+ /** State snapshot interval in ms (default: 60000 = 1 min) */
827
+ snapshotIntervalMs: number;
828
+ /** Whether to align seeks to video keyframes */
829
+ keyframeAligned: boolean;
830
+ }
831
+ /**
832
+ * Main Streaming Configuration
833
+ */
834
+ interface CTStreamingConfig {
835
+ /** Priority loading order */
836
+ priority: CTStreamingPriority;
837
+ /** Buffering strategy */
838
+ buffer: CTBufferStrategy;
839
+ /** Seek optimization */
840
+ seeking: CTSeekConfig;
841
+ }
842
+ /**
843
+ * Recovery information for corrupted files
844
+ */
845
+ interface CTRecoveryInfo {
846
+ /** Last chunk that was fully written */
847
+ lastGoodChunk: number;
848
+ /** Safe seek points (chunk boundaries) */
849
+ recoveryPoints: number[];
850
+ }
851
+ /**
852
+ * File integrity information
853
+ */
854
+ interface CTIntegrityInfo {
855
+ /** Hash algorithm used */
856
+ algorithm: 'SHA-256';
857
+ /** ISO 8601 timestamp when hashes were generated */
858
+ generatedAt: string;
859
+ /** Map of file paths to their SHA-256 hashes */
860
+ files: Record<string, string>;
861
+ /** Recovery information */
862
+ recovery?: CTRecoveryInfo;
863
+ }
864
+
865
+ /**
866
+ * Chunked events reference (v1.1.0+)
867
+ * Events are stored in time-indexed chunks for efficient streaming.
868
+ */
869
+ interface CTEventsReference {
870
+ /** Path to chunk index file (e.g., "events/index.json") */
871
+ indexFile: string;
872
+ /** Total events across all chunks */
873
+ totalCount: number;
874
+ /** Number of chunk files */
875
+ chunkCount: number;
876
+ /** Duration per chunk in milliseconds (default: 300000 = 5 min) */
877
+ chunkDurationMs: number;
878
+ /** Whether chunks are gzip compressed */
879
+ compressed: boolean;
880
+ }
881
+ /**
882
+ * Legacy events reference (v1.0.0)
883
+ * Single events.json file - kept for backwards compatibility
884
+ */
885
+ interface CTEventsInfoLegacy {
886
+ /** Relative path in archive (typically "events.json") */
887
+ file: string;
888
+ /** Total number of events */
889
+ count: number;
890
+ /** Whether events file is gzip compressed */
891
+ compressed?: boolean;
892
+ }
893
+ /**
894
+ * Events info - supports both legacy and chunked formats
895
+ */
896
+ type CTEventsInfo = CTEventsReference | CTEventsInfoLegacy;
897
+ /**
898
+ * Author information
899
+ */
900
+ interface CTAuthorInfo {
901
+ /** Author's unique ID */
902
+ id: string;
903
+ /** Display name */
904
+ name: string;
905
+ /** Email address */
906
+ email?: string;
907
+ /** Website URL */
908
+ url?: string;
909
+ }
910
+ /**
911
+ * Main manifest structure for a .ct file (v1.1.0)
912
+ */
913
+ interface CTManifest {
914
+ /** Format version following semver (e.g., "1.1.0") */
915
+ formatVersion: string;
916
+ /** Generator application identifier (e.g., "CT-Courses Recorder v2.1.0") */
917
+ generator: string;
918
+ /** Unique identifier for this recording (UUID) */
919
+ id: string;
920
+ /** Display title of the recording */
921
+ name: string;
922
+ /** Optional description */
923
+ description?: string;
924
+ /** Author information (v1.1.0+) */
925
+ author?: CTAuthorInfo;
926
+ /** Total duration in seconds */
927
+ duration: number;
928
+ /** ISO 8601 timestamp of creation */
929
+ createdAt: string;
930
+ /** ISO 8601 timestamp of last modification */
931
+ modifiedAt: string;
932
+ /** Access control and licensing (v1.1.0+) */
933
+ access?: CTAccessControl;
934
+ /** Streaming configuration (v1.1.0+) */
935
+ streaming?: CTStreamingConfig;
936
+ /** Integrity checksums (v1.1.0+) */
937
+ integrity?: CTIntegrityInfo;
938
+ /** Media file references */
939
+ media: CTMediaInfo;
940
+ /** Events reference (chunked in v1.1.0+, single file in v1.0.0) */
941
+ events: CTEventsInfo;
942
+ /** Chapter/highlight markers */
943
+ markers: CTMarker[];
944
+ /** Optional embedded assets */
945
+ assets?: CTAssets;
946
+ /** Edit history (for edited recordings) */
947
+ editHistory?: CTEditHistory;
948
+ /** Playback configuration hints */
949
+ playback?: CTPlaybackHints;
950
+ }
951
+ /**
952
+ * Video segment information for streaming
953
+ */
954
+ interface CTVideoSegments {
955
+ /** Segment duration in seconds */
956
+ duration: number;
957
+ /** Segment filename pattern (e.g., "media/seg-{index}.webm") */
958
+ pattern: string;
959
+ /** Total segment count */
960
+ count: number;
961
+ }
962
+ /**
963
+ * Media file references
964
+ */
965
+ interface CTMediaInfo {
966
+ video?: CTVideoInfo;
967
+ audio?: CTAudioInfo;
968
+ /** Pre-generated waveform for timeline UI (v1.1.0+) */
969
+ waveform?: CTWaveformInfo;
970
+ }
971
+ /**
972
+ * Video file metadata
973
+ */
974
+ interface CTVideoInfo {
975
+ /** Relative path in archive (e.g., "media/video.webm") */
976
+ file: string;
977
+ /** MIME type (e.g., "video/webm", "video/mp4") */
978
+ mimeType: string;
979
+ /** Duration in seconds */
980
+ duration: number;
981
+ /** Video width in pixels */
982
+ width: number;
983
+ /** Video height in pixels */
984
+ height: number;
985
+ /** Codec identifier (e.g., "vp9", "h264") */
986
+ codec?: string;
987
+ /** Video segments for streaming (v1.1.0+) */
988
+ segments?: CTVideoSegments;
989
+ /** Keyframe positions in ms for fast seeking (v1.1.0+) */
990
+ keyframes?: number[];
991
+ }
992
+ /**
993
+ * Audio file metadata (when separate from video)
994
+ */
995
+ interface CTAudioInfo {
996
+ /** Relative path in archive */
997
+ file: string;
998
+ /** MIME type (e.g., "audio/webm", "audio/mp3") */
999
+ mimeType: string;
1000
+ /** Duration in seconds */
1001
+ duration: number;
1002
+ /** Sample rate in Hz */
1003
+ sampleRate?: number;
1004
+ }
1005
+ /**
1006
+ * Pre-generated waveform data reference
1007
+ */
1008
+ interface CTWaveformInfo {
1009
+ /** Path to waveform file */
1010
+ file: string;
1011
+ /** Samples per second */
1012
+ samplesPerSecond: number;
1013
+ }
1014
+ /**
1015
+ * Chapter/highlight marker
1016
+ */
1017
+ interface CTMarker {
1018
+ /** Unique identifier */
1019
+ id: string;
1020
+ /** Time position in milliseconds */
1021
+ time: number;
1022
+ /** Display label */
1023
+ label: string;
1024
+ /** Marker type */
1025
+ type: CTMarkerType;
1026
+ /** Type-specific additional data */
1027
+ data?: Record<string, unknown>;
1028
+ }
1029
+ /**
1030
+ * Marker types
1031
+ */
1032
+ type CTMarkerType = 'chapter' | 'highlight' | 'quiz' | 'note';
1033
+ /**
1034
+ * Embedded assets manifest
1035
+ */
1036
+ interface CTAssets {
1037
+ documents?: CTAssetReference[];
1038
+ images?: CTAssetReference[];
1039
+ }
1040
+ /**
1041
+ * Reference to an embedded asset
1042
+ */
1043
+ interface CTAssetReference {
1044
+ /** Unique identifier */
1045
+ id: string;
1046
+ /** Relative path in archive */
1047
+ file: string;
1048
+ /** Display name */
1049
+ name: string;
1050
+ /** MIME type */
1051
+ mimeType: string;
1052
+ /** File size in bytes */
1053
+ size: number;
1054
+ }
1055
+ /**
1056
+ * Edit history for modified recordings
1057
+ */
1058
+ interface CTEditHistory {
1059
+ /** Original recording ID */
1060
+ sourceRecordingId: string;
1061
+ /** List of edit operations applied */
1062
+ operations: CTEditOperation[];
1063
+ /** ISO 8601 timestamp of last edit */
1064
+ editedAt: string;
1065
+ }
1066
+ /**
1067
+ * Edit operation record
1068
+ */
1069
+ interface CTEditOperation {
1070
+ /** Unique identifier */
1071
+ id: string;
1072
+ /** Operation type */
1073
+ type: 'cut' | 'trim_start' | 'trim_end' | 'speed';
1074
+ /** Start time in milliseconds (for cut/speed) */
1075
+ startTime?: number;
1076
+ /** End time in milliseconds (for cut/speed) */
1077
+ endTime?: number;
1078
+ /** Amount trimmed in milliseconds (for trims) */
1079
+ trimAmount?: number;
1080
+ /** Speed factor (for speed changes) */
1081
+ factor?: number;
1082
+ }
1083
+ /**
1084
+ * Playback configuration hints
1085
+ */
1086
+ interface CTPlaybackHints {
1087
+ /** Default playback speed (1.0 = normal) */
1088
+ defaultSpeed?: number;
1089
+ /** Whether viewer can edit code when paused */
1090
+ allowInteraction?: boolean;
1091
+ /** Whether to start playing immediately */
1092
+ autoPlay?: boolean;
1093
+ }
1094
+ /**
1095
+ * Complete recording data structure
1096
+ */
1097
+ interface CTRecording {
1098
+ /** Manifest metadata */
1099
+ manifest: CTManifest;
1100
+ /** All events in the recording (flat array) */
1101
+ events: CTEvent[];
1102
+ /** Pre-computed event chunks (v1.1.0+, optional) */
1103
+ chunks?: CTEventChunk[];
1104
+ /** Pre-computed chunk index (v1.1.0+, optional) */
1105
+ chunkIndex?: CTEventChunkIndex;
1106
+ /** State snapshots for fast seeking (v1.1.0+, optional) */
1107
+ snapshots?: StateSnapshot[];
1108
+ /** Video/audio media blob */
1109
+ mediaBlob?: Blob;
1110
+ /** Embedded assets by ID */
1111
+ assets?: Map<string, Blob>;
1112
+ }
1113
+
1114
+ /**
1115
+ * CT Format Reader
1116
+ *
1117
+ * Parses .ct files (ZIP archives) and extracts all components.
1118
+ * Supports both v1.0.0 (single events.json) and v1.1.0 (chunked events/).
1119
+ */
1120
+
1121
+ /**
1122
+ * Options for reading a CT file
1123
+ */
1124
+ interface CTReadOptions {
1125
+ /** Whether to load all events immediately (false = lazy loading for chunked)
1126
+ * WARNING: Setting to true can cause memory exhaustion for large files (>100MB)
1127
+ * Use streaming API (streamCTEvents) or lazy loading instead
1128
+ */
1129
+ loadAllEvents?: boolean;
1130
+ /** Validate events after loading */
1131
+ validateEvents?: boolean;
1132
+ /** Whether to load media blobs */
1133
+ loadMedia?: boolean;
1134
+ /** Whether to load assets */
1135
+ loadAssets?: boolean;
1136
+ }
1137
+ /**
1138
+ * Extended recording type for chunked format
1139
+ */
1140
+ interface CTRecordingWithChunks extends CTRecording {
1141
+ /** Chunk index for lazy loading (v1.1.0+) */
1142
+ chunkIndex?: CTEventChunkIndex;
1143
+ /** Function to load a specific chunk (v1.1.0+) */
1144
+ loadChunk?: (chunkNumber: number) => Promise<ChunkLoadResult>;
1145
+ /** Whether events are stored in chunked format */
1146
+ isChunked: boolean;
1147
+ }
1148
+ /**
1149
+ * Read and parse a .ct file
1150
+ *
1151
+ * @param file - The .ct file as a File, Blob, or ArrayBuffer
1152
+ * @param options - Reading options
1153
+ * @returns Parsed recording data
1154
+ */
1155
+ declare function readCTFile(file: File | Blob | ArrayBuffer, options?: CTReadOptions): Promise<CTRecordingWithChunks>;
1156
+ /**
1157
+ * Read only the manifest from a .ct file
1158
+ * Faster than full read when you just need metadata
1159
+ */
1160
+ declare function readCTManifest(file: File | Blob | ArrayBuffer): Promise<CTManifest>;
1161
+
1162
+ /**
1163
+ * CT Format Writer
1164
+ *
1165
+ * Creates .ct files (ZIP archives) from recording data.
1166
+ * Supports both v1.0.0 (single events.json) and v1.1.0 (chunked events/).
1167
+ */
1168
+
1169
+ /**
1170
+ * Options for writing a .ct file
1171
+ */
1172
+ interface WriteCTOptions {
1173
+ /** Compression level (0-9, default: 6) */
1174
+ compressionLevel?: number;
1175
+ /** Whether to validate before writing (default: true) */
1176
+ validate?: boolean;
1177
+ /** Skip media embedding (useful for draft saves) */
1178
+ skipMedia?: boolean;
1179
+ /** Use chunked events format (v1.1.0+, default: true for large recordings) */
1180
+ useChunkedEvents?: boolean;
1181
+ /** Target events per chunk (default: 1000) */
1182
+ eventsPerChunk?: number;
1183
+ /** Target chunk duration in ms (default: 300000 = 5 minutes) */
1184
+ chunkDurationMs?: number;
1185
+ /** Generate checksums for chunks (default: true) */
1186
+ generateChecksums?: boolean;
1187
+ /** Generate integrity.json for file verification (default: true) */
1188
+ generateIntegrity?: boolean;
1189
+ /** Use SHA-256 for checksums (default: true, falls back to simple hash if unavailable) */
1190
+ useSHA256?: boolean;
1191
+ }
1192
+ /**
1193
+ * Create a .ct file from recording data
1194
+ *
1195
+ * @param recording - The recording data to package
1196
+ * @param options - Write options
1197
+ * @returns The .ct file as a Blob
1198
+ */
1199
+ declare function writeCTFile(recording: CTRecording, options?: WriteCTOptions): Promise<Blob>;
1200
+ /**
1201
+ * Create a new empty recording with default manifest
1202
+ */
1203
+ declare function createEmptyRecording(name?: string): CTRecording;
1204
+
1205
+ /**
1206
+ * CT Format Validator
1207
+ *
1208
+ * Validates .ct file structure and content.
1209
+ * Supports both v1.0.0 (single events) and v1.1.0 (chunked events) formats.
1210
+ */
1211
+
1212
+ /**
1213
+ * Validation result
1214
+ */
1215
+ interface ValidationResult$1 {
1216
+ /** Whether the validation passed */
1217
+ valid: boolean;
1218
+ /** Error messages (if invalid) */
1219
+ errors?: string[];
1220
+ /** Warning messages (valid but concerning) */
1221
+ warnings?: string[];
1222
+ }
1223
+ /**
1224
+ * Validate a complete CT recording
1225
+ */
1226
+ declare function validateCTFile(recording: CTRecording): ValidationResult$1;
1227
+
1228
+ /**
1229
+ * CT-Courses UI Types
1230
+ *
1231
+ * Shared type definitions for all UI components.
1232
+ */
1233
+ /**
1234
+ * Component operation mode
1235
+ */
1236
+ type PanelMode = 'recording' | 'playback' | 'interactive';
1237
+ /**
1238
+ * Base props shared by all panels
1239
+ */
1240
+ interface BasePanelProps {
1241
+ /** Current operation mode */
1242
+ mode: PanelMode;
1243
+ /** Whether playback is currently active (playback mode only) */
1244
+ isPlaying?: boolean;
1245
+ /** Called when user interacts during playback */
1246
+ onInteract?: () => void;
1247
+ /** Additional CSS classes */
1248
+ className?: string;
1249
+ }
1250
+ /**
1251
+ * File system representation
1252
+ */
1253
+ interface FileSystemEntry {
1254
+ name: string;
1255
+ path: string;
1256
+ type: 'file' | 'folder' | 'directory';
1257
+ language?: string;
1258
+ children?: FileSystemEntry[];
1259
+ }
1260
+ /**
1261
+ * Cursor position in editor
1262
+ */
1263
+ interface CursorPosition$1 {
1264
+ line: number;
1265
+ column: number;
1266
+ }
1267
+ /**
1268
+ * Terminal line structure
1269
+ */
1270
+ interface TerminalLineData {
1271
+ type: 'input' | 'output' | 'system' | 'error' | 'success' | 'warning' | 'info' | 'header' | 'divider' | 'execution_header' | 'execution_result';
1272
+ text: string;
1273
+ status?: string;
1274
+ time?: number;
1275
+ memory?: number;
1276
+ }
1277
+ /**
1278
+ * IDE Panel props
1279
+ */
1280
+ interface IDEPanelProps extends BasePanelProps {
1281
+ /** Current code content */
1282
+ code?: string;
1283
+ /** Current language */
1284
+ language?: string;
1285
+ /** Current file path */
1286
+ currentFile?: string;
1287
+ /** Cursor position */
1288
+ cursorPosition?: CursorPosition$1;
1289
+ /** Terminal output lines */
1290
+ terminalLines?: TerminalLineData[];
1291
+ /** Current terminal input */
1292
+ terminalInput?: string;
1293
+ /** Called when code changes */
1294
+ onCodeChange?: (code: string, language: string) => void;
1295
+ /** Called when cursor moves */
1296
+ onCursorChange?: (position: CursorPosition$1) => void;
1297
+ /** Called when language changes */
1298
+ onLanguageChange?: (language: string) => void;
1299
+ /** Called when a file is selected */
1300
+ onFileSelect?: (path: string, content: string, language: string) => void;
1301
+ /** Called when file content changes */
1302
+ onFileChange?: (path: string, content: string, language?: string) => void;
1303
+ /** Called when a file is created */
1304
+ onFileCreate?: (path: string, content: string) => void;
1305
+ /** Called when a file is deleted */
1306
+ onFileDelete?: (path: string) => void;
1307
+ /** Called when a file is renamed */
1308
+ onFileRename?: (oldPath: string, newPath: string) => void;
1309
+ /**
1310
+ * File creation state during playback - shows inline input for typing animation.
1311
+ * When set, displays the file creation UI with the inputValue.
1312
+ */
1313
+ fileCreationState?: {
1314
+ type: 'file' | 'folder';
1315
+ parentPath: string;
1316
+ inputValue: string;
1317
+ } | null;
1318
+ /** Called when file creation starts (user clicks New File/Folder button) */
1319
+ onFileCreationStart?: (type: 'file' | 'folder', parentPath: string) => void;
1320
+ /** Called when file creation input changes (user types in the file name input) */
1321
+ onFileCreationInput?: (value: string) => void;
1322
+ /** Called when file creation is cancelled */
1323
+ onFileCreationCancel?: (reason?: string) => void;
1324
+ /** Called when terminal input changes */
1325
+ onTerminalInputChange?: (input: string) => void;
1326
+ /** Called when a command is executed */
1327
+ onTerminalCommand?: (command: string, output: string) => void;
1328
+ /** Called to add lines to terminal */
1329
+ onTerminalAddLines?: (lines: TerminalLineData[]) => void;
1330
+ /** Called when terminal is cleared */
1331
+ onTerminalClear?: () => void;
1332
+ /** Initial file system state */
1333
+ initialFiles?: Record<string, string>;
1334
+ /** Show run code button */
1335
+ showRunButton?: boolean;
1336
+ /** Show file explorer */
1337
+ showFileExplorer?: boolean;
1338
+ /** Default show terminal */
1339
+ defaultShowTerminal?: boolean;
1340
+ /** Default show explorer */
1341
+ defaultShowExplorer?: boolean;
1342
+ /** Read-only editor */
1343
+ readOnly?: boolean;
1344
+ /** Initial active file */
1345
+ initialActiveFile?: string;
1346
+ /** Interactive label text */
1347
+ interactiveLabel?: string;
1348
+ /** Execute code handler */
1349
+ onExecute?: (path: string, language: string) => Promise<TerminalLineData[] | undefined>;
1350
+ /** Execute terminal command handler (uses TerminalService for full command support) */
1351
+ onTerminalExecute?: (command: string) => Promise<TerminalLineData[]>;
1352
+ }
1353
+ /**
1354
+ * Excalidraw scene structure (simplified)
1355
+ */
1356
+ interface WhiteboardScene {
1357
+ elements: unknown[];
1358
+ appState?: Record<string, unknown>;
1359
+ files?: Record<string, unknown>;
1360
+ }
1361
+ /**
1362
+ * Whiteboard Panel props
1363
+ */
1364
+ interface WhiteboardPanelProps extends BasePanelProps {
1365
+ /** Current Excalidraw scene */
1366
+ scene?: WhiteboardScene | null;
1367
+ /** Called when scene changes */
1368
+ onSceneChange?: (scene: WhiteboardScene) => void;
1369
+ /** Called when scene is cleared */
1370
+ onSceneClear?: () => void;
1371
+ /** Show Excalidraw toolbar */
1372
+ showToolbar?: boolean;
1373
+ /** Background color */
1374
+ backgroundColor?: string;
1375
+ }
1376
+ /**
1377
+ * Document data structure
1378
+ */
1379
+ interface DocumentDataInput {
1380
+ /** Unique document ID (for multi-document support) */
1381
+ id?: string;
1382
+ /** Document content (base64, ArrayBuffer, or URL) */
1383
+ data: string | ArrayBuffer;
1384
+ /** Document filename */
1385
+ name: string;
1386
+ /** MIME type */
1387
+ type: string;
1388
+ }
1389
+ /**
1390
+ * Scroll position
1391
+ */
1392
+ interface ScrollPosition {
1393
+ x: number;
1394
+ y: number;
1395
+ }
1396
+ /**
1397
+ * Document info returned on load
1398
+ */
1399
+ interface DocumentInfo {
1400
+ id?: string;
1401
+ data: string;
1402
+ name: string;
1403
+ numPages: number;
1404
+ type: string;
1405
+ }
1406
+ /**
1407
+ * Document Panel props
1408
+ */
1409
+ interface DocumentPanelProps extends BasePanelProps {
1410
+ /** Document data (single document - for backwards compatibility) */
1411
+ documentData?: DocumentDataInput | null;
1412
+ /** Multiple documents (new multi-document support) */
1413
+ documents?: DocumentDataInput[];
1414
+ /** Currently active document ID (for multi-document mode) */
1415
+ activeDocumentId?: string;
1416
+ /** Current page number (1-indexed) */
1417
+ currentPage?: number;
1418
+ /** Zoom level (1.0 = 100%) */
1419
+ zoom?: number;
1420
+ /** Scroll position within page */
1421
+ scrollPosition?: ScrollPosition;
1422
+ /** Called when document is loaded */
1423
+ onDocumentLoad?: (info: DocumentInfo) => void;
1424
+ /** Called when active document changes (multi-document mode) */
1425
+ onDocumentSelect?: (documentId: string) => void;
1426
+ /** Called when a document is removed (multi-document mode) */
1427
+ onDocumentRemove?: (documentId: string) => void;
1428
+ /** Called when page changes */
1429
+ onPageChange?: (page: number) => void;
1430
+ /** Called when zoom changes */
1431
+ onZoomChange?: (zoom: number) => void;
1432
+ /** Called when scroll position changes */
1433
+ onScrollChange?: (position: ScrollPosition) => void;
1434
+ /** Called when document is cleared */
1435
+ onDocumentClear?: () => void;
1436
+ /** Show document tab bar (for multiple documents) */
1437
+ showTabBar?: boolean;
1438
+ /** Show navigation toolbar */
1439
+ showToolbar?: boolean;
1440
+ /** Show page indicator */
1441
+ showPageIndicator?: boolean;
1442
+ /** Allow file upload */
1443
+ allowUpload?: boolean;
1444
+ /** Allow multiple document uploads */
1445
+ allowMultiple?: boolean;
1446
+ /** Background color */
1447
+ backgroundColor?: string;
1448
+ }
1449
+ /**
1450
+ * Terminal component props
1451
+ */
1452
+ interface TerminalProps {
1453
+ /** Output lines */
1454
+ lines?: TerminalLineData[];
1455
+ /** Current input value */
1456
+ input?: string;
1457
+ /** Called when input changes */
1458
+ onInputChange?: (value: string) => void;
1459
+ /** Called when command is submitted */
1460
+ onCommand?: (command: string) => void;
1461
+ /** Called when terminal is cleared (Ctrl+L) */
1462
+ onClear?: () => void;
1463
+ /** Is code currently executing */
1464
+ isExecuting?: boolean;
1465
+ /** Read-only mode */
1466
+ isReadOnly?: boolean;
1467
+ /** Input placeholder */
1468
+ placeholder?: string;
1469
+ /** Additional CSS classes */
1470
+ className?: string;
1471
+ /** Show prompt */
1472
+ showPrompt?: boolean;
1473
+ /** Auto-focus input */
1474
+ autoFocus?: boolean;
1475
+ }
1476
+ /**
1477
+ * Terminal ref interface
1478
+ */
1479
+ interface TerminalRef {
1480
+ focus: () => void;
1481
+ scrollToBottom: () => void;
1482
+ }
1483
+ /**
1484
+ * File Explorer props
1485
+ */
1486
+ interface FileExplorerProps {
1487
+ /** Currently selected file path */
1488
+ selectedFile?: string | null;
1489
+ /** Called when file is selected */
1490
+ onFileSelect: (path: string) => void;
1491
+ /** Called when file is created */
1492
+ onFileCreate?: (path: string, content: string) => void;
1493
+ /** Called when folder is created */
1494
+ onFolderCreate?: (path: string) => void;
1495
+ /** Called when file is deleted */
1496
+ onFileDelete?: (path: string) => void;
1497
+ /** Called when file is renamed */
1498
+ onFileRename?: (oldPath: string, newPath: string) => void;
1499
+ /** Called when user starts creating a file/folder (clicks New File/Folder button) */
1500
+ onFileCreationStart?: (type: 'file' | 'folder', parentPath: string) => void;
1501
+ /** Called when user types in the file creation input */
1502
+ onFileCreationInput?: (value: string) => void;
1503
+ /** Called when user cancels file creation (Escape or blur) */
1504
+ onFileCreationCancel?: (reason?: string) => void;
1505
+ /**
1506
+ * Playback file creation state - for showing the file creation input during playback.
1507
+ * When set, displays a read-only input showing the filename being typed.
1508
+ */
1509
+ playbackFileCreation?: {
1510
+ type: 'file' | 'folder';
1511
+ parentPath: string;
1512
+ inputValue: string;
1513
+ } | null;
1514
+ /** Additional CSS classes */
1515
+ className?: string;
1516
+ }
1517
+ /**
1518
+ * Available tool types
1519
+ */
1520
+ type ToolType = 'code' | 'whiteboard' | 'document';
1521
+ /**
1522
+ * Tool Sidebar props
1523
+ */
1524
+ interface ToolSidebarProps {
1525
+ /** Currently active tool */
1526
+ activeTool: ToolType;
1527
+ /** Called when tool changes */
1528
+ onToolChange: (tool: ToolType) => void;
1529
+ /** Available tools */
1530
+ tools?: ToolType[];
1531
+ /** Additional CSS classes */
1532
+ className?: string;
1533
+ }
1534
+
1535
+ declare function ToolSidebar({ activeTool, onToolChange, tools, className, }: ToolSidebarProps): react_jsx_runtime.JSX.Element;
1536
+
1537
+ declare function WhiteboardPanel({ scene, onSceneChange, onSceneClear, mode, isPlaying, onInteract, showToolbar, backgroundColor, className, }: WhiteboardPanelProps): react_jsx_runtime.JSX.Element;
1538
+
1539
+ declare function DocumentPanel({ documentData, documents: externalDocuments, activeDocumentId: externalActiveId, currentPage, zoom, scrollPosition, onDocumentLoad, onDocumentSelect, onDocumentRemove, onPageChange, onZoomChange, onScrollChange, onDocumentClear, mode, isPlaying, onInteract, showTabBar, showToolbar, showPageIndicator, allowUpload, allowMultiple, backgroundColor, className, }: DocumentPanelProps): react_jsx_runtime.JSX.Element;
1540
+
1541
+ interface VirtualFileSystem {
1542
+ getFileTree: () => FileSystemEntry;
1543
+ subscribe: (callback: () => void) => () => void;
1544
+ writeFile: (path: string, content: string) => void;
1545
+ /** Optional: Read file content by path */
1546
+ readFile?: (path: string) => string;
1547
+ /** Optional: Get all files as a record */
1548
+ getFiles?: () => Record<string, string>;
1549
+ }
1550
+ declare function FileExplorer({ fileSystem, selectedFile, onFileSelect, onFileCreate, onFolderCreate, onFileDelete, onFileRename, onFileCreationStart, onFileCreationInput, onFileCreationCancel, playbackFileCreation, className }: FileExplorerProps & {
1551
+ fileSystem: VirtualFileSystem;
1552
+ }): react_jsx_runtime.JSX.Element;
1553
+
1554
+ declare function IDEPanel({ fileSystem, code: externalCode, language: externalLanguage, currentFile: externalCurrentFile, onCodeChange, onFileChange, onFileCreate, onFileDelete, onFileRename, onFileSelect, onTerminalCommand, onTerminalClear, onTerminalAddLines, fileCreationState, onFileCreationStart, onFileCreationInput, onFileCreationCancel, terminalLines: externalTerminalLines, terminalInput: externalTerminalInput, onTerminalInputChange, onExecute, onTerminalExecute, mode, isPlaying, defaultShowExplorer, defaultShowTerminal, showRunButton, interactiveLabel, initialFiles, initialActiveFile }: IDEPanelProps & {
1555
+ fileSystem: VirtualFileSystem;
1556
+ }): react_jsx_runtime.JSX.Element;
1557
+
1558
+ declare const Terminal: react.ForwardRefExoticComponent<TerminalProps & react.RefAttributes<TerminalRef>>;
1559
+
1560
+ /**
1561
+ * Active tool type - matches ToolType from @ct-courses/ui
1562
+ */
1563
+ type ActiveTool$1 = ToolType;
1564
+ /**
1565
+ * Props for the CoursePlayer component
1566
+ */
1567
+ interface CoursePlayerProps {
1568
+ /** Pre-loaded recording data */
1569
+ recording?: CTRecording;
1570
+ /** URL to a .ct file */
1571
+ recordingUrl?: string;
1572
+ /** Recording ID to fetch from API */
1573
+ recordingId?: string;
1574
+ /** Base API URL for fetching recordings */
1575
+ apiUrl?: string;
1576
+ /** Authentication token */
1577
+ authToken?: string;
1578
+ /** Go-Judge server URL */
1579
+ goJudgeUrl?: string;
1580
+ /** Go-Judge API key */
1581
+ goJudgeApiKey?: string;
1582
+ /** Theme setting */
1583
+ theme?: 'light' | 'dark' | 'system';
1584
+ /** Aspect ratio of the player */
1585
+ aspectRatio?: '16:9' | '4:3' | 'auto';
1586
+ /** Show playback controls toolbar */
1587
+ showToolbar?: boolean;
1588
+ /** Show timeline below player */
1589
+ showTimeline?: boolean;
1590
+ /** Show chapter markers */
1591
+ showChapters?: boolean;
1592
+ /** Show tool sidebar */
1593
+ showToolSidebar?: boolean;
1594
+ /** Auto-play when loaded */
1595
+ autoPlay?: boolean;
1596
+ /** Default playback speed */
1597
+ defaultSpeed?: number;
1598
+ /** Allow fullscreen mode */
1599
+ allowFullscreen?: boolean;
1600
+ /** Default active tool */
1601
+ defaultTool?: ActiveTool$1;
1602
+ /** Called when player is ready */
1603
+ onReady?: () => void;
1604
+ /** Called when playback starts */
1605
+ onPlay?: () => void;
1606
+ /** Called when playback pauses */
1607
+ onPause?: () => void;
1608
+ /** Called on progress update */
1609
+ onProgress?: (time: number, duration: number) => void;
1610
+ /** Called when playback completes */
1611
+ onComplete?: () => void;
1612
+ /** Called on error */
1613
+ onError?: (error: Error) => void;
1614
+ /** Called when entering interactive mode */
1615
+ onInteractionStart?: () => void;
1616
+ /** Called when exiting interactive mode */
1617
+ onInteractionEnd?: (code: string) => void;
1618
+ /** Called when tool changes */
1619
+ onToolChange?: (tool: string) => void;
1620
+ }
1621
+ /**
1622
+ * Imperative handle for CoursePlayer
1623
+ */
1624
+ interface CoursePlayerRef {
1625
+ play(): void;
1626
+ pause(): void;
1627
+ seek(timeMs: number): void;
1628
+ setSpeed(speed: number): void;
1629
+ getCurrentTime(): number;
1630
+ getDuration(): number;
1631
+ getState(): PlaybackState$1;
1632
+ enterInteractiveMode(): void;
1633
+ exitInteractiveMode(): void;
1634
+ setActiveTool(tool: ActiveTool$1): void;
1635
+ }
1636
+ /**
1637
+ * CoursePlayer component
1638
+ */
1639
+ declare const CoursePlayer: react.ForwardRefExoticComponent<CoursePlayerProps & react.RefAttributes<CoursePlayerRef>>;
1640
+
1641
+ /**
1642
+ * CT-Courses Player - Remote Streaming Types
1643
+ *
1644
+ * Types for streaming playback from a remote CDN/R2 storage.
1645
+ * These types match the streaming service manifest structure.
1646
+ *
1647
+ * @packageDocumentation
1648
+ */
1649
+
1650
+ /**
1651
+ * Audio quality level information
1652
+ */
1653
+ interface AudioQuality {
1654
+ /** Quality name (low, medium, high) */
1655
+ name: string;
1656
+ /** Bitrate in bits per second */
1657
+ bitrate: number;
1658
+ /** URL to the quality-specific playlist */
1659
+ playlistUrl: string;
1660
+ }
1661
+ /**
1662
+ * Recording metadata from the streaming manifest
1663
+ */
1664
+ interface StreamingRecordingInfo {
1665
+ /** Recording ID */
1666
+ id: string;
1667
+ /** Recording name/title */
1668
+ name: string;
1669
+ /** Optional description */
1670
+ description?: string;
1671
+ /** Duration in milliseconds */
1672
+ duration: number;
1673
+ /** Creation timestamp (ISO 8601) */
1674
+ createdAt: string;
1675
+ }
1676
+ /**
1677
+ * Audio streaming configuration
1678
+ */
1679
+ interface StreamingAudioConfig {
1680
+ /** Audio type (always 'hls' for adaptive streaming) */
1681
+ type: 'hls';
1682
+ /** URL to the HLS master playlist */
1683
+ masterPlaylistUrl: string;
1684
+ /** Available quality levels */
1685
+ qualities: AudioQuality[];
1686
+ /** Audio duration in seconds */
1687
+ duration: number;
1688
+ }
1689
+ /**
1690
+ * Events streaming configuration
1691
+ */
1692
+ interface StreamingEventsConfig {
1693
+ /** URL to the events chunk index */
1694
+ indexUrl: string;
1695
+ /** Total number of event chunks */
1696
+ totalChunks: number;
1697
+ /** Total event count */
1698
+ totalEvents: number;
1699
+ /** Duration of each chunk in milliseconds */
1700
+ chunkDurationMs: number;
1701
+ /** Whether chunks are gzip compressed */
1702
+ compressed: boolean;
1703
+ }
1704
+ /**
1705
+ * Streaming playback configuration hints
1706
+ */
1707
+ interface StreamingConfig {
1708
+ /** Number of chunks to prefetch ahead */
1709
+ prefetchChunks: number;
1710
+ /** Minimum buffer before play starts (ms) */
1711
+ minBufferMs: number;
1712
+ /** Maximum buffer to maintain (ms) */
1713
+ maxBufferMs: number;
1714
+ }
1715
+ /**
1716
+ * Complete streaming manifest structure
1717
+ * This is the main entry point returned by the streaming service.
1718
+ */
1719
+ interface StreamingManifest {
1720
+ /** Manifest version */
1721
+ version: string;
1722
+ /** Content ID */
1723
+ contentId: string;
1724
+ /** Recording metadata */
1725
+ recording: StreamingRecordingInfo;
1726
+ /** Audio streaming configuration */
1727
+ audio: StreamingAudioConfig;
1728
+ /** Events streaming configuration */
1729
+ events: StreamingEventsConfig;
1730
+ /** Streaming playback hints */
1731
+ streaming: StreamingConfig;
1732
+ }
1733
+ /**
1734
+ * Options for useRemoteStreamingPlayback hook
1735
+ */
1736
+ interface UseRemoteStreamingPlaybackOptions {
1737
+ /** URL to the streaming manifest.json */
1738
+ manifestUrl: string;
1739
+ /** Auto-play when ready */
1740
+ autoPlay?: boolean;
1741
+ /** Initial playback speed (default: 1.0) */
1742
+ defaultSpeed?: number;
1743
+ /** Maximum chunks to keep in memory (default: 5) */
1744
+ maxCacheSize?: number;
1745
+ /** Called when streaming is ready to play */
1746
+ onReady?: () => void;
1747
+ /** Called when playback starts */
1748
+ onPlay?: () => void;
1749
+ /** Called when playback pauses */
1750
+ onPause?: () => void;
1751
+ /** Called on playback progress */
1752
+ onProgress?: (timeMs: number, duration: number) => void;
1753
+ /** Called when playback completes */
1754
+ onComplete?: () => void;
1755
+ /** Called when buffering state changes */
1756
+ onBuffering?: (isBuffering: boolean) => void;
1757
+ /** Called on error */
1758
+ onError?: (error: Error) => void;
1759
+ }
1760
+ /**
1761
+ * Buffer health status for remote streaming
1762
+ */
1763
+ interface RemoteBufferHealth {
1764
+ /** Current buffer status */
1765
+ status: 'healthy' | 'buffering' | 'critical' | 'empty';
1766
+ /** Number of chunks currently cached */
1767
+ cachedChunks: number;
1768
+ /** Total number of chunks */
1769
+ totalChunks: number;
1770
+ /** Current chunk being played */
1771
+ currentChunk: number;
1772
+ /** Total buffered time in milliseconds */
1773
+ bufferedTimeMs: number;
1774
+ }
1775
+ /**
1776
+ * Performance metrics for remote streaming
1777
+ */
1778
+ interface RemoteStreamingMetrics {
1779
+ /** Average chunk fetch time in ms */
1780
+ avgChunkFetchTimeMs: number;
1781
+ /** Cache hit rate (0-1) */
1782
+ cacheHitRate: number;
1783
+ /** Number of times playback had to wait for buffering */
1784
+ bufferUnderrunCount: number;
1785
+ /** Average seek time in ms */
1786
+ avgSeekTimeMs: number;
1787
+ /** Total bytes downloaded */
1788
+ totalBytesLoaded: number;
1789
+ /** Peak number of chunks in cache */
1790
+ peakChunksCached: number;
1791
+ }
1792
+ /**
1793
+ * Complete state returned by the remote streaming hook
1794
+ */
1795
+ interface RemoteStreamingPlaybackState {
1796
+ /** Current playback state (code, terminal, etc.) */
1797
+ state: PlaybackState$1;
1798
+ /** Current playback time in milliseconds */
1799
+ currentTime: number;
1800
+ /** Total duration in milliseconds */
1801
+ duration: number;
1802
+ /** Whether playback is active */
1803
+ isPlaying: boolean;
1804
+ /** Current playback speed */
1805
+ speed: number;
1806
+ /** Whether the player is ready */
1807
+ isReady: boolean;
1808
+ /** Whether currently buffering */
1809
+ isBuffering: boolean;
1810
+ /** Buffer health information */
1811
+ bufferHealth: RemoteBufferHealth;
1812
+ /** Streaming metrics */
1813
+ metrics: RemoteStreamingMetrics;
1814
+ /** Current error (if any) */
1815
+ error: Error | null;
1816
+ /** The loaded manifest */
1817
+ manifest: StreamingManifest | null;
1818
+ }
1819
+ /**
1820
+ * Controls for remote streaming playback
1821
+ */
1822
+ interface RemoteStreamingPlaybackControls {
1823
+ /** Start playback */
1824
+ play(): void;
1825
+ /** Pause playback */
1826
+ pause(): void;
1827
+ /** Seek to a specific time (milliseconds) */
1828
+ seek(timeMs: number): Promise<void>;
1829
+ /** Set playback speed */
1830
+ setSpeed(speed: number): void;
1831
+ /** Get the audio element for custom controls */
1832
+ getAudioElement(): HTMLAudioElement | null;
1833
+ }
1834
+ /**
1835
+ * HLS player configuration
1836
+ */
1837
+ interface HLSPlayerConfig {
1838
+ /** Max buffer length in seconds */
1839
+ maxBufferLength?: number;
1840
+ /** Max max buffer length in seconds */
1841
+ maxMaxBufferLength?: number;
1842
+ /** Start level (-1 for auto) */
1843
+ startLevel?: number;
1844
+ /** Auto-start load */
1845
+ autoStartLoad?: boolean;
1846
+ }
1847
+ /**
1848
+ * HLS quality level info
1849
+ */
1850
+ interface HLSQualityLevel {
1851
+ /** Level index */
1852
+ index: number;
1853
+ /** Bitrate */
1854
+ bitrate: number;
1855
+ /** Codec string */
1856
+ codecs: string;
1857
+ }
1858
+
1859
+ type ActiveTool = ToolType;
1860
+ /**
1861
+ * Props for StreamingCoursePlayer
1862
+ */
1863
+ interface StreamingCoursePlayerProps {
1864
+ /** URL to the streaming manifest.json */
1865
+ manifestUrl: string;
1866
+ /** Theme setting */
1867
+ theme?: 'light' | 'dark' | 'system';
1868
+ /** Aspect ratio of the player */
1869
+ aspectRatio?: '16:9' | '4:3' | 'auto';
1870
+ /** Show playback controls toolbar */
1871
+ showToolbar?: boolean;
1872
+ /** Show tool sidebar */
1873
+ showToolSidebar?: boolean;
1874
+ /** Auto-play when loaded */
1875
+ autoPlay?: boolean;
1876
+ /** Default playback speed */
1877
+ defaultSpeed?: number;
1878
+ /** Allow fullscreen mode */
1879
+ allowFullscreen?: boolean;
1880
+ /** Default active tool */
1881
+ defaultTool?: ActiveTool;
1882
+ /** Maximum chunks to cache */
1883
+ maxCacheSize?: number;
1884
+ /** Additional CSS class */
1885
+ className?: string;
1886
+ /** Called when player is ready */
1887
+ onReady?: () => void;
1888
+ /** Called when playback starts */
1889
+ onPlay?: () => void;
1890
+ /** Called when playback pauses */
1891
+ onPause?: () => void;
1892
+ /** Called on progress update */
1893
+ onProgress?: (time: number, duration: number) => void;
1894
+ /** Called when playback completes */
1895
+ onComplete?: () => void;
1896
+ /** Called on error */
1897
+ onError?: (error: Error) => void;
1898
+ /** Called when buffering state changes */
1899
+ onBuffering?: (isBuffering: boolean) => void;
1900
+ /** Called when tool changes */
1901
+ onToolChange?: (tool: string) => void;
1902
+ }
1903
+ /**
1904
+ * Imperative handle for StreamingCoursePlayer
1905
+ */
1906
+ interface StreamingCoursePlayerRef {
1907
+ play(): void;
1908
+ pause(): void;
1909
+ seek(timeMs: number): Promise<void>;
1910
+ setSpeed(speed: number): void;
1911
+ getCurrentTime(): number;
1912
+ getDuration(): number;
1913
+ getState(): PlaybackState$1;
1914
+ setActiveTool(tool: ActiveTool): void;
1915
+ getManifest(): StreamingManifest | null;
1916
+ getBufferHealth(): RemoteBufferHealth;
1917
+ }
1918
+ declare const StreamingCoursePlayer: react.ForwardRefExoticComponent<StreamingCoursePlayerProps & react.RefAttributes<StreamingCoursePlayerRef>>;
1919
+
1920
+ /**
1921
+ * @ct-courses/player - Type Definitions
1922
+ */
1923
+
1924
+ /**
1925
+ * Backend adapter interface for loading recordings
1926
+ */
1927
+ interface BackendAdapter {
1928
+ getRecording(id: string): Promise<InternalRecording | null>;
1929
+ getMediaUrl?(recordingId: string): Promise<string | null>;
1930
+ }
1931
+ /**
1932
+ * Internal recording structure (from backend)
1933
+ */
1934
+ interface InternalRecording {
1935
+ id: string;
1936
+ name?: string;
1937
+ duration: number;
1938
+ events: InternalEvent[];
1939
+ markers?: RecordingMarker[];
1940
+ hasMedia?: boolean;
1941
+ mediaUrl?: string;
1942
+ createdAt?: number;
1943
+ }
1944
+ /**
1945
+ * Internal event structure (from backend)
1946
+ */
1947
+ interface InternalEvent {
1948
+ type: string;
1949
+ time: number;
1950
+ data: Record<string, unknown>;
1951
+ }
1952
+ /**
1953
+ * Recording marker for chapters
1954
+ */
1955
+ interface RecordingMarker {
1956
+ id: string;
1957
+ time: number;
1958
+ label: string;
1959
+ color?: string;
1960
+ }
1961
+ /**
1962
+ * Cursor position for replay
1963
+ */
1964
+ interface CursorPosition {
1965
+ x: number;
1966
+ y: number;
1967
+ visible: boolean;
1968
+ }
1969
+ /**
1970
+ * File system snapshot
1971
+ */
1972
+ interface FileSystemSnapshot {
1973
+ [path: string]: string;
1974
+ }
1975
+ /**
1976
+ * Document data with content (extends DocumentInfo with raw data)
1977
+ */
1978
+ interface PlayerDocumentData extends DocumentInfo {
1979
+ /** Raw document data (base64 for PDFs, etc.) */
1980
+ data: string;
1981
+ }
1982
+ /**
1983
+ * Playback engine configuration
1984
+ */
1985
+ interface PlaybackEngineConfig {
1986
+ /** Recording ID to load */
1987
+ recordingId?: string;
1988
+ /** Backend adapter for loading */
1989
+ backendAdapter?: BackendAdapter;
1990
+ /** Pre-loaded recording */
1991
+ recording?: InternalRecording;
1992
+ /** CT file blob to load */
1993
+ ctFile?: Blob;
1994
+ /** Auto-play on load */
1995
+ autoPlay?: boolean;
1996
+ /** Initial playback speed */
1997
+ initialSpeed?: number;
1998
+ /** Initial volume (0-1) */
1999
+ initialVolume?: number;
2000
+ onReady?: () => void;
2001
+ onPlay?: () => void;
2002
+ onPause?: () => void;
2003
+ onEnded?: () => void;
2004
+ onTimeUpdate?: (time: number) => void;
2005
+ onError?: (error: Error) => void;
2006
+ }
2007
+ /**
2008
+ * Playback engine state
2009
+ */
2010
+ interface PlaybackState {
2011
+ loading: boolean;
2012
+ error: string | null;
2013
+ recording: InternalRecording | null;
2014
+ isPlaying: boolean;
2015
+ currentTime: number;
2016
+ duration: number;
2017
+ playbackSpeed: number;
2018
+ volume: number;
2019
+ muted: boolean;
2020
+ code: string;
2021
+ language: string;
2022
+ terminalLines: TerminalLineData[];
2023
+ terminalInput: string;
2024
+ strokes: unknown[];
2025
+ excalidrawScene: ExcalidrawScene | null;
2026
+ activeTool: ToolType;
2027
+ markers: RecordingMarker[];
2028
+ currentFile: string | null;
2029
+ fileSystemSnapshot: FileSystemSnapshot;
2030
+ cursorPosition: CursorPosition;
2031
+ documentData: PlayerDocumentData | null;
2032
+ documentPage: number;
2033
+ documentZoom: number;
2034
+ documentScroll: ScrollPosition;
2035
+ mediaUrl: string | null;
2036
+ isInteracting: boolean;
2037
+ }
2038
+ /**
2039
+ * Playback controls
2040
+ */
2041
+ interface PlaybackControls$1 {
2042
+ setAudioElement: (element: HTMLAudioElement | null) => void;
2043
+ setVolume: (volume: number) => void;
2044
+ setMuted: (muted: boolean) => void;
2045
+ play: () => void;
2046
+ pause: () => void;
2047
+ togglePlay: () => void;
2048
+ seekTo: (timeSeconds: number) => void;
2049
+ skip: (seconds: number) => void;
2050
+ restart: () => void;
2051
+ setSpeed: (speed: number) => void;
2052
+ enterInteractiveMode: () => void;
2053
+ interactiveSetCode: (code: string) => void;
2054
+ interactiveSetLanguage: (language: string) => void;
2055
+ interactiveSetTerminalInput: (input: string) => void;
2056
+ interactiveSetTerminalLines: (lines: TerminalLineData[]) => void;
2057
+ interactiveAddTerminalLines: (lines: TerminalLineData[]) => void;
2058
+ interactiveSetStrokes: (strokes: unknown[]) => void;
2059
+ interactiveSetExcalidrawScene: (scene: ExcalidrawScene | null) => void;
2060
+ interactiveSetDocumentPage: (page: number) => void;
2061
+ interactiveSetDocumentZoom: (zoom: number) => void;
2062
+ interactiveSetDocumentScroll: (scroll: ScrollPosition) => void;
2063
+ setActiveTool: (tool: ToolType) => void;
2064
+ }
2065
+ /**
2066
+ * Full playback engine result
2067
+ */
2068
+ type UsePlaybackEngineResult = PlaybackState & PlaybackControls$1;
2069
+ /**
2070
+ * Player component props
2071
+ */
2072
+ interface PlayerProps {
2073
+ ctFile?: Blob;
2074
+ recording?: CTRecording;
2075
+ recordingId?: string;
2076
+ backendAdapter?: BackendAdapter;
2077
+ autoPlay?: boolean;
2078
+ showControls?: boolean;
2079
+ showTimeline?: boolean;
2080
+ showToolSidebar?: boolean;
2081
+ showAudio?: boolean;
2082
+ defaultSpeed?: number;
2083
+ allowInteraction?: boolean;
2084
+ theme?: 'light' | 'dark' | 'system';
2085
+ className?: string;
2086
+ onReady?: () => void;
2087
+ onPlay?: () => void;
2088
+ onPause?: () => void;
2089
+ onEnded?: () => void;
2090
+ onTimeUpdate?: (time: number) => void;
2091
+ onError?: (error: Error) => void;
2092
+ onInteractionStart?: () => void;
2093
+ onInteractionEnd?: (code: string) => void;
2094
+ }
2095
+ /**
2096
+ * Player imperative handle
2097
+ */
2098
+ interface PlayerRef {
2099
+ play(): void;
2100
+ pause(): void;
2101
+ seek(timeMs: number): void;
2102
+ setSpeed(speed: number): void;
2103
+ getCurrentTime(): number;
2104
+ getDuration(): number;
2105
+ enterInteractiveMode(): void;
2106
+ exitInteractiveMode(): void;
2107
+ setActiveTool(tool: ToolType): void;
2108
+ }
2109
+ /**
2110
+ * PlayerControls props
2111
+ */
2112
+ interface PlayerControlsProps$1 {
2113
+ isPlaying: boolean;
2114
+ currentTime: number;
2115
+ duration: number;
2116
+ playbackSpeed: number;
2117
+ volume: number;
2118
+ muted: boolean;
2119
+ isInteracting: boolean;
2120
+ onPlay: () => void;
2121
+ onPause: () => void;
2122
+ onSeek: (time: number) => void;
2123
+ onSpeedChange: (speed: number) => void;
2124
+ onVolumeChange: (volume: number) => void;
2125
+ onMuteToggle: () => void;
2126
+ className?: string;
2127
+ }
2128
+ /**
2129
+ * Timeline props
2130
+ */
2131
+ interface TimelineProps$1 {
2132
+ currentTime: number;
2133
+ duration: number;
2134
+ markers?: RecordingMarker[];
2135
+ buffered?: Array<{
2136
+ start: number;
2137
+ end: number;
2138
+ }>;
2139
+ onSeek: (time: number) => void;
2140
+ onMarkerClick?: (marker: RecordingMarker) => void;
2141
+ className?: string;
2142
+ }
2143
+ /**
2144
+ * Speed selector props
2145
+ */
2146
+ interface SpeedSelectorProps {
2147
+ speed: number;
2148
+ onSpeedChange: (speed: number) => void;
2149
+ speeds?: number[];
2150
+ className?: string;
2151
+ }
2152
+ /**
2153
+ * Volume control props
2154
+ */
2155
+ interface VolumeControlProps {
2156
+ volume: number;
2157
+ muted: boolean;
2158
+ onVolumeChange: (volume: number) => void;
2159
+ onMuteToggle: () => void;
2160
+ className?: string;
2161
+ }
2162
+
2163
+ /**
2164
+ * usePlayback Hook
2165
+ *
2166
+ * Core playback engine hook using @ct-courses/core StateEngine.
2167
+ * Supports audio synchronization as master clock (no video/webcam).
2168
+ *
2169
+ * CRITICAL SYNC ARCHITECTURE:
2170
+ * - AUDIO is the MASTER CLOCK when media exists
2171
+ * - Events are applied based on audio.currentTime
2172
+ * - Without media, use requestAnimationFrame timing
2173
+ */
2174
+
2175
+ /**
2176
+ * Playback state returned by the hook
2177
+ */
2178
+ interface PlaybackHookState {
2179
+ /** Current playback state */
2180
+ state: PlaybackState$1;
2181
+ /** Current time in milliseconds */
2182
+ currentTime: number;
2183
+ /** Total duration in milliseconds */
2184
+ duration: number;
2185
+ /** Whether currently playing */
2186
+ isPlaying: boolean;
2187
+ /** Current playback speed */
2188
+ speed: number;
2189
+ /** Whether recording is loaded */
2190
+ isLoaded: boolean;
2191
+ /** Volume level (0-1) */
2192
+ volume: number;
2193
+ /** Whether audio is muted */
2194
+ muted: boolean;
2195
+ /** Whether user is interacting (paused with edits) */
2196
+ isInteracting: boolean;
2197
+ }
2198
+ /**
2199
+ * Playback controls
2200
+ */
2201
+ interface PlaybackControls {
2202
+ play(): void;
2203
+ pause(): void;
2204
+ seek(timeMs: number): void;
2205
+ setSpeed(speed: number): void;
2206
+ setVolume(volume: number): void;
2207
+ setMuted(muted: boolean): void;
2208
+ setAudioElement(audio: HTMLAudioElement | null): void;
2209
+ enterInteractiveMode(): void;
2210
+ exitInteractiveMode(): void;
2211
+ setInteractiveCode(code: string): void;
2212
+ setInteractiveLanguage(language: string): void;
2213
+ setInteractiveTerminalLines(lines: PlaybackState$1['terminalLines']): void;
2214
+ addInteractiveTerminalLines(lines: PlaybackState$1['terminalLines']): void;
2215
+ setInteractiveExcalidrawScene(scene: PlaybackState$1['excalidrawScene']): void;
2216
+ setInteractiveDocumentPage(page: number): void;
2217
+ setInteractiveDocumentZoom(zoom: number): void;
2218
+ setInteractiveDocumentScroll(scroll: {
2219
+ x: number;
2220
+ y: number;
2221
+ }): void;
2222
+ }
2223
+ /**
2224
+ * Options for usePlayback hook
2225
+ */
2226
+ interface UsePlaybackOptions {
2227
+ recording: CTRecording | null;
2228
+ autoPlay?: boolean;
2229
+ defaultSpeed?: number;
2230
+ defaultVolume?: number;
2231
+ onPlay?: () => void;
2232
+ onPause?: () => void;
2233
+ onProgress?: (time: number, duration: number) => void;
2234
+ onComplete?: () => void;
2235
+ onError?: (error: Error) => void;
2236
+ }
2237
+ /**
2238
+ * Hook for managing playback of a CT recording
2239
+ * Supports audio synchronization as master clock
2240
+ */
2241
+ declare function usePlayback(options: UsePlaybackOptions): PlaybackHookState & {
2242
+ controls: PlaybackControls;
2243
+ };
2244
+
2245
+ /**
2246
+ * useStreamingPlayback Hook
2247
+ *
2248
+ * Streaming playback engine hook for large recordings.
2249
+ * Supports lazy chunk loading, adaptive buffering, and efficient seeking.
2250
+ *
2251
+ * @packageDocumentation
2252
+ */
2253
+
2254
+ /**
2255
+ * Buffer health status
2256
+ */
2257
+ interface BufferHealth {
2258
+ status: 'healthy' | 'buffering' | 'critical' | 'empty';
2259
+ loadedChunks: number;
2260
+ totalChunks: number;
2261
+ currentChunk: number;
2262
+ bufferedTimeMs: number;
2263
+ percentLoaded: number;
2264
+ }
2265
+ /**
2266
+ * Streaming metrics for performance monitoring
2267
+ */
2268
+ interface StreamingMetrics {
2269
+ avgChunkLoadTimeMs: number;
2270
+ chunkCacheHitRate: number;
2271
+ bufferUnderrunCount: number;
2272
+ avgBufferHealthPercent: number;
2273
+ avgSeekTimeMs: number;
2274
+ seekCacheHitRate: number;
2275
+ peakChunksCached: number;
2276
+ totalBytesLoaded: number;
2277
+ }
2278
+ /**
2279
+ * Streaming playback state
2280
+ */
2281
+ interface StreamingPlaybackState {
2282
+ state: PlaybackState$1;
2283
+ currentTime: number;
2284
+ duration: number;
2285
+ isPlaying: boolean;
2286
+ speed: number;
2287
+ isLoaded: boolean;
2288
+ isBuffering: boolean;
2289
+ bufferHealth: BufferHealth;
2290
+ isStreaming: boolean;
2291
+ metrics: StreamingMetrics;
2292
+ }
2293
+ /**
2294
+ * Streaming playback controls
2295
+ */
2296
+ interface StreamingPlaybackControls {
2297
+ play(): void;
2298
+ pause(): void;
2299
+ seek(timeMs: number): Promise<void>;
2300
+ setSpeed(speed: number): void;
2301
+ preloadRange(startMs: number, endMs: number): Promise<void>;
2302
+ }
2303
+ /**
2304
+ * Options for useStreamingPlayback hook
2305
+ */
2306
+ interface UseStreamingPlaybackOptions {
2307
+ recording: CTRecording | null;
2308
+ chunkIndex?: CTEventChunkIndex | null;
2309
+ loadChunk?: (chunkNumber: number) => Promise<ChunkLoadResult>;
2310
+ autoPlay?: boolean;
2311
+ defaultSpeed?: number;
2312
+ bufferAhead?: number;
2313
+ bufferBehind?: number;
2314
+ maxChunksInMemory?: number;
2315
+ onPlay?: () => void;
2316
+ onPause?: () => void;
2317
+ onProgress?: (time: number, duration: number) => void;
2318
+ onComplete?: () => void;
2319
+ onBuffering?: (isBuffering: boolean) => void;
2320
+ onChunkLoad?: (chunkNumber: number) => void;
2321
+ onError?: (error: Error) => void;
2322
+ }
2323
+ /**
2324
+ * Hook for streaming playback of large CT recordings
2325
+ */
2326
+ declare function useStreamingPlayback(options: UseStreamingPlaybackOptions): StreamingPlaybackState & {
2327
+ controls: StreamingPlaybackControls;
2328
+ };
2329
+
2330
+ /**
2331
+ * useRemoteStreamingPlayback Hook
2332
+ *
2333
+ * React hook for streaming playback from a remote CDN/R2 storage.
2334
+ * Handles HLS audio streaming and lazy-loading of event chunks.
2335
+ *
2336
+ * This is designed for the streaming service architecture where:
2337
+ * - Audio is served via HLS adaptive bitrate streaming
2338
+ * - Events are stored in gzip-compressed chunks on CDN
2339
+ * - The manifest provides URLs for all resources
2340
+ *
2341
+ * @packageDocumentation
2342
+ */
2343
+
2344
+ /**
2345
+ * Hook for remote streaming playback from CDN
2346
+ */
2347
+ declare function useRemoteStreamingPlayback(options: UseRemoteStreamingPlaybackOptions): RemoteStreamingPlaybackState & {
2348
+ controls: RemoteStreamingPlaybackControls;
2349
+ };
2350
+
2351
+ /**
2352
+ * useInteractiveMode Hook
2353
+ *
2354
+ * Manages interactive mode where users can edit code while paused.
2355
+ */
2356
+
2357
+ /**
2358
+ * Interactive mode state
2359
+ */
2360
+ interface InteractiveModeState {
2361
+ /** Whether interactive mode is active */
2362
+ isActive: boolean;
2363
+ /** Modified code (user edits) */
2364
+ modifiedCode: string;
2365
+ /** Whether code has been modified from original */
2366
+ hasChanges: boolean;
2367
+ }
2368
+ /**
2369
+ * Interactive mode controls
2370
+ */
2371
+ interface InteractiveModeControls {
2372
+ /** Enter interactive mode */
2373
+ enter(): void;
2374
+ /** Exit interactive mode */
2375
+ exit(): void;
2376
+ /** Update the modified code */
2377
+ updateCode(code: string): void;
2378
+ /** Reset code to original */
2379
+ resetCode(): void;
2380
+ /** Run the modified code */
2381
+ runCode(): Promise<string>;
2382
+ }
2383
+ /**
2384
+ * Options for useInteractiveMode hook
2385
+ */
2386
+ interface UseInteractiveModeOptions {
2387
+ /** Current playback state */
2388
+ playbackState: PlaybackState$1;
2389
+ /** Callback when entering interactive mode */
2390
+ onEnter?: () => void;
2391
+ /** Callback when exiting interactive mode */
2392
+ onExit?: (code: string, hasChanges: boolean) => void;
2393
+ /** Code execution function */
2394
+ executeCode?: (code: string, language: string) => Promise<string>;
2395
+ }
2396
+ /**
2397
+ * Hook for managing interactive mode
2398
+ */
2399
+ declare function useInteractiveMode(options: UseInteractiveModeOptions): InteractiveModeState & {
2400
+ controls: InteractiveModeControls;
2401
+ };
2402
+
2403
+ /**
2404
+ * useAudioSync Hook
2405
+ *
2406
+ * Synchronizes audio playback with event state.
2407
+ * Handles audio/event drift and maintains sync within tolerance.
2408
+ *
2409
+ * @packageDocumentation
2410
+ */
2411
+ /**
2412
+ * Audio sync state
2413
+ */
2414
+ interface AudioSyncState {
2415
+ /** Current audio time in ms */
2416
+ audioTime: number;
2417
+ /** Current event time in ms */
2418
+ eventTime: number;
2419
+ /** Drift between audio and events (ms) */
2420
+ drift: number;
2421
+ /** Is sync healthy (within tolerance) */
2422
+ isSynced: boolean;
2423
+ /** Is audio loaded */
2424
+ isAudioReady: boolean;
2425
+ }
2426
+ /**
2427
+ * Audio sync controls
2428
+ */
2429
+ interface AudioSyncControls {
2430
+ /** Sync events to audio time */
2431
+ syncToAudio(): void;
2432
+ /** Sync audio to event time */
2433
+ syncAudioTo(timeMs: number): void;
2434
+ /** Force resync */
2435
+ forceResync(): void;
2436
+ }
2437
+ /**
2438
+ * Options for useAudioSync hook
2439
+ */
2440
+ interface UseAudioSyncOptions {
2441
+ /** Reference to audio element */
2442
+ audioRef: React.RefObject<HTMLAudioElement>;
2443
+ /** Current event time */
2444
+ eventTime: number;
2445
+ /** Is currently playing */
2446
+ isPlaying: boolean;
2447
+ /** Playback speed */
2448
+ speed: number;
2449
+ /** Maximum allowed drift in ms before resync (default: 500ms) */
2450
+ driftTolerance?: number;
2451
+ /** Callback when audio time updates */
2452
+ onAudioTimeUpdate?: (timeMs: number) => void;
2453
+ /** Callback when sync is lost */
2454
+ onSyncLost?: (drift: number) => void;
2455
+ /** Callback when sync is restored */
2456
+ onSyncRestored?: () => void;
2457
+ }
2458
+ /**
2459
+ * Hook for synchronizing audio playback with event state
2460
+ */
2461
+ declare function useAudioSync(options: UseAudioSyncOptions): AudioSyncState & {
2462
+ controls: AudioSyncControls;
2463
+ };
2464
+ /**
2465
+ * Hook for managing audio element lifecycle
2466
+ */
2467
+ declare function useAudioElement(src: string | null): {
2468
+ audioRef: react.MutableRefObject<HTMLAudioElement | null>;
2469
+ isLoaded: boolean;
2470
+ error: Error | null;
2471
+ duration: number;
2472
+ };
2473
+ /** @deprecated Use AudioSyncState instead */
2474
+ type VideoSyncState = AudioSyncState;
2475
+ /** @deprecated Use AudioSyncControls instead */
2476
+ type VideoSyncControls = AudioSyncControls;
2477
+ /** @deprecated Use UseAudioSyncOptions instead */
2478
+ type UseVideoSyncOptions = UseAudioSyncOptions;
2479
+ /** @deprecated Use useAudioSync instead */
2480
+ declare const useVideoSync: typeof useAudioSync;
2481
+ /** @deprecated Use useAudioElement instead */
2482
+ declare const useVideoElement: typeof useAudioElement;
2483
+
2484
+ /**
2485
+ * HLS Loader Utility
2486
+ *
2487
+ * Wrapper around HLS.js for adaptive audio streaming.
2488
+ * Handles both native HLS support (Safari) and HLS.js polyfill.
2489
+ *
2490
+ * @packageDocumentation
2491
+ */
2492
+
2493
+ interface HLSPlayerInstance {
2494
+ /** The HLS.js instance (null if using native HLS) */
2495
+ hls: Hls | null;
2496
+ /** The audio element */
2497
+ audioElement: HTMLAudioElement;
2498
+ /** Whether this is using native HLS (Safari) */
2499
+ isNative: boolean;
2500
+ /** Destroy and cleanup */
2501
+ destroy: () => void;
2502
+ /** Get current quality levels */
2503
+ getQualityLevels: () => HLSQualityLevel[];
2504
+ /** Set quality level (-1 for auto) */
2505
+ setQualityLevel: (index: number) => void;
2506
+ /** Get current quality level */
2507
+ getCurrentQualityLevel: () => number;
2508
+ /** Add event listener for HLS events */
2509
+ on: (event: string, callback: (...args: unknown[]) => void) => void;
2510
+ /** Remove event listener */
2511
+ off: (event: string, callback: (...args: unknown[]) => void) => void;
2512
+ }
2513
+ interface HLSEvents {
2514
+ /** Manifest has been parsed and is ready */
2515
+ MANIFEST_PARSED: 'hlsManifestParsed';
2516
+ /** Level has switched */
2517
+ LEVEL_SWITCHED: 'hlsLevelSwitched';
2518
+ /** Error occurred */
2519
+ ERROR: 'hlsError';
2520
+ /** Buffering started */
2521
+ BUFFER_CREATED: 'hlsBufferCreated';
2522
+ /** Fragment loaded */
2523
+ FRAG_LOADED: 'hlsFragLoaded';
2524
+ }
2525
+ declare const HLS_EVENTS: HLSEvents;
2526
+ /**
2527
+ * Check if the browser supports HLS.js
2528
+ */
2529
+ declare function isHlsSupported(): boolean;
2530
+ /**
2531
+ * Check if the browser has native HLS support (Safari)
2532
+ */
2533
+ declare function hasNativeHlsSupport(): boolean;
2534
+ /**
2535
+ * Check if any form of HLS playback is possible
2536
+ */
2537
+ declare function canPlayHls(): boolean;
2538
+ /**
2539
+ * Create an HLS player instance
2540
+ *
2541
+ * @param audioElement - The audio element to attach to
2542
+ * @param masterPlaylistUrl - URL to the HLS master playlist
2543
+ * @param config - Optional configuration
2544
+ * @returns HLS player instance
2545
+ * @throws Error if HLS is not supported
2546
+ */
2547
+ declare function createHlsPlayer(audioElement: HTMLAudioElement, masterPlaylistUrl: string, config?: HLSPlayerConfig): HLSPlayerInstance;
2548
+ /**
2549
+ * Destroy an HLS player instance safely
2550
+ */
2551
+ declare function destroyHlsPlayer(player: HLSPlayerInstance | null): void;
2552
+
2553
+ interface Marker$1 {
2554
+ time: number;
2555
+ label?: string;
2556
+ type?: 'chapter' | 'highlight';
2557
+ }
2558
+ interface PlayerControlsProps {
2559
+ isPlaying: boolean;
2560
+ currentTime: number;
2561
+ duration: number;
2562
+ volume: number;
2563
+ muted: boolean;
2564
+ playbackSpeed: number;
2565
+ markers?: Marker$1[];
2566
+ isFullscreen?: boolean;
2567
+ onPlayPause: () => void;
2568
+ onSeek: (timeMs: number) => void;
2569
+ onSeekStart?: () => void;
2570
+ onSeekEnd?: () => void;
2571
+ onSkip: (seconds: number) => void;
2572
+ onRestart: () => void;
2573
+ onVolumeChange: (volume: number) => void;
2574
+ onMuteToggle: () => void;
2575
+ onSpeedChange: (speed: number) => void;
2576
+ onFullscreenToggle?: () => void;
2577
+ showMarkers?: boolean;
2578
+ compact?: boolean;
2579
+ containerRef?: react__default.RefObject<HTMLElement>;
2580
+ }
2581
+ declare function PlayerControls({ isPlaying, currentTime, duration, volume, muted, playbackSpeed, markers, isFullscreen, onPlayPause, onSeek, onSeekStart, onSeekEnd, onSkip, onRestart, onVolumeChange, onMuteToggle, onSpeedChange, onFullscreenToggle, showMarkers, compact, }: PlayerControlsProps): react_jsx_runtime.JSX.Element;
2582
+
2583
+ /**
2584
+ * Timeline Component
2585
+ *
2586
+ * Enhanced visual timeline with markers, chunk indicators, and chapter navigation.
2587
+ * Supports streaming playback visualization and buffer status.
2588
+ *
2589
+ * @packageDocumentation
2590
+ */
2591
+ /**
2592
+ * Timeline marker
2593
+ */
2594
+ interface Marker {
2595
+ id: string;
2596
+ time: number;
2597
+ label: string;
2598
+ type: 'chapter' | 'highlight' | 'quiz' | 'note' | 'bookmark' | 'error';
2599
+ description?: string;
2600
+ }
2601
+ /**
2602
+ * Chunk info for streaming visualization
2603
+ */
2604
+ interface ChunkInfo {
2605
+ id: number;
2606
+ startTime: number;
2607
+ endTime: number;
2608
+ loaded: boolean;
2609
+ loading?: boolean;
2610
+ size?: number;
2611
+ }
2612
+ /**
2613
+ * Buffered range
2614
+ */
2615
+ interface BufferedRange {
2616
+ start: number;
2617
+ end: number;
2618
+ }
2619
+ /**
2620
+ * Props for Timeline component
2621
+ */
2622
+ interface TimelineProps {
2623
+ /** Current time in ms */
2624
+ currentTime: number;
2625
+ /** Total duration in ms */
2626
+ duration: number;
2627
+ /** Timeline markers */
2628
+ markers?: Marker[];
2629
+ /** Chunk info for streaming visualization */
2630
+ chunks?: ChunkInfo[];
2631
+ /** Buffered ranges */
2632
+ buffered?: BufferedRange[];
2633
+ /** Seek callback */
2634
+ onSeek: (timeMs: number) => void;
2635
+ /** Marker click callback */
2636
+ onMarkerClick?: (marker: Marker) => void;
2637
+ /** Theme */
2638
+ theme?: 'light' | 'dark';
2639
+ /** Show chapter labels */
2640
+ showChapterLabels?: boolean;
2641
+ /** Show buffer status */
2642
+ showBufferStatus?: boolean;
2643
+ /** Show chunk indicators */
2644
+ showChunkIndicators?: boolean;
2645
+ /** Compact mode */
2646
+ compact?: boolean;
2647
+ }
2648
+ /**
2649
+ * Timeline component with markers and chunk indicators
2650
+ */
2651
+ declare function Timeline({ currentTime, duration, markers, chunks, buffered, onSeek, onMarkerClick, theme, showChapterLabels, showBufferStatus, showChunkIndicators, compact, }: TimelineProps): JSX.Element;
2652
+
2653
+ /**
2654
+ * AudioOverlay Component
2655
+ *
2656
+ * Audio playback overlay with controls and visualization.
2657
+ * Replaces WebcamOverlay for audio-only playback.
2658
+ *
2659
+ * @packageDocumentation
2660
+ */
2661
+ /**
2662
+ * Overlay position presets
2663
+ */
2664
+ type OverlayPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'custom';
2665
+ /**
2666
+ * Custom position
2667
+ */
2668
+ interface CustomPosition {
2669
+ x: number;
2670
+ y: number;
2671
+ }
2672
+ /**
2673
+ * Props for AudioOverlay component
2674
+ */
2675
+ interface AudioOverlayProps {
2676
+ /** Audio source URL */
2677
+ src: string | null;
2678
+ /** Current time to sync to (ms) */
2679
+ currentTime: number;
2680
+ /** Whether audio should be playing */
2681
+ isPlaying: boolean;
2682
+ /** Playback rate */
2683
+ playbackRate?: number;
2684
+ /** Overlay position preset */
2685
+ position?: OverlayPosition;
2686
+ /** Custom position (when position='custom') */
2687
+ customPosition?: CustomPosition;
2688
+ /** Whether to show the overlay */
2689
+ visible?: boolean;
2690
+ /** Enable dragging */
2691
+ draggable?: boolean;
2692
+ /** Show controls on hover */
2693
+ showControls?: boolean;
2694
+ /** Opacity (0-1) */
2695
+ opacity?: number;
2696
+ /** On position change callback */
2697
+ onPositionChange?: (position: CustomPosition) => void;
2698
+ /** Callback to pass audio element reference for sync */
2699
+ onAudioRef?: (audio: HTMLAudioElement | null) => void;
2700
+ /** Whether audio is muted */
2701
+ muted?: boolean;
2702
+ /** Volume level (0-1) */
2703
+ volume?: number;
2704
+ /** Sync tolerance in ms */
2705
+ syncTolerance?: number;
2706
+ }
2707
+ /**
2708
+ * Audio overlay for instructor audio
2709
+ *
2710
+ * NOTE: Audio playback is now controlled entirely by parent (usePlayback).
2711
+ * Props like currentTime, isPlaying, playbackRate, muted, volume, syncTolerance
2712
+ * are kept for backward compatibility but are no longer used.
2713
+ */
2714
+ 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;
2715
+
2716
+ 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 };