@vanillaskyai/video 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/PUBLIC-API.md +123 -9
  3. package/README.md +69 -115
  4. package/dist/{bg-confetti-SHQI7ATB.js → bg-confetti-HITCGLGD.js} +1 -1
  5. package/dist/{bg-emoji-XYFRA63Q.js → bg-emoji-VU4UZYZN.js} +1 -1
  6. package/dist/{bg-media-G4XOQEAS.js → bg-media-L34PDQXJ.js} +2 -2
  7. package/dist/{brand-message-XHONEDNW.js → brand-message-FUJ4STFO.js} +1 -1
  8. package/dist/{builtin-server-YHEZ2JRF.js → builtin-server-KB7FKF6A.js} +2 -2
  9. package/dist/{chart-bar-HRHD57ML.js → chart-bar-EGPHJATL.js} +2 -2
  10. package/dist/{chart-counter-KFPV44RB.js → chart-counter-5FFWQNZO.js} +2 -2
  11. package/dist/{chart-progress-ring-OR2VOIHV.js → chart-progress-ring-JMXQLMLC.js} +2 -2
  12. package/dist/{chunk-66MNRUCR.js → chunk-2PYO6VAC.js} +51 -3
  13. package/dist/{chunk-ZQQQAAKP.js → chunk-2XT4MZ76.js} +33 -2
  14. package/dist/{chunk-PNS52FL4.js → chunk-5SLENAJW.js} +19 -6
  15. package/dist/{chunk-EFL34TXF.js → chunk-AITKH6QT.js} +24 -8
  16. package/dist/{chunk-FZHMQFG3.js → chunk-GAIOHGNR.js} +5 -21
  17. package/dist/{chunk-3RV4YKB3.js → chunk-JNN3EYVP.js} +51 -26
  18. package/dist/{chunk-HVCPEAQF.js → chunk-LKBZX7GV.js} +9 -6
  19. package/dist/{chunk-34O5BY6X.js → chunk-LLPMVDJZ.js} +21 -4
  20. package/dist/{chunk-G66Z5CWR.js → chunk-MMUXVA47.js} +27 -3
  21. package/dist/{chunk-7BGAU6C3.js → chunk-MXZSDGZQ.js} +2 -1
  22. package/dist/{chunk-3OU7HIEB.js → chunk-RE4IMWJR.js} +15 -31
  23. package/dist/{chunk-FVTMYS6U.js → chunk-RGF452LL.js} +1 -1
  24. package/dist/chunk-SKRGRKHY.js +142 -0
  25. package/dist/{chunk-TCEHK2BW.js → chunk-YJJC4N4D.js} +2 -1
  26. package/dist/cli.js +438 -30
  27. package/dist/{compose-video-JWIEDTEJ.js → compose-video-PD6LKKRK.js} +4 -4
  28. package/dist/{cta-logo-JJOGK4UC.js → cta-logo-YR7LYUR5.js} +1 -1
  29. package/dist/{cta-media-IQ3MAWEH.js → cta-media-DQJBKUO2.js} +2 -2
  30. package/dist/{events-BBP30j3c.d.ts → events-B6qS1Lsb.d.ts} +2 -2
  31. package/dist/{incoming-call-KXF67OT2.js → incoming-call-54KQ7O5A.js} +1 -1
  32. package/dist/index.d.ts +89 -3
  33. package/dist/index.js +12 -1
  34. package/dist/{infographic-before-after-2I7YZVDD.js → infographic-before-after-ROS52GOW.js} +1 -1
  35. package/dist/{infographic-feature-list-QDM4I7XE.js → infographic-feature-list-E7MGUDAN.js} +2 -2
  36. package/dist/{infographic-problem-solution-FMLJCPG6.js → infographic-problem-solution-3S6NGO5N.js} +2 -2
  37. package/dist/{infographic-stat-row-VFTIXS5F.js → infographic-stat-row-SYB7AB7H.js} +2 -2
  38. package/dist/{infographic-steps-L7W24Z35.js → infographic-steps-KCE6JWE2.js} +2 -2
  39. package/dist/{kit-DEG3fcaL.d.ts → kit-8g46H2RZ.d.ts} +1 -1
  40. package/dist/{prompt-input-F3CYU2XH.js → prompt-input-MHX4O42G.js} +1 -1
  41. package/dist/react.d.ts +194 -6
  42. package/dist/react.js +1849 -40
  43. package/dist/{reaction-2XCLOJOK.js → reaction-SLEGR3BE.js} +2 -2
  44. package/dist/server.d.ts +102 -4
  45. package/dist/server.js +972 -27
  46. package/dist/{showcase-code-KHSMIPG6.js → showcase-code-2HLAVKBM.js} +2 -2
  47. package/dist/{showcase-phone-M4CEANIW.js → showcase-phone-Q4HEO4LH.js} +2 -2
  48. package/dist/{showcase-terminal-26I3DYF7.js → showcase-terminal-DL45LUFG.js} +2 -2
  49. package/dist/{showcase-web-TY6CZV2Z.js → showcase-web-2QZO73FZ.js} +2 -2
  50. package/dist/{social-milestone-TF6MX7ET.js → social-milestone-GEFUQSBF.js} +1 -1
  51. package/dist/{social-notification-2RJDAZSF.js → social-notification-FJ5VHVLK.js} +1 -1
  52. package/dist/{social-review-stack-2ICKJQG7.js → social-review-stack-KXQCKFRP.js} +1 -1
  53. package/dist/{social-testimonial-X7OGADA3.js → social-testimonial-JZ7CHC7S.js} +1 -1
  54. package/dist/{social-tweet-TK7SH2F6.js → social-tweet-UCDXM25F.js} +1 -1
  55. package/dist/{system-prompt-4I6Z5HK3.js → system-prompt-RRXIWDDD.js} +5 -3
  56. package/dist/template-catalog.js +1 -1
  57. package/dist/templates.d.ts +3 -3
  58. package/dist/test.d.ts +2 -2
  59. package/dist/test.js +3 -3
  60. package/dist/{text-stream-J6EDDJP4.js → text-stream-ROTNGSD4.js} +2 -2
  61. package/dist/{types-BV9IqExh.d.ts → types-2wHBqtg8.d.ts} +29 -1
  62. package/dist/types-DrABlRa7.d.ts +46 -0
  63. package/docs/agent-integration.md +49 -25
  64. package/docs/architecture.md +37 -22
  65. package/docs/branding-and-personalization.md +1 -1
  66. package/docs/concepts.md +14 -0
  67. package/docs/custom-templates.md +9 -9
  68. package/docs/customization.md +41 -5
  69. package/docs/getting-started.md +81 -84
  70. package/docs/media-and-audio.md +103 -166
  71. package/docs/persistence.md +1 -1
  72. package/docs/production.md +81 -92
  73. package/docs/prompt-and-input.md +71 -161
  74. package/docs/provider-integration.md +91 -49
  75. package/docs/responsive-orientation.md +1 -1
  76. package/docs/security.md +6 -5
  77. package/docs/streaming-protocol.md +1 -1
  78. package/docs/testing.md +51 -43
  79. package/examples/custom-template/README.md +1 -1
  80. package/package.json +20 -22
  81. package/registry/items/barChart.json +6 -4
  82. package/registry/items/beforeAfter.json +1 -1
  83. package/registry/items/bigNumber.json +4 -3
  84. package/registry/items/brandMessage.json +3 -2
  85. package/registry/items/cardList.json +6 -4
  86. package/registry/items/codeEditor.json +4 -3
  87. package/registry/items/confetti.json +1 -1
  88. package/registry/items/ctaLogo.json +3 -2
  89. package/registry/items/ctaMedia.json +4 -3
  90. package/registry/items/emojiBurst.json +1 -1
  91. package/registry/items/incomingCall.json +3 -2
  92. package/registry/items/media.json +4 -3
  93. package/registry/items/milestone.json +3 -2
  94. package/registry/items/notification.json +3 -2
  95. package/registry/items/phoneMockup.json +4 -3
  96. package/registry/items/problemSolution.json +4 -3
  97. package/registry/items/progressRing.json +4 -3
  98. package/registry/items/promptInput.json +3 -2
  99. package/registry/items/reaction.json +2 -2
  100. package/registry/items/reviewStack.json +3 -2
  101. package/registry/items/steps.json +6 -4
  102. package/registry/items/terminal.json +5 -4
  103. package/registry/items/testimonial.json +3 -2
  104. package/registry/items/tripleStats.json +4 -3
  105. package/registry/items/tweet.json +3 -2
  106. package/registry/items/webMockup.json +4 -3
  107. package/starters/video-chat/.env.example +16 -0
  108. package/starters/video-chat/README.md +63 -0
  109. package/starters/video-chat/index.html +12 -0
  110. package/starters/video-chat/package.json +28 -0
  111. package/starters/video-chat/server.ts +152 -0
  112. package/starters/video-chat/src/main.tsx +8 -0
  113. package/starters/video-chat/stock.ts +139 -0
  114. package/starters/video-chat/tsconfig.json +20 -0
  115. package/starters/video-chat/vite.config.ts +81 -0
  116. package/styles/video-chat.css +713 -0
  117. package/docs/input-and-first-scene.md +0 -64
  118. package/docs/integrate-nextjs.md +0 -86
  119. package/docs/live-channels.md +0 -149
  120. package/docs/use-cases.md +0 -59
  121. package/examples/nextjs-quickstart/.env.example +0 -2
  122. package/examples/nextjs-quickstart/README.md +0 -27
  123. package/examples/nextjs-quickstart/next-env.d.ts +0 -4
  124. package/examples/nextjs-quickstart/package.json +0 -25
  125. package/examples/nextjs-quickstart/src/app/api/video/route.ts +0 -33
  126. package/examples/nextjs-quickstart/src/app/layout.tsx +0 -5
  127. package/examples/nextjs-quickstart/src/app/page.tsx +0 -31
  128. package/examples/nextjs-quickstart/tsconfig.json +0 -26
  129. package/examples/server-integrations/README.md +0 -20
  130. package/examples/server-integrations/src/ai-sdk-media.ts +0 -90
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { c as Video, g as VideoBrandInput, h as VideoBrand } from './types-BV9IqExh.js';
2
- export { d as VideoAudio, i as VideoBackground, j as VideoInput, k as VideoKnowledgeMode, b as VideoOrientation, e as VideoScene, V as VideoStyle, l as VideoStyleOptions, m as VideoSuppliedMedia } from './types-BV9IqExh.js';
1
+ import { c as Video, h as VideoBrandInput, i as VideoBrand, e as VideoScene, d as VideoAudio, V as VideoStyle, b as VideoOrientation, j as VideoTemplatePacing } from './types-2wHBqtg8.js';
2
+ export { k as VideoBackground, g as VideoInput, l as VideoKnowledgeMode, m as VideoStyleOptions, n as VideoSuppliedMedia } from './types-2wHBqtg8.js';
3
3
  export { V as VideoStatus } from './state-DZcKuS32.js';
