@vanillaskyai/video 0.7.1 → 0.8.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 (84) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/PUBLIC-API.md +83 -79
  3. package/README.md +16 -15
  4. package/dist/{builtin-server-KB7FKF6A.js → builtin-server-CUYPIDE7.js} +2 -2
  5. package/dist/check-runtime.js +1 -1
  6. package/dist/{chunk-2PYO6VAC.js → chunk-2DOLF4QN.js} +1 -43
  7. package/dist/{chunk-GAIOHGNR.js → chunk-2OKB27TG.js} +42 -45
  8. package/dist/{chunk-K746NUIP.js → chunk-2USVB3CY.js} +80 -29
  9. package/dist/{chunk-RE4IMWJR.js → chunk-3VRMKFM7.js} +87 -14
  10. package/dist/{chunk-JNN3EYVP.js → chunk-4UNKZEAT.js} +46 -46
  11. package/dist/{chunk-2XT4MZ76.js → chunk-APQKY6P3.js} +36 -3
  12. package/dist/{chunk-LLPMVDJZ.js → chunk-L7QGGKJ2.js} +69 -38
  13. package/dist/{chunk-RGF452LL.js → chunk-OWBT45EN.js} +1 -1
  14. package/dist/{chunk-LKBZX7GV.js → chunk-PP3MCPN4.js} +4 -4
  15. package/dist/chunk-ZD2VTUYR.js +28 -0
  16. package/dist/cli.js +131 -24
  17. package/dist/{compose-video-PD6LKKRK.js → compose-video-2NFH4DZY.js} +3 -3
  18. package/dist/{events-B6qS1Lsb.d.ts → events-BQ6z264n.d.ts} +1 -1
  19. package/dist/index.d.ts +5 -67
  20. package/dist/index.js +2 -4
  21. package/dist/{kit-8g46H2RZ.d.ts → kit-tQnCPMOM.d.ts} +1 -1
  22. package/dist/react.d.ts +33 -53
  23. package/dist/react.js +642 -536
  24. package/dist/server.d.ts +11 -13
  25. package/dist/server.js +170 -81
  26. package/dist/template-catalog.js +1 -1
  27. package/dist/templates.d.ts +3 -3
  28. package/dist/test.d.ts +2 -2
  29. package/dist/test.js +3 -3
  30. package/dist/{text-stream-ROTNGSD4.js → text-stream-54LXABJW.js} +1 -1
  31. package/dist/{types-2wHBqtg8.d.ts → types-CEh9eUFu.d.ts} +1 -1
  32. package/dist/{types-DrABlRa7.d.ts → types-DWFO6qca.d.ts} +1 -1
  33. package/docs/agent-integration.md +9 -3
  34. package/docs/architecture.md +8 -10
  35. package/docs/concepts.md +16 -40
  36. package/docs/custom-templates.md +27 -23
  37. package/docs/customization.md +12 -49
  38. package/docs/errors.md +58 -68
  39. package/docs/getting-started.md +21 -14
  40. package/docs/media-and-audio.md +2 -2
  41. package/docs/performance.md +69 -0
  42. package/docs/persistence.md +12 -27
  43. package/docs/production.md +2 -2
  44. package/docs/provider-integration.md +11 -5
  45. package/docs/reference/provider-adapters.md +37 -89
  46. package/docs/security.md +1 -1
  47. package/docs/streaming-protocol.md +2 -2
  48. package/examples/custom-template/README.md +6 -6
  49. package/package.json +6 -7
  50. package/registry/items/barChart.json +2 -2
  51. package/registry/items/bigNumber.json +2 -2
  52. package/registry/items/brandMessage.json +2 -2
  53. package/registry/items/cardList.json +2 -2
  54. package/registry/items/codeEditor.json +2 -2
  55. package/registry/items/ctaLogo.json +2 -2
  56. package/registry/items/ctaMedia.json +2 -2
  57. package/registry/items/incomingCall.json +2 -2
  58. package/registry/items/media.json +2 -2
  59. package/registry/items/milestone.json +2 -2
  60. package/registry/items/notification.json +2 -2
  61. package/registry/items/phoneMockup.json +2 -2
  62. package/registry/items/problemSolution.json +2 -2
  63. package/registry/items/progressRing.json +2 -2
  64. package/registry/items/promptInput.json +2 -2
  65. package/registry/items/reaction.json +2 -2
  66. package/registry/items/reviewStack.json +2 -2
  67. package/registry/items/steps.json +2 -2
  68. package/registry/items/terminal.json +2 -2
  69. package/registry/items/testimonial.json +2 -2
  70. package/registry/items/tripleStats.json +2 -2
  71. package/registry/items/tweet.json +2 -2
  72. package/registry/items/webMockup.json +2 -2
  73. package/starters/video-chat/.env.example +4 -2
  74. package/starters/video-chat/README.md +17 -5
  75. package/starters/video-chat/package.json +2 -4
  76. package/starters/video-chat/providers/speech.ts +20 -0
  77. package/starters/video-chat/providers/video.ts +66 -0
  78. package/starters/video-chat/providers.ts +3 -0
  79. package/starters/video-chat/server.ts +4 -80
  80. package/starters/video-chat/stock.ts +114 -99
  81. package/dist/chunk-SKRGRKHY.js +0 -142
  82. package/dist/state-DZcKuS32.d.ts +0 -3
  83. package/docs/branding-and-personalization.md +0 -87
  84. package/examples/custom-template/supplied-media.tsx +0 -92
