@vanillaskyai/video 0.8.8 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/PUBLIC-API.md +5 -8
- package/dist/{builtin-server-CUYPIDE7.js → builtin-server-W4PLJUZ5.js} +2 -2
- package/dist/{catalog-types-BIhSpOWK.d.ts → catalog-types-WTbLP6Jh.d.ts} +5 -1
- package/dist/chapter-title-YRLIQY3V.js +7 -0
- package/dist/check-runtime.js +5 -14
- package/dist/{chunk-AITKH6QT.js → chunk-2HFO22K2.js} +15 -40
- package/dist/chunk-4YM2M62S.js +13 -0
- package/dist/chunk-4ZJLPHBV.js +684 -0
- package/dist/chunk-77VY4O7A.js +390 -0
- package/dist/{chunk-MMUXVA47.js → chunk-7M56IUUX.js} +9 -8
- package/dist/chunk-7NZOMTAL.js +63 -0
- package/dist/{chunk-2DOLF4QN.js → chunk-AUPC6MDK.js} +12 -14
- package/dist/{chunk-352ZZCET.js → chunk-EGVQODKU.js} +2 -2
- package/dist/{chunk-2USVB3CY.js → chunk-ELVOT2FQ.js} +284 -177
- package/dist/chunk-EWWCQFTI.js +18 -0
- package/dist/{chunk-KT3M7KDL.js → chunk-HKUI5BTB.js} +3 -3
- package/dist/chunk-IIN5M5HW.js +697 -0
- package/dist/{chunk-LMG3GHLL.js → chunk-IQMYK5DX.js} +29 -3
- package/dist/{chunk-OWBT45EN.js → chunk-IR44XKBI.js} +1 -1
- package/dist/{chunk-MXZSDGZQ.js → chunk-NMFDC2W2.js} +4 -6
- package/dist/{chunk-5SLENAJW.js → chunk-PAJ44TFW.js} +1 -2
- package/dist/{chunk-L7QGGKJ2.js → chunk-PDQFQIQW.js} +1 -1
- package/dist/{chunk-WJ6FLKNC.js → chunk-R3XAOMKP.js} +14 -0
- package/dist/{chunk-2OKB27TG.js → chunk-RXTN2CW6.js} +2 -2
- package/dist/{chunk-XWWLKRNU.js → chunk-TVIU23OM.js} +38 -49
- package/dist/chunk-XX4GXKTX.js +35 -0
- package/dist/chunk-Z67Q5KUW.js +16 -0
- package/dist/{chunk-3VRMKFM7.js → chunk-ZDJNFA52.js} +11 -24
- package/dist/cinema-media-C7OUPNSH.js +12 -0
- package/dist/cli.js +18 -9
- package/dist/comparison-GNZOR7MF.js +37 -0
- package/dist/compose-video-TBFTONUC.js +12 -0
- package/dist/editorial-timeline-EMV5335S.js +43 -0
- package/dist/{events-BQ6z264n.d.ts → events-B4YCc4vc.d.ts} +1 -1
- package/dist/index.d.ts +4 -6
- package/dist/index.js +3 -7
- package/dist/key-figure-P37VK425.js +30 -0
- package/dist/{kit-tQnCPMOM.d.ts → kit-DrRpdn0p.d.ts} +2 -2
- package/dist/mobile-message-OF7T62B7.js +50 -0
- package/dist/quote-T6WYLN7A.js +33 -0
- package/dist/react.d.ts +21 -11
- package/dist/react.js +585 -826
- package/dist/scene-video-backdrop-PCTARAAJ.js +7 -0
- package/dist/server.d.ts +7 -8
- package/dist/server.js +179 -84
- package/dist/{system-prompt-RRXIWDDD.js → system-prompt-SYRT5DWM.js} +1 -1
- package/dist/template-catalog.d.ts +392 -16
- package/dist/template-catalog.js +1 -1
- package/dist/templates.d.ts +5 -5
- package/dist/test.d.ts +3 -3
- package/dist/test.js +18 -18
- package/dist/text-stream-LD364KBI.js +9 -0
- package/dist/{types-DWFO6qca.d.ts → types-CdBmNTGD.d.ts} +1 -1
- package/dist/{types-CEh9eUFu.d.ts → types-DdZw4GRQ.d.ts} +17 -48
- package/dist/validate-4OUD2CLX.js +10 -0
- package/docs/architecture.md +1 -1
- package/docs/concepts.md +1 -1
- package/docs/custom-templates.md +13 -28
- package/docs/customization.md +11 -59
- package/docs/getting-started.md +2 -2
- package/docs/immersive-interface.md +3 -4
- package/docs/maintainers/cinematic-migration.md +38 -0
- package/docs/media-and-audio.md +14 -14
- package/docs/motion-and-effects.md +6 -14
- package/docs/persistence.md +3 -3
- package/docs/production.md +11 -9
- package/docs/provider-integration.md +9 -16
- package/docs/reference/design-system.html +1 -1
- package/docs/reference/protocol.md +14 -4
- package/docs/testing.md +1 -1
- package/package.json +6 -3
- package/registry/items/backgrounds.json +1 -1
- package/registry/items/chapterTitle.json +80 -0
- package/registry/items/cinemaMedia.json +136 -0
- package/registry/items/comparison.json +168 -0
- package/registry/items/editorialTimeline.json +172 -0
- package/registry/items/keyFigure.json +162 -0
- package/registry/items/mobileMessage.json +153 -0
- package/registry/items/quote.json +161 -0
- package/registry/items/template-context.json +1 -1
- package/registry/items/theme.json +1 -1
- package/starters/video-chat/README.md +24 -26
- package/starters/video-chat/package.json +1 -1
- package/starters/video-chat/providers/video.ts +6 -5
- package/starters/video-chat/stock.ts +35 -151
- package/styles/fonts/OFL.txt +93 -0
- package/styles/fonts/manifest.json +66 -0
- package/styles/fonts/roboto-v51-cyrillic-ext.woff2 +0 -0
- package/styles/fonts/roboto-v51-cyrillic.woff2 +0 -0
- package/styles/fonts/roboto-v51-greek-ext.woff2 +0 -0
- package/styles/fonts/roboto-v51-greek.woff2 +0 -0
- package/styles/fonts/roboto-v51-latin-ext.woff2 +0 -0
- package/styles/fonts/roboto-v51-latin.woff2 +0 -0
- package/styles/fonts/roboto-v51-math.woff2 +0 -0
- package/styles/fonts/roboto-v51-symbols.woff2 +0 -0
- package/styles/fonts/roboto-v51-vietnamese.woff2 +0 -0
- package/styles/fonts/roboto.css +91 -0
- package/styles/video-chat.css +30 -22
- package/dist/bg-confetti-HITCGLGD.js +0 -89
- package/dist/bg-emoji-VU4UZYZN.js +0 -150
- package/dist/bg-media-L34PDQXJ.js +0 -106
- package/dist/brand-message-FUJ4STFO.js +0 -256
- package/dist/chart-bar-EGPHJATL.js +0 -310
- package/dist/chart-counter-5FFWQNZO.js +0 -306
- package/dist/chart-progress-ring-JMXQLMLC.js +0 -302
- package/dist/chunk-4UNKZEAT.js +0 -3575
- package/dist/chunk-5CDAM24P.js +0 -31
- package/dist/chunk-AOWSXU2K.js +0 -18
- package/dist/chunk-CJ7F2CE6.js +0 -104
- package/dist/chunk-FRN6WKHA.js +0 -185
- package/dist/chunk-G5JPHBX7.js +0 -336
- package/dist/chunk-L5BTTCZV.js +0 -97
- package/dist/chunk-P22HHFDK.js +0 -43
- package/dist/chunk-PP3MCPN4.js +0 -1998
- package/dist/chunk-QAAO7OAY.js +0 -19
- package/dist/chunk-S7HFLYNN.js +0 -35
- package/dist/chunk-W3VDIBGR.js +0 -217
- package/dist/chunk-XGRA2MUV.js +0 -242
- package/dist/chunk-XTOXFMLM.js +0 -105
- package/dist/chunk-YJJC4N4D.js +0 -761
- package/dist/compose-video-2NFH4DZY.js +0 -13
- package/dist/cta-logo-YR7LYUR5.js +0 -212
- package/dist/cta-media-DQJBKUO2.js +0 -221
- package/dist/incoming-call-54KQ7O5A.js +0 -323
- package/dist/infographic-before-after-ROS52GOW.js +0 -460
- package/dist/infographic-feature-list-E7MGUDAN.js +0 -272
- package/dist/infographic-problem-solution-3S6NGO5N.js +0 -343
- package/dist/infographic-stat-row-SYB7AB7H.js +0 -247
- package/dist/infographic-steps-KCE6JWE2.js +0 -406
- package/dist/prompt-input-MHX4O42G.js +0 -239
- package/dist/reaction-SLEGR3BE.js +0 -122
- package/dist/scene-video-backdrop-XFPX4O3I.js +0 -10
- package/dist/showcase-code-2HLAVKBM.js +0 -357
- package/dist/showcase-phone-Q4HEO4LH.js +0 -278
- package/dist/showcase-terminal-DL45LUFG.js +0 -312
- package/dist/showcase-web-2QZO73FZ.js +0 -396
- package/dist/social-conversation-75SD2637.js +0 -695
- package/dist/social-milestone-GEFUQSBF.js +0 -296
- package/dist/social-notification-FJ5VHVLK.js +0 -247
- package/dist/social-review-stack-KXQCKFRP.js +0 -242
- package/dist/social-testimonial-JZ7CHC7S.js +0 -287
- package/dist/social-tweet-UCDXM25F.js +0 -298
- package/dist/text-stream-54LXABJW.js +0 -10
- package/dist/validate-T7GBU2YF.js +0 -8
- package/registry/items/barChart.json +0 -245
- package/registry/items/beforeAfter.json +0 -180
- package/registry/items/bigNumber.json +0 -232
- package/registry/items/brandMessage.json +0 -164
- package/registry/items/cardList.json +0 -214
- package/registry/items/chatMessenger.json +0 -151
- package/registry/items/chatWhatsapp.json +0 -151
- package/registry/items/codeEditor.json +0 -191
- package/registry/items/confetti.json +0 -107
- package/registry/items/ctaLogo.json +0 -167
- package/registry/items/ctaMedia.json +0 -200
- package/registry/items/emojiBurst.json +0 -101
- package/registry/items/incomingCall.json +0 -177
- package/registry/items/media.json +0 -187
- package/registry/items/milestone.json +0 -212
- package/registry/items/notification.json +0 -189
- package/registry/items/phoneMockup.json +0 -261
- package/registry/items/problemSolution.json +0 -193
- package/registry/items/progressRing.json +0 -206
- package/registry/items/promptInput.json +0 -155
- package/registry/items/reaction.json +0 -176
- package/registry/items/reviewStack.json +0 -231
- package/registry/items/steps.json +0 -215
- package/registry/items/terminal.json +0 -219
- package/registry/items/testimonial.json +0 -171
- package/registry/items/tripleStats.json +0 -235
- package/registry/items/tweet.json +0 -210
- package/registry/items/webMockup.json +0 -280
package/docs/architecture.md
CHANGED
|
@@ -67,7 +67,7 @@ prompt/validation registry in `vanillasky/server.ts`.
|
|
|
67
67
|
5. The system prompt combines the opening and composition rules with the trusted template
|
|
68
68
|
catalog, including generated metadata for customer-owned templates. The user
|
|
69
69
|
prompt serializes the prompt, completed conversation, instructions,
|
|
70
|
-
|
|
70
|
+
style, and approved media.
|
|
71
71
|
6. The model streams one host-consumed opening object followed by NDJSON plan
|
|
72
72
|
parts. The server emits the opening event, then parses and validates complete
|
|
73
73
|
scenes before emitting them.
|
package/docs/concepts.md
CHANGED
|
@@ -31,7 +31,7 @@ or export pipeline when an encoded file is required.
|
|
|
31
31
|
|
|
32
32
|
The viewer sends a prompt with bounded completed conversation turns. The server
|
|
33
33
|
adds trusted application `instructions`, template capabilities, and the selected
|
|
34
|
-
|
|
34
|
+
cinematic mode. `VideoChat` options control style, orientation, and custom
|
|
35
35
|
templates. Exact facts belong in the authorized prompt or conversation; secrets
|
|
36
36
|
and provider configuration stay on the server.
|
|
37
37
|
|
package/docs/custom-templates.md
CHANGED
|
@@ -37,7 +37,7 @@ npx vanillasky templates describe customer-health
|
|
|
37
37
|
Or copy a built-in when its behavior is already close:
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
npx vanillasky templates add
|
|
40
|
+
npx vanillasky templates add keyFigure
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Then edit the owned `.tsx` file, regenerate the two small registries, and check
|
|
@@ -50,7 +50,7 @@ npx vanillasky templates check
|
|
|
50
50
|
|
|
51
51
|
For an original template, the source is
|
|
52
52
|
`vanillasky/templates/customer-health.tsx`. For the copied built-in, it is
|
|
53
|
-
`vanillasky/templates/
|
|
53
|
+
`vanillasky/templates/keyFigure.tsx`. These are application source: commit them,
|
|
54
54
|
review them, and change them like any other React component.
|
|
55
55
|
|
|
56
56
|
`create` and `add` run `sync` once, so the generated entry points exist
|
|
@@ -62,8 +62,8 @@ registry parity.
|
|
|
62
62
|
Preview either operation without applying the proposed file writes:
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
npx vanillasky templates add
|
|
66
|
-
npx vanillasky templates add
|
|
65
|
+
npx vanillasky templates add keyFigure --dry-run
|
|
66
|
+
npx vanillasky templates add keyFigure --diff
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
`--dry-run` lists every proposed file and `--diff` shows its content changes,
|
|
@@ -119,8 +119,8 @@ the selected catalog contains a template with one of those two jobs.
|
|
|
119
119
|
|
|
120
120
|
Customer templates hard-cut by default. Opt into renderer-owned fades only
|
|
121
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
|
|
123
|
-
|
|
122
|
+
both timing points are visually tested in portrait and landscape. Shared render
|
|
123
|
+
black backgrounds and unchanged media do not crossfade:
|
|
124
124
|
|
|
125
125
|
```tsx
|
|
126
126
|
export default defineTemplate({
|
|
@@ -277,7 +277,7 @@ import { VideoPlayer } from "@vanillaskyai/video/react";
|
|
|
277
277
|
import { templates } from "../vanillasky";
|
|
278
278
|
|
|
279
279
|
const savedVideo: Video = {
|
|
280
|
-
schemaVersion: "0.
|
|
280
|
+
schemaVersion: "0.2",
|
|
281
281
|
orientation: "portrait",
|
|
282
282
|
scenes: [{
|
|
283
283
|
id: "customer-health-preview",
|
|
@@ -288,21 +288,7 @@ const savedVideo: Video = {
|
|
|
288
288
|
},
|
|
289
289
|
timing: { fixedDuration: 5 },
|
|
290
290
|
}],
|
|
291
|
-
style: {
|
|
292
|
-
brand: {
|
|
293
|
-
font: "Inter",
|
|
294
|
-
scriptFont: "Caveat",
|
|
295
|
-
background: { type: "gradient", colors: ["#8711C1", "#2167E3"] },
|
|
296
|
-
colors: {
|
|
297
|
-
primary: "#00E5A0",
|
|
298
|
-
secondary: "#006BE5",
|
|
299
|
-
foreground: "#FFFFFF",
|
|
300
|
-
surface: "#0A0A14",
|
|
301
|
-
surfaceElevated: "#14152A",
|
|
302
|
-
muted: "#A7A6B0",
|
|
303
|
-
},
|
|
304
|
-
},
|
|
305
|
-
},
|
|
291
|
+
style: {},
|
|
306
292
|
};
|
|
307
293
|
|
|
308
294
|
export function TemplatePreview() {
|
|
@@ -328,8 +314,8 @@ maps.
|
|
|
328
314
|
|
|
329
315
|
Useful formats add grounding behavior:
|
|
330
316
|
|
|
331
|
-
- `grounded-stat`
|
|
332
|
-
|
|
317
|
+
- `grounded-stat` accepts numeric or string quantities and requires an exact
|
|
318
|
+
quantity in raw input, preserving its unit;
|
|
333
319
|
- `grounded-quote` requires the quote to exist verbatim in the input;
|
|
334
320
|
- `uri` validates approved media URLs restored by the server;
|
|
335
321
|
- `stock-media-keyword` is only for hosts that resolve stock media before a
|
|
@@ -338,14 +324,13 @@ Useful formats add grounding behavior:
|
|
|
338
324
|
Templates whose core proof needs a real statistic can add
|
|
339
325
|
`"x-vanillasky": { "requiresStat": true }`. See the structured-data reference for a complete example.
|
|
340
326
|
|
|
341
|
-
For media-backed chat scenes, copy the built-in `
|
|
327
|
+
For media-backed chat scenes, copy the built-in `cinemaMedia` template and keep its
|
|
342
328
|
`mediaKeyword`, `mediaUrl`, and `mediaType` contract. Configure `searchMedia` on
|
|
343
329
|
the chat handler so the server resolves semantic searches into approved assets.
|
|
344
330
|
The chat request does not accept a separate supplied-media input list.
|
|
345
331
|
|
|
346
|
-
The automatic `opening` uses the built-in `
|
|
347
|
-
|
|
348
|
-
openings, keep that variable contract.
|
|
332
|
+
The automatic `opening` uses the built-in `chapterTitle` variable `title`.
|
|
333
|
+
If you replace that template while using automatic openings, keep this contract.
|
|
349
334
|
|
|
350
335
|
## What belongs where
|
|
351
336
|
|
package/docs/customization.md
CHANGED
|
@@ -14,7 +14,6 @@ heading and a root class when the application needs its own copy or chrome color
|
|
|
14
14
|
<VideoChat
|
|
15
15
|
className="acme-chat"
|
|
16
16
|
welcomeTitle={<>Ask Acme<br />See the answer</>}
|
|
17
|
-
options={{ brand: acmeBrand }}
|
|
18
17
|
/>
|
|
19
18
|
```
|
|
20
19
|
|
|
@@ -32,10 +31,10 @@ that instance:
|
|
|
32
31
|
```
|
|
33
32
|
|
|
34
33
|
The built-in navigation carries the VanillaSky logo. `welcomeTitle` changes
|
|
35
|
-
the welcome heading; it does not replace the navigation logo.
|
|
36
|
-
|
|
34
|
+
the welcome heading; it does not replace the navigation logo. Graphic scenes
|
|
35
|
+
use fixed black backgrounds and white/neutral system typography.
|
|
37
36
|
|
|
38
|
-
Use `options` for the endpoint, templates, orientation,
|
|
37
|
+
Use `options` for the endpoint, templates, orientation, request
|
|
39
38
|
headers, and an optional custom voice. Provider capabilities are discovered
|
|
40
39
|
from the server. Use `useVideoChat()` only when the application needs to own the
|
|
41
40
|
entire interface.
|
|
@@ -44,63 +43,16 @@ Pass the following visual settings through `VideoChat` or `useVideoChat` options
|
|
|
44
43
|
Keep viewer context in the prompt and completed conversation turns; use the
|
|
45
44
|
server handler’s `instructions` for trusted product guidance.
|
|
46
45
|
|
|
47
|
-
##
|
|
46
|
+
## Cinematic visual direction
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
Graphics use black backgrounds and white/neutral typography. Full-bleed media
|
|
49
|
+
and Reach out can show naturally colored footage; the other six templates
|
|
50
|
+
explain with their own composition and motion. There is no brand-kit option.
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
font: "Inter",
|
|
57
|
-
scriptFont: "Caveat",
|
|
58
|
-
background: "twilight",
|
|
59
|
-
colors: {
|
|
60
|
-
primary: "#6D5EF5",
|
|
61
|
-
secondary: "#3D2A78",
|
|
62
|
-
foreground: "#FFFFFF",
|
|
63
|
-
surface: "#17122F",
|
|
64
|
-
surfaceElevated: "#231B42",
|
|
65
|
-
muted: "#A7A6B0",
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Gradient presets: `cosmic`, `horizon`, `twilight`, `meadow`, `velvet`,
|
|
71
|
-
`flamingo`, `peach`, `saffron`. Solid presets: `black`, `midnight`,
|
|
72
|
-
`aubergine`, `coal`, `navy`. When a named choice genuinely cannot express the
|
|
73
|
-
brand, use `{ colors: ["#112233", "#334455"] }` for a custom gradient or
|
|
74
|
-
`{ color: "#070B20" }` for a custom solid.
|
|
75
|
-
|
|
76
|
-
`colors` may be partial; the resolver fills every semantic token before the
|
|
77
|
-
video is emitted. With no foreground, named and custom backgrounds
|
|
78
|
-
deterministically select black or white for at least 4.5:1 contrast across the
|
|
79
|
-
full rendered sRGB ramp, including gradient interiors. A ramp that neither can
|
|
80
|
-
cover is rejected. An explicit foreground is preserved and validated by the
|
|
81
|
-
same invariant during input resolution and replay; low-contrast values are
|
|
82
|
-
rejected with the failing path and minimum ratio. Elevated surfaces derive an
|
|
83
|
-
accessible internal text treatment without changing the semantic foreground.
|
|
84
|
-
Use an approved public or signed URL for logos, and never put a private storage
|
|
85
|
-
credential in the config.
|
|
86
|
-
|
|
87
|
-
## Global visual direction
|
|
88
|
-
|
|
89
|
-
Leave visual direction unset to use VanillaSky's defaults, or set one coherent
|
|
90
|
-
look for the completed video:
|
|
91
|
-
|
|
92
|
-
```ts
|
|
93
|
-
style: {
|
|
94
|
-
density: "airy", // airy | normal | packed
|
|
95
|
-
motion: "calm", // calm | normal | punchy
|
|
96
|
-
textArchetype: "cinematic",
|
|
97
|
-
backgroundEffect: "slow-zoom-out",
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
These are defaults, not generated CSS. A validated scene may still select a
|
|
102
|
-
more appropriate text or background treatment when its trusted template allows
|
|
103
|
-
it.
|
|
52
|
+
The host can provide a shared `generatedLook` description for media preparation.
|
|
53
|
+
Custom source-owned templates can define their own visual language in code.
|
|
54
|
+
Do not rely on old global brand, text-effect, or gradient controls to restyle
|
|
55
|
+
the seven cinematic templates.
|
|
104
56
|
|
|
105
57
|
## Opening
|
|
106
58
|
|
package/docs/getting-started.md
CHANGED
|
@@ -96,8 +96,8 @@ spoken hook from the response stream before the full plan is complete, holds its
|
|
|
96
96
|
scene is ready, reaches its final frame, and leaves the composer ready for
|
|
97
97
|
another turn. With stock media enabled, click a welcome or follow-up card and
|
|
98
98
|
confirm its footage carries directly into that opening. With generated video
|
|
99
|
-
enabled, confirm
|
|
100
|
-
first
|
|
99
|
+
enabled, confirm that relevant generated shots and editorial templates form one
|
|
100
|
+
cinematic response, and the first shot continues the hook without repeating it.
|
|
101
101
|
|
|
102
102
|
The generated local authorization accepts localhost only. Replace it with your
|
|
103
103
|
real session check, rate limits, and usage policy before deploying.
|
|
@@ -67,8 +67,7 @@ hover movement remain inside the rail's available space.
|
|
|
67
67
|
## Layout and access
|
|
68
68
|
|
|
69
69
|
The foreground video preserves its scene ratio, so diagrams and text remain
|
|
70
|
-
visible without cropping or distortion.
|
|
71
|
-
surrounding viewport, with a gradient fallback when media is unavailable.
|
|
70
|
+
visible without cropping or distortion. The surrounding viewport remains black during playback.
|
|
72
71
|
Display layout does not rewrite the saved response's orientation. See
|
|
73
72
|
[responsive orientation](responsive-orientation.md) for saved videos and custom
|
|
74
73
|
players.
|
|
@@ -79,9 +78,9 @@ radio behavior, and popovers support Escape and outside-click dismissal.
|
|
|
79
78
|
Reduced motion removes movement and fades; increased contrast strengthens
|
|
80
79
|
surface opacity and borders.
|
|
81
80
|
|
|
82
|
-
##
|
|
81
|
+
## Customization
|
|
83
82
|
|
|
84
83
|
Use the existing `welcomeTitle`, `className` and `options` props to customize
|
|
85
|
-
copy, scoped CSS properties and generated
|
|
84
|
+
copy, scoped CSS properties and generated footage direction. There is no separate
|
|
86
85
|
light/dark appearance picker. See [customization](customization.md) for examples.
|
|
87
86
|
Use `useVideoChat` when the application needs to own the whole interface.
|
|
@@ -0,0 +1,38 @@
|
|
|
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.
|
package/docs/media-and-audio.md
CHANGED
|
@@ -6,20 +6,19 @@ VanillaSky keeps provider choice in the application. The SDK defines small
|
|
|
6
6
|
server callbacks, advertises only the capabilities you configure, and keeps
|
|
7
7
|
all credentials out of React and the browser bundle.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## One cinematic mode
|
|
10
10
|
|
|
11
|
-
The
|
|
11
|
+
The director combines relevant footage and seven editorial templates. Graphics
|
|
12
|
+
use black and white; footage carries atmosphere and concrete action. Each media
|
|
13
|
+
scene declares `mediaSource: "stock"` or `"generate"`. Provider availability and
|
|
14
|
+
host budgets constrain those choices. There is no all-stock or all-AI switch.
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
The canonical templates are `cinemaMedia`, `chapterTitle`,
|
|
17
|
+
`editorialTimeline`, `mobileMessage`, `comparison`, `quote`, and `keyFigure`.
|
|
18
|
+
All except `chapterTitle` accept optional media backgrounds. Editorial overlays use soft text shadows and a dark contrast scrim over relevant media, and fall back to black. Use at most one explanatory overlay per typical thirty-second answer. Full-bleed
|
|
19
|
+
footage has no headline; narration and subtitles carry the explanation.
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
`full` mode is advertised only when `generateVideo` exists. VanillaSky does not
|
|
20
|
-
offer a mixed mode that generates only some scenes.
|
|
21
|
-
|
|
22
|
-
## Stock media for templates
|
|
21
|
+
## Reviewed stock
|
|
23
22
|
|
|
24
23
|
Add `searchMedia` when template answers, the welcome screen, and follow-up
|
|
25
24
|
cards should use approved photography or footage:
|
|
@@ -46,15 +45,16 @@ createVideoChatHandler({
|
|
|
46
45
|
The planner emits a short semantic keyword, not a URL. The callback returns an
|
|
47
46
|
application-approved image or video URL, and the SDK validates it before it
|
|
48
47
|
reaches a scene. Return `null` when no licensed, safe, relevant asset exists;
|
|
49
|
-
|
|
48
|
+
`cinemaMedia` becomes a chapter using its grounded `fallbackText`; a message can
|
|
49
|
+
keep its content on black. Missing fallback copy produces an explicit error.
|
|
50
50
|
|
|
51
51
|
For Pexels, keep `PEXELS_API_KEY` on the server, enforce a deadline, filter for
|
|
52
52
|
orientation, and return only validated Pexels asset domains. Licensing,
|
|
53
53
|
attribution, caching, MIME checks, and byte limits remain application-owned.
|
|
54
54
|
|
|
55
|
-
##
|
|
55
|
+
## Planned generated shots
|
|
56
56
|
|
|
57
|
-
Add `generateVideo` to enable
|
|
57
|
+
Add `generateVideo` to enable generated shots within cinematic responses. It receives the planned visual
|
|
58
58
|
subject plus the generated look so every clip can follow the same direction:
|
|
59
59
|
|
|
60
60
|
```ts
|
|
@@ -47,22 +47,14 @@ only when two ranges are contiguous (allowing floating-point arithmetic noise)
|
|
|
47
47
|
and both templates declare `usesGlobalTransition: true` with valid
|
|
48
48
|
`transitionTiming` metadata. It is also conditional on the effective backdrop:
|
|
49
49
|
the 300 ms outer crossfade runs only when the resolved background media changes.
|
|
50
|
-
Scenes that share the
|
|
50
|
+
Scenes that share the black base, or the same resolved media backdrop, do
|
|
51
51
|
not crossfade. This keeps one stable background visible while each template
|
|
52
52
|
plays its own entrance, hold, and exit choreography.
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
flash between scene-specific phases.
|
|
59
|
-
|
|
60
|
-
The player owns a persistent brand-color backdrop beneath every scene. Built-in
|
|
61
|
-
renderers preload through the same component state used for playback, so their
|
|
62
|
-
first frame does not suspend when a new template type appears. If a genuinely
|
|
63
|
-
cold custom renderer does suspend, its transparent loading frame reveals the
|
|
64
|
-
brand backdrop rather than a black canvas. Scene media still belongs to the
|
|
65
|
-
scene and covers that base only while the media scene is active.
|
|
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.
|
|
66
58
|
|
|
67
59
|
During a changed-media overlap, the current scene continues to its exact end.
|
|
68
60
|
The incoming component may be pre-mounted for media readiness, but remains
|
|
@@ -98,7 +90,7 @@ also protects intentional hard cuts; it does not pause or otherwise alter the
|
|
|
98
90
|
visual or soundtrack clocks.
|
|
99
91
|
|
|
100
92
|
Undefined or unknown transition names preserve a hard cut and unmodified local
|
|
101
|
-
motion. Overlapping ranges also hard-cut. A timeline gap renders the
|
|
93
|
+
motion. Overlapping ranges also hard-cut. A timeline gap renders the fixed black
|
|
102
94
|
background instead of replaying an earlier scene.
|
|
103
95
|
|
|
104
96
|
## Reduced motion
|
package/docs/persistence.md
CHANGED
|
@@ -10,7 +10,7 @@ SDK serializer. An interrupted turn can remain visible without qualifying as
|
|
|
10
10
|
completed conversation history. The default `VideoChat` keeps history in memory;
|
|
11
11
|
use the headless hook when the application needs durable storage.
|
|
12
12
|
|
|
13
|
-
Every stored video has `schemaVersion: "0.
|
|
13
|
+
Every stored video has `schemaVersion: "0.2"`. This storage version is separate
|
|
14
14
|
from streaming protocol `0.5`. The 0.1 policy supports the current storage
|
|
15
15
|
schema only: there are no compatibility aliases or implicit coercions.
|
|
16
16
|
|
|
@@ -39,12 +39,12 @@ The release verifier compiles this exact documented snippet against the packed
|
|
|
39
39
|
SDK artifact, including its root and React subpath imports.
|
|
40
40
|
|
|
41
41
|
`parseVideo(value: unknown)` validates the complete shape, known fields,
|
|
42
|
-
|
|
42
|
+
style, audio, metadata, unique scenes, timing, and JSON-safe
|
|
43
43
|
template variables. It returns a detached, deeply frozen `Video`, so later
|
|
44
44
|
changes to the loaded object cannot mutate player state.
|
|
45
45
|
|
|
46
46
|
Invalid data throws `VideoValidationError` with `code: "invalid_video"`.
|
|
47
|
-
|
|
47
|
+
Previous, unknown, or future storage versions throw the same error class with
|
|
48
48
|
`code: "unsupported_video_version"`. `<VideoPlayer video={value} />` repeats
|
|
49
49
|
this boundary validation and rejects the entire value before any renderer
|
|
50
50
|
runs; it never renders a partial future document.
|
package/docs/production.md
CHANGED
|
@@ -20,12 +20,14 @@ The handler rejects unknown templates and fields, invalid variables, unsafe
|
|
|
20
20
|
media, and fabricated quote-template content before a scene reaches the
|
|
21
21
|
player. Read the [security guide](security.md) for the complete controls.
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Cinematic direction and providers
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
One cinematic mode combines footage and editorial graphics according to the
|
|
26
|
+
story. Keep templates available as grounded fallbacks. Add `searchMedia` for
|
|
27
|
+
reviewed stock and `generateVideo` for selected illustrative shots. The planner
|
|
28
|
+
sets `mediaSource` per media scene; the host enforces the generation budget.
|
|
29
|
+
A stock candidate must match the subject, action and permitted crop. Return
|
|
30
|
+
`null` for uncertainty rather than broadening an essential detail.
|
|
29
31
|
|
|
30
32
|
Use explicit provider deadlines. Generated video should use idempotency keys
|
|
31
33
|
and `maxRetries: 0` so one visible action cannot silently create several
|
|
@@ -36,13 +38,13 @@ licensing before use.
|
|
|
36
38
|
|
|
37
39
|
The planner's first streamed object supplies the spoken hook and media keyword.
|
|
38
40
|
Start speech immediately, resolve stock in parallel, and keep the opening
|
|
39
|
-
playing until the
|
|
41
|
+
playing until the contiguous preparation cushion and first frame are ready. Welcome cards
|
|
40
42
|
should carry a prepared hook and preloaded footage so they can start without a
|
|
41
43
|
model round trip.
|
|
42
44
|
|
|
43
45
|
Do not wait for the complete plan before showing the first validated scene.
|
|
44
46
|
Preload upcoming assets and keep the current visual if the next one is late.
|
|
45
|
-
|
|
47
|
+
When generated footage is useful, reserve the first shot in the opening object so generation
|
|
46
48
|
can begin while the planner streams later scenes.
|
|
47
49
|
|
|
48
50
|
## Data and privacy
|
|
@@ -101,8 +103,8 @@ npm test
|
|
|
101
103
|
- [ ] Keys exist only in the server secret store.
|
|
102
104
|
- [ ] Authentication, tenant policy, rate limits, and origin allowlist are live.
|
|
103
105
|
- [ ] Cancellation, timeouts, fallbacks, and safe errors are tested.
|
|
104
|
-
- [ ]
|
|
105
|
-
- [ ]
|
|
106
|
+
- [ ] Grounded graphic recovery works when every optional provider is unavailable.
|
|
107
|
+
- [ ] Per-scene media choices obey provider availability and spending limits.
|
|
106
108
|
- [ ] Both orientations render and narration stays synchronized.
|
|
107
109
|
- [ ] A packed-artifact consumer and deterministic browser chat pass.
|
|
108
110
|
- [ ] One bounded real-provider run meets the product's latency and quality target.
|
|
@@ -61,11 +61,10 @@ dependencies and never enter the browser bundle.
|
|
|
61
61
|
The planner emits a 6-9 word hook first, then continues into the scenes in the
|
|
62
62
|
same stream. The stock lookup is a separate cancellable request, so it cannot
|
|
63
63
|
delay speech or planning. A welcome card can carry a prewritten `opening`, which
|
|
64
|
-
starts immediately with its already-loaded media.
|
|
64
|
+
starts immediately with its already-loaded media. When generated shots are available, the
|
|
65
65
|
same first streamed object reserves the exact first body scene. Its clip starts
|
|
66
|
-
generating while the planner continues
|
|
67
|
-
|
|
68
|
-
plan, and normal narration is written in that same planner call rather than
|
|
66
|
+
generating while the planner continues the story. Playback begins after its
|
|
67
|
+
contiguous preparation cushion, without requiring the entire plan, and normal narration is written in that same planner call rather than
|
|
69
68
|
through a second model round trip.
|
|
70
69
|
|
|
71
70
|
The matching complete React interface is one component and one scoped style
|
|
@@ -121,14 +120,10 @@ streamText: ({ systemPrompt, userPrompt, signal }) => streamText({
|
|
|
121
120
|
}),
|
|
122
121
|
```
|
|
123
122
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
values as host-owned tuning: the lowest effort setting is the fastest, but a
|
|
129
|
-
weaker plan misses schema limits more often, which shows up as rejected scenes
|
|
130
|
-
in `onComplete`. Compare `timeToFirstSceneMs` and `rejectedSceneCount` across
|
|
131
|
-
settings before fixing one.
|
|
123
|
+
Reasoning settings can substantially affect startup latency. Measure them with
|
|
124
|
+
your installed catalog and representative requests. Compare first-scene timing,
|
|
125
|
+
rejected scenes and factual accuracy; the fastest token stream is not useful if
|
|
126
|
+
its scenes cannot be rendered. Keep these settings in the provider adapter.
|
|
132
127
|
|
|
133
128
|
VanillaSky never sets these controls. Provider selection, sampling parameters,
|
|
134
129
|
and credentials stay with the application.
|
|
@@ -185,10 +180,8 @@ is intentionally substantial. It is stable for the same SDK version, template
|
|
|
185
180
|
kit, media policy, and base prompt. Record input-token usage, keep the selected
|
|
186
181
|
kit no broader than the product needs, and enable provider-side prompt caching
|
|
187
182
|
where the chosen provider/model supports it. VanillaSky does not assume one
|
|
188
|
-
provider's cache controls in its provider-neutral adapter.
|
|
189
|
-
|
|
190
|
-
7,000 tokens before user input; tokenizer-dependent); provider-reported usage
|
|
191
|
-
is the authoritative measurement.
|
|
183
|
+
provider's cache controls in its provider-neutral adapter. The cinematic catalog contains seven templates; use provider-reported token
|
|
184
|
+
usage as the authoritative measurement rather than a character estimate.
|
|
192
185
|
|
|
193
186
|
Provider finish reasons `error` and `tool-calls` are terminal failures.
|
|
194
187
|
`length` and `content-filter` may complete with already accepted scenes; a
|
|
@@ -104,7 +104,7 @@ body { background: #080b16; }
|
|
|
104
104
|
<section class="doc-section" id="conversation"><div class="section-heading"><span class="number">03</span><h2>One field. Every follow-up.</h2></div><p class="section-copy">Speak or type directly over the picture. Beginning a question pauses playback. Sending starts the next answer; canceling returns to the previous playback state.</p><div class="doc-preview"><div class="demo-toolbar" aria-label="Composer preview states"><button type="button" data-state="ready" aria-pressed="true">Ready</button><button type="button" data-state="listening" aria-pressed="false">Listening</button><button type="button" data-state="thinking" aria-pressed="false">Transcribing</button></div><div class="conversation-composer"><div class="composer-meta"><span id="composer-status" role="status">Interactive preview · no microphone or model call</span></div><form class="composer" id="composer-demo"><button class="ghost transport" type="button" aria-label="Play preview" id="play-demo"><svg data-icon="play"></svg></button><label class="sr-only" for="demo-question">Question</label><textarea id="demo-question" rows="1" placeholder="Ask a follow-up…"></textarea><button class="ghost" type="button" id="mic-demo" aria-label="Preview listening state" aria-pressed="false"><svg data-icon="mic"></svg></button><button class="send" type="submit" aria-label="Preview send" disabled><svg data-icon="send"></svg></button></form></div></div><p class="doc-note">44px targets. 10px between microphone and send. The field grows to 120px and keeps the controls within reach.</p></section>
|
|
105
105
|
<section class="doc-section" id="captions"><div class="section-heading"><span class="number">04</span><h2>Words stay with the picture</h2></div><p class="section-copy">The first subtitle takes the input’s bottom baseline. The complete cue remains readable without truncation. Reveal the input to move subtitles upward; expand for the transcript or restore hidden subtitles in Settings.</p><div class="doc-preview"><div class="demo-toolbar"><button type="button" id="restore-caption">Show subtitles</button><button type="button" id="toggle-transcript">Expand transcript</button></div><div class="line-row" id="caption-demo" data-expanded="false"><div class="caption-actions"><button class="caption-action" type="button" id="expand-action" aria-label="Expand subtitles" aria-expanded="false">Expand <svg data-icon="up"></svg></button><button class="caption-action" type="button" id="hide-action" aria-label="Hide subtitles"><svg data-icon="close"></svg></button></div><p class="line" id="compact-caption">Water absorbs the warm colors of sunlight,<br>leaving more blue light to reach your eyes.</p><div class="expanded-captions" id="transcript-demo" tabindex="0" aria-label="Expanded subtitles" hidden><span class="eyebrow">Full answer</span><p>The ocean’s color begins with sunlight.</p><p>Water absorbs the warm colors of sunlight, leaving more blue light to reach your eyes.</p><p>Depth, particles and the sky change what we see. That is why a shallow lagoon and the open ocean can look so different.</p></div></div></div></section>
|
|
106
106
|
<section class="doc-section" id="suggestions"><div class="section-heading"><span class="number">05</span><h2>A little more curiosity</h2></div><p class="section-copy">A horizontal rail offers the next question. Video cards show their poster image before playback, including when autoplay is blocked. Hover or keyboard focus selects a card. Its outline and lift have room to breathe.</p><div class="doc-preview"><ul class="cards" aria-label="Example suggested questions"><li><button type="button" data-active><span class="card-art"></span><span class="card-wash"></span><span class="card-prompt">What is hiding in the deep ocean?</span></button></li><li><button type="button"><span class="card-art space"></span><span class="card-wash"></span><span class="card-prompt">Why do planets stay in orbit?</span></button></li><li><button type="button"><span class="card-art mind"></span><span class="card-wash"></span><span class="card-prompt">How does a memory begin?</span></button></li></ul></div><p class="doc-note">Reference artwork uses abstract color fields. The live rail uses the answer’s resolved media. Select a card here to place its question in the preview composer.</p></section>
|
|
107
|
-
<section class="doc-section" id="foundations"><div class="section-heading"><span class="number">06</span><h2>Small decisions, shared everywhere</h2></div><p class="section-copy">System typography, generous touch targets and a compact spacing scale. The video carries the color; the interface carries meaning.</p><div class="doc-preview"><div class="type-row"><span style="font-size:40px;letter-spacing:-.055em;line-height:1.08">An answer worth watching.</span><code>Display · responsive / 1.08</code></div><div class="type-row"><span style="font-size:22px;letter-spacing:-.02em;line-height:1.45">A clear line over a moving picture.</span><code>Subtitles · 17–22px / 1.45</code></div><div class="type-row"><span style="font-size:16px;letter-spacing:-.015em;line-height:1.625">Ask a follow-up…</span><code>Input · 16px / 26px</code></div><div class="type-row"><span style="font-size:13px;color:var(--vs-media-muted)">One answer leads to another.</span><code>Context · 13px</code></div><div class="metrics"><div class="metric"><strong>44<span style="display:inline;font-size:15px"> px</span></strong><span>Minimum primary control target</span></div><div class="metric"><strong>180<span style="display:inline;font-size:15px"> ms</span></strong><span>Navigation and opacity fade</span></div><div class="metric"><strong>280<span style="display:inline;font-size:15px"> ms</span></strong><span>Input and subtitle movement</span></div><div class="metric"><strong>2<span style="display:inline;font-size:15px"> s</span></strong><span>Idle delay after revealing controls</span></div></div></div><p class="doc-note">First subtitles hide the input immediately unless the viewer is editing, listening or using keyboard focus. Reduced motion removes movement and fades. Increased contrast strengthens the surfaces and borders. The input respects bottom safe areas. Subtitle actions fade while inactive and return on hover, touch or keyboard focus. The foreground preserves the scene ratio and readable text.
|
|
107
|
+
<section class="doc-section" id="foundations"><div class="section-heading"><span class="number">06</span><h2>Small decisions, shared everywhere</h2></div><p class="section-copy">System typography, generous touch targets and a compact spacing scale. The video carries the color; the interface carries meaning.</p><div class="doc-preview"><div class="type-row"><span style="font-size:40px;letter-spacing:-.055em;line-height:1.08">An answer worth watching.</span><code>Display · responsive / 1.08</code></div><div class="type-row"><span style="font-size:22px;letter-spacing:-.02em;line-height:1.45">A clear line over a moving picture.</span><code>Subtitles · 17–22px / 1.45</code></div><div class="type-row"><span style="font-size:16px;letter-spacing:-.015em;line-height:1.625">Ask a follow-up…</span><code>Input · 16px / 26px</code></div><div class="type-row"><span style="font-size:13px;color:var(--vs-media-muted)">One answer leads to another.</span><code>Context · 13px</code></div><div class="metrics"><div class="metric"><strong>44<span style="display:inline;font-size:15px"> px</span></strong><span>Minimum primary control target</span></div><div class="metric"><strong>180<span style="display:inline;font-size:15px"> ms</span></strong><span>Navigation and opacity fade</span></div><div class="metric"><strong>280<span style="display:inline;font-size:15px"> ms</span></strong><span>Input and subtitle movement</span></div><div class="metric"><strong>2<span style="display:inline;font-size:15px"> s</span></strong><span>Idle delay after revealing controls</span></div></div></div><p class="doc-note">First subtitles hide the input immediately unless the viewer is editing, listening or using keyboard focus. Reduced motion removes movement and fades. Increased contrast strengthens the surfaces and borders. The input respects bottom safe areas. Subtitle actions fade while inactive and return on hover, touch or keyboard focus. The foreground preserves the scene ratio and readable text. The surrounding viewport remains black during playback.</p></section>
|
|
108
108
|
<footer class="doc-footer"><span>VanillaSky · VideoChat immersive interface</span><span>Rendered with the same tokens and component CSS as the experience.</span></footer>
|
|
109
109
|
</div></main>
|
|
110
110
|
<script>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# Video Response Protocol 0.
|
|
1
|
+
# Video Response Protocol 0.6
|
|
2
2
|
|
|
3
3
|
## Transport
|
|
4
4
|
|
|
5
5
|
The public transport is UTF-8 Server-Sent Events returned from a `POST` request.
|
|
6
6
|
Responses use `Content-Type: text/event-stream`,
|
|
7
|
-
`x-vanillasky-video-stream: 0.
|
|
7
|
+
`x-vanillasky-video-stream: 0.6`, `Cache-Control: no-cache, no-transform`, and
|
|
8
8
|
`X-Accel-Buffering: no`. Each block has an SSE `id`, the event name
|
|
9
9
|
`video`, and one JSON envelope in `data`. A final `data: [DONE]`
|
|
10
10
|
closes the transport after a terminal protocol event. Comment heartbeats do not
|
|
@@ -14,7 +14,7 @@ change protocol state.
|
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
16
|
type VideoEvent<T extends string, D> = {
|
|
17
|
-
protocolVersion: "0.
|
|
17
|
+
protocolVersion: "0.6";
|
|
18
18
|
runId: string;
|
|
19
19
|
sequence: number;
|
|
20
20
|
eventId: string; // exactly `${runId}:${sequence}`
|
|
@@ -42,7 +42,7 @@ finish reason, and a deterministic checksum. The reducer verifies that the
|
|
|
42
42
|
snapshot equals the state produced by all prior events. The checksum detects
|
|
43
43
|
accidental drift; it is not a cryptographic signature.
|
|
44
44
|
|
|
45
|
-
The terminal snapshot carries persisted `schemaVersion: "0.
|
|
45
|
+
The terminal snapshot carries persisted `schemaVersion: "0.2"`. That storage
|
|
46
46
|
version is independent from this streaming protocol version. Load stored
|
|
47
47
|
snapshots through the universal `parseVideo` boundary described in the
|
|
48
48
|
[persistence guide](../persistence.md).
|
|
@@ -100,3 +100,13 @@ SDK does not prescribe or operate a persistence service.
|
|
|
100
100
|
Validate adapter output and persisted replay logs against this protocol before
|
|
101
101
|
accepting them. A replay log must preserve ordering, checksums, and a terminal
|
|
102
102
|
event.
|
|
103
|
+
|
|
104
|
+
## Host-authored narration across cuts
|
|
105
|
+
|
|
106
|
+
`VideoScene.narrationGroup` optionally joins adjacent shots to one prepared spoken paragraph. A host supplies the shared `id`, `text`, measured `totalSeconds`, and each segment's `offsetSeconds` and `durationSeconds`. Each scene retains its narration fragment and a matching `timing.fixedDuration`; fragments must exactly cover the paragraph in order. The planner cannot emit this field or guess speech timings.
|
|
107
|
+
|
|
108
|
+
Grouped playback requires prepared speech with `supportsOffsets: true`. The generated-audio voice supports offsets; browser speech synthesis does not. The chat hook prepares and validates a complete group before showing its first scene, including saved replay. Hosts using a standalone player must prepare the paragraph and coordinate narration themselves before starting playback. Unsupported voices and mismatched measured durations fail explicitly. Default planner responses still prepare narration per scene.
|
|
109
|
+
|
|
110
|
+
For standalone playback, provide a synchronous `narrationReady` callback alongside your `onSceneChange` narration handler. Return false while a new grouped paragraph awaits actual audio onset, then true from the voice's `onStart` callback; also release readiness on completion, failure, or interruption. Abort pending narration from the player's `onError` handler. `VideoChat` wires this automatically through its internal narration hook. For grouped paragraphs, the voice must invoke `onStart` when audio actually begins, not when audio is prepared or `play()` is requested. The first visual cue starts narration, then the playhead waits for that onset without pausing the voice. A missing onset stops the player with an error after eight seconds of active waiting. For prepared audio, also provide `narrationTime(scene)` using the active voice's optional `getCurrentTime()`: return paragraph-relative seconds (including the seek offset) for a group, or scene-relative seconds otherwise. This makes the actual audio clock authoritative through cold-start delays and mid-speech stalls. Return `undefined` for silent scenes or unavailable clocks; after ordinary narration completes, release to wall time so the authored reading hold can finish. `VideoChat` coordinates these callbacks automatically. A clock that stops advancing for eight active seconds produces an error; visual-readiness holds and deliberate pauses do not consume that timeout. Voices without an observable playback clock retain wall-time playback.
|
|
111
|
+
|
|
112
|
+
Readiness holds pause narration together with the picture. The same audio continues across adjacent group scenes; replay starts a new playback session. This preserves words through delayed media rather than promising uninterrupted playback on every network.
|
package/docs/testing.md
CHANGED
|
@@ -34,7 +34,7 @@ describe("POST /api/video-chat", () => {
|
|
|
34
34
|
body: JSON.stringify({
|
|
35
35
|
prompt: "Explain why the Moon shows one face",
|
|
36
36
|
opening: "The Moon turns, perfectly matching its orbit.",
|
|
37
|
-
mode: "
|
|
37
|
+
mode: "cinematic",
|
|
38
38
|
orientation: "landscape",
|
|
39
39
|
}),
|
|
40
40
|
},
|