4
+ import { b as VideoEvent } from './events-B6qS1Lsb.js';
4
5
 
5
6
  type VideoValidationErrorCode = "invalid_video" | "unsupported_video_version";
6
7
  declare class VideoValidationError extends Error {
@@ -14,4 +15,89 @@ declare function getVideoDuration(config: Video): number;
14
15
 
15
16
  declare function resolveVideoBrand(input?: VideoBrandInput): VideoBrand;
16
17
 
17
- export { Video, VideoBrand, VideoBrandInput, VideoValidationError, type VideoValidationErrorCode, getVideoDuration, parseVideo, resolveVideoBrand };
18
+ /**
19
+ * Compose a playable video from scenes the host builds itself.
20
+ *
21
+ * `VideoInput.opening` is a single line of copy, so an application that wants
22
+ * several scenes of its own before the generated ones has nowhere to put them.
23
+ * Handing the player a fresh `video` prop is not an answer either: that resets
24
+ * playback to zero on every change, so a video that grows replays its opening
25
+ * each time something is appended. The player's `stream` prop appends, and this
26
+ * builds a stream.
27
+ *
28
+ * The reason it belongs here rather than in each application is that the
29
+ * envelope rules are exact and their failure is silent. `response.start` must
30
+ * be sequence zero, every event exactly one higher, `eventId` exactly
31
+ * `${runId}:${sequence}`, `scene.add.position` the index the scene lands at,
32
+ * and the completion snapshot must reproduce what the reducer built. Miss any
33
+ * one and the whole stream is rejected: the player renders nothing, and the
34
+ * console stays clean.
35
+ */
36
+ interface SceneTimeline {
37
+ /**
38
+ * Hand this to the player's `stream` prop once. Never swap it: a new stream
39
+ * is a new video, and playback restarts.
40
+ */
41
+ stream: AsyncIterable<VideoEvent>;
42
+ /** Append a scene. Ignored once the timeline has completed. */
43
+ add(scene: VideoScene): void;
44
+ /**
45
+ * Say what the soundtrack is, or that there is none.
46
+ *
47
+ * Only meaningful with `awaitAudio`, where it releases the scenes held back
48
+ * while the track was unknown. Calling it twice, or after the first scene has
49
+ * been emitted, does nothing.
50
+ */
51
+ setAudio(audio: VideoAudio | undefined): void;
52
+ /** Finish the video. Safe to call more than once. */
53
+ complete(): void;
54
+ }
55
+ interface SceneTimelineOptions {
56
+ style: VideoStyle;
57
+ orientation?: VideoOrientation;
58
+ /**
59
+ * The soundtrack, when it is already known.
60
+ *
61
+ * Use `awaitAudio` instead when it is resolved by a request that has not
62
+ * answered yet.
63
+ */
64
+ audio?: VideoAudio;
65
+ /**
66
+ * Hold scenes until `setAudio` is called.
67
+ *
68
+ * `audio.set` is only valid before the first scene, so a timeline that opens
69
+ * with host-built scenes cannot add a soundtrack afterwards - the event
70
+ * arrives too late and the video plays silently, with nothing to show for it.
71
+ * Holding the openings costs the wait for the track to resolve, not the wait
72
+ * for the video to be planned.
73
+ */
74
+ awaitAudio?: boolean;
75
+ requestId?: string;
76
+ runId?: string;
77
+ }
78
+ declare function createSceneTimeline(options: SceneTimelineOptions): SceneTimeline;
79
+
80
+ interface SceneDurationBounds {
81
+ /**
82
+ * The least this scene survives being shown for.
83
+ *
84
+ * A compression bound, used when a video must fit a fixed length. It is not
85
+ * a readability bound and should not be used as one.
86
+ */
87
+ minimum: number;
88
+ /** How long the scene's own content takes to read, given what it holds. */
89
+ readable: number;
90
+ }
91
+ declare function getSceneDurationBounds(scene: Pick<VideoScene, "variables">, metadata: VideoTemplatePacing | undefined): SceneDurationBounds;
92
+ /**
93
+ * How long a narrated line takes to say.
94
+ *
95
+ * Reading is faster than speech - the readable estimate runs at 4.5 words a
96
+ * second, a realtime voice lands nearer 2.6 - so the two bounds measure
97
+ * different things and a scene needs whichever is longer. The tail covers the
98
+ * breath between lines.
99
+ */
100
+ declare function getSpokenDuration(narration: string): number;
101
+ declare function getSceneDuration(scene: Pick<VideoScene, "variables" | "narration">, metadata: VideoTemplatePacing | undefined): number;
102
+
103
+ export { type SceneDurationBounds, type SceneTimeline, type SceneTimelineOptions, Video, VideoAudio, VideoBrand, VideoBrandInput, VideoOrientation, VideoScene, VideoStyle, VideoValidationError, type VideoValidationErrorCode, createSceneTimeline, getSceneDuration, getSceneDurationBounds, getSpokenDuration, getVideoDuration, parseVideo, resolveVideoBrand };
package/dist/index.js CHANGED
@@ -1,8 +1,15 @@
1
+ import {
2
+ createSceneTimeline,
3
+ getSceneDuration,
4
+ getSceneDurationBounds,
5
+ getSpokenDuration
6
+ } from "./chunk-SKRGRKHY.js";
1
7
  import {
2
8
  VideoValidationError,
3
9
  parseVideo
4
- } from "./chunk-66MNRUCR.js";
10
+ } from "./chunk-2PYO6VAC.js";
5
11
  import "./chunk-AOWSXU2K.js";