@@ -3,9 +3,12 @@
3
3
  # Persistence and replay
4
4
 
5
5
  A completed `Video` is ordinary JSON owned by your application. VanillaSky
6
- does not provide a database or hosted media store. Save the value returned by
7
- `await video.generate(...)` with the platform-native `JSON.stringify`; there is
8
- no SDK serializer.
6
+ does not provide a database or hosted media store. For a custom interface, observe `useVideoChat().turns` and save a turn’s
7
+ `video` only when `turn.completed` is true and `turn.video` is present. Use
8
+ `JSON.stringify(turn.video)` and deduplicate writes by `turn.id`; there is no
9
+ SDK serializer. An interrupted turn can remain visible without qualifying as
10
+ completed conversation history. The default `VideoChat` keeps history in memory;
11
+ use the headless hook when the application needs durable storage.
9
12
 
10
13
  Every stored video has `schemaVersion: "0.1"`. This storage version is separate
11
14
  from streaming protocol `0.5`. The 0.1 policy supports the current storage
@@ -48,31 +51,13 @@ runs; it never renders a partial future document.
48
51
 
49
52
  ## Retention
50
53
 
51
- By default, completed snapshots omit raw source, creative instructions, and
52
- the supplied-media URL index. A customer-owned route may retain individual
53
- fields only when its privacy and deletion policy allows it:
54
-
55
- ```ts
56
- createVideoHandler({
57
- authorize: verifySession,
58
- streamText,
59
- snapshotRetention: {
60
- source: true,
61
- instructions: true,
62
- suppliedMediaUrls: true,
63
- },
64
- });
65
- ```
66
-
67
- Opt-in values are bounded in the snapshot:
68
-
69
- - source: 16,384 characters;
70
- - instructions: 4,096 characters;
71
- - supplied-media index: 16 URLs, each at most 2,048 characters.
54
+ Completed snapshots omit raw source, creative instructions, and the supplied-media
55
+ URL index. Store an authorized prompt separately with the completed turn only
56
+ when the host's privacy and deletion policy permits it. Saved-video replay does
57
+ not rehydrate a chat session or its voice queue.
72
58
 
73
- These metadata limits do not replace a host retention policy. Renderable scene
74
- variables may still contain a media URL when that asset is necessary for
75
- replay. Store only approved assets and avoid signed URLs whose lifetime is
59
+ Renderable scene variables may contain a media URL when that asset is necessary
60
+ for replay. Store only approved assets and avoid signed URLs whose lifetime is
76
61
  shorter than the replay window.
77
62
 
78
63
  ## Storage ownership
@@ -59,7 +59,7 @@ can begin while the planner streams later scenes.
59
59
  - Treat late media as a fallback case, not a reason to freeze playback.
60
60
  - Keep the current scene and its narration during recoverable generation gaps.
61
61
  - End cleanly on a terminal error and show an application retry control.
62
- - Retry only before visible output or from an explicit validated resume point.
62
+ - Retry only before visible output; preserve accepted scenes after playback starts.
63
63
 
64
64
  ## Measure the stages
65
65
 
@@ -106,6 +106,6 @@ npm test
106
106
  - [ ] Both orientations render and narration stays synchronized.
107
107
  - [ ] A packed-artifact consumer and deterministic browser chat pass.
