@vanillaskyai/video 0.8.8 → 0.9.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 (175) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/PUBLIC-API.md +5 -8
  3. package/dist/{builtin-server-CUYPIDE7.js → builtin-server-HW6HGXCZ.js} +2 -2
  4. package/dist/{catalog-types-BIhSpOWK.d.ts → catalog-types-WTbLP6Jh.d.ts} +5 -1
  5. package/dist/chapter-title-YRLIQY3V.js +7 -0
  6. package/dist/check-runtime.js +6 -15
  7. package/dist/{chunk-2USVB3CY.js → chunk-3ZTEFJIR.js} +285 -178
  8. package/dist/chunk-4YM2M62S.js +13 -0
  9. package/dist/chunk-77VY4O7A.js +390 -0
  10. package/dist/{chunk-MMUXVA47.js → chunk-7M56IUUX.js} +9 -8
  11. package/dist/chunk-7NZOMTAL.js +63 -0
  12. package/dist/{chunk-2DOLF4QN.js → chunk-AUPC6MDK.js} +12 -14
  13. package/dist/{chunk-352ZZCET.js → chunk-EGVQODKU.js} +2 -2
  14. package/dist/chunk-EWWCQFTI.js +18 -0
  15. package/dist/{chunk-MXZSDGZQ.js → chunk-G7IZBBWF.js} +14 -9
  16. package/dist/{chunk-KT3M7KDL.js → chunk-HKUI5BTB.js} +3 -3
  17. package/dist/{chunk-LMG3GHLL.js → chunk-IQMYK5DX.js} +29 -3
  18. package/dist/chunk-LH4BPALA.js +564 -0
  19. package/dist/{chunk-OWBT45EN.js → chunk-MQILEEXC.js} +1 -1
  20. package/dist/chunk-MXEYPK7M.js +552 -0
  21. package/dist/{chunk-AITKH6QT.js → chunk-OR52UMSF.js} +13 -39
  22. package/dist/{chunk-5SLENAJW.js → chunk-PAJ44TFW.js} +1 -2
  23. package/dist/{chunk-L7QGGKJ2.js → chunk-PDQFQIQW.js} +1 -1
  24. package/dist/{chunk-WJ6FLKNC.js → chunk-R3XAOMKP.js} +14 -0
  25. package/dist/{chunk-2OKB27TG.js → chunk-RXTN2CW6.js} +2 -2
  26. package/dist/{chunk-XWWLKRNU.js → chunk-TVIU23OM.js} +38 -49
  27. package/dist/{chunk-224QNWRA.js → chunk-UDIODEDK.js} +1 -5
  28. package/dist/{chunk-3VRMKFM7.js → chunk-ZDJNFA52.js} +11 -24
  29. package/dist/cinema-media-YQHSIFDA.js +11 -0
  30. package/dist/cli.js +18 -9
  31. package/dist/comparison-RZMMHZR2.js +27 -0
  32. package/dist/compose-video-TBFTONUC.js +12 -0
  33. package/dist/editorial-timeline-OZX7OS6G.js +36 -0
  34. package/dist/{events-BQ6z264n.d.ts → events-B4YCc4vc.d.ts} +1 -1
  35. package/dist/focus-cards-TJ72BT7U.js +20 -0
  36. package/dist/index.d.ts +4 -6
  37. package/dist/index.js +3 -7
  38. package/dist/key-figure-GYENXKH3.js +20 -0
  39. package/dist/{kit-tQnCPMOM.d.ts → kit-DrRpdn0p.d.ts} +2 -2
  40. package/dist/mobile-message-UZUPIKHD.js +49 -0
  41. package/dist/{preload-media-LJXWKTWG.js → preload-media-CFTZIMZL.js} +1 -1
  42. package/dist/quote-EW5HQA6H.js +23 -0
  43. package/dist/react.d.ts +21 -11
  44. package/dist/react.js +590 -833
  45. package/dist/scene-video-backdrop-PCTARAAJ.js +7 -0
  46. package/dist/server.d.ts +7 -8
  47. package/dist/server.js +91 -74
  48. package/dist/{system-prompt-RRXIWDDD.js → system-prompt-SYRT5DWM.js} +1 -1
  49. package/dist/template-catalog.d.ts +257 -16
  50. package/dist/template-catalog.js +1 -1
  51. package/dist/templates.d.ts +5 -5
  52. package/dist/test.d.ts +3 -3
  53. package/dist/test.js +18 -18
  54. package/dist/text-stream-LD364KBI.js +9 -0
  55. package/dist/{types-DWFO6qca.d.ts → types-CdBmNTGD.d.ts} +1 -1
  56. package/dist/{types-CEh9eUFu.d.ts → types-DdZw4GRQ.d.ts} +17 -48
  57. package/dist/validate-4OUD2CLX.js +10 -0
  58. package/docs/architecture.md +1 -1
  59. package/docs/concepts.md +1 -1
  60. package/docs/custom-templates.md +13 -28
  61. package/docs/customization.md +11 -59
  62. package/docs/getting-started.md +2 -2
  63. package/docs/immersive-interface.md +3 -4
  64. package/docs/maintainers/cinematic-migration.md +34 -0
  65. package/docs/media-and-audio.md +14 -14
  66. package/docs/motion-and-effects.md +6 -14
  67. package/docs/persistence.md +3 -3
  68. package/docs/production.md +11 -9
  69. package/docs/provider-integration.md +9 -16
  70. package/docs/reference/design-system.html +1 -1
  71. package/docs/reference/protocol.md +14 -4
  72. package/docs/testing.md +1 -1
  73. package/package.json +6 -3
  74. package/registry/items/backgrounds.json +1 -1
  75. package/registry/items/chapterTitle.json +80 -0
  76. package/registry/items/cinemaMedia.json +136 -0
  77. package/registry/items/comparison.json +101 -0
  78. package/registry/items/editorialTimeline.json +105 -0
  79. package/registry/items/focusCards.json +90 -0
  80. package/registry/items/keyFigure.json +97 -0
  81. package/registry/items/mobileMessage.json +153 -0
  82. package/registry/items/quote.json +94 -0
  83. package/registry/items/template-context.json +1 -1
  84. package/registry/items/theme.json +1 -1
  85. package/starters/video-chat/README.md +24 -26
  86. package/starters/video-chat/package.json +1 -1
  87. package/starters/video-chat/providers/video.ts +6 -5
  88. package/starters/video-chat/stock.ts +35 -151
  89. package/styles/fonts/OFL.txt +93 -0
  90. package/styles/fonts/manifest.json +66 -0
  91. package/styles/fonts/roboto-v51-cyrillic-ext.woff2 +0 -0
  92. package/styles/fonts/roboto-v51-cyrillic.woff2 +0 -0
  93. package/styles/fonts/roboto-v51-greek-ext.woff2 +0 -0
  94. package/styles/fonts/roboto-v51-greek.woff2 +0 -0
  95. package/styles/fonts/roboto-v51-latin-ext.woff2 +0 -0
  96. package/styles/fonts/roboto-v51-latin.woff2 +0 -0
  97. package/styles/fonts/roboto-v51-math.woff2 +0 -0
  98. package/styles/fonts/roboto-v51-symbols.woff2 +0 -0
  99. package/styles/fonts/roboto-v51-vietnamese.woff2 +0 -0
  100. package/styles/fonts/roboto.css +91 -0
  101. package/styles/video-chat.css +30 -22
  102. package/dist/bg-confetti-HITCGLGD.js +0 -89
  103. package/dist/bg-emoji-VU4UZYZN.js +0 -150
  104. package/dist/bg-media-L34PDQXJ.js +0 -106
  105. package/dist/brand-message-FUJ4STFO.js +0 -256
  106. package/dist/chart-bar-EGPHJATL.js +0 -310
  107. package/dist/chart-counter-5FFWQNZO.js +0 -306
  108. package/dist/chart-progress-ring-JMXQLMLC.js +0 -302
  109. package/dist/chunk-4UNKZEAT.js +0 -3575
  110. package/dist/chunk-5CDAM24P.js +0 -31
  111. package/dist/chunk-AOWSXU2K.js +0 -18
  112. package/dist/chunk-CJ7F2CE6.js +0 -104
  113. package/dist/chunk-FRN6WKHA.js +0 -185
  114. package/dist/chunk-G5JPHBX7.js +0 -336
  115. package/dist/chunk-L5BTTCZV.js +0 -97
  116. package/dist/chunk-P22HHFDK.js +0 -43
  117. package/dist/chunk-PP3MCPN4.js +0 -1998
  118. package/dist/chunk-QAAO7OAY.js +0 -19
  119. package/dist/chunk-S7HFLYNN.js +0 -35
  120. package/dist/chunk-W3VDIBGR.js +0 -217
  121. package/dist/chunk-XGRA2MUV.js +0 -242
  122. package/dist/chunk-XTOXFMLM.js +0 -105
  123. package/dist/chunk-YJJC4N4D.js +0 -761
  124. package/dist/compose-video-2NFH4DZY.js +0 -13
  125. package/dist/cta-logo-YR7LYUR5.js +0 -212
  126. package/dist/cta-media-DQJBKUO2.js +0 -221
  127. package/dist/incoming-call-54KQ7O5A.js +0 -323
  128. package/dist/infographic-before-after-ROS52GOW.js +0 -460
  129. package/dist/infographic-feature-list-E7MGUDAN.js +0 -272
  130. package/dist/infographic-problem-solution-3S6NGO5N.js +0 -343
  131. package/dist/infographic-stat-row-SYB7AB7H.js +0 -247
  132. package/dist/infographic-steps-KCE6JWE2.js +0 -406
  133. package/dist/prompt-input-MHX4O42G.js +0 -239
  134. package/dist/reaction-SLEGR3BE.js +0 -122
  135. package/dist/scene-video-backdrop-XFPX4O3I.js +0 -10
  136. package/dist/showcase-code-2HLAVKBM.js +0 -357
  137. package/dist/showcase-phone-Q4HEO4LH.js +0 -278
  138. package/dist/showcase-terminal-DL45LUFG.js +0 -312
  139. package/dist/showcase-web-2QZO73FZ.js +0 -396
  140. package/dist/social-conversation-75SD2637.js +0 -695
  141. package/dist/social-milestone-GEFUQSBF.js +0 -296
  142. package/dist/social-notification-FJ5VHVLK.js +0 -247
  143. package/dist/social-review-stack-KXQCKFRP.js +0 -242
  144. package/dist/social-testimonial-JZ7CHC7S.js +0 -287
  145. package/dist/social-tweet-UCDXM25F.js +0 -298
  146. package/dist/text-stream-54LXABJW.js +0 -10
  147. package/dist/validate-T7GBU2YF.js +0 -8
  148. package/registry/items/barChart.json +0 -245
  149. package/registry/items/beforeAfter.json +0 -180
  150. package/registry/items/bigNumber.json +0 -232
  151. package/registry/items/brandMessage.json +0 -164
  152. package/registry/items/cardList.json +0 -214
  153. package/registry/items/chatMessenger.json +0 -151
  154. package/registry/items/chatWhatsapp.json +0 -151
  155. package/registry/items/codeEditor.json +0 -191
  156. package/registry/items/confetti.json +0 -107
  157. package/registry/items/ctaLogo.json +0 -167
  158. package/registry/items/ctaMedia.json +0 -200
  159. package/registry/items/emojiBurst.json +0 -101
  160. package/registry/items/incomingCall.json +0 -177
  161. package/registry/items/media.json +0 -187
  162. package/registry/items/milestone.json +0 -212
  163. package/registry/items/notification.json +0 -189
  164. package/registry/items/phoneMockup.json +0 -261
  165. package/registry/items/problemSolution.json +0 -193
  166. package/registry/items/progressRing.json +0 -206
  167. package/registry/items/promptInput.json +0 -155
  168. package/registry/items/reaction.json +0 -176
  169. package/registry/items/reviewStack.json +0 -231
  170. package/registry/items/steps.json +0 -215
  171. package/registry/items/terminal.json +0 -219
  172. package/registry/items/testimonial.json +0 -171
  173. package/registry/items/tripleStats.json +0 -235
  174. package/registry/items/tweet.json +0 -210
  175. package/registry/items/webMockup.json +0 -280
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  validateTemplateSchemaValue
3
- } from "./chunk-352ZZCET.js";
3
+ } from "./chunk-EGVQODKU.js";
4
4
  import {
5
5
  getTemplateSchemaGates,
6
6
  isMeaningfullyPresentTemplateValue
@@ -29,7 +29,7 @@ function schemaValues(schema, variables) {
29
29
  }
30
30
  return values;
31
31
  }