12
+ import "./chunk-3O7OMMMF.js";
6
13
  import {
7
14
  getVideoDuration
8
15
  } from "./chunk-SPVTJH3F.js";
@@ -11,6 +18,10 @@ import {
11
18
  } from "./chunk-XGRA2MUV.js";
12
19
  export {
13
20
  VideoValidationError,
21
+ createSceneTimeline,
22
+ getSceneDuration,
23
+ getSceneDurationBounds,
24
+ getSpokenDuration,
14
25
  getVideoDuration,
15
26
  parseVideo,
16
27
  resolveVideoBrand
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-S7HFLYNN.js";
7
7
  import {
8
8
  smoothSize
9
- } from "./chunk-TCEHK2BW.js";
9
+ } from "./chunk-YJJC4N4D.js";
10
10
  import {
11
11
  Emoji,
12
12
  renderWithEmoji
@@ -7,10 +7,10 @@ import {
7
7
  import {
8
8
  SceneBackground,
9
9
  getMediaBackgroundProps
10
- } from "./chunk-7BGAU6C3.js";
10
+ } from "./chunk-MXZSDGZQ.js";
11
11
  import {
12
12
  TemplateText
13
- } from "./chunk-TCEHK2BW.js";
13
+ } from "./chunk-YJJC4N4D.js";
14
14
  import {
15
15
  Emoji
16
16
  } from "./chunk-L5BTTCZV.js";