108
108
  - [ ] One bounded real-provider run meets the product's latency and quality target.
109
- - [ ] Stored responses replay exactly and application-owned export is verified.
109
+ - [ ] Completed stored responses parse and replay correctly.
110
110
 
111
111
  [← Documentation home](../README.md) · [Previous: Errors and recovery](errors.md)
@@ -1,4 +1,4 @@
1
- [← Documentation home](../README.md) · [Previous: Getting started](getting-started.md) · [Next: Branding and personalization →](branding-and-personalization.md)
1
+ [← Documentation home](../README.md) · [Previous: Getting started](getting-started.md) · [Next: Customization →](customization.md)
2
2
 
3
3
  # Provider integration
4
4
 
@@ -11,10 +11,16 @@ npx vanillasky doctor
11
11
  npm run dev
12
12
  ```
13
13
 
14
- The generated `server.ts` is the canonical provider example. It starts with one
15
- text key, packaged templates, and browser voice. Adding the optional generated
16
- speech, stock, transcription, or generated-video key enables its callback and
17
- advertises the capability automatically; `src/main.tsx` does not change.
14
+ Init runs doctor automatically. The generated `server.ts` starts with one
15
+ `ANTHROPIC_API_KEY`, packaged templates, and browser voice; it installs no
16
+ optional speech or video packages.
17
+
18
+ Use `npx vanillasky providers add speech` to install xAI speech, or
19
+ `npx vanillasky providers add video` to install FAL video and transcription.
20
+ Add `XAI_API_KEY` or `FAL_KEY` to `.env.local` and restart the server. Stock media
21
+ needs only `PEXELS_API_KEY`, with no extra installation. These app-owned
22
+ adapters advertise their capabilities automatically; `src/main.tsx` does not
23
+ change. Rerun an interrupted setup command to finish installation.
18
24
 
19
25
  For the full chat experience, mount one `createVideoChatHandler` and keep every
20
26
  provider choice in its callbacks:
@@ -1,11 +1,11 @@
1
1
  # Secure LLM provider adapters
2
2
 
3
3
  This page covers the planner boundary. For Pexels and other visual providers,
4
- read [Media and audio](../media-and-audio.md#media-providers).
4
+ read [Media and voice](../media-and-audio.md).
5
5
 
6
6
  VanillaSky deliberately does not depend on a model provider or AI framework.
7
- Your server owns the model and credentials; `createVideoHandler` accepts one
8
- small `streamText` callback. The recommended adapter is the [AI SDK](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text),
7
+ Your server owns the model and credentials; `createVideoChatHandler` accepts
8
+ `streamText` and `generateText` callbacks. The recommended adapter is the [AI SDK](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text),
9
9
  which gives the application one `LanguageModel` interface across official,
10
10
  community, AI Gateway, OpenAI-compatible, and custom providers.
11
11
 
@@ -19,14 +19,23 @@ npm install ai @ai-sdk/anthropic
19
19
 
20
20
  ```ts
21
21
  import { anthropic } from "@ai-sdk/anthropic";
22
- import { streamText } from "ai";
23
- import { createVideoHandler } from "@vanillaskyai/video/server";
22
+ import { generateText, streamText } from "ai";
23
+ import { createVideoChatHandler } from "@vanillaskyai/video/server";
24
24
 
25
25
  const modelId = process.env.ANTHROPIC_MODEL;
26
26
  if (!modelId) throw new Error("Set ANTHROPIC_MODEL in the server environment");
27
27
 