32
- function validateSchema(schema, value) {
32
+ function validateTemplateSceneStructure(schema, value, deferMediaUrls = false) {
33
33
  if (!value || typeof value !== "object" || Array.isArray(value)) {
34
34
  throw new Error("Template variable variables must be object");
35
35
  }
@@ -45,6 +45,7 @@ function validateSchema(schema, value) {
45
45
  }
46
46
  for (const [name, property] of Object.entries(schema.properties)) {
47
47
  if (Object.hasOwn(object, name)) validateTemplateSchemaValue(property, object[name], name, {
48
+ deferMediaUrls,
48
49
  errorPrefix: "Template variable ",
49
50
  includeTypeArticle: true,
50
51
  allowEmptyOptionalMedia: property.default === "",
@@ -66,6 +67,24 @@ function suppliedUrls(input) {
66
67
  }
67
68
  return urls;
68
69
  }
70
+ function containsSuppliedQuantity(input, value) {
71
+ if (typeof value !== "string" && typeof value !== "number") return false;
72
+ const normalize = (text) => text.normalize("NFKC").replace(/\u2212/g, "-").replace(/\s+/gu, " ").replace(/([\p{Sc}]) (?=[+−-]?\d)/gu, "$1").replace(/(\d) (?=[%‰])/gu, "$1").trim();
73
+ const quantity = normalize(String(value));
74
+ if (!/\d/u.test(quantity)) return false;
75
+ const source = normalize(input);
76
+ let offset = source.indexOf(quantity);
77
+ while (offset !== -1) {
78
+ const before = source.slice(0, offset);
79
+ const after = source.slice(offset + quantity.length);
80
+ const beginsInside = /[\p{L}\p{N}\p{Sc}%‰+−-]$/u.test(before) || /\d[.,]$/u.test(before);
81
+ const endsInside = /^[\p{L}\p{N}\p{Sc}%‰]/u.test(after) || /^[.,]\d/u.test(after);
82
+ const dropsUnit = /\d$/u.test(quantity) && /^ (?:%|‰|percent\b|per cent\b|thousand\b|million\b|billion\b|trillion\b|usd\b|eur\b|gbp\b|dollars?\b|euros?\b|pounds?\b)/iu.test(after);
83
+ if (!beginsInside && !endsInside && !dropsUnit) return true;
84
+ offset = source.indexOf(quantity, offset + 1);
85
+ }
86
+ return false;
87
+ }
69
88
  function createTemplateSceneValidator(options) {
70
89
  return (scene, context) => {
71
90
  const template = options.kit.getTemplateMetadata(scene.templateId);
@@ -73,7 +92,7 @@ function createTemplateSceneValidator(options) {
73
92
  const schema = template.schema;
74
93
  const gates = getTemplateSchemaGates(schema);
75
94
  validateConditionalPresence(scene.templateId, gates.requiredAnyOf, scene.variables);
76
- validateSchema(schema, scene.variables);
95
+ validateTemplateSceneStructure(schema, scene.variables);
77
96
  const values = schemaValues(schema, scene.variables);
78
97
  const allowedUrls = suppliedUrls(context.input);
79
98
  const suppliedImageUrls = new Set((context.input.suppliedMedia ?? []).filter(({ type }) => type === "image").map(({ url }) => url));
@@ -93,6 +112,12 @@ function createTemplateSceneValidator(options) {
93
112
  });
94
113
  if (!permitted) throw new Error(`Template variable ${path} must use supplied media`);
95
114
  }
115
+ if (gates.requiresStat) {
116
+ const quantities = values.filter(({ property }) => property.format === "grounded-stat");
117
+ if (!quantities.length || quantities.some(({ value }) => !containsSuppliedQuantity(context.input.input, value))) {
118
+ throw new Error(`Template ${scene.templateId} requires an exact supplied quantity, preserving its unit`);
119
+ }
120
+ }
96
121
  if (gates.requiresQuote) {
97
122
  const quoteValues = values.filter(({ property, value }) => property.format === "grounded-quote" && typeof value === "string" && value.trim()).map(({ value }) => String(value).trim());
98
123
  if (!quoteValues.length || quoteValues.some((quote) => !context.input.input.includes(quote))) {
@@ -103,5 +128,6 @@ function createTemplateSceneValidator(options) {
103
128
  }
104
129
 
105
130
  export {
131
+ validateTemplateSceneStructure,
106
132
  createTemplateSceneValidator
107
133
  };
@@ -0,0 +1,564 @@
1
+ // src/visual-system/catalog/catalog.generated.ts
2
+ var GENERATED_BUILTIN_TEMPLATE_CATALOG = [
3
+ {
4
+ "label": "Full-bleed",
5
+ "description": "Immersive photo or video without a headline.",
6
+ "usesGlobalTextEffect": false,
7
+ "usesGlobalTransition": false,
8
+ "usesGlobalBackgroundEffect": false,
9
+ "textCanvas": "tight",
10
+ "id": "cinemaMedia",
11
+ "family": "Media & motion",
12
+ "jobs": [
13
+ "setup",
14
+ "atmosphere",
15
+ "payoff"
16
+ ],
17
+ "register": "motion-led",
18
+ "useWhen": "Show a relevant place, activity or subject. The asset is resolved separately from a shot description. ",
19
+ "avoidWhen": "No relevant asset can be resolved or the scene needs structured explanation.",
20
+ "minDuration": 3,
21
+ "preferredDuration": 6,
22
+ "timing": {
23
+ "contentFields": [],
24
+ "contentUnit": "words",
25
+ "revealSeconds": 0,
26
+ "holdSeconds": 3,
27
+ "exitSeconds": 0
28
+ },
29
+ "schema": {
30
+ "type": "object",
31
+ "properties": {
32
+ "mediaKeyword": {
33
+ "type": "string",
34
+ "format": "stock-media-keyword",
35
+ "minLength": 1,
36
+ "maxLength": 80,
37
+ "description": "2\u20138 word literal subject/action search intent, maximum 80 characters. Host resolves URLs.",
38
+ "examples": [
39
+ "Ocean waves breaking on a rocky shore"
40
+ ]
41
+ },
42
+ "mediaUrl": {
43
+ "type": "string",
44
+ "format": "uri",
45
+ "description": "Host-only approved photo or video URL.",
46
+ "default": ""
47
+ },
48
+ "mediaType": {
49
+ "type": "string",
50
+ "enum": [
51
+ "photo",
52
+ "video"
53
+ ],
54
+ "default": "video",
55
+ "description": "Host-resolved asset kind."
56
+ },
57
+ "mediaPoster": {
58
+ "type": "string",
59
+ "format": "uri",
60
+ "description": "Host-only approved poster URL for video decoding.",
61
+ "default": ""
62
+ },
63
+ "shotDirection": {
64
+ "type": "string",
65
+ "maxLength": 220,
66
+ "description": "Optional action, framing and continuity for generation. Preserve the subject; do not request rendered text."
67
+ },
68
+ "mediaSource": {
69
+ "type": "string",
70
+ "enum": [
71
+ "generate",
72
+ "stock"
73
+ ],
74
+ "description": "Generate distinctive illustrative shots; use approved stock for familiar observable subjects."
75
+ },
76
+ "fallbackText": {
77
+ "type": "string",
78
+ "maxLength": 65,
79
+ "description": "Optional grounded concise chapter text if this shot cannot be resolved; not visible over footage."
80
+ }
81
+ },
82
+ "required": [],
83
+ "additionalProperties": false,
84
+ "x-vanillasky": {
85
+ "allowsStockMedia": true,
86
+ "requiredAnyOf": [
87
+ [
88
+ "mediaKeyword",
89
+ "mediaUrl"
90
+ ]
91
+ ]
92
+ }
93
+ }
94
+ },
95
+ {
96
+ "label": "Chapter",
97
+ "description": "Centered white typography fades in, holds, and fades out on black.",
98
+ "usesGlobalTextEffect": false,
99
+ "usesGlobalTransition": false,
100
+ "usesGlobalBackgroundEffect": false,
101
+ "textCanvas": "tight",
102
+ "id": "chapterTitle",
103
+ "family": "Explainers",
104
+ "jobs": [
105
+ "setup",
106
+ "payoff"
107
+ ],
108
+ "register": "motion-led",
109
+ "useWhen": "An opening, new chapter or deliberate short takeaway needs its own visual beat. ",
110
+ "avoidWhen": "A headline would merely repeat subtitles over an ordinary footage scene.",
111
+ "minDuration": 3,
112
+ "preferredDuration": 4,
113
+ "timing": {
114
+ "contentFields": [
115
+ "title"
116
+ ],
117
+ "contentUnit": "words",
118
+ "revealSeconds": 0.8,
119
+ "holdSeconds": 1.5,
120
+ "exitSeconds": 0.8
121
+ },
122
+ "schema": {
123
+ "type": "object",
124
+ "properties": {
125
+ "title": {
126
+ "type": "string",
127
+ "maxLength": 65,
128
+ "description": "Short title. Line breaks optional.",
129
+ "default": "A different perspective"
130
+ }
131
+ },
132
+ "required": [
133
+ "title"
134
+ ],
135
+ "additionalProperties": false
136
+ }
137
+ },
138
+ {
139
+ "label": "Focus cards",
140
+ "description": "Two to four short phrases fade in sequentially on black; no boxes or heading.",
141
+ "usesGlobalTextEffect": false,
142
+ "usesGlobalTransition": false,
143
+ "usesGlobalBackgroundEffect": false,
144
+ "textCanvas": "tight",
145
+ "id": "focusCards",
146
+ "family": "Explainers",
147
+ "jobs": [
148
+ "setup",
149
+ "proof"
150
+ ],
151
+ "register": "card-led",
152
+ "useWhen": "Two to four short parallel points support an explanation. ",
153
+ "avoidWhen": "The points require an order, long paragraphs, numerical data or additional images to make sense.",
154
+ "minDuration": 4,
155
+ "preferredDuration": 5,
156
+ "timing": {
157
+ "contentFields": [
158
+ "items"
159
+ ],
160
+ "contentUnit": "items",
161
+ "revealSeconds": 2.4,
162
+ "holdSeconds": 1.8,
163
+ "exitSeconds": 0
164
+ },
165
+ "schema": {
166
+ "type": "object",
167
+ "properties": {
168
+ "items": {
169
+ "type": "array",
170
+ "minItems": 2,
171
+ "maxItems": 4,
172
+ "items": {
173
+ "type": "string",
174
+ "minLength": 1,
175
+ "maxLength": 55
176
+ },
177
+ "default": [
178
+ "Listen closely",
179
+ "Notice the pattern",
180
+ "Make room for change"
181
+ ],
182
+ "description": "2\u20134 parallel phrases, about 2\u20136 words each; no heading or numbering."
183
+ }
184
+ },
185
+ "required": [
186
+ "items"
187
+ ],
188
+ "additionalProperties": false
189
+ }
190
+ },
191
+ {
192
+ "label": "Timeline",
193
+ "description": "Three to five events on a fine continuous line on black; without dates.",
194
+ "usesGlobalTextEffect": false,
195
+ "usesGlobalTransition": false,
196
+ "usesGlobalBackgroundEffect": false,
197
+ "textCanvas": "tight",
198
+ "id": "editorialTimeline",
199
+ "family": "Explainers",
200
+ "jobs": [
201
+ "setup",
202
+ "proof"
203
+ ],
204
+ "register": "card-led",
205
+ "useWhen": "Events unfold in an order, or actions form a process. No dates or heading. ",
206
+ "avoidWhen": "The points are unordered or the story needs branching relationships.",
207
+ "minDuration": 5,
208
+ "preferredDuration": 6,
209
+ "timing": {
210
+ "contentFields": [
211
+ "events"
212
+ ],
213
+ "contentUnit": "items",
214
+ "revealSeconds": 3.2,
215
+ "holdSeconds": 1.8,
216
+ "exitSeconds": 0
217
+ },
218
+ "schema": {
219
+ "type": "object",
220
+ "properties": {
221
+ "events": {
222
+ "type": "array",
223
+ "minItems": 3,
224
+ "maxItems": 5,
225
+ "items": {
226
+ "type": "object",
227
+ "properties": {
228
+ "label": {
229
+ "type": "string",
230
+ "minLength": 1,
231
+ "maxLength": 45
232
+ }
233
+ },
234
+ "required": [
235
+ "label"
236
+ ],
237
+ "additionalProperties": false
238
+ },
239
+ "default": [
240
+ {
241
+ "label": "Observe"
242
+ },
243
+ {
244
+ "label": "Understand"
245
+ },
246
+ {
247
+ "label": "Act"
248
+ }
249
+ ],
250
+ "description": "3\u20135 ordered events or actions, each with one short label; no dates."
251
+ }
252
+ },
253
+ "required": [
254
+ "events"
255
+ ],
256
+ "additionalProperties": false
257
+ }
258
+ },
259
+ {
260
+ "label": "Reach out",
261
+ "description": "A frosted glass message over resolved media, without sender or timestamp.",
262
+ "usesGlobalTextEffect": false,
263
+ "usesGlobalTransition": false,
264
+ "usesGlobalBackgroundEffect": false,
265
+ "textCanvas": "tight",
266
+ "id": "mobileMessage",
267
+ "family": "Social & messaging",
268
+ "jobs": [
269
+ "setup"
270
+ ],
271
+ "register": "card-led",
272
+ "useWhen": "A person or organization reaches out with a short message, alert or invitation. Message must be supplied or explicitly illustrative.",
273
+ "avoidWhen": "The scene is a generic fact, a long exchange, or a message that would fabricate evidence.",
274
+ "minDuration": 4,
275
+ "preferredDuration": 6,
276
+ "timing": {
277
+ "contentFields": [
278
+ "message",
279
+ "app"
280
+ ],
281
+ "contentUnit": "words",
282
+ "revealSeconds": 1,
283
+ "holdSeconds": 2.2,
284
+ "exitSeconds": 0
285
+ },
286
+ "schema": {
287
+ "type": "object",
288
+ "properties": {
289
+ "mediaKeyword": {
290
+ "type": "string",
291
+ "format": "stock-media-keyword",
292
+ "minLength": 1,
293
+ "maxLength": 80,
294
+ "description": "2\u20138 word literal subject/action search intent, maximum 80 characters. Host resolves URLs.",
295
+ "examples": [
296
+ "Ocean waves breaking on a rocky shore"
297
+ ]
298
+ },
299
+ "mediaUrl": {
300
+ "type": "string",
301
+ "format": "uri",
302
+ "description": "Host-only approved photo or video URL.",
303
+ "default": ""
304
+ },
305
+ "mediaType": {
306
+ "type": "string",
307
+ "enum": [
308
+ "photo",
309
+ "video"
310
+ ],
311
+ "default": "video",
312
+ "description": "Host-resolved asset kind."
313
+ },
314
+ "mediaPoster": {
315
+ "type": "string",
316
+ "format": "uri",
317
+ "description": "Host-only approved poster URL for video decoding.",
318
+ "default": ""
319
+ },
320
+ "message": {
321
+ "type": "string",
322
+ "maxLength": 120,
323
+ "default": "Can we talk?",
324
+ "description": "Exact supplied or explicitly illustrative message, preferably 6\u201316 words."
325
+ },
326
+ "app": {
327
+ "type": "string",
328
+ "maxLength": 24,
329
+ "default": "Messages",
330
+ "description": "Optional app label; Messages is the visual default."
331
+ },
332
+ "shotDirection": {
333
+ "type": "string",
334
+ "maxLength": 220,
335
+ "description": "Optional action, framing and continuity for generation. Preserve the subject; do not request rendered text."
336
+ },
337
+ "mediaSource": {
338
+ "type": "string",
339
+ "enum": [
340
+ "generate",
341
+ "stock"
342
+ ],
343
+ "description": "Generate distinctive illustrative shots; use approved stock for familiar observable subjects."
344
+ }
345
+ },
346
+ "required": [
347
+ "message"
348
+ ],
349
+ "additionalProperties": false,
350
+ "x-vanillasky": {
351
+ "allowsStockMedia": true
352
+ }
353
+ }
354
+ },
355
+ {
356
+ "label": "Comparison",
357
+ "description": "Two short statements with equal weight on black, side by side or stacked in portrait.",
358
+ "usesGlobalTextEffect": false,
359
+ "usesGlobalTransition": false,
360
+ "usesGlobalBackgroundEffect": false,
361
+ "textCanvas": "tight",
362
+ "id": "comparison",
363
+ "family": "Explainers",
364
+ "jobs": [
365
+ "proof"
366
+ ],
367
+ "register": "motion-led",
368
+ "useWhen": "Explain a before/after change or two alternatives with short parallel statements. ",
369
+ "avoidWhen": "There are more than two alternatives or a numerical chart is needed.",
370
+ "minDuration": 4,
371
+ "preferredDuration": 6,
372
+ "timing": {
373
+ "contentFields": [
374
+ "leftText",
375
+ "rightText",
376
+ "leftLabel",
377
+ "rightLabel"
378
+ ],
379
+ "contentUnit": "words",
380
+ "revealSeconds": 1.2,
381
+ "holdSeconds": 2.5,
382
+ "exitSeconds": 0
383
+ },
384
+ "schema": {
385
+ "type": "object",
386
+ "properties": {
387
+ "leftLabel": {
388
+ "type": "string",
389
+ "maxLength": 20,
390
+ "description": "Optional short identifier for the first alternative."
391
+ },
392
+ "rightLabel": {
393
+ "type": "string",
394
+ "maxLength": 20,
395
+ "description": "Optional short identifier for the second alternative."
396
+ },
397
+ "leftText": {
398
+ "type": "string",
399
+ "minLength": 1,
400
+ "maxLength": 60,
401
+ "default": "More distractions",
402
+ "description": "First real alternative in one short phrase."
403
+ },
404
+ "rightText": {
405
+ "type": "string",
406
+ "minLength": 1,
407
+ "maxLength": 60,
408
+ "default": "More room to think",
409
+ "description": "Second real alternative, parallel to the first."
410
+ }
411
+ },
412
+ "required": [
413
+ "leftText",
414
+ "rightText"
415
+ ],
416
+ "additionalProperties": false
417
+ }
418
+ },
419
+ {
420
+ "label": "Quote",
421
+ "description": "A short exact quotation with a legible attribution on black.",
422
+ "usesGlobalTextEffect": false,
423
+ "usesGlobalTransition": false,
424
+ "usesGlobalBackgroundEffect": false,
425
+ "textCanvas": "tight",
426
+ "id": "quote",
427
+ "family": "Explainers",
428
+ "jobs": [
429
+ "proof"
430
+ ],
431
+ "register": "motion-led",
432
+ "useWhen": "A supplied quotation deserves its own moment. Use exact source words and attribution only.",
433
+ "avoidWhen": "No exact quotation or reliable attribution is supplied; never invent testimony.",
434
+ "minDuration": 5,
435
+ "preferredDuration": 7,
436
+ "timing": {
437
+ "contentFields": [
438
+ "quote",
439
+ "attribution"
440
+ ],
441
+ "contentUnit": "words",
442
+ "revealSeconds": 1.2,
443
+ "holdSeconds": 3,
444
+ "exitSeconds": 0
445
+ },
446
+ "schema": {
447
+ "type": "object",
448
+ "properties": {
449
+ "quote": {
450
+ "type": "string",
451
+ "minLength": 1,
452
+ "maxLength": 140,
453
+ "format": "grounded-quote",
454
+ "examples": [
455
+ "Look closely. There is always more to see."
456
+ ],
457
+ "description": "Exact supplied quotation; do not paraphrase or invent."
458
+ },
459
+ "attribution": {
460
+ "type": "string",
461
+ "minLength": 1,
462
+ "maxLength": 60,
463
+ "examples": [
464
+ "Illustrative example"
465
+ ],
466
+ "description": "Grounded attribution belonging to these exact quoted words."
467
+ }
468
+ },
469
+ "required": [
470
+ "quote",
471
+ "attribution"
472
+ ],
473
+ "additionalProperties": false
474
+ }
475
+ },
476
+ {
477
+ "label": "Key figure",
478
+ "description": "One supplied figure with one short label on black.",
479
+ "usesGlobalTextEffect": false,
480
+ "usesGlobalTransition": false,
481
+ "usesGlobalBackgroundEffect": false,
482
+ "textCanvas": "tight",
483
+ "id": "keyFigure",
484
+ "family": "Explainers",
485
+ "jobs": [
486
+ "proof"
487
+ ],
488
+ "register": "motion-led",
489
+ "useWhen": "One verified quantity or supplied target anchors the explanation. Value, unit and context must match supplied evidence.",
490
+ "avoidWhen": "No reliable figure is supplied or multiple values require a chart.",
491
+ "minDuration": 4,
492
+ "preferredDuration": 5,
493
+ "timing": {
494
+ "contentFields": [
495
+ "value",
496
+ "label"
497
+ ],
498
+ "contentUnit": "words",
499
+ "revealSeconds": 0.8,
500
+ "holdSeconds": 2.5,
501
+ "exitSeconds": 0
502
+ },
503
+ "schema": {
504
+ "type": "object",
505
+ "properties": {
506
+ "value": {
507
+ "type": "string",
508
+ "minLength": 1,
509
+ "maxLength": 14,
510
+ "format": "grounded-stat",
511
+ "examples": [
512
+ "42%"
513
+ ],
514
+ "description": "One supplied supported quantity, preserving its unit."
515
+ },
516
+ "label": {
517
+ "type": "string",
518
+ "minLength": 1,
519
+ "maxLength": 50,
520
+ "examples": [
521
+ "Illustrative example"
522
+ ],
523
+ "description": "Exactly one short label identifying the quantity and its context."
524
+ }
525
+ },
526
+ "required": [
527
+ "value",
528
+ "label"
529
+ ],
530
+ "additionalProperties": false,
531
+ "x-vanillasky": {
532
+ "requiresStat": true
533
+ }
534
+ }
535
+ }
536
+ ];
537
+
538
+ // src/visual-system/catalog/builtin-metadata.ts
539
+ function freezeValue(value) {
540
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
541
+ for (const nested of Object.values(value)) freezeValue(nested);
542
+ Object.freeze(value);
543
+ }
544
+ return value;
545
+ }
546
+ var BUILTIN_TEMPLATE_CATALOG = freezeValue(
547
+ [...GENERATED_BUILTIN_TEMPLATE_CATALOG]
548
+ );
549
+ var metadataById = new Map(BUILTIN_TEMPLATE_CATALOG.map((template) => [template.id, template]));
550
+ var BUILTIN_TEMPLATE_CAPABILITIES = freezeValue({
551
+ templates: BUILTIN_TEMPLATE_CATALOG.map(({ id }) => id).sort()
552
+ });
553
+ function listBuiltinTemplateMetadata() {
554
+ return BUILTIN_TEMPLATE_CATALOG;
555
+ }
556
+ function getBuiltinTemplateMetadata(id) {
557
+ return metadataById.get(id);
558
+ }
559
+
560
+ export {
561
+ BUILTIN_TEMPLATE_CATALOG,
562
+ listBuiltinTemplateMetadata,
563
+ getBuiltinTemplateMetadata
564
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BUILTIN_TEMPLATE_CATALOG
3
- } from "./chunk-4UNKZEAT.js";
3
+ } from "./chunk-LH4BPALA.js";
4
4
  import {
5
5
  assertTemplateTransitionMetadata
6
6
  } from "./chunk-2E6T633S.js";