@@ -4,10 +4,10 @@ import {
4
4
  import {
5
5
  SceneBackground,
6
6
  getMediaBackgroundProps
7
- } from "./chunk-7BGAU6C3.js";
7
+ } from "./chunk-MXZSDGZQ.js";
8
8
  import {
9
9
  smoothSize
10
- } from "./chunk-TCEHK2BW.js";
10
+ } from "./chunk-YJJC4N4D.js";
11
11
  import "./chunk-L5BTTCZV.js";
12
12
  import "./chunk-FRN6WKHA.js";
13
13
  import "./chunk-W3VDIBGR.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  SceneBackground,
3
3
  getMediaBackgroundProps
4
- } from "./chunk-7BGAU6C3.js";
4
+ } from "./chunk-MXZSDGZQ.js";
5
5
  import {
6
6
  TemplateText
7
- } from "./chunk-TCEHK2BW.js";
7
+ } from "./chunk-YJJC4N4D.js";
8
8
  import "./chunk-L5BTTCZV.js";
9
9
  import "./chunk-FRN6WKHA.js";
10
10
  import {
@@ -8,10 +8,10 @@ import {
8
8
  import {
9
9
  SceneBackground,
10
10
  getMediaBackgroundProps
11
- } from "./chunk-7BGAU6C3.js";
11
+ } from "./chunk-MXZSDGZQ.js";
12
12
  import {
13
13
  TemplateText
14
- } from "./chunk-TCEHK2BW.js";
14
+ } from "./chunk-YJJC4N4D.js";
15
15
  import {
16
16
  Emoji
17
17
  } from "./chunk-L5BTTCZV.js";