28
- export const POST = createVideoHandler({
28
+ export const POST = createVideoChatHandler({
29
29
  authorize: verifySession,
30
+ generateText: async ({ systemPrompt, userPrompt, signal }) => {
31
+ const result = await generateText({
32
+ model: anthropic(modelId),
33
+ system: systemPrompt,
34
+ prompt: userPrompt,
35
+ abortSignal: signal,
36
+ });
37
+ return result.text;
38
+ },
30
39
  streamText: ({ systemPrompt, userPrompt, signal }) => streamText({
31
40
  model: anthropic(modelId),
32
41
  system: systemPrompt,
@@ -67,92 +76,31 @@ replace that per-line validator with whole-response structured output: motion
67
76
  streaming intentionally renders the first scene before the full composition is
68
77
  complete.
69
78
 
70
- ## Advanced: native provider loops
71
-
72
- Use the lower-level callback directly when the AI SDK does not expose a
73
- provider-specific feature you need. `streamText` may return either an
74
- `AsyncIterable<string>` or an object with `textStream` plus optional
75
- `finishReason`, `rawFinishReason`, `usage`, `providerMetadata`, and
76
- response/final-step metadata. Requested model IDs are read from the final
77
- step's `model.modelId`; resolved IDs are read from response metadata. Prefer the
78
- richer form when the native provider exposes completion metadata.
79
-
80
- Provider retries remain host-owned. Retry only within an explicit request and
81
- time budget, and never silently restart after visible output unless the host
82
- has validated durable resume storage.
83
-
84
- ### OpenAI Responses API
85
-
86
- ```ts
87
- import OpenAI from "openai";
88
- import { createVideoHandler } from "@vanillaskyai/video/server";
89
-
90
- const apiKey = process.env.OPENAI_API_KEY;
91
- const model = process.env.OPENAI_MODEL;
92
- if (!apiKey || !model) throw new Error("Set OPENAI_API_KEY and OPENAI_MODEL");
79
+ ## Native or self-hosted providers
93
80
 
94
- const openai = new OpenAI({ apiKey });
81
+ The same chat contract supports a native provider without an AI SDK dependency.
82
+ Return an `AsyncIterable<string>` from `streamText`, or an object with
83
+ `textStream` and optional completion metadata. Implement `generateText` for the
84
+ small welcome, suggestion, and fallback narration tasks and return its text.
85
+ Infer each callback from `VideoChatHandlerOptions` so the adapter stays aligned
86
+ with the public contract.
95
87
 
96
- export const POST = createVideoHandler({
97
- authorize: verifySession,
98
- streamText: async function* ({ systemPrompt, userPrompt, signal }) {
99
- const stream = await openai.responses.create({
100
- model,
101
- input: [
102
- { role: "system", content: systemPrompt },
103
- { role: "user", content: userPrompt },
104
- ],
105
- stream: true,
106
- }, { signal });
107
-
108
- for await (const event of stream) {
109
- if (event.type === "response.output_text.delta") yield event.delta;
110
- }
111
- },
112
- });
113
- ```
88
+ Forward the supplied signal, preserve both prompt strings, and keep provider
89
+ errors and credentials on the server. Retry only within an explicit time and
90
+ spend budget before output is visible. The chat does not expose a durable
91
+ stream-reconnect contract.
114
92
 
115
- OpenAI documents the typed `response.output_text.delta` event in its
116
- [Responses streaming guide](https://developers.openai.com/api/docs/guides/streaming-responses).
117
-
118
- ### Anthropic Messages API
119
-
120
- ```ts
121
- import Anthropic from "@anthropic-ai/sdk";
122
- import { createVideoHandler } from "@vanillaskyai/video/server";
123
-
124
- const apiKey = process.env.ANTHROPIC_API_KEY;
125
- const model = process.env.ANTHROPIC_MODEL;
126
- if (!apiKey || !model) throw new Error("Set ANTHROPIC_API_KEY and ANTHROPIC_MODEL");
127
-
128
- const anthropic = new Anthropic({ apiKey });
129
-
130
- export const POST = createVideoHandler({
131
- authorize: verifySession,
132
- streamText: async function* ({ systemPrompt, userPrompt, signal }) {
133
- const stream = anthropic.messages.stream({
134
- model,
135
- max_tokens: 4096,
136
- system: systemPrompt,
137
- messages: [{ role: "user", content: userPrompt }],
138
- }, { signal });
139
-
140
- for await (const event of stream) {
141
- if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
142
- yield event.delta.text;
143
- }
144
- }
145
- },
146
- });
147
- ```
93
+ ## Generated-video budget
148
94
 
149
- Anthropic documents `content_block_delta` and `text_delta` in its
150
- [Messages streaming guide](https://platform.claude.com/docs/en/build-with-claude/streaming).
95
+ Set `maxGeneratedVideos` on `createVideoChatHandler` to a nonnegative safe integer
96
+ (default `5`). This is a per-response attempt limit for full mode, including the
97
+ reserved first shot and failures. Use `0` to keep the configured full mode on
98
+ stock footage. Stock lookup is independent of this limit. Retries inside your
99
+ provider callback can incur additional charges; bound those separately. Never
100
+ copy an untrusted request value into this application-owned option.
151
101
 
152
- ## Optional web fetch and other tools
102
+ ## Application retrieval
153
103
 
154
- Keep tools server-side and outside the SDK core. Fetch or search before motion
155
- generation, append only the approved grounded result to `input`, and
156
- record provenance separately. Apply domain allowlists, SSRF protection,
157
- timeouts, redirect limits, and response-size limits. Do not give a model a
158
- general-purpose fetch tool unless the application truly needs one.
104
+ Fetch or search approved context in the application before asking the chat.
105
+ Include only authorized facts in the prompt or conversation and record
106
+ provenance separately. Keep retrieval tools and private URLs server-side.
package/docs/security.md CHANGED
@@ -7,7 +7,7 @@ The SDK validates protocol shape; your application still owns identity, authoriz
7
7
  ## Required server controls
8
8
 
9
9
  - Authenticate the user and tenant before reading the prompt body.
10
- - `createVideoChatHandler` and the lower-level `createVideoHandler` require an
10
+ - `createVideoChatHandler` requires an
11
11
  explicit `authorize` policy. The
12
12
  `authorize: "none"` escape hatch is for intentionally non-public in-process
13
13
  tests only; do not use it on a billable generation route.
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Streaming protocol
4
4
 
5
- `createVideoHandler` returns validated server-sent events and `useVideo` consumes
5
+ `createVideoChatHandler` returns validated server-sent events and `useVideoChat` consumes
6
6
  them. Normal applications do not parse SSE or reduce events themselves.
7
7
 
8
8
  The internal protocol is deterministic and versioned. A run starts once, adds or
@@ -10,6 +10,6 @@ patches only complete validated scenes, and terminates exactly once as complete,
10
10
  error, or aborted. Every event has a run ID and sequence. Completion carries the
11
11
  authoritative snapshot and drift-detection checksum.
12
12
 
13
- Persist `video.video` when replay, editing, or export is required. Played scenes
13
+ Persist completed `chat.turns` video values when replay is required. Played scenes
14
14
  are immutable; patches may affect only future scenes. See the [protocol reference](reference/protocol.md)
15
15
  when implementing infrastructure rather than an ordinary SDK integration.
@@ -8,12 +8,12 @@ templates sync` and `npx vanillasky templates check`.
8
8
  | --- | --- |
9
9
  | [Minimal text](minimal-text.tsx) | One short, grounded idea should fill the scene. |
10
10
  | [Structured data](structured-data.tsx) | An exact metric and its change are the central proof. |
11
- | [Supplied media](supplied-media.tsx) | An image already supplied by the application is the strongest evidence. |
12
11
 
13
- All three use only `defineTemplate` from the public
12
+ Both use only `defineTemplate` from the public
14
13
  `@vanillaskyai/video/templates` entry point. They include selection guidance,
15
14
  JSON Schema defaults, a named example, deterministic progress-based motion,
16
- safe-zone layout, and portrait/landscape handling. The media reference uses
17
- `format: "supplied-image"` for an image that must appear in
18
- `VideoInput.suppliedMedia`; use `format: "uri"` for another approved media or
19
- link URL governed by the same server media policy.
15
+ safe-zone layout, and portrait/landscape handling. Connect the generated browser
16
+ registry through `VideoChat` options and the server registry through
17
+ `createVideoChatHandler`, as shown in [Custom templates](../../docs/custom-templates.md).
18
+ For media-backed answers, start from a built-in template using
19
+ `npx vanillasky templates add media` and configure the handler's `searchMedia`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanillaskyai/video",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "Open-source voice-and-video chat SDK for AI applications.",
5
5
  "keywords": [
6
6
  "video-chat",
@@ -36,6 +36,9 @@
36
36
  "starters/video-chat/index.html",
37
37
  "starters/video-chat/package.json",
38
38
  "starters/video-chat/server.ts",
39
+ "starters/video-chat/providers.ts",
40
+ "starters/video-chat/providers/speech.ts",
41
+ "starters/video-chat/providers/video.ts",
39
42
  "starters/video-chat/src/main.tsx",
40
43
  "starters/video-chat/stock.ts",
41
44
  "starters/video-chat/tsconfig.json",
@@ -90,9 +93,6 @@
90
93
  "./video-chat.css": "./styles/video-chat.css"
91
94
  },
92
95
  "scripts": {
93
- "acceptance:live": "tsx scripts/acceptance/run-live.ts",
94
- "acceptance:review": "tsx scripts/acceptance/review.ts",
95
- "acceptance:replay": "tsx scripts/acceptance/run-replay.ts",
96
96
  "browser:install": "playwright install chromium firefox webkit",
97
97
  "browser:test": "playwright test",
98
98
  "build": "tsup",
@@ -112,7 +112,8 @@
112
112
  "verify:package-size": "tsx scripts/verify-package-size.ts",
113
113
  "verify:api": "npm run build && node scripts/verify-public-api-surface.mjs",
114
114
  "verify:package": "npm run build && node scripts/verify-packed-package.mjs",
115
- "release:build": "node scripts/release-build.mjs"
115
+ "release:build": "node scripts/release-build.mjs",
116
+ "acceptance:chat": "tsx scripts/acceptance/run.ts"
116
117
  },
117
118
  "peerDependencies": {
118
119
  "react": ">=18 <20",
@@ -131,7 +132,6 @@
131
132
  }
132
133
  },
133
134
  "devDependencies": {
134
- "@anthropic-ai/sdk": "^0.120.0",
135
135
  "@eslint/js": "^9.39.1",
136
136
  "@playwright/test": "1.62.0",
137
137
  "@testing-library/react": "^16.3.0",
@@ -142,7 +142,6 @@
142
142
  "eslint": "^9.39.1",
143
143
  "globals": "^16.5.0",
144
144
  "jsdom": "^26.1.0",
145
- "openai": "^7.5.0",
146
145
  "react": "^19.2.8",
147
146
  "react-dom": "^19.2.8",
148
147
  "tsup": "^8.5.1",
@@ -164,7 +164,7 @@
164
164
  "mediaKeyword": {
165
165
  "type": "string",
166
166
  "title": "Background search keyword",
167
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
167
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
168
168
  "format": "stock-media-keyword",
169
169
  "default": ""
170
170
  },
@@ -183,7 +183,7 @@
183
183
  "mediaPoster": {
184
184
  "type": "string",
185
185
  "title": "Background poster image",
186
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
186
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
187
187
  "format": "uri",
188
188
  "default": ""
189
189
  },
@@ -149,7 +149,7 @@
149
149
  "mediaKeyword": {
150
150
  "type": "string",
151
151
  "title": "Background search keyword",
152
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
152
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
153
153
  "format": "stock-media-keyword",
154
154
  "default": ""
155
155
  },
@@ -168,7 +168,7 @@
168
168
  "mediaPoster": {
169
169
  "type": "string",
170
170
  "title": "Background poster image",
171
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
171
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
172
172
  "format": "uri",
173
173
  "default": ""
174
174
  },
@@ -89,7 +89,7 @@
89
89
  "mediaKeyword": {
90
90
  "type": "string",
91
91
  "title": "Background search keyword",
92
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
92
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
93
93
  "format": "stock-media-keyword",
94
94
  "default": ""
95
95
  },
@@ -108,7 +108,7 @@
108
108
  "mediaPoster": {
109
109
  "type": "string",
110
110
  "title": "Background poster image",
111
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
111
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
112
112
  "format": "uri",
113
113
  "default": ""
114
114
  },
@@ -134,7 +134,7 @@
134
134
  "mediaKeyword": {
135
135
  "type": "string",
136
136
  "title": "Background search keyword",
137
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
137
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
138
138
  "format": "stock-media-keyword",
139
139
  "default": ""
140
140
  },
@@ -153,7 +153,7 @@
153
153
  "mediaPoster": {
154
154
  "type": "string",
155
155
  "title": "Background poster image",
156
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
156
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
157
157
  "format": "uri",
158
158
  "default": ""
159
159
  },
@@ -110,7 +110,7 @@
110
110
  "mediaKeyword": {
111
111
  "type": "string",
112
112
  "title": "Background search keyword",
113
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
113
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
114
114
  "format": "stock-media-keyword",
115
115
  "default": ""
116
116
  },
@@ -129,7 +129,7 @@
129
129
  "mediaPoster": {
130
130
  "type": "string",
131
131
  "title": "Background poster image",
132
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
132
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
133
133
  "format": "uri",
134
134
  "default": ""
135
135
  },
@@ -86,7 +86,7 @@
86
86
  "mediaKeyword": {
87
87
  "type": "string",
88
88
  "title": "Background search keyword",
89
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
89
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
90
90
  "default": ""
91
91
  },
92
92
  "mediaType": {
@@ -104,7 +104,7 @@
104
104
  "mediaPoster": {
105
105
  "type": "string",
106
106
  "title": "Background poster image",
107
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
107
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
108
108
  "format": "uri",
109
109
  "default": ""
110
110
  },
@@ -110,7 +110,7 @@
110
110
  "mediaKeyword": {
111
111
  "type": "string",
112
112
  "title": "Background search keyword",
113
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
113
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
114
114
  "format": "stock-media-keyword",
115
115
  "default": ""
116
116
  },
@@ -129,7 +129,7 @@
129
129
  "mediaPoster": {
130
130
  "type": "string",
131
131
  "title": "Background poster image",
132
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
132
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
133
133
  "format": "uri",
134
134
  "default": ""
135
135
  },
@@ -101,7 +101,7 @@
101
101
  "mediaKeyword": {
102
102
  "type": "string",
103
103
  "title": "Background search keyword",
104
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
104
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
105
105
  "format": "stock-media-keyword",
106
106
  "default": ""
107
107
  },
@@ -120,7 +120,7 @@
120
120
  "mediaPoster": {
121
121
  "type": "string",
122
122
  "title": "Background poster image",
123
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
123
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
124
124
  "format": "uri",
125
125
  "default": ""
126
126
  },
@@ -102,7 +102,7 @@
102
102
  "mediaKeyword": {
103
103
  "type": "string",
104
104
  "title": "Background search keyword",
105
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
105
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
106
106
  "format": "stock-media-keyword",
107
107
  "default": ""
108
108
  },
@@ -121,7 +121,7 @@
121
121
  "mediaPoster": {
122
122
  "type": "string",
123
123
  "title": "Background poster image",
124
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
124
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
125
125
  "format": "uri",
126
126
  "default": ""
127
127
  },
@@ -134,7 +134,7 @@
134
134
  "mediaKeyword": {
135
135
  "type": "string",
136
136
  "title": "Background search keyword",
137
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
137
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
138
138
  "format": "stock-media-keyword",
139
139
  "default": ""
140
140
  },
@@ -153,7 +153,7 @@
153
153
  "mediaPoster": {
154
154
  "type": "string",
155
155
  "title": "Background poster image",
156
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
156
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
157
157
  "format": "uri",
158
158
  "default": ""
159
159
  },
@@ -108,7 +108,7 @@
108
108
  "mediaKeyword": {
109
109
  "type": "string",
110
110
  "title": "Background search keyword",
111
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
111
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
112
112
  "format": "stock-media-keyword",
113
113
  "default": ""
114
114
  },
@@ -127,7 +127,7 @@
127
127
  "mediaPoster": {
128
128
  "type": "string",
129
129
  "title": "Background poster image",
130
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
130
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
131
131
  "format": "uri",
132
132
  "default": ""
133
133
  },
@@ -185,7 +185,7 @@
185
185
  "mediaKeyword": {
186
186
  "type": "string",
187
187
  "title": "Background search keyword",
188
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
188
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
189
189
  "default": ""
190
190
  },
191
191
  "mediaType": {
@@ -203,7 +203,7 @@
203
203
  "mediaPoster": {
204
204
  "type": "string",
205
205
  "title": "Background poster image",
206
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
206
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
207
207
  "format": "uri",
208
208
  "default": ""
209
209
  },
@@ -116,7 +116,7 @@
116
116
  "mediaKeyword": {
117
117
  "type": "string",
118
118
  "title": "Background search keyword",
119
- "description": "2-4 word English term for Pexels stock-footage search (auto-fills mediaUrl).",
119
+ "description": "2-4 word English term for stock-media search (auto-fills mediaUrl).",
120
120
  "format": "stock-media-keyword",
121
121
  "default": ""
122
122
  },
@@ -135,7 +135,7 @@
135
135
  "mediaPoster": {
136
136
  "type": "string",
137
137
  "title": "Background poster image",
138
- "description": "Still image URL shown while a video backdrop is decoding its first frame. Auto-filled from Pexels' thumbnail when fillPexelsUrls sets a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
138
+ "description": "Still image URL shown while a video backdrop is decoding its first frame. A media resolver can supply a poster alongside a video mediaUrl. Hides the gradient flash that would otherwise appear in the ~50–400ms gap between a <video> mounting and decoding its first frame.",
139
139
  "format": "uri",
140
140
  "default": ""
141
141
  },