@vanillaskyai/video 0.10.22 → 0.11.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 (128) hide show
  1. package/CHANGELOG.md +74 -1
  2. package/PUBLIC-API.md +45 -438
  3. package/README.md +57 -96
  4. package/dist/builtin-metadata-OT6V7TB4.js +8 -0
  5. package/dist/{chapter-title-2JVDU62E.js → chapter-title-2RCXX7SN.js} +1 -2
  6. package/dist/{chunk-PDQFQIQW.js → chunk-3EQ6PVWL.js} +1 -1
  7. package/dist/chunk-4G4JBMCM.js +37 -0
  8. package/dist/{chunk-7AA2JWHZ.js → chunk-5DOQTIMD.js} +6 -6
  9. package/dist/chunk-666HGTVZ.js +41 -0
  10. package/dist/{chunk-7M56IUUX.js → chunk-6Z3ID54H.js} +0 -18
  11. package/dist/{chunk-5BSJLT6H.js → chunk-E7FHBLAC.js} +16 -29
  12. package/dist/chunk-HIQM4J3U.js +30 -0
  13. package/dist/chunk-ISWQ6T5X.js +36 -0
  14. package/dist/{chunk-224QNWRA.js → chunk-K5J7ESRO.js} +1 -10
  15. package/dist/chunk-KMVRBUL5.js +50 -0
  16. package/dist/chunk-NM4CXXZY.js +25 -0
  17. package/dist/{chunk-44WND2VP.js → chunk-V2CP7PVY.js} +19 -63
  18. package/dist/{chunk-3O7OMMMF.js → chunk-WZESNEPT.js} +0 -1
  19. package/dist/{chunk-RXTN2CW6.js → chunk-Z3DLSLAJ.js} +1 -1
  20. package/dist/cinema-media-YZ2UANJG.js +365 -0
  21. package/dist/cli.js +154 -1753
  22. package/dist/{compose-video-BH5K6XWT.js → compose-video-H2YUQDUY.js} +4 -4
  23. package/dist/{events-B4YCc4vc.d.ts → events-BZAfl0Dm.d.ts} +1 -1
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.js +4 -6
  26. package/dist/preload-media-23JXUFCF.js +77 -0
  27. package/dist/react.d.ts +39 -15
  28. package/dist/react.js +1350 -739
  29. package/dist/scene-validation-SGLLLFY5.js +9 -0
  30. package/dist/server.d.ts +67 -117
  31. package/dist/server.js +262 -614
  32. package/dist/test.d.ts +2 -2
  33. package/dist/test.js +21 -21
  34. package/dist/{text-stream-LD364KBI.js → text-stream-SOVLYR2L.js} +2 -2
  35. package/dist/{types-BqB8zC9u.d.ts → types-CG-kPI81.d.ts} +3 -1
  36. package/dist/{types-DdZw4GRQ.d.ts → types-ht-Zw3Wv.d.ts} +1 -1
  37. package/docs/agent-integration.md +19 -64
  38. package/docs/architecture.md +82 -87
  39. package/docs/customization.md +49 -66
  40. package/docs/development.md +18 -17
  41. package/docs/errors.md +4 -4
  42. package/docs/getting-started.md +74 -93
  43. package/docs/media-and-audio.md +9 -7
  44. package/docs/performance.md +11 -6
  45. package/docs/persistence.md +3 -7
  46. package/docs/production.md +4 -15
  47. package/docs/prompt-and-input.md +1 -2
  48. package/docs/provider-integration.md +134 -181
  49. package/docs/reference/protocol.md +5 -14
  50. package/docs/reference/provider-adapters.md +21 -13
  51. package/docs/security.md +1 -14
  52. package/docs/testing.md +56 -123
  53. package/package.json +5 -27
  54. package/starters/video-chat/.env.example +12 -4
  55. package/starters/video-chat/.env.native.example +13 -0
  56. package/starters/video-chat/README.md +72 -11
  57. package/starters/video-chat/package.json +1 -1
  58. package/starters/video-chat/providers/text-native.ts +94 -0
  59. package/starters/video-chat/providers/text.ts +19 -0
  60. package/starters/video-chat/providers/transcription.ts +32 -0
  61. package/starters/video-chat/providers/video-custom.ts +45 -0
  62. package/starters/video-chat/providers/video-delivery.ts +57 -0
  63. package/starters/video-chat/providers/video-google.ts +48 -0
  64. package/starters/video-chat/providers/video-job.ts +103 -0
  65. package/starters/video-chat/providers/video-runway.ts +45 -0
  66. package/starters/video-chat/providers/video.ts +39 -63
  67. package/starters/video-chat/server.ts +3 -29
  68. package/starters/video-chat/vite.config.ts +2 -8
  69. package/styles/video-chat.css +8 -105
  70. package/dist/builtin-server-W4PLJUZ5.js +0 -8
  71. package/dist/catalog-types-WTbLP6Jh.d.ts +0 -78
  72. package/dist/check-runtime.d.ts +0 -15
  73. package/dist/check-runtime.js +0 -96
  74. package/dist/chunk-2E6T633S.js +0 -27
  75. package/dist/chunk-4YM2M62S.js +0 -13
  76. package/dist/chunk-4ZJLPHBV.js +0 -684
  77. package/dist/chunk-5JBMYQP6.js +0 -156
  78. package/dist/chunk-73NTSFFI.js +0 -81
  79. package/dist/chunk-EGVQODKU.js +0 -83
  80. package/dist/chunk-HFVNAPHZ.js +0 -35
  81. package/dist/chunk-IIN5M5HW.js +0 -697
  82. package/dist/chunk-IQMYK5DX.js +0 -133
  83. package/dist/chunk-IR44XKBI.js +0 -46
  84. package/dist/chunk-JKVOBTRO.js +0 -145
  85. package/dist/chunk-LVM5Q2DL.js +0 -68
  86. package/dist/chunk-M4QTEJTK.js +0 -709
  87. package/dist/chunk-QSBDB4J2.js +0 -16
  88. package/dist/chunk-R3XAOMKP.js +0 -29
  89. package/dist/chunk-SPVTJH3F.js +0 -24
  90. package/dist/chunk-YAHT3LST.js +0 -663
  91. package/dist/chunk-ZD2VTUYR.js +0 -28
  92. package/dist/cinema-media-HYCDG65Z.js +0 -11
  93. package/dist/comparison-XXAP4S4J.js +0 -36
  94. package/dist/editorial-timeline-VUQC6KPA.js +0 -42
  95. package/dist/key-figure-4TJK7HLT.js +0 -29
  96. package/dist/kit-DrRpdn0p.d.ts +0 -79
  97. package/dist/mobile-message-FIHAO6XC.js +0 -49
  98. package/dist/preload-media-LJXWKTWG.js +0 -57
  99. package/dist/quote-GRPIYKQJ.js +0 -32
  100. package/dist/system-prompt-AG26KJAA.js +0 -12
  101. package/dist/template-catalog.d.ts +0 -400
  102. package/dist/template-catalog.js +0 -6
  103. package/dist/templates.d.ts +0 -25
  104. package/dist/templates.js +0 -102
  105. package/dist/validate-4OUD2CLX.js +0 -10
  106. package/docs/concepts.md +0 -107
  107. package/docs/custom-templates.md +0 -346
  108. package/docs/immersive-interface.md +0 -86
  109. package/docs/maintainers/cinematic-migration.md +0 -38
  110. package/docs/motion-and-effects.md +0 -109
  111. package/docs/reference/design-system.html +0 -125
  112. package/docs/responsive-orientation.md +0 -37
  113. package/docs/streaming-protocol.md +0 -15
  114. package/examples/custom-template/README.md +0 -19
  115. package/examples/custom-template/minimal-text.tsx +0 -82
  116. package/examples/custom-template/structured-data.tsx +0 -104
  117. package/registry/items/backgrounds.json +0 -70
  118. package/registry/items/chapterTitle.json +0 -80
  119. package/registry/items/cinemaMedia.json +0 -136
  120. package/registry/items/comparison.json +0 -168
  121. package/registry/items/editorialTimeline.json +0 -172
  122. package/registry/items/keyFigure.json +0 -162
  123. package/registry/items/mobileMessage.json +0 -153
  124. package/registry/items/motion.json +0 -45
  125. package/registry/items/quote.json +0 -161
  126. package/registry/items/template-context.json +0 -31
  127. package/registry/items/theme.json +0 -47
  128. package/registry/items/typography.json +0 -47
