@bendyline/squisq-react 1.4.1 → 2.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.
Files changed (45) hide show
  1. package/README.md +30 -3
  2. package/dist/index.d.ts +185 -27
  3. package/dist/index.js +1323 -614
  4. package/dist/index.js.map +1 -1
  5. package/dist/squisq-player.global.js +54 -37
  6. package/dist/squisq-player.global.js.map +1 -1
  7. package/dist/standalone-source.js +1 -1
  8. package/package.json +2 -2
  9. package/src/BlockRenderer.tsx +53 -17
  10. package/src/DocControlsSlideshow.tsx +235 -7
  11. package/src/DocPlayer.tsx +462 -195
  12. package/src/DocPlayerWithSidebar.tsx +4 -0
  13. package/src/DocProgressBar.tsx +40 -1
  14. package/src/LinearDocView.tsx +135 -62
  15. package/src/MarkdownRenderer.tsx +40 -97
  16. package/src/MediaClipLayer.tsx +12 -2
  17. package/src/__tests__/BlockRenderer.test.tsx +79 -8
  18. package/src/__tests__/DocControlsSlideshow.test.tsx +94 -1
  19. package/src/__tests__/DocPlayer.test.tsx +556 -2
  20. package/src/__tests__/DocProgressBar.test.tsx +28 -2
  21. package/src/__tests__/LinearDocView.test.tsx +91 -11
  22. package/src/__tests__/MapLayer.test.tsx +63 -0
  23. package/src/__tests__/MarkdownRenderer.test.tsx +13 -2
  24. package/src/__tests__/MediaClipLayer.test.tsx +70 -0
  25. package/src/__tests__/MediaContext.test.tsx +51 -0
  26. package/src/__tests__/PathLayer.test.tsx +12 -1
  27. package/src/__tests__/VideoLayer.test.tsx +94 -0
  28. package/src/__tests__/fillStyle.test.tsx +3 -2
  29. package/src/__tests__/standaloneEntry.test.tsx +103 -0
  30. package/src/__tests__/useAudioSync.test.ts +49 -0
  31. package/src/__tests__/useDocPlayback.transition.test.ts +48 -5
  32. package/src/__tests__/useViewportOrientation.test.ts +22 -0
  33. package/src/hooks/MediaContext.tsx +12 -3
  34. package/src/hooks/useAudioSync.ts +61 -12
  35. package/src/hooks/useDocPlayback.ts +40 -12
  36. package/src/hooks/useViewportOrientation.ts +2 -4
  37. package/src/index.ts +5 -2
  38. package/src/layers/MapLayer.tsx +7 -6
  39. package/src/layers/PathLayer.tsx +20 -11
  40. package/src/layers/ShapeLayer.tsx +4 -2
  41. package/src/layers/TextLayer.tsx +4 -3
  42. package/src/layers/TreeLayer.tsx +167 -0
  43. package/src/layers/VideoLayer.tsx +20 -6
  44. package/src/standalone-entry.tsx +91 -14
  45. package/src/types.ts +19 -13
package/README.md CHANGED
@@ -70,6 +70,7 @@ Blocks are composed of typed layers rendered as SVG:
70
70
  | `VideoLayer` | Embedded video with playback sync |
71
71
  | `TableLayer` | HTML table embedded via SVG `<foreignObject>` |
72
72
  | `MapLayer` | Tile-based map rendering |
73
+ | `TreeLayer` | Interactive filesystem/outline tree |
73
74
 
74
75
  ## Hooks
75
76
 
@@ -82,24 +83,50 @@ Blocks are composed of typed layers rendered as SVG:
82
83
  | `useAutoSurface` | Live light/dark surface detection via `prefers-color-scheme` |
83
84
  | `useMediaProvider` / `useMediaUrl` | Media URL resolution via `MediaContext` |
84
85
 
86
+ `useDocPlayback` takes configuration as an options object:
87
+
88
+ ```ts
89
+ useDocPlayback(doc, currentTime, { viewport, theme, onSeek });
90
+ ```
91
+
85
92
  ## Standalone Player
86
93
 
87
94
  A self-contained global build is available for non-React environments. It