@@ -1,4 +1,4 @@
1
- import { V as VideoStyle, a as VideoCapabilities } from './types-BV9IqExh.js';
1
+ import { V as VideoStyle, a as VideoCapabilities } from './types-2wHBqtg8.js';
2
2
  import { ComponentType } from 'react';
3
3
  import { S as SceneTemplateMetadata, d as TemplateJsonSchema, f as TemplateJsonSchemaProperty } from './catalog-types-BIhSpOWK.js';
4
4
 
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  SceneBackground,
6
6
  getMediaBackgroundProps
7
- } from "./chunk-7BGAU6C3.js";
7
+ } from "./chunk-MXZSDGZQ.js";
8
8
  import "./chunk-FRN6WKHA.js";
9
9
  import "./chunk-W3VDIBGR.js";
10
10
  import {
package/dist/react.d.ts CHANGED
@@ -1,8 +1,10 @@
1
- import { CSSProperties, ReactElement } from 'react';
2
- import { b as VideoEvent, V as VideoWarning } from './events-BBP30j3c.js';
3
- import { b as VideoOrientation, c as Video, e as VideoScene, j as VideoInput } from './types-BV9IqExh.js';
4
- import { T as TemplateRegistry } from './kit-DEG3fcaL.js';
1
+ import * as react from 'react';
2
+ import { CSSProperties, ReactElement, ReactNode } from 'react';
3
+ import { b as VideoEvent, V as VideoWarning } from './events-B6qS1Lsb.js';
4
+ import { b as VideoOrientation, c as Video, e as VideoScene, g as VideoInput, h as VideoBrandInput, m as VideoStyleOptions } from './types-2wHBqtg8.js';
5
+ import { T as TemplateRegistry } from './kit-8g46H2RZ.js';
5
6
  import { V as VideoStatus } from './state-DZcKuS32.js';
7
+ import { c as VideoChatMode, e as VideoChatAskOptions, f as VideoChatMedia, g as VideoChatSuggestion, a as VideoChatCapabilities, h as VideoChatWelcome } from './types-DrABlRa7.js';
6
8
  import './catalog-types-BIhSpOWK.js';
7
9
 
8
10
  type VideoPlaybackMode = "manual" | "muted-autoplay" | "autoplay-with-sound" | "autoplay-after-interaction";
@@ -29,8 +31,35 @@ interface VideoPlayerSharedProps {
29
31
  style?: CSSProperties;
30
32
  /** Accessible name for the player region. */
31
33
  ariaLabel?: string;
34
+ /**
35
+ * Show the player's own controls: play, mute, fullscreen, and the replay
36
+ * offered when the video ends. Default true.
37
+ *
38
+ * Turn them off where the host drives playback itself and a second set of
39
+ * controls would contradict it - a narrated answer whose voice and picture
40
+ * are one thing, where pausing the picture alone desynchronises them, and
41
+ * where a replay scrim would cover the answer the moment it finished.
42
+ */
43
+ controls?: boolean;
44
+ /**
45
+ * Hold the playhead where it is, and release it again.
46
+ *
47
+ * The counterpart to turning `controls` off. A host that owns playback needs
48
+ * a lever to drive it with, and until this there was none: the clock is the
49
+ * player's, so a narrated answer could silence its voice but not stop its
50
+ * picture, and the two came apart. Setting it back to false resumes from the
51
+ * same playhead rather than restarting.
52
+ *
53
+ * Leave it undefined to keep the player's own behaviour untouched. A video
54
+ * that has already reached its end is not resumed by it - the playhead is
55
+ * already there, and starting again is a replay, which is a different act.
56
+ */
57
+ paused?: boolean;
32
58
  /** Repeat the saved video and its soundtrack instead of showing the replay affordance. */
33
59
  loop?: boolean;
60
+ /** Fires once when the playhead reaches the end of a non-looping video. */
61
+ onPlaybackEnd?: (video: Video) => void;
62
+ /** Fires when a streamed response has finished composing. */
34
63
  onComplete?: (video: Video) => void;
35
64
  onError?: (error: Error) => void;
36
65
  /** Fires when the scene under the playhead changes, including on a loop wrap. */
@@ -46,7 +75,7 @@ type VideoPlayerProps = VideoPlayerSharedProps & ({
46
75
  templates?: TemplateRegistry;
47
76
  });
48
77
 
49
- declare function VideoPlayer({ templates, stream, video, onComplete, onError, ...props }: VideoPlayerProps): ReactElement | null;
78
+ declare function VideoPlayer({ templates, stream, video, onPlaybackEnd, onComplete, onError, ...props }: VideoPlayerProps): ReactElement | null;
50
79
 
51
80
  interface VideoErrorOptions {
52
81
  code: string;
@@ -92,4 +121,163 @@ interface UseVideoResult {
92
121
  }
93
122
  declare function useVideo(options?: UseVideoOptions): UseVideoResult;
94
123
 
95
- export { type UseVideoOptions, type UseVideoResult, VideoError, type VideoErrorOptions, type VideoPlaybackMode, VideoPlayer, type VideoPlayerProps, useVideo };
124
+ /**
125
+ * Say a video's narration as it plays.
126
+ *
127
+ * A narrated video is not a video with audio bolted on. The line belongs to the
128
+ * scene, so it has to begin when that scene does and stop when the viewer moves
129
+ * on - and every one of those was a bug in the application this was extracted
130
+ * from: the voice starting before the first frame, a follow-up question
131
+ * silently cutting the response off mid-sentence, a line still playing over the
132
+ * scene after it.
133
+ *
134
+ * The provider is not the SDK's business. An application supplies something
135
+ * that can speak - a realtime session, a speech model, the browser's own
136
+ * synthesiser - and this decides what is said, when it starts, and when it
137
+ * stops. That keeps the package free of provider dependencies and leaves the
138
+ * choice of voice where the choice of model already is.
139
+ */
140
+ interface NarrationVoice {
141
+ /**
142
+ * Say this line, and resolve when it has been said.
143
+ *
144
+ * The signal aborts when the scene changes, when the viewer interrupts, or
145
+ * when the player goes away. Stop speaking promptly: talking over the next
146
+ * scene is worse than being cut off.
147
+ */
148
+ speak(text: string, options: {
149
+ signal: AbortSignal;
150
+ }): void | Promise<void>;
151
+ }
152
+ interface NarrationOptions {
153
+ voice: NarrationVoice;
154
+ /** Say nothing at all while false. Defaults to true. */
155
+ enabled?: boolean;
156
+ }
157
+ interface Narration {
158
+ /**
159
+ * Hand this to the player's `onSceneChange`.
160
+ *
161
+ * The player already reports which scene is showing, which is the only cue a
162
+ * narrator needs, so nothing here has to run its own clock.
163
+ */
164
+ onSceneChange: (scene: VideoScene, index: number) => void;
165
+ /** Stop the current line. Nothing is said again until the next scene. */
166
+ interrupt: () => void;
167
+ /** Whether a line is being spoken right now. */
168
+ speaking: boolean;
169
+ }
170
+ declare function useNarration(options: NarrationOptions): Narration;
171
+
172
+ interface VideoChatPreparedSpeech {
173
+ /** Measured or conservatively estimated spoken duration, in seconds. */
174
+ seconds: number;
175
+ }
176
+ interface VideoChatVoice extends NarrationVoice {
177
+ prepare(text: string, options?: {
178
+ signal?: AbortSignal;
179
+ }): Promise<VideoChatPreparedSpeech>;
180
+ pause(): void;
181
+ resume(): void;
182
+ setMuted(muted: boolean): void;
183
+ dispose?(): void;
184
+ }
185
+ interface CreateVideoChatVoiceOptions {
186
+ endpoint?: string | URL;
187
+ headers?: HeadersInit;
188
+ credentials?: RequestCredentials;
189
+ fetcher?: typeof fetch;
190
+ maxCachedLines?: number;
191
+ }
192
+ /**
193
+ * Create the SDK's generated-speech client with a browser-voice fallback.
194
+ *
195
+ * The endpoint is provider-neutral. A no-content response (or a compatible
196
+ * endpoint's 404) selects browser speech for the rest of the session.
197
+ */
198
+ declare function createVideoChatVoice(options?: CreateVideoChatVoiceOptions): VideoChatVoice;
199
+
200
+ type VideoChatStatus = "idle" | "composing" | "playing" | "paused" | "ended" | "cancelled" | "error";
201
+ interface VideoChatTurn {
202
+ id: string;
203
+ prompt: string;
204
+ /** True only after the complete response has been received. */
205
+ completed: boolean;
206
+ opening?: string;
207
+ /** Optional stock footage held behind the opening hook until playback starts. */
208
+ openingMedia?: VideoChatMedia;
209
+ orientation: VideoOrientation;
210
+ /** Generated footage keeps the orientation it was created in. */
211
+ fixedOrientation: boolean;
212
+ video?: Video;
213
+ suggestions: readonly VideoChatSuggestion[];
214
+ }
215
+ interface UseVideoChatOptions {
216
+ /** One provider-neutral route created with createVideoChatHandler. */
217
+ endpoint?: string | URL;
218
+ /** Customer-owned templates that replace built-ins and add new renderers. */
219
+ templates?: TemplateRegistry;
220
+ mode?: VideoChatMode;
221
+ orientation?: VideoOrientation;
222
+ brand?: VideoBrandInput;
223
+ style?: VideoStyleOptions;
224
+ headers?: HeadersInit;
225
+ credentials?: RequestCredentials;
226
+ fetcher?: typeof fetch;
227
+ /** Replace the SDK speech client while keeping session timing and cancellation. */
228
+ voice?: VideoChatVoice;
229
+ initialMuted?: boolean;
230
+ timeoutMs?: number;
231
+ createTurnId?: () => string;
232
+ /** Observe how long a fresh response takes to display its first actual scene. */
233
+ onFirstFrame?: (metric: VideoChatFirstFrameMetric) => unknown;
234
+ }
235
+ interface VideoChatFirstFrameMetric {
236
+ turnId: string;
237
+ mode: VideoChatMode;
238
+ timeToFirstFrameMs: number;
239
+ }
240
+ interface UseVideoChatResult {
241
+ ask(prompt: string, options?: VideoChatAskOptions): Promise<Video | undefined>;
242
+ cancel(reason?: string): void;
243
+ pause(): void;
244
+ resume(): void;
245
+ replay(): void;
246
+ selectTurn(id: string): void;
247
+ reset(): void;
248
+ turns: readonly VideoChatTurn[];
249
+ currentTurn?: VideoChatTurn;
250
+ shownTurn?: VideoChatTurn;
251
+ capabilities?: VideoChatCapabilities;
252
+ welcome?: VideoChatWelcome;
253
+ availableModes: readonly VideoChatMode[];
254
+ status: VideoChatStatus;
255
+ error?: VideoError;
256
+ suggestions: readonly VideoChatSuggestion[];
257
+ caption?: string;
258
+ /** Narration revealed so far for the shown response. */
259
+ transcript: readonly string[];
260
+ speaking: boolean;
261
+ muted: boolean;
262
+ setMuted(muted: boolean): void;
263
+ playbackEnded: boolean;
264
+ /** Changes whenever saved content should restart from zero. */
265
+ playerKey: number;
266
+ /** Spread into VideoPlayer when present. */
267
+ playerProps?: VideoPlayerProps;
268
+ }
269
+ /** Own a complete video conversation while the application owns its UI. */
270
+ declare function useVideoChat(options?: UseVideoChatOptions): UseVideoChatResult;
271
+
272
+ interface VideoChatProps {
273
+ /** Connection, providers, templates, and rendering defaults for the session. */
274
+ options?: UseVideoChatOptions;
275
+ /** Added to the scoped component root for application layout and branding. */
276
+ className?: string;
277
+ /** Replaces the default two-line welcome heading without changing the interaction. */
278
+ welcomeTitle?: ReactNode;
279
+ }
280
+ /** A complete voice-and-video chat interface backed by createVideoChatHandler. */
281
+ declare function VideoChat({ options, className, welcomeTitle }: VideoChatProps): react.JSX.Element;
282
+
283
+ export { type CreateVideoChatVoiceOptions, type Narration, type NarrationOptions, type NarrationVoice, type UseVideoChatOptions, type UseVideoChatResult, type UseVideoOptions, type UseVideoResult, VideoChat, VideoChatAskOptions, VideoChatCapabilities, type VideoChatFirstFrameMetric, VideoChatMedia, VideoChatMode, type VideoChatPreparedSpeech, type VideoChatProps, type VideoChatStatus, VideoChatSuggestion, type VideoChatTurn, type VideoChatVoice, VideoChatWelcome, VideoError, type VideoErrorOptions, type VideoPlaybackMode, VideoPlayer, type VideoPlayerProps, createVideoChatVoice, useNarration, useVideo, useVideoChat };