@@ -1,346 +0,0 @@
1
- [← Documentation home](../README.md) · [Previous: Customization](customization.md) · [Next: Motion and effects →](motion-and-effects.md)
2
-
3
- # Custom templates
4
-
5
- VanillaSky turns context into a visual response. Your AI determines what matters
6
- from the available context; a template defines how one kind of grounded answer
7
- appears in motion. Custom templates let your application own that visual
8
- vocabulary without letting the model generate React, HTML, or CSS.
9
-
10
- You edit one source file. VanillaSky derives the model-facing description,
11
- server validation, browser registry, and TypeScript variable shape from it.
12
-
13
- ## The shortest path
14
-
15
- The playback and server package does not install a TypeScript compiler. Install
16
- the optional compiler only for source-owned templates and the template
17
- ownership commands below:
18
-
19
- ```bash
20
- npm install --save-dev tsx
21
- ```
22
-
23
- List the effective catalog, including project-owned templates, before choosing
24
- what to build or copy:
25
-
26
- ```bash
27
- npx vanillasky templates list
28
- ```
29
-
30
- Create an original template:
31
-
32
- ```bash
33
- npx vanillasky templates create customer-health
34
- npx vanillasky templates describe customer-health
35
- ```
36
-
37
- Or copy a built-in when its behavior is already close:
38
-
39
- ```bash
40
- npx vanillasky templates add keyFigure
41
- ```
42
-
43
- Then edit the owned `.tsx` file, regenerate the two small registries, and check
44
- the complete contract:
45
-
46
- ```bash
47
- npx vanillasky templates sync
48
- npx vanillasky templates check
49
- ```
50
-
51
- For an original template, the source is
52
- `vanillasky/templates/customer-health.tsx`. For the copied built-in, it is
53
- `vanillasky/templates/keyFigure.tsx`. These are application source: commit them,
54
- review them, and change them like any other React component.
55
-
56
- `create` and `add` run `sync` once, so the generated entry points exist
57
- immediately. Run `sync` again after every source edit. Run `check` before every
58
- commit. `check` validates metadata, schema/default validity, named examples, deterministic
59
- renders at progress boundaries in portrait and landscape, and browser/server
60
- registry parity.
61
-
62
- Preview either operation without applying the proposed file writes:
63
-
64
- ```bash
65
- npx vanillasky templates add keyFigure --dry-run
66
- npx vanillasky templates add keyFigure --diff
67
- ```
68
-
69
- `--dry-run` lists every proposed file and `--diff` shows its content changes,
70
- including the generated browser and server registries. The CLI does not apply
71
- any proposed file write. When project templates already exist, these previews
72
- execute that trusted application source to derive the complete registry plan.
73
- Because trusted project source can have its own side effects, preview execution is
74
- resource-bounded but is not a sandbox and does not guarantee that the entire
75
- project remains byte-identical. Review project template code before running
76
- preview commands.
77
-
78
- An edited file is never replaced unless you explicitly pass `--overwrite`.
79
-
80
- ## One file is the contract
81
-
82
- The file created by `vanillasky templates create` is a complete working template. Keep
83
- these concerns together:
84
-
85
- - `useWhen` and `avoidWhen` tell the AI when the visual is appropriate;
86
- - `jobs` declares the narrative roles the template can fill, and decides
87
- whether it may close a video;
88
- - `schema` defines allowed variables, validation, defaults, labels, and
89
- grounding formats;
90
- - named `examples` provide complete deterministic preview values;
91
- - `component` receives only validated variables and render context;
92
- - raw `progress`, dimensions, and `safeZone` make semantic state deterministic
93
- and layout safe in portrait and landscape.
94
-
95
- ### Which templates may close a video
96
-
97
- Every complete plan ends on exactly one closer, and the runtime only accepts a
98
- closer whose `jobs` include `"ask"` or `"payoff"`. Marking any other template as
99
- the closer rejects that scene with `Scene template <id> cannot be used as a
100
- closer`, and the reserved closing time is given to a template that qualifies.
101
-
102
- Declare `jobs: ["ask"]` on a call to action and `jobs: ["payoff"]` on a
103
- celebration or resolution beat. A template that only presents evidence keeps
104
- `jobs: ["proof"]` and is never asked to close.
105
-
106
- The same rule reads the built-in catalog, so an application that wants to
107
- constrain how its videos end can compute the eligible IDs instead of guessing:
108
-
109
- ```ts
110
- import { builtinTemplates } from "@vanillaskyai/video/templates/catalog";
111
-
112
- const closerTemplateIds = builtinTemplates
113
- .filter((template) => template.jobs.some((job) => job === "ask" || job === "payoff"))
114
- .map((template) => template.id);
115
- ```
116
-
117
- Pacing uses the same signal: the planner reserves time for the closer whenever
118
- the selected catalog contains a template with one of those two jobs.
119
-
120
- Customer templates hard-cut by default. Opt into renderer-owned fades only
121
- for scenes that use the standard media-background variables, and only after
122
- both timing points are visually tested in portrait and landscape. Shared render
123
- black backgrounds and unchanged media do not crossfade:
124
-
125
- ```tsx
126
- export default defineTemplate({
127
- // ...the normal one-file contract
128
- usesGlobalTransition: true,
129
- transitionTiming: { entryReadyProgress: 0.2, holdProgress: 0.7 },
130
- component: ({ progress, motionProgress = progress, ...props }) => {
131
- // Both clocks cover the complete declared 0→1 scene duration.
132
- // Use progress for facts/media/screens; motionProgress for presentation.
133
- return <CustomerScene {...props} dataProgress={progress} motionProgress={motionProgress} />;
134
- },
135
- });
136
- ```
137
-
138
- `entryReadyProgress` must show recognizable content in verification captures.
139
- `holdProgress` is the audited complete-readable checkpoint before the
140
- template's own exit begins. These values document and test the choreography;
141
- they never advance or shorten the runtime clock. The SDK validates
142
- `0 <= entryReadyProgress < holdProgress <= 1`.
143
-
144
- When changed media crossfades, the incoming layer can be partly visible while
145
- raw `progress` is exactly zero. A custom template that counts or types a value
146
- from a synthetic placeholder must hide only that transient wrapper during the
147
- crossfade. Compare the formatted display value to the formatted final value so
148
- a sourced zero is not mistaken for a placeholder:
149
-
150
- <!-- verify:transition-semantic-value:start -->
151
- ```tsx
152
- import type { CSSProperties } from "react";
153
-
154
- interface TransitionSemanticValueProps {
155
- displayValue: string;
156
- finalValue: string;
157
- }
158
-
159
- export function TransitionSemanticValue({
160
- displayValue,
161
- finalValue,
162
- }: TransitionSemanticValueProps) {
163
- const isTransient = displayValue !== finalValue;
164
-
165
- return <span
166
- data-transition-semantic={isTransient ? "transient" : undefined}
167
- style={isTransient ? {
168
- visibility: "var(--vanillasky-transition-semantic-visibility, visible)" as CSSProperties["visibility"],
169
- } : undefined}
170
- >
171
- {displayValue}
172
- </span>;
173
- }
174
- ```
175
- <!-- verify:transition-semantic-value:end -->
176
-
177
- The variable defaults to `visible`, so direct rendering and hard cuts are
178
- unchanged. Do not apply it to grounded headings, CTA copy, supplied media, or
179
- the whole scene: those must remain recognizable at `entryReadyProgress`.
180
-
181
- The only SDK import an original one-file template needs is public:
182
-
183
- ```tsx
184
- import { defineTemplate } from "@vanillaskyai/video/templates";
185
- ```
186
-
187
- Start from the generated file or one of the packaged references:
188
-
189
- | Content shape | Reference |
190
- | --- | --- |
191
- | One headline and supporting line | [Minimal text](../examples/custom-template/minimal-text.tsx) |
192
- | One exact metric and its change | [Structured data](../examples/custom-template/structured-data.tsx) |
193
-
194
- The [reference comparison](../examples/custom-template/README.md) explains when
195
- to choose each. Copy a file into `vanillasky/templates/`, change its ID and
196
- content contract, then run `sync` and `check`.
197
-
198
- ## Connect the generated registries
199
-
200
- `sync` generates two files from the owned templates:
201
-
202
- ```text
203
- vanillasky/
204
- ├── templates/
205
- │ └── customer-health.tsx # source you edit
206
- ├── index.ts # browser registry, generated
207
- └── server.ts # React-free model/validation registry, generated
208
- ```
209
-
210
- The server registry connects custom template metadata to the prompt, model
211
- selection, and validator. Import it in the route that connects your model:
212
-
213
- ```ts
214
- // src/video-route.ts
215
- import { generateText, streamText } from "ai";
216
- import { createVideoChatHandler } from "@vanillaskyai/video/server";
217
- import { videoModel } from "./video-model";
218
- import { templates } from "../vanillasky/server";
219
-
220
- export const handleVideoChat = createVideoChatHandler({
221
- templates,
222
- authorize: (request) => {
223
- if (process.env.VANILLASKY_LOCAL_DEMO !== "1") return false;
224
- const hostname = new URL(request.url).hostname;
225
- return hostname === "localhost" || hostname === "127.0.0.1";
226
- },
227
- generateText: async ({ systemPrompt, userPrompt, signal }) => {
228
- const result = await generateText({
229
- model: videoModel,
230
- system: systemPrompt,
231
- prompt: userPrompt,
232
- abortSignal: signal,
233
- });
234
- return result.text;
235
- },
236
- streamText: ({ systemPrompt, userPrompt, signal }) => streamText({
237
- model: videoModel,
238
- system: systemPrompt,
239
- prompt: userPrompt,
240
- abortSignal: signal,
241
- }),
242
- });
243
- ```
244
-
245
- The local-only authorization above is intentionally narrow. Supply its marker
246
- only from the development command; replace it with your application's session
247
- check before deployment, as shown in
248
- [Getting started](getting-started.md).
249
-
250
- Use the browser registry for generation and playback:
251
-
252
- ```tsx
253
- // src/video-chat.tsx
254
- import { VideoChat } from "@vanillaskyai/video/react";
255
- import "@vanillaskyai/video/video-chat.css";
256
- import { templates } from "../vanillasky";
257
-
258
- export function App() {
259
- return <VideoChat options={{ templates }} />;
260
- }
261
- ```
262
-
263
- Adjust relative paths for your application layout. Do not edit `index.ts` or
264
- `server.ts`; `sync` replaces them. A matching ID replaces that built-in on both
265
- sides, a new ID extends the catalog, and every other built-in remains available.
266
-
267
- ## Preview without an LLM
268
-
269
- Template rendering is deterministic. Preview a saved `Video` directly in your
270
- application so iteration uses your actual CSS, fonts, container, React version,
271
- and browser. This path calls no model and needs no server route:
272
-
273
- <!-- verify:custom-template-preview:start -->
274
- ```tsx
275
- import type { Video } from "@vanillaskyai/video";
276
- import { VideoPlayer } from "@vanillaskyai/video/react";
277
- import { templates } from "../vanillasky";
278
-
279
- const savedVideo: Video = {
280
- schemaVersion: "0.2",
281
- orientation: "portrait",
282
- scenes: [{
283
- id: "customer-health-preview",
284
- templateId: "customer-health",
285
- variables: {
286
- title: "Customer health is improving",
287
- subtitle: "Activation increased after guided onboarding.",
288
- },
289
- timing: { fixedDuration: 5 },
290
- }],
291
- style: {},
292
- };
293
-
294
- export function TemplatePreview() {
295
- return <VideoPlayer video={savedVideo} templates={templates} autoPlay={false} />;
296
- }
297
- ```
298
- <!-- verify:custom-template-preview:end -->
299
-
300
- Change the saved variables to each named example, inspect both orientations,
301
- and play the scene to inspect its full progress range. This is also the
302
- production replay path for a completed chat turn saved from `chat.turns`.
303
-
304
- ## Schema and grounding
305
-
306
- Use JSON Schema as the single source of truth.
307
-
308
- Property defaults are optional authoring and renderer smoke values; they do not
309
- need to form a complete scene. Named examples must resolve to complete valid
310
- scenes. They may inherit omitted values from property defaults. Never invent
311
- media URLs or actions just to supply a default. Put complete scene examples in
312
- the top-level `examples` array, and do not maintain parallel variable or default
313
- maps.
314
-
315
- Useful formats add grounding behavior:
316
-
317
- - `grounded-stat` accepts numeric or string quantities and requires an exact
318
- quantity in raw input, preserving its unit;
319
- - `grounded-quote` requires the quote to exist verbatim in the input;
320
- - `uri` validates approved media URLs restored by the server;
321
- - `stock-media-keyword` is only for hosts that resolve stock media before a
322
- scene is committed.
323
-
324
- Templates whose core proof needs a real statistic can add
325
- `"x-vanillasky": { "requiresStat": true }`. See the structured-data reference for a complete example.
326
-
327
- For media-backed chat scenes, copy the built-in `cinemaMedia` template and keep its
328
- `mediaKeyword`, `mediaUrl`, and `mediaType` contract. Configure `searchMedia` on
329
- the chat handler so the server resolves semantic searches into approved assets.
330
- The chat request does not accept a separate supplied-media input list.
331
-
332
- The automatic `opening` uses the built-in `chapterTitle` variable `title`.
333
- If you replace that template while using automatic openings, keep this contract.
334
-
335
- ## What belongs where
336
-
337
- Your application owns the model, credentials, live context, custom template
338
- source, authentication, media authorization, and saved `Video` values.
339
- VanillaSky owns the generated planning instructions, streaming protocol,
340
- runtime validation, built-in template catalog, and player. The model selects a
341
- trusted template and fills its declared schema; it never writes executable UI
342
- code.
343
-
344
- For the exact request path and source locations, see
345
- [Architecture](architecture.md). For media policies and provider callbacks,
346
- see [Media and audio](media-and-audio.md).
@@ -1,86 +0,0 @@
1
- [← Documentation home](../README.md)
2
-
3
- # Immersive video chat
4
-
5
- `VideoChat` provides the complete conversation interface over an adaptive video
6
- canvas. Import its stylesheet once; no copied example UI or component setup is
7
- required.
8
-
9
- ```tsx
10
- import { VideoChat } from "@vanillaskyai/video/react";
11
- import "@vanillaskyai/video/video-chat.css";
12
-
13
- export function App() {
14
- return <VideoChat options={{ endpoint: "/api/video-chat" }} />;
15
- }
16
- ```
17
-
18
- The [interactive component reference](reference/design-system.html) uses the
19
- same packaged stylesheet. It demonstrates navigation, settings, history,
20
- conversation input, subtitles, suggestions and interaction states without
21
- requesting a microphone or calling a model.
22
-
23
- ## Watching and asking
24
-
25
- The video owns the canvas. The navigation contains the VanillaSky logo, new
26
- session, history, voice and settings. One floating field supports speech and
27
- text; playback, microphone and send controls stay beside the question.
28
-
29
- Beginning a question pauses the picture and narration together. Speech becomes
30
- a draft to review. Sending begins the next answer; canceling returns to the
31
- previous playback state. Canceling voice input also discards pending
32
- transcription so a late result cannot replace a new draft.
33
-
34
- The first subtitle hides the input unless editing, listening or keyboard focus
35
- requires it. Pointer activity or touch reveals the controls again. They hide
36
- after two seconds of inactivity during playback; paused playback and active
37
- controls remain accessible. A stationary pointer left over Send does not hold
38
- the input open. Settings can keep the input visible.
39
-
40
- ## Subtitles and transcripts
41
-
42
- Subtitles sit on a dark backing over the picture. The complete current cue
43
- remains available without a line clamp or ellipsis. When the input appears,
44
- subtitles move upward; when it disappears, they return to the bottom baseline.
45
- The transition preserves space for both rows instead of abruptly repositioning
46
- the subtitle.
47
-
48
- Subtitle actions fade while inactive and return on hover, touch or keyboard
49
- focus. Expand opens the answer transcript in the same surface. Hide removes
50
- subtitles; the Subtitles switch in Settings restores them. The transcript is
51
- part of the video interface rather than a separate modal.
52
-
53
- ## Settings and history
54
-
55
- Settings and history share one dark glass treatment. Watching preferences
56
- control subtitles and input visibility. Video creation and style preferences
57
- apply to the next question; provider capabilities determine available options.
58
- History replays saved answers without generating them again. New session
59
- retains up to ten sessions in memory, preserving completed answers for replay.
60
- This history does not provide server or durable persistence; storage remains
61
- application-owned. See [persistence](persistence.md).
62
-
63
- Suggestions appear in a horizontal media-card rail. Pointer hover and keyboard
64
- focus select a card; choosing it begins a follow-up answer. Focus outlines and
65
- hover movement remain inside the rail's available space.
66
-
67
- ## Layout and access
68
-
69
- The foreground video preserves its scene ratio, so diagrams and text remain
70
- visible without cropping or distortion. The surrounding viewport remains black during playback.
71
- Display layout does not rewrite the saved response's orientation. See
72
- [responsive orientation](responsive-orientation.md) for saved videos and custom
73
- players.
74
-
75
- Primary control targets are at least 44px. Bottom spacing includes the device
76
- safe area. Keyboard focus stays visible, settings retain native switch and
77
- radio behavior, and popovers support Escape and outside-click dismissal.
78
- Reduced motion removes movement and fades; increased contrast strengthens
79
- surface opacity and borders.
80
-
81
- ## Customization
82
-
83
- Use the existing `welcomeTitle`, `className` and `options` props to customize
84
- copy, scoped CSS properties and generated footage direction. There is no separate
85
- light/dark appearance picker. See [customization](customization.md) for examples.
86
- Use `useVideoChat` when the application needs to own the whole interface.
@@ -1,38 +0,0 @@
1
- # Cinematic contract migration
2
-
3
- The eight-template replacement is an approved breaking pre-1.0 change. Persisted Video schema is now `0.2`; event protocol is `0.6`.
4
-
5
- ## Breaking changes
6
-
7
- - Removed `VideoInput.brand`, `VideoStyle.brand`, `VideoBrand`, `VideoBrandInput`, `VideoBackground`, and `resolveVideoBrand`. Graphics use black, white/neutral text and system typography. Naturally colored media is unaffected.
8
- - Removed all 28 old built-in IDs. Eight new IDs describe different schemas: `cinemaMedia`, `chapterTitle`, `focusCards`, `editorialTimeline`, `mobileMessage`, `comparison`, `quote`, `keyFigure`.
9
- - `parseVideo` rejects the old persisted `0.1` fixture with `unsupported_video_version`. The parser also rejects `style.brand` if a caller merely stamps the new version onto an old object.
10
- - Scene source intent uses `mediaKeyword` (up to 80 characters) and optional `mediaSource`. The host owns `mediaUrl`, `mediaPoster` and resolved `mediaType`. No gradient fallback mode. Full-bleed requires a resolvable intent or asset; Reach out can remain on black when media is unavailable.
11
-
12
- ## Adoption
13
-
14
- Regenerate videos from the retained source and narration using the new catalog. Do not automatically relabel old IDs: before/after emojis, count-ups and factual quote/stat schemas have different meanings. Retain an older published SDK in a separate legacy playback boundary if historical exports must continue to render; do not pass those payloads into the new parser.
15
-
16
- Before (old persisted format):
17
-
18
- ```json
19
- {"schemaVersion":"0.1","scenes":[{"id":"one","templateId":"media","variables":{"texts":"A new perspective","mediaType":"gradient"},"timing":{"fixedDuration":4}}],"style":{"brand":{"font":"Inter"}}}
20
- ```
21
-
22
- After re-authoring that title as a chapter:
23
-
24
- ```json
25
- {"schemaVersion":"0.2","scenes":[{"id":"one","templateId":"chapterTitle","variables":{"title":"A new perspective"},"timing":{"fixedDuration":4}}],"style":{}}
26
- ```
27
-
28
- Evidence: persistence tests preserve the untouched old release fixture and assert rejection, accept current-style round trips, reject hidden/non-JSON input as before, and pin new checksums. Template tests cover both orientations, deterministic seeking, exact evidence text and single-decoder backdrop ownership. Final packed consumer and mobile playback checks remain release gates.
29
-
30
- ## Render fonts
31
-
32
- The cinematic templates use `-apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto, Arial, sans-serif` at regular and medium weights. Apple devices keep native system typography. The existing `@vanillaskyai/video/video-chat.css` entry registers packaged Roboto v51 WOFF2 subsets as the fallback for environments without those fonts. Standalone player and source-owned template integrations should also import that stylesheet. No font is fetched from Google at runtime; browsers fetch local packaged subsets only when Roboto is selected for the rendered glyphs. The font assets include the SIL Open Font License and a source/hash manifest.
33
-
34
- Live native fonts and a Linux renderer’s Roboto have slightly different metrics. For repeatable exports, keep the browser, installed fonts, viewport and package version fixed, and await `document.fonts.ready` after mounting the final scene before capturing frames. This is a host export responsibility; the SDK does not add a separate export API or force downloaded fonts onto Apple devices.
35
-
36
- ## Media-led follow-up
37
-
38
- The owner requested removing `focusCards`. Regenerate persisted videos using that ID; migrate parallel explanations to narration over footage rather than another bullet layout. The remaining seven templates retain their IDs. Comparison, quote, key figure and timeline accept optional standard media variables and remain readable on black when assets are absent. No provider callback signatures or host limits change.
@@ -1,109 +0,0 @@
1
- [← Documentation home](../README.md) · [Previous: Custom templates](custom-templates.md) · [Next: Production →](production.md)
2
-
3
- # Motion and effects
4
-
5
- VanillaSky motion is deterministic. The model selects from controlled names;
6
- the SDK calculates the same frame from the same video JSON and playback time.
7
- No generated CSS, animation code, or arbitrary transition is executed.
8
-
9
- ## Text archetypes
10
-
11
- Text archetypes own a complete entrance, hold, and exit lifecycle:
12
-
13
- - `subtle` — quiet supporting copy;
14
- - `typewriter` — character-by-character reveal;
15
- - `wordStagger` — sequential word build;
16
- - `slam` — short, high-energy impact;
17
- - `cinematic` — depth-led trailer movement;
18
- - `heroWord` — one dominant word at a time.
19
-
20
- Templates declare whether they have a tight or open text canvas. VanillaSky
21
- normalizes incompatible or unknown values to a safe default.
22
-
23
- ## Background effects
24
-
25
- Templates that support background motion can use:
26
-
27
- - `static`;
28
- - `slow-zoom-in`;
29
- - `slow-zoom-out`;
30
- - `ken-burns`;
31
- - `drift`;
32
- - `pulse`;
33
- - `breathe`;
34
- - `slow-tilt`;
35
- - `camera-shake`.
36
-
37
- `static` is the default, so a media change cannot restart an implicit camera
38
- transform. Apply another effect explicitly when a still image or authored scene
39
- benefits from it; footage keeps its own native motion by default.
40
-
41
- ## Scene continuity
42
-
43
- Generated videos use `crossfade` by default. Persisted or application-authored
44
- `Video` values can set `style.defaultTransition` to `crossfade` or `fade`; an
45
- undefined or unknown value keeps the hard-cut behavior. The player applies a fade
46
- only when two ranges are contiguous (allowing floating-point arithmetic noise)
47
- and both templates declare `usesGlobalTransition: true` with valid
48
- `transitionTiming` metadata. It is also conditional on the effective backdrop:
49
- the 300 ms outer crossfade runs only when the resolved background media changes.
50
- Scenes that share the black base, or the same resolved media backdrop, do
51
- not crossfade. This keeps one stable background visible while each template
52
- plays its own entrance, hold, and exit choreography.
53
-
54
- The player owns a fixed black backdrop beneath the scenes. Built-in renderers
55
- preload through the same component state used for playback. A cold custom
56
- renderer reveals this black base while loading. Resolved scene media covers it
57
- only while the media scene is active.
58
-
59
- During a changed-media overlap, the current scene continues to its exact end.
60
- The incoming component may be pre-mounted for media readiness, but remains
61
- frozen at its true initial frame (`progress === motionProgress === 0`) until its
62
- declared range begins. The current scene remains interactive and exposed to
63
- assistive technology until the exact timeline boundary; the preview layer
64
- remains inert throughout the overlap.
65
-
66
- Templates always receive raw semantic scene time as `progress`. Grounded
67
- numbers, media time, screen sequences, and other content state must use that
68
- clock. An opted-in template also receives `motionProgress`; throughout active
69
- playback it is the same complete `0→1` clock. The player never pre-advances,
70
- caps, rewinds, or skips a template's entrance, internal motion, exit, or
71
- terminal frame. `transitionTiming` records audited entry-ready and readable
72
- checkpoints for verification, but does not remap runtime time. Use
73
- `motionProgress` only for presentation and fall back to `progress` when it is
74
- absent. Templates opt out by default.
75
-
76
- An incoming changed-media fade can expose the template's initial frame while
77
- its raw semantic clock is still zero.
78
- Do not show a synthetic `0%`, `0x`, empty total, or another value that could be
79
- mistaken for sourced content. Keep the grounded frame and CTA visible, but mark
80
- only a transient value wrapper with
81
- `visibility: var(--vanillasky-transition-semantic-visibility, visible)`. The
82
- player hides that wrapper for the incoming preview and reveals it as soon as
83
- the same mounted scene becomes active. This guard does not change `progress`,
84
- media time, the component lifecycle, or final values.
85
-
86
- As soon as a streamed scene arrives, the player starts warming its template and
87
- backdrop. A changed-media scene is also mounted invisibly before its cut so the
88
- browser can attach and decode the real element in advance. This media preroll
89
- also protects intentional hard cuts; it does not pause or otherwise alter the
90
- visual or soundtrack clocks.
91
-
92
- Undefined or unknown transition names preserve a hard cut and unmodified local
93
- motion. Overlapping ranges also hard-cut. A timeline gap renders the fixed black
94
- background instead of replaying an earlier scene.
95
-
96
- ## Reduced motion
97
-
98
- The player respects `prefers-reduced-motion`. Applications should keep a
99
- visible playback control and must not rely on motion alone to communicate a
100
- fact or state.
101
-
102
- ## Preview the catalog
103
-
104
- The public [motion and effects gallery](https://vanillasky.ai/motion/) renders
105
- the real SDK effects with their exact configuration. Use it to choose a
106
- controlled effect, then keep the initial integration on the defaults unless a
107
- specific editorial need calls for an override.
108
-
109
- [← Documentation home](../README.md) · [Previous: Custom templates](custom-templates.md) · [Next: Production →](production.md)