88
- exposes a `SquisqPlayer` global with `mount`, `mountStatic`, `unmount`, and
89
- `version`:
95
+ exposes a `SquisqPlayer` global with `mount`, `getHandle`, `unmount`, and
96
+ `version`. `mount` returns an instance handle.
97
+
98
+ The former `mountStatic()` shortcut was removed; pass `mode: 'static'` to
99
+ `mount()`. Render methods are instance-scoped and are no longer copied to
100
+ top-level `window.seekTo` / `window.getDuration` properties.
101
+
102
+ Interactive mount:
90
103
 
91
104
  ```html
92
105
  <script src="https://unpkg.com/@bendyline/squisq-react/dist/squisq-player.global.js"></script>
93
106
  <div id="player"></div>
94
107
  <script>
95
108
  // docJson is a Doc (e.g. produced by markdownToDoc and serialized)
96
- SquisqPlayer.mount(document.getElementById('player'), docJson, {
109
+ const root = document.getElementById('player');
110
+ const handle = SquisqPlayer.mount(root, docJson, {
97
111
  mode: 'slideshow', // or 'static' for a scrollable document view
98
112
  basePath: '/',
99
113
  });
114
+
115
+ // In render mode: const api = await handle.renderAPI;
116
+ // The same handle is available later as SquisqPlayer.getHandle(root).
100
117
  </script>
101
118
  ```
102
119
 
120
+ For headless capture, add `renderMode: true`, then await
121
+ `handle.renderAPI` before calling `seekTo()` or reading render metadata.
122
+ TypeScript hosts can import `MountOptions` and `SquisqPlayerHandle` from the
123
+ package root.
124
+
125
+ Set `animationsEnabled: false` on `DocPlayer`, `BlockRenderer`, or standalone
126
+ `mount()` to render authored layer animations and block transitions as static
127
+ content. Embedded video, timed media, captions, audio, and document timing stay
128
+ active; this makes the option suitable for compact MP4 and animated-GIF export.
129
+
103
130
  For build-time embedding, `@bendyline/squisq-react/standalone-source` exports
104
131
  the same bundle as a string constant (`PLAYER_BUNDLE`) — used by
105
132
  `@bendyline/squisq-formats` and the CLI to produce single-file HTML exports.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Block, Doc, Theme, SurfaceScheme, Transition, CaptionTrack, ViewportConfig as ViewportConfig$1, ImageLayer as ImageLayer$1, TextLayer as TextLayer$1, ShapeLayer as ShapeLayer$1, PathLayer as PathLayer$1, VideoLayer as VideoLayer$1, TableLayer as TableLayer$1, MapLayer as MapLayer$1, ScheduledClip, AudioTrack, MediaProvider } from '@bendyline/squisq/schemas';
2
+ import { Block, Doc, Theme, SurfaceScheme, Transition, CaptionTrack, ViewportConfig as ViewportConfig$1, ImageLayer as ImageLayer$1, TextLayer as TextLayer$1, ShapeLayer as ShapeLayer$1, PathLayer as PathLayer$1, VideoLayer as VideoLayer$1, TableLayer as TableLayer$1, TreeLayer as TreeLayer$1, MapLayer as MapLayer$1, ScheduledClip, AudioTrack, MediaProvider } from '@bendyline/squisq/schemas';
3
3
  import { ViewportConfig, ViewportOrientation } from '@bendyline/squisq/doc';
4
4
  export { getAnimationStyle, getTransitionClass } from '@bendyline/squisq/doc';
5
5
  import { MarkdownBlockNode, HtmlPolicy } from '@bendyline/squisq/markdown';
@@ -86,8 +86,12 @@ type ControlsLayout = 'overlay' | 'sidebar' | 'bottom';
86
86
  * `markdownDocToPlainHtml` export produces. No SquisqPlayer, no SVG
87
87
  * cards — just `<h1>`/`<p>`/`<ul>` etc. inside a sandboxed iframe.
88
88
  * Use when you want a WYSIWYG view of the simple HTML export.
89
+ * - `'narrate'` — Teleprompter/performance surface. DocPlayer does not
90
+ * implement this mode; it is owned by the editor package
91
+ * (`@bendyline/squisq-editor-react`), which renders its own
92
+ * voice-paced teleprompter view for it.
89
93
  */
90
- type DisplayMode = 'video' | 'slideshow' | 'linear' | 'page';
94
+ type DisplayMode = 'video' | 'slideshow' | 'linear' | 'page' | 'narrate';
91
95
  /**
92
96
  * Caption display style.
93
97
  *
@@ -117,6 +121,8 @@ interface PlaybackState$1 {
117
121
  isPlaying: boolean;
118
122
  currentTime: number;
119
123
  totalDuration: number;
124
+ /** Whether the managed cover is the visual currently shown. */
125
+ isCoverVisible?: boolean;
120
126
  currentBlockIndex: number;
121
127
  totalBlocks: number;
122
128
  docProgress: number;
@@ -131,6 +137,12 @@ interface PlaybackState$1 {
131
137
  currentSegmentName: string | null;
132
138
  /** Current block data (for extracting image info, etc.) */
133
139
  currentBlock: Block | null;
140
+ /** Optional display label for non-block slides, e.g. the managed cover. */
141
+ currentSlideLabel?: string;
142
+ /** Optional human-facing slide number, separate from internal nav index. */
143
+ currentSlideNumber?: number;
144
+ /** Optional human-facing slide total, separate from internal nav total. */
145
+ totalSlideNumber?: number;
134
146
  }
135
147
  /** Playback actions exposed to external control components */
136
148
  interface PlaybackActions$1 {
@@ -178,15 +190,15 @@ interface RenderChapterInfo {
178
190
  duration: number;
179
191
  }
180
192
  /**
181
- * API surface exposed on `window` in render mode and debug mode.
182
- * Used by Playwright for video export and by ?debug=true for testing.
193
+ * Instance-scoped API created in render mode and debug mode.
194
+ * React hosts receive it via `DocPlayer.onRenderAPIReady`; standalone hosts
195
+ * receive it from their mount handle.
183
196
  *
184
197
  * @example
185
198
  * ```ts
186
- * // In Playwright:
187
- * const w = window as unknown as SquisqWindow;
188
- * await w.seekTo!(5.0);
189
- * const blocks = w.getBlocks!();
199
+ * const handle = SquisqPlayer.getHandle(rootElement);
200
+ * const api = await handle?.renderAPI;
201
+ * await api?.seekTo(5.0);
190
202
  * ```
191
203
  */
192
204
  interface SquisqRenderAPI {
@@ -200,11 +212,6 @@ interface SquisqRenderAPI {
200
212
  hideCover: () => Promise<void>;
201
213
  hasCoverBlock: () => boolean;
202
214
  }
203
- /**
204
- * Window augmented with optional SquisqRenderAPI properties.
205
- * Each property is optional because they're only present in render/debug mode.
206
- */
207
- type SquisqWindow = Window & typeof globalThis & Partial<SquisqRenderAPI>;
208
215
  /** Format time in seconds to MM:SS string */
209
216
  declare function formatTime(seconds: number): string;
210
217
 
@@ -223,8 +230,19 @@ interface DocPlayerProps {
223
230
  markdown?: string;
224
231
  /** Base path for resolving media URLs (default: `'.'`) */
225
232
  basePath?: string;
226
- /** Render mode for video capture (hides controls, exposes seekTo) */
233
+ /** Render mode for video capture (hides controls and creates a render API). */
227
234
  renderMode?: boolean;
235
+ /**
236
+ * Whether to render slide transitions and per-layer animations (default: true).
237
+ * Set to false for static slide changes while preserving timeline and media
238
+ * playback.
239
+ */
240
+ animationsEnabled?: boolean;
241
+ /**
242
+ * Receives this player's instance-scoped render API, and `null` on cleanup.
243
+ * The API is created in render mode and `?debug=true` mode only.
244
+ */
245
+ onRenderAPIReady?: (api: SquisqRenderAPI | null) => void;
228
246
  /** Auto-play when loaded */
229
247
  autoPlay?: boolean;
230
248
  /** Callback when playback ends */
@@ -280,6 +298,17 @@ interface DocPlayerProps {
280
298
  * template-annotated sections as inline SVG cards. No audio, no timeline.
281
299
  */
282
300
  displayMode?: DisplayMode;
301
+ /**
302
+ * Whether to synthesize and show the managed cover slide from
303
+ * `doc.startBlock`. Defaults to true for existing documents.
304
+ */
305
+ showCoverSlide?: boolean;
306
+ /**
307
+ * Optional controlled cover visibility. Intended for synchronized audience
308
+ * mirrors that follow another DocPlayer's visual cursor. When omitted, the
309
+ * player owns its normal cover lifecycle.
310
+ */
311
+ coverVisible?: boolean;
283
312
  /** Caption display style (default: 'standard').
284
313
  * 'social' shows large centered words with the active word highlighted. */
285
314
  captionStyle?: CaptionStyle;
@@ -290,6 +319,12 @@ interface DocPlayerProps {
290
319
  * `displayMode === 'slideshow'` and not in render/headless mode.
291
320
  */
292
321
  enableSwipe?: boolean;
322
+ /**
323
+ * Listen for playback/navigation shortcuts at the document level instead of
324
+ * requiring this player to hold focus. Intended for a primary preview or
325
+ * standalone presentation; leave disabled when several players share a page.
326
+ */
327
+ globalKeyboardShortcuts?: boolean;
293
328
  }
294
329
  /**
295
330
  * Front-door component: resolves the `doc` / `markdown` props into a Doc
@@ -299,11 +334,80 @@ interface DocPlayerProps {
299
334
  */
300
335
  declare function DocPlayer(props: DocPlayerProps): react_jsx_runtime.JSX.Element;
301
336
 
302
- /** Default viewport dimensions (1080p landscape) - for backwards compatibility */
303
- declare const VIEWPORT: {
304
- width: number;
305
- height: number;
306
- };
337
+ /**
338
+ * Standalone Entry Point — IIFE bundle for self-contained HTML rendering.
339
+ *
340
+ * This file is the entry point for the standalone `squisq-player.iife.js` bundle.
341
+ * It bundles Preact (via preact/compat), squisq core, and all rendering components
342
+ * into a single self-contained script that can be loaded in any HTML page.
343
+ *
344
+ * The bundle exposes a global `SquisqPlayer` object with methods to mount
345
+ * interactive or static document views into any DOM element.
346
+ *
347
+ * Usage (in HTML):
348
+ * <script src="squisq-player.iife.js"></script>
349
+ * <div id="root"></div>
350
+ * <script>
351
+ * const root = document.getElementById('root');
352
+ * const handle = SquisqPlayer.mount(root, docJson, {
353
+ * mode: 'slideshow',
354
+ * images: { 'hero.jpg': 'data:image/jpeg;base64,...' }
355
+ * });
356
+ * // In render mode: const api = await handle.renderAPI;
357
+ * </script>
358
+ */
359
+
360
+ interface MountOptions {
361
+ /** Rendering mode: 'slideshow' (interactive, default) or 'static' (scrollable) */
362
+ mode?: 'slideshow' | 'static';
363
+ /** Base path for resolving relative media URLs */
364
+ basePath?: string;
365
+ /**
366
+ * Map of relative image paths to data URIs or blob URLs.
367
+ * Used in single-HTML exports where images are inlined as base64.
368
+ * Example: { 'hero.jpg': 'data:image/jpeg;base64,...' }
369
+ */
370
+ images?: Record<string, string>;
371
+ /**
372
+ * Map of audio segment names/paths to URLs (data URIs, blob URLs, or relative paths).
373
+ * Used in ZIP exports where audio files are included alongside the HTML.
374
+ */
375
+ audio?: Record<string, string>;
376
+ /** Optional theme override */
377
+ theme?: Theme;
378
+ /** Auto-play on mount (only for slideshow mode, default: false) */
379
+ autoPlay?: boolean;
380
+ /**
381
+ * Capture presentation arrow keys without requiring focus (default: true).
382
+ * Disable when mounting multiple interactive players on the same page.
383
+ */
384
+ globalKeyboardShortcuts?: boolean;
385
+ /**
386
+ * Enable render mode for headless frame capture. The instance API is
387
+ * available through the returned mount handle. Disables controls and
388
+ * auto-play.
389
+ */
390
+ renderMode?: boolean;
391
+ /**
392
+ * Whether to render slide transitions and per-layer animations (default: true).
393
+ * Timed media continues to play when disabled.
394
+ */
395
+ animationsEnabled?: boolean;
396
+ /** Caption style: 'standard' or 'social'. Omit or set to undefined for no captions. */
397
+ captionStyle?: 'standard' | 'social';
398
+ }
399
+ /** Instance handle returned by {@link mount}. */
400
+ interface SquisqPlayerHandle {
401
+ /** DOM element that owns this player instance. */
402
+ readonly element: Element;
403
+ /** Resolves to this instance's render API, or null when render mode is off. */
404
+ readonly renderAPI: Promise<SquisqRenderAPI | null>;
405
+ /** Current render API without waiting for effects to run. */
406
+ getRenderAPI(): SquisqRenderAPI | null;
407
+ /** Unmount this exact player instance. */
408
+ unmount(): void;
409
+ }
410
+
307
411
  /** Viewport configuration type */
308
412
  interface ViewportDimensions {
309
413
  width: number;
@@ -326,8 +430,14 @@ interface BlockRendererProps {
326
430
  viewport?: ViewportDimensions;
327
431
  /** Whether the doc is currently playing (controls video playback) */
328
432
  isPlaying?: boolean;
433
+ /**
434
+ * Whether to render block transitions and layer animations (default: true).
435
+ * Disabling this only removes authored/render-style motion; timed video
436
+ * layers continue to advance normally.
437
+ */
438
+ animationsEnabled?: boolean;
329
439
  }
330
- declare function BlockRenderer({ block, blockTime, basePath, isEntering, isExiting, transition, viewport, isPlaying, }: BlockRendererProps): react_jsx_runtime.JSX.Element;
440
+ declare function BlockRenderer({ block, blockTime, basePath, isEntering, isExiting, transition, viewport, isPlaying, animationsEnabled, }: BlockRendererProps): react_jsx_runtime.JSX.Element;
331
441
 
332
442
  interface CaptionOverlayProps {
333
443
  /** Caption track with timestamped phrases */
@@ -380,11 +490,25 @@ interface DocControlsSidebarProps {
380
490
  }
381
491
  declare function DocControlsSidebar({ state, actions }: DocControlsSidebarProps): react_jsx_runtime.JSX.Element;
382
492
 
493
+ interface SlideshowPickerItem {
494
+ /** Stable identifier for the slide/block. */
495
+ id: string;
496
+ /** Human-facing slide number, or a special label such as "Cover". */
497
+ label: string;
498
+ /** Short description shown in the slide picker. */
499
+ summary: string;
500
+ }
383
501
  interface DocControlsSlideshowProps {
384
502
  state: PlaybackState$1;
385
503
  slideNav: SlideNavActions;
504
+ /** Slides available for direct navigation from the counter popover. */
505
+ slides?: readonly SlideshowPickerItem[];
506
+ /** Controlled open state for hosts that expose their own picker shortcut. */
507
+ pickerOpen?: boolean;
508
+ /** Called whenever the slide picker should open or close. */
509
+ onPickerOpenChange?: (open: boolean) => void;
386
510
  }
387
- declare function DocControlsSlideshow({ state, slideNav }: DocControlsSlideshowProps): react_jsx_runtime.JSX.Element;
511
+ declare function DocControlsSlideshow({ state, slideNav, slides, pickerOpen, onPickerOpenChange, }: DocControlsSlideshowProps): react_jsx_runtime.JSX.Element;
388
512
 
389
513
  interface DocPlayerWithSidebarProps {
390
514
  /** The Doc to play */
@@ -396,6 +520,8 @@ interface DocPlayerWithSidebarProps {
396
520
  onTimeUpdate?: (time: number) => void;
397
521
  /** Optional audio controller (if not provided, uses default HTML5 audio) */
398
522
  audioController?: AudioController;
523
+ /** Whether to render slide transitions and per-layer animations (default: true). */
524
+ animationsEnabled?: boolean;
399
525
  muted?: boolean;
400
526
  captionsEnabled?: boolean;
401
527
  isFullscreen?: boolean;
@@ -412,7 +538,7 @@ interface DocPlayerWithSidebarProps {
412
538
  */
413
539
  theme?: Theme;
414
540
  }
415
- declare function DocPlayerWithSidebar({ doc, basePath, autoPlay, onEnded, onTimeUpdate, audioController, muted, captionsEnabled, isFullscreen, onFullscreenToggle, forceViewport, onPlayingChange, theme, }: DocPlayerWithSidebarProps): react_jsx_runtime.JSX.Element;
541
+ declare function DocPlayerWithSidebar({ doc, basePath, autoPlay, onEnded, onTimeUpdate, audioController, animationsEnabled, muted, captionsEnabled, isFullscreen, onFullscreenToggle, forceViewport, onPlayingChange, theme, }: DocPlayerWithSidebarProps): react_jsx_runtime.JSX.Element;
416
542
 
417
543
  interface DocProgressBarProps {
418
544
  state: PlaybackState$1;
@@ -472,6 +598,8 @@ interface LinearDocViewProps {
472
598
  className?: string;
473
599
  /** Theme to use for rendering (default: DEFAULT_THEME from the theme library) */
474
600
  theme?: Theme;
601
+ /** Whether inline visual cards render their layer animations (default: true). */
602
+ animationsEnabled?: boolean;
475
603
  /**
476
604
  * Optional surface scheme (light / dark paper) overlaid on top of the
477
605
  * theme's colors. Orthogonal to `theme` — a theme picks editorial
@@ -497,6 +625,11 @@ interface LinearDocViewProps {
497
625
  * full-size images would dominate the layout.
498
626
  */
499
627
  imageDisplayMode?: ImageDisplayMode;
628
+ /**
629
+ * Let unmodified Up/Down arrows scroll this view even when it does not
630
+ * currently hold focus. Intended for a primary document preview.
631
+ */
632
+ globalKeyboardShortcuts?: boolean;
500
633
  }
501
634
  type ImageDisplayMode = 'inline' | 'thumbnail';
502
635
  /**
@@ -511,7 +644,7 @@ type ImageDisplayMode = 'inline' | 'thumbnail';
511
644
  * <LinearDocView doc={doc} basePath="/media/" />
512
645
  * ```
513
646
  */
514
- declare function LinearDocView({ doc, markdown, basePath, viewport, className, theme, surface, thinMargins, imageDisplayMode, }: LinearDocViewProps): react_jsx_runtime.JSX.Element;
647
+ declare function LinearDocView({ doc, markdown, basePath, viewport, className, theme, surface, animationsEnabled, thinMargins, imageDisplayMode, globalKeyboardShortcuts, }: LinearDocViewProps): react_jsx_runtime.JSX.Element;
515
648
 
516
649
  interface InlineVideoPlayerProps {
517
650
  /** Source path — resolved through MediaContext when relative. */
@@ -629,6 +762,16 @@ interface TableLayerProps {
629
762
  }
630
763
  declare function TableLayer({ layer, viewport, blockTime }: TableLayerProps): react_jsx_runtime.JSX.Element;
631
764
 
765
+ interface TreeLayerProps {
766
+ layer: TreeLayer$1;
767
+ viewport: {
768
+ width: number;
769
+ height: number;
770
+ };
771
+ blockTime: number;
772
+ }
773
+ declare function TreeLayer({ layer, viewport, blockTime }: TreeLayerProps): react_jsx_runtime.JSX.Element;
774
+
632
775
  interface MapLayerProps {
633
776
  layer: MapLayer$1;
634
777
  /** Base path for resolving relative image URLs */
@@ -649,8 +792,10 @@ interface MediaClipLayerProps {
649
792
  isPlaying: boolean;
650
793
  basePath: string;
651
794
  renderMode?: boolean;
795
+ /** Silence every scheduled clip during live playback. */
796
+ muted?: boolean;
652
797
  }
653
- declare function MediaClipLayer({ schedule, currentTime, isPlaying, basePath, renderMode, }: MediaClipLayerProps): react_jsx_runtime.JSX.Element | null;
798
+ declare function MediaClipLayer({ schedule, currentTime, isPlaying, basePath, renderMode, muted, }: MediaClipLayerProps): react_jsx_runtime.JSX.Element | null;
654
799
 
655
800
  /**
656
801
  * useAudioSync Hook
@@ -666,7 +811,7 @@ declare function MediaClipLayer({ schedule, currentTime, isPlaying, basePath, re
666
811
  * can supply their own AudioController to DocPlayer instead of this hook.
667
812
  */
668
813
 
669
- declare function useAudioSync(audioRef: RefObject<HTMLAudioElement>, audioTrack: AudioTrack | undefined, basePath?: string): AudioController;
814
+ declare function useAudioSync(audioRef: RefObject<HTMLAudioElement>, audioTrack: AudioTrack | undefined, basePath?: string, enabled?: boolean): AudioController;
670
815
 
671
816
  /**
672
817
  * useMediaSchedule
@@ -733,8 +878,21 @@ interface PlaybackActions {
733
878
  prevBlock: () => void;
734
879
  /** Go to specific block by index */
735
880
  goToBlock: (index: number) => void;
881
+ /**
882
+ * Let the identified block enter without remounting the outgoing block.
883
+ * Used when another interaction (such as a swipe) already removed it.
884
+ */
885
+ suppressOutgoingForNextBlock: (blockId: string) => void;
886
+ }
887
+ interface UseDocPlaybackOptions {
888
+ /** Target viewport used to materialize template blocks. */
889
+ viewport?: ViewportConfig;
890
+ /** Active theme used for materialization and transition defaults. */
891
+ theme?: Theme;
892
+ /** Host seek callback used by block navigation actions. */
893
+ onSeek?: (time: number) => void;
736
894
  }
737
- declare function useDocPlayback(script: Doc | null, currentTime: number, viewport?: ViewportConfig, renderMode?: boolean, theme?: Theme): PlaybackState & PlaybackActions;
895
+ declare function useDocPlayback(script: Doc | null, currentTime: number, options?: UseDocPlaybackOptions): PlaybackState & PlaybackActions;
738
896
 
739
897
  /**
740
898
  * useViewportOrientation Hook
@@ -812,4 +970,4 @@ interface JsonViewProps {
812
970
  }
813
971
  declare function JsonView(props: JsonViewProps): react_jsx_runtime.JSX.Element;
814
972
 
815
- export { type AudioActions, type AudioController, type AudioState, type BlockMarker, BlockRenderer, type CaptionMode, CaptionOverlay, type CaptionStyle, type ControlsLayout, type DisplayMode, DocControlsBottom, DocControlsOverlay, DocControlsSidebar, DocControlsSlideshow, DocPlayer, DocPlayerWithSidebar, DocProgressBar, type ImageDisplayMode, ImageLayer, InlineAudioPlayer, type InlineAudioPlayerProps, InlineVideoPlayer, type InlineVideoPlayerProps, JsonView, type JsonViewProps, LinearDocView, type LinearDocViewProps, MapLayer, MarkdownRenderer, MediaClipLayer, type MediaClipLayerProps, MediaContext, type MediaScheduleController, PathLayer, type PlaybackActions$1 as PlaybackActions, type PlaybackState$1 as PlaybackState, type RenderAudioSegmentInfo, type RenderBlockInfo, type RenderCaptionInfo, type RenderChapterInfo, ShapeLayer, type SlideNavActions, SocialCaptionOverlay, type SquisqRenderAPI, type SquisqWindow, TableLayer, TextLayer, VIEWPORT, VideoLayer, formatTime, useAudioSync, useAutoSurface, useDocPlayback, useMediaProvider, useMediaSchedule, useMediaUrl, useViewportOrientation };
973
+ export { type AudioActions, type AudioController, type AudioState, type BlockMarker, BlockRenderer, type CaptionMode, CaptionOverlay, type CaptionStyle, type ControlsLayout, type DisplayMode, DocControlsBottom, DocControlsOverlay, DocControlsSidebar, DocControlsSlideshow, DocPlayer, type DocPlayerProps, DocPlayerWithSidebar, DocProgressBar, type ImageDisplayMode, ImageLayer, InlineAudioPlayer, type InlineAudioPlayerProps, InlineVideoPlayer, type InlineVideoPlayerProps, JsonView, type JsonViewProps, LinearDocView, type LinearDocViewProps, MapLayer, MarkdownRenderer, MediaClipLayer, type MediaClipLayerProps, MediaContext, type MediaScheduleController, type MountOptions, PathLayer, type PlaybackActions$1 as PlaybackActions, type PlaybackState$1 as PlaybackState, type RenderAudioSegmentInfo, type RenderBlockInfo, type RenderCaptionInfo, type RenderChapterInfo, ShapeLayer, type SlideNavActions, SocialCaptionOverlay, type SquisqPlayerHandle, type SquisqRenderAPI, TableLayer, TextLayer, TreeLayer, type UseDocPlaybackOptions, VideoLayer, formatTime, useAudioSync, useAutoSurface, useDocPlayback, useMediaProvider, useMediaSchedule, useMediaUrl, useViewportOrientation };