@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.
- package/CHANGELOG.md +30 -0
- package/PUBLIC-API.md +5 -8
- package/dist/{builtin-server-CUYPIDE7.js → builtin-server-HW6HGXCZ.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 +6 -15
- package/dist/{chunk-2USVB3CY.js → chunk-3ZTEFJIR.js} +285 -178
- package/dist/chunk-4YM2M62S.js +13 -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-EWWCQFTI.js +18 -0
- package/dist/{chunk-MXZSDGZQ.js → chunk-G7IZBBWF.js} +14 -9
- package/dist/{chunk-KT3M7KDL.js → chunk-HKUI5BTB.js} +3 -3
- package/dist/{chunk-LMG3GHLL.js → chunk-IQMYK5DX.js} +29 -3
- package/dist/chunk-LH4BPALA.js +564 -0
- package/dist/{chunk-OWBT45EN.js → chunk-MQILEEXC.js} +1 -1
- package/dist/chunk-MXEYPK7M.js +552 -0
- package/dist/{chunk-AITKH6QT.js → chunk-OR52UMSF.js} +13 -39
- 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-224QNWRA.js → chunk-UDIODEDK.js} +1 -5
- package/dist/{chunk-3VRMKFM7.js → chunk-ZDJNFA52.js} +11 -24
- package/dist/cinema-media-YQHSIFDA.js +11 -0
- package/dist/cli.js +18 -9
- package/dist/comparison-RZMMHZR2.js +27 -0
- package/dist/compose-video-TBFTONUC.js +12 -0
- package/dist/editorial-timeline-OZX7OS6G.js +36 -0
- package/dist/{events-BQ6z264n.d.ts → events-B4YCc4vc.d.ts} +1 -1
- package/dist/focus-cards-TJ72BT7U.js +20 -0
- package/dist/index.d.ts +4 -6
- package/dist/index.js +3 -7
- package/dist/key-figure-GYENXKH3.js +20 -0
- package/dist/{kit-tQnCPMOM.d.ts → kit-DrRpdn0p.d.ts} +2 -2
- package/dist/mobile-message-UZUPIKHD.js +49 -0
- package/dist/{preload-media-LJXWKTWG.js → preload-media-CFTZIMZL.js} +1 -1
- package/dist/quote-EW5HQA6H.js +23 -0
- package/dist/react.d.ts +21 -11
- package/dist/react.js +590 -833
- package/dist/scene-video-backdrop-PCTARAAJ.js +7 -0
- package/dist/server.d.ts +7 -8
- package/dist/server.js +91 -74
- package/dist/{system-prompt-RRXIWDDD.js → system-prompt-SYRT5DWM.js} +1 -1
- package/dist/template-catalog.d.ts +257 -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 +34 -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 +101 -0
- package/registry/items/editorialTimeline.json +105 -0
- package/registry/items/focusCards.json +90 -0
- package/registry/items/keyFigure.json +97 -0
- package/registry/items/mobileMessage.json +153 -0
- package/registry/items/quote.json +94 -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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createVideoSystemPrompt
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PAJ44TFW.js";
|
|
4
4
|
import {
|
|
5
5
|
PACING_PLANNER_RULES
|
|
6
6
|
} from "./chunk-3O7OMMMF.js";
|
|
@@ -15,7 +15,7 @@ function getStandardMediaResolverContract(schema) {
|
|
|
15
15
|
const url = schema.properties.mediaUrl;
|
|
16
16
|
const type = schema.properties.mediaType;
|
|
17
17
|
const allowedTypes = new Set(type?.enum ?? []);
|
|
18
|
-
if (keyword?.format !== "stock-media-keyword" || url?.format !== "uri" || !["photo", "video"
|
|
18
|
+
if (keyword?.format !== "stock-media-keyword" || url?.format !== "uri" || !["photo", "video"].every((value) => allowedTypes.has(value))) {
|
|
19
19
|
return void 0;
|
|
20
20
|
}
|
|
21
21
|
return {
|
|
@@ -26,6 +26,8 @@ function getStandardMediaResolverContract(schema) {
|
|
|
26
26
|
// src/visual-system/catalog/prompt.ts
|
|
27
27
|
function plannerProperty(property) {
|
|
28
28
|
return {
|
|
29
|
+
...property.description == null ? {} : { description: property.description },
|
|
30
|
+
...property.examples == null ? {} : { examples: property.examples.slice(0, 1) },
|
|
29
31
|
...property.type == null ? {} : { type: property.type },
|
|
30
32
|
...property.format == null ? {} : { format: property.format },
|
|
31
33
|
...property.enum == null ? {} : { enum: property.enum },
|
|
@@ -60,10 +62,6 @@ function plannerSchema(schema, exposeMediaKeyword) {
|
|
|
60
62
|
}
|
|
61
63
|
};
|
|
62
64
|
}
|
|
63
|
-
function needsPlannerSchema(schema) {
|
|
64
|
-
const visit = (property) => property.minimum != null || property.maximum != null || property.type === "object" || property.items != null && visit(property.items);
|
|
65
|
-
return Object.values(schema.properties).some(visit);
|
|
66
|
-
}
|
|
67
65
|
function isMediaProperty(property) {
|
|
68
66
|
return property?.format === "uri" || property?.format === "supplied-image" || property?.format === "stock-media-keyword";
|
|
69
67
|
}
|
|
@@ -71,13 +69,6 @@ function requiresAvailableMedia(template) {
|
|
|
71
69
|
const gates = getTemplateSchemaGates(template.schema);
|
|
72
70
|
return (template.schema.required ?? []).some((name) => isMediaProperty(template.schema.properties[name])) || gates.requiredAnyOf.some((group) => group.every((name) => isMediaProperty(template.schema.properties[name])));
|
|
73
71
|
}
|
|
74
|
-
var COMMON_MEDIA_VARIABLES = {
|
|
75
|
-
mediaUrl: "media",
|
|
76
|
-
mediaType: "enum(auto|photo|video|gradient)",
|
|
77
|
-
mediaPoster: "media",
|
|
78
|
-
mediaPosition: "enum(center|top|bottom|left|right)",
|
|
79
|
-
mediaTreatment: "enum(none|subtle|cinematic|text-safe)"
|
|
80
|
-
};
|
|
81
72
|
function plannerCatalog(templates, mediaResolverAvailable) {
|
|
82
73
|
return templates.map((template) => {
|
|
83
74
|
const gates = getTemplateSchemaGates(template.schema);
|
|
@@ -88,23 +79,19 @@ function plannerCatalog(templates, mediaResolverAvailable) {
|
|
|
88
79
|
name === "mediaKeyword" ? "string{2..80}" : templateVariableNotation(property, template.schema.required?.includes(name) === true)
|
|
89
80
|
])
|
|
90
81
|
);
|
|
91
|
-
const usesCommonMedia = Object.entries(COMMON_MEDIA_VARIABLES).every(([name, notation]) => variables[name] === notation);
|
|
92
|
-
if (usesCommonMedia) {
|
|
93
|
-
for (const name of Object.keys(COMMON_MEDIA_VARIABLES)) delete variables[name];
|
|
94
|
-
}
|
|
95
82
|
return {
|
|
96
83
|
id: template.id,
|
|
97
84
|
jobs: template.jobs,
|
|
98
85
|
use: template.useWhen ?? template.description,
|
|
86
|
+
...template.avoidWhen ? { avoid: template.avoidWhen } : {},
|
|
99
87
|
...template.minDuration == null && template.preferredDuration == null ? {} : {
|
|
100
88
|
seconds: [template.minDuration ?? null, template.preferredDuration ?? null]
|
|
101
89
|
},
|
|
102
90
|
...gates.requiresStat ? { requiresStat: true } : {},
|
|
103
91
|
...gates.requiresQuote ? { requiresQuote: true } : {},
|
|
104
92
|
...gates.requiresScreenshot ? { requiresScreenshot: true } : {},
|
|
105
|
-
...gates.requiredAnyOf.length > 0 ? { requiredAnyOf: gates.requiredAnyOf } : {},
|
|
106
|
-
|
|
107
|
-
...usesCommonMedia ? { media: true } : {},
|
|
93
|
+
...gates.requiredAnyOf.length > 0 ? { requiredAnyOf: gates.requiredAnyOf.map((group) => group.filter((name) => name !== "mediaKeyword" || exposeMediaKeyword)) } : {},
|
|
94
|
+
schema: plannerSchema(template.schema, exposeMediaKeyword),
|
|
108
95
|
variables
|
|
109
96
|
};
|
|
110
97
|
});
|
|
@@ -112,24 +99,14 @@ function plannerCatalog(templates, mediaResolverAvailable) {
|
|
|
112
99
|
function createTemplateSystemPrompt(options) {
|
|
113
100
|
const templates = options.kit.listTemplateMetadata().filter((template) => !requiresAvailableMedia(template) || options.suppliedMediaAvailable === true || options.mediaResolverAvailable === true && getStandardMediaResolverContract(template.schema) != null);
|
|
114
101
|
const resolverMediaAvailable = options.mediaResolverAvailable === true && templates.some(({ schema }) => getStandardMediaResolverContract(schema) != null);
|
|
115
|
-
const ids = new Set(templates.map(({ id }) => id));
|
|
116
|
-
const fields = new Set(templates.flatMap(({ schema }) => Object.keys(schema.properties)));
|
|
117
102
|
const basePrompt = createVideoSystemPrompt(options.knowledgeMode, options.narrate === true).split("\n").filter(
|
|
118
103
|
(line) => !line.includes("Never use media, ctaMedia, or reaction as the first generated body template") && // The rule that keeps the opening beat asset-free belongs to the same
|
|
119
104
|
// pair as the one below it: both exist so playback can start without
|
|
120
105
|
// waiting on a provider, and both go when the host owns that wait.
|
|
121
106
|
!(options.mediaOnFirstScene === true && line.includes("The first generated body scene must be asset-free")) && !(resolverMediaAvailable && line.includes("Never expose a loading placeholder or unresolved media keyword"))
|
|
122
107
|
).join("\n");
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
...ids.has("steps") ? ["steps needs two or three unused sequential facts"] : [],
|
|
126
|
-
...ids.has("tripleStats") ? ["tripleStats needs exactly three unused peer values"] : []
|
|
127
|
-
];
|
|
128
|
-
const mediaTemplates = ["media", "ctaMedia", "reaction"].filter((id) => ids.has(id));
|
|
129
|
-
const mediaTemplateNames = mediaTemplates.length === 3 ? "media, ctaMedia, and reaction" : mediaTemplates.join(", ");
|
|
130
|
-
const terminalPayoffs = ["media", "emojiBurst", "confetti"].filter((id) => ids.has(id));
|
|
131
|
-
const terminalPayoffNames = terminalPayoffs.length < 2 ? terminalPayoffs.join("") : `${terminalPayoffs.slice(0, -1).join(", ")}, or ${terminalPayoffs.at(-1)}`;
|
|
132
|
-
const listFields = ["items", "itemEmojis", "steps", "stepEmojis", "problemEmojis", "solutionEmojis"].filter((name) => fields.has(name));
|
|
108
|
+
const mediaTemplates = templates.filter(({ schema }) => getStandardMediaResolverContract(schema) != null).map(({ id }) => id);
|
|
109
|
+
const terminalPayoffs = templates.filter(({ jobs }) => jobs?.includes("payoff")).map(({ id }) => id);
|
|
133
110
|
return [
|
|
134
111
|
basePrompt.trim(),
|
|
135
112
|
options.basePrompt?.trim() ? `
|
|
@@ -139,20 +116,17 @@ ${options.basePrompt.trim()}` : void 0,
|
|
|
139
116
|
"TRUSTED TEMPLATE CATALOG",
|
|
140
117
|
"Only use template IDs from this catalog. Only emit variables declared for the selected template.",
|
|
141
118
|
"Variable notation is type[count]{characters}(options)! where count is list cardinality, characters is the inclusive character count for a string or each string-array item, and ! means required. Omitted ! means optional.",
|
|
142
|
-
`seconds is [minimum, preferred]. media=true adds these optional variables: ${Object.entries(COMMON_MEDIA_VARIABLES).map(([name, notation]) => `${name}:${notation}`).join(", ")}.`,
|
|
143
119
|
"Choose a template only when the permitted factual basis contains every fact it needs. Never invent peer values to complete a chart, comparison, stat set, timeline, or list.",
|
|
144
120
|
...PACING_PLANNER_RULES,
|
|
145
|
-
ids.has("cardList") && ids.has("steps") && ids.has("tripleStats") ? "Fact availability carries across templates: cardList and steps each need two or three unused facts (parallel for cardList, sequential for steps) and must carry only the count the evidence supports, and tripleStats needs exactly three unused peer values. Never invent a fact to fill a collection, and do not fill one with facts already shown in another scene." : factRules.length > 0 ? `Fact availability carries across templates: ${factRules.join(", and ")}. Use only the count the evidence supports. Never invent a fact to fill a collection, and do not fill one with facts already shown in another scene.` : void 0,
|
|
146
121
|
"Do not compress a list, sequence, metric set, or comparison into a general-purpose prose field when a specific catalog template can show that structure.",
|
|
147
122
|
"If the catalog includes a suitable ask template and the input supplies a grounded CTA or URL, keep that concise action closer as its own final scene instead of folding it into preceding content.",
|
|
148
123
|
"When a grounded CTA or URL is supplied and the catalog contains jobs:[ask], emit that final closer. A brand name may accompany the action but never qualifies as an ask by itself.",
|
|
149
|
-
terminalPayoffs.length > 0 ? `When
|
|
124
|
+
terminalPayoffs.length > 0 ? `When there is no grounded action, end with a concise supported payoff using a suitable template from ${terminalPayoffs.join(", ")}. Do not repeat the hook or invent a CTA.` : void 0,
|
|
150
125
|
"requiresQuote is a hard gate: use those templates only for exact quoted words and attribution present in raw input. Never turn a role, relationship, or summary into speech. requiresScreenshot likewise needs an actual supplied screenshot URL.",
|
|
151
126
|
templates.some(({ schema }) => (schema["x-vanillasky"]?.requiredAnyOf?.length ?? 0) > 0) ? "requiredAnyOf is a hard presence gate: satisfy every listed group with at least one non-empty value." : void 0,
|
|
152
|
-
mediaTemplates.length > 0 && options.mediaOnFirstScene !== true ? `
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
resolverMediaAvailable ? `Prefer a relevant resolved image or video background on ${options.mediaOnFirstScene === true ? "every media-capable scene, the first included," : "later media-capable scenes"} whenever the permitted factual basis names a concrete person, place, product context, activity, or outcome that can be depicted honestly. Emit mediaKeyword on scene.add as a specific 2\u20138 word semantic query of at most 80 characters. The host removes mediaKeyword before the complete scene reaches the browser and replaces it with an approved asset. Use mediaType=gradient for abstract, sensitive, unsafe, or visually ambiguous material. Never emit or invent mediaUrl or mediaPoster.` : mediaTemplates.length > 0 ? `Use exact grounded values for required fields. mediaUrl must come verbatim from supplied input. Stock queries are not available. Do not select ${mediaTemplateNames} without a supplied mediaUrl; if another template has no mediaUrl, explicitly use mediaType=gradient. mediaType auto detects a URL, while gradient deliberately uses no external asset.` : "Use exact grounded values for required fields.",
|
|
127
|
+
mediaTemplates.length > 0 && options.mediaOnFirstScene !== true ? `The host owns immediate startup; reserve external media templates (${mediaTemplates.join(", ")}) for later beats when an asset-free opening is required.` : void 0,
|
|
128
|
+
"For list and event variables emit actual JSON arrays. Follow each field's content budget; never use pipe-delimited strings or invent entries.",
|
|
129
|
+
resolverMediaAvailable ? "Media-capable scenes may carry mediaKeyword: a literal 2\u20138 word shot description, at most 80 characters. Choose mediaSource=generate for distinctive illustrative shots and mediaSource=stock for common subjects a verified asset can depict. For generated footage, optional shotDirection gives action, framing and continuity separately from the stock query. Keep people, actions and essential details precise. Never broaden an exact identity or action into unrelated atmosphere. Supply a grounded fallbackText where declared. Only the host fills mediaUrl and mediaPoster; never invent them. If no media fits an abstract beat, choose an appropriate graphic template instead." : "Use media only when a supplied asset satisfies the scene. Never invent asset URLs. Otherwise choose a grounded graphic template.",
|
|
156
130
|
"Catalog guidance describes composition; it is not a factual source and must never replace the permitted factual basis.",
|
|
157
131
|
JSON.stringify(plannerCatalog(templates, resolverMediaAvailable)),
|
|
158
132
|
// Last, because the catalogue is thousands of tokens of per-scene field
|
|
@@ -42,13 +42,12 @@ Composition rules:
|
|
|
42
42
|
- Before emitting, assign each supported fact to at most one scene. The supplied opening counts: once a fact is visible, treat it as unavailable to later scenes. Finish when the supported material is covered instead of padding the response.
|
|
43
43
|
- Do not infer that something is scheduled, ready, triggered, enabled, automatic, causal, or available unless the permitted factual basis supports it.
|
|
44
44
|
- The first generated body scene must be asset-free and fully playable before any external media resolves.
|
|
45
|
-
- Never use media, ctaMedia, or reaction as the first generated body template, including in gradient mode.
|
|
46
45
|
- Use only media URLs present in the supplied input or already resolved by the host. Never expose a loading placeholder or unresolved media keyword. Audio is optional and must never delay the first scene.
|
|
47
46
|
- Audio is selected by the host before generation. Never emit audio.
|
|
48
47
|
|
|
49
48
|
Streaming rules:
|
|
50
49
|
- Emit every scene once as a complete scene.add.
|
|
51
|
-
- Emit exactly one closer
|
|
50
|
+
- Emit exactly one closer using placement:"closer". It is held and appended last; preserve the intended story order.
|
|
52
51
|
- Prefer resolved media on scene.add. Scenes are immutable after emission.
|
|
53
52
|
- End explicitly with plan.complete. A truncated stream is never treated as complete.
|
|
54
53
|
- Return only plan parts accepted by the provided schema.
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
// src/visual-system/catalog/video-backdrop-capability.ts
|
|
2
2
|
var EXTERNAL_VIDEO_BACKDROP_CAPABILITY = "__vanillaskyExternalVideoBackdrop";
|
|
3
|
+
function markExternalVideoBackdropTemplate(template) {
|
|
4
|
+
const component = template.component;
|
|
5
|
+
if ((typeof component !== "object" || component === null) && typeof component !== "function") {
|
|
6
|
+
throw new Error("External video backdrop templates require a component");
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(component, EXTERNAL_VIDEO_BACKDROP_CAPABILITY, {
|
|
9
|
+
value: true,
|
|
10
|
+
enumerable: false,
|
|
11
|
+
configurable: false,
|
|
12
|
+
writable: false
|
|
13
|
+
});
|
|
14
|
+
return template;
|
|
15
|
+
}
|
|
3
16
|
function supportsExternalVideoBackdrop(template) {
|
|
4
17
|
if (typeof template !== "object" || template === null) return false;
|
|
5
18
|
const component = template.component;
|
|
@@ -10,6 +23,7 @@ function externalVideoBackdropCapabilitySource() {
|
|
|
10
23
|
}
|
|
11
24
|
|
|
12
25
|
export {
|
|
26
|
+
markExternalVideoBackdropTemplate,
|
|
13
27
|
supportsExternalVideoBackdrop,
|
|
14
28
|
externalVideoBackdropCapabilitySource
|
|
15
29
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseVideoEvent
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7M56IUUX.js";
|
|
4
4
|
import {
|
|
5
5
|
VIDEO_PROTOCOL_VERSION,
|
|
6
6
|
VIDEO_SCHEMA_VERSION
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7NZOMTAL.js";
|
|
8
8
|
|
|
9
9
|
// src/protocol/stable-json.ts
|
|
10
10
|
function stableJson(value) {
|
|
@@ -1,23 +1,30 @@
|
|
|
1
|
-
// src/visual-system/scene-templates/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
// src/visual-system/scene-templates/external-video-backdrop.tsx
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
var DEFAULT = { mode: false, audioMuted: true, audioVolume: 1 };
|
|
5
|
+
var sharedContext = globalThis;
|
|
6
|
+
var BackdropContext = sharedContext.__vanillaskyVideoBackdropContext ??= React.createContext(DEFAULT);
|
|
7
|
+
function ExternalVideoBackdropProvider({
|
|
8
|
+
mode,
|
|
9
|
+
audioMuted = true,
|
|
10
|
+
audioVolume = 1,
|
|
11
|
+
children
|
|
12
|
+
}) {
|
|
13
|
+
const value = React.useMemo(
|
|
14
|
+
() => ({ mode, audioMuted, audioVolume }),
|
|
15
|
+
[mode, audioMuted, audioVolume]
|
|
16
|
+
);
|
|
17
|
+
return /* @__PURE__ */ jsx(BackdropContext.Provider, { value, children });
|
|
18
|
+
}
|
|
19
|
+
function useExternalVideoBackdrop() {
|
|
20
|
+
return React.useContext(BackdropContext).mode;
|
|
20
21
|
}
|
|
22
|
+
function useMediaAudio() {
|
|
23
|
+
const { audioMuted, audioVolume } = React.useContext(BackdropContext);
|
|
24
|
+
return { muted: audioMuted, volume: audioVolume };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/visual-system/scene-templates/tokens.ts
|
|
21
28
|
var STYLE_PRESETS = {
|
|
22
29
|
bold: {
|
|
23
30
|
id: "bold",
|
|
@@ -94,7 +101,6 @@ function resolveMotion(id) {
|
|
|
94
101
|
return id && MOTION_SCALES[id] || MOTION_SCALES[DEFAULT_MOTION_ID];
|
|
95
102
|
}
|
|
96
103
|
function resolveTokens(style) {
|
|
97
|
-
const brand = style.brand;
|
|
98
104
|
const preset = resolvePreset(style.preset);
|
|
99
105
|
const density = resolveDensity(style.density);
|
|
100
106
|
const motion = resolveMotion(style.motion);
|
|
@@ -107,17 +113,15 @@ function resolveTokens(style) {
|
|
|
107
113
|
}
|
|
108
114
|
};
|
|
109
115
|
return {
|
|
110
|
-
primary:
|
|
111
|
-
secondary:
|
|
112
|
-
background:
|
|
113
|
-
surface:
|
|
114
|
-
surfaceElevated:
|
|
115
|
-
foreground:
|
|
116
|
-
muted:
|
|
117
|
-
font:
|
|
118
|
-
scriptFont:
|
|
119
|
-
logoUrl: brand.logoUrl,
|
|
120
|
-
name: brand.name,
|
|
116
|
+
primary: "#FFFFFF",
|
|
117
|
+
secondary: "#FFFFFF",
|
|
118
|
+
background: { type: "solid", color: "#000000" },
|
|
119
|
+
surface: "#000000",
|
|
120
|
+
surfaceElevated: "#171717",
|
|
121
|
+
foreground: "#FFFFFF",
|
|
122
|
+
muted: "#B7B7BC",
|
|
123
|
+
font: '-apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto, Arial, sans-serif',
|
|
124
|
+
scriptFont: "Georgia",
|
|
121
125
|
preset: composedPreset,
|
|
122
126
|
density,
|
|
123
127
|
motion
|
|
@@ -131,27 +135,12 @@ function darken(hex, factor) {
|
|
|
131
135
|
const ch = (i) => Math.max(0, Math.round(parseInt(full.slice(i, i + 2), 16) * (1 - factor))).toString(16).padStart(2, "0");
|
|
132
136
|
return `#${ch(1)}${ch(3)}${ch(5)}`;
|
|
133
137
|
}
|
|
134
|
-
function lighten(hex, factor) {
|
|
135
|
-
if (!hex.startsWith("#") || hex.length !== 4 && hex.length !== 7) {
|
|
136
|
-
return hex;
|
|
137
|
-
}
|
|
138
|
-
const full = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
|
|
139
|
-
const r = parseInt(full.slice(1, 3), 16);
|
|
140
|
-
const g = parseInt(full.slice(3, 5), 16);
|
|
141
|
-
const b = parseInt(full.slice(5, 7), 16);
|
|
142
|
-
const lr = Math.min(255, Math.round(r + (255 - r) * factor));
|
|
143
|
-
const lg = Math.min(255, Math.round(g + (255 - g) * factor));
|
|
144
|
-
const lb = Math.min(255, Math.round(b + (255 - b) * factor));
|
|
145
|
-
return `#${lr.toString(16).padStart(2, "0")}${lg.toString(16).padStart(2, "0")}${lb.toString(16).padStart(2, "0")}`;
|
|
146
|
-
}
|
|
147
|
-
var MEDIA_TEXT_SHADOW = "0 2px 8px rgba(0,0,0,0.55), 0 6px 16px rgba(0,0,0,0.35)";
|
|
148
138
|
|
|
149
139
|
export {
|
|
150
|
-
TOKEN_DEFAULTS,
|
|
151
|
-
fontStack,
|
|
152
140
|
resolveDensity,
|
|
153
141
|
resolveTokens,
|
|
154
142
|
darken,
|
|
155
|
-
|
|
156
|
-
|
|
143
|
+
ExternalVideoBackdropProvider,
|
|
144
|
+
useExternalVideoBackdrop,
|
|
145
|
+
useMediaAudio
|
|
157
146
|
};
|
|
@@ -19,12 +19,8 @@ function resolveMediaType(mediaType, mediaUrl) {
|
|
|
19
19
|
if (mediaType === "photo") return "photo";
|
|
20
20
|
return mediaUrl && isVideoUrl(mediaUrl) ? "video" : "photo";
|
|
21
21
|
}
|
|
22
|
-
function hasSceneMedia(variables) {
|
|
23
|
-
return String(variables.mediaUrl || "").trim() !== "" && String(variables.mediaType || "auto") !== "gradient";
|
|
24
|
-
}
|
|
25
22
|
|
|
26
23
|
export {
|
|
27
24
|
limitsConcurrentVideoDecoders,
|
|
28
|
-
resolveMediaType
|
|
29
|
-
hasSceneMedia
|
|
25
|
+
resolveMediaType
|
|
30
26
|
};
|
|
@@ -6,30 +6,27 @@ import {
|
|
|
6
6
|
checksumVideo,
|
|
7
7
|
createVideoEventFactory,
|
|
8
8
|
createVideoState
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RXTN2CW6.js";
|
|
10
10
|
import {
|
|
11
11
|
parseVideoPlanPart,
|
|
12
12
|
safePublicDiagnostic
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-7M56IUUX.js";
|
|
14
14
|
import {
|
|
15
15
|
MAX_RETAINED_INSTRUCTIONS_LENGTH,
|
|
16
16
|
MAX_RETAINED_MEDIA_URLS,
|
|
17
17
|
MAX_RETAINED_MEDIA_URL_LENGTH,
|
|
18
18
|
MAX_RETAINED_SOURCE_LENGTH,
|
|
19
19
|
parseVideo
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-AUPC6MDK.js";
|
|
21
21
|
import {
|
|
22
22
|
VIDEO_SCHEMA_VERSION,
|
|
23
23
|
createVideoRequest
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-7NZOMTAL.js";
|
|
25
25
|
import {
|
|
26
26
|
getCloserReserve,
|
|
27
27
|
getReadableSceneDuration,
|
|
28
28
|
paceScene
|
|
29
29
|
} from "./chunk-3O7OMMMF.js";
|
|
30
|
-
import {
|
|
31
|
-
resolveVideoBrand
|
|
32
|
-
} from "./chunk-XGRA2MUV.js";
|
|
33
30
|
|
|
34
31
|
// src/replayable-stream.ts
|
|
35
32
|
function createReplayableStream(source, onError) {
|
|
@@ -114,7 +111,6 @@ function buildVideoUserPrompt(input, openingDurationSec = 0) {
|
|
|
114
111
|
input.opening === false ? "The host owns the opening wait. Add the first grounded scene as soon as it is complete; it may use host-resolved media." : typeof input.opening === "string" && input.opening.trim() ? `The host has already added the opening scene, which consumes ${openingDurationSec} seconds. Continue after it and do not repeat or rewrite it.` : "Add the first grounded scene as soon as it is complete.",
|
|
115
112
|
...input.opening === false ? [] : [
|
|
116
113
|
"The first generated body scene must be fully playable without external media. Use a content-fit text, data, comparison, list, or device-free template with no media URL or keyword.",
|
|
117
|
-
"Never use media, ctaMedia, or reaction as the first generated body template, even with mediaType=gradient. Choose a non-media template first.",
|
|
118
114
|
"Add that scene before resolving any stock or supplied asset. Resolve media as part of each complete later body scene."
|
|
119
115
|
],
|
|
120
116
|
"Use only claims supported by the factual basis permitted by the trusted system prompt.",
|
|
@@ -125,7 +121,7 @@ function buildVideoUserPrompt(input, openingDurationSec = 0) {
|
|
|
125
121
|
"If the creative instructions explicitly require one separate scene per named item, release, section, or list entry, do not merge, group, or omit those required items. Keep related required scenes adjacent in a coherent progression while preserving each item as its own scene.",
|
|
126
122
|
"Before emitting, verify that the explicitly requested structure can fit readably within the maximum duration. If it cannot, preserve readability and the requested separation for the scenes that fit, then finish with plan.complete using finishReason length rather than silently changing the structure.",
|
|
127
123
|
"For ordinary multi-fact input, form at least three distinct beats: hook, comprehension, and payoff. Use only one or two beats when the source genuinely contains no more than two independent grounded takeaways. This is a narrative guideline, never permission to repeat facts or add filler.",
|
|
128
|
-
"
|
|
124
|
+
"Emit exactly one final scene.add with placement closer. Generate a short grounded conclusion that answers the story's so-what; it must not repeat hook language or imply another scene follows.",
|
|
129
125
|
"Use a different suitable template for each body scene when the catalog supports it.",
|
|
130
126
|
"Never add filler to satisfy a count or diversity target.",
|
|
131
127
|
input.suppliedMedia?.length ? input.opening === false ? "Select zero or more relevant opaque supplied-media references for visible scenes. Never invent or transform a reference. Only emit mediaKeyword when the trusted system catalog explicitly exposes it. Never invent mediaUrl or mediaPoster." : "Select zero or more relevant opaque supplied-media references for visible later scenes. Never invent or transform a reference. Only emit mediaKeyword when the trusted system catalog explicitly exposes it, and only on later scenes. Never invent mediaUrl or mediaPoster." : input.opening === false ? "No supplied media URL is available. Use asset-free templates unless the trusted system catalog explicitly permits host-resolved media intent, which may begin on the first scene. Only emit mediaKeyword when the trusted system catalog explicitly exposes it. Never invent mediaUrl or mediaPoster." : "No supplied media URL is available. Use asset-free templates unless the trusted system catalog explicitly permits host-resolved media intent. Only emit mediaKeyword when the trusted system catalog explicitly exposes it, and only on later scenes. Never invent mediaUrl or mediaPoster.",
|
|
@@ -140,13 +136,7 @@ function buildVideoUserPrompt(input, openingDurationSec = 0) {
|
|
|
140
136
|
JSON.stringify(input.personalization ?? {}),
|
|
141
137
|
"",
|
|
142
138
|
"SUPPLIED MEDIA",
|
|
143
|
-
JSON.stringify(suppliedMediaReferences(input))
|
|
144
|
-
"",
|
|
145
|
-
"BRAND",
|
|
146
|
-
JSON.stringify({
|
|
147
|
-
...input.brand?.name?.trim() ? { name: input.brand.name.trim() } : {},
|
|
148
|
-
hasLogo: Boolean(input.brand?.logoUrl?.trim())
|
|
149
|
-
})
|
|
139
|
+
JSON.stringify(suppliedMediaReferences(input))
|
|
150
140
|
].join("\n");
|
|
151
141
|
}
|
|
152
142
|
|
|
@@ -162,7 +152,7 @@ function resolveStreamCapabilities(capabilities, hasRuntimeOpening) {
|
|
|
162
152
|
if (!hasRuntimeOpening || capabilities?.templates == null) return capabilities;
|
|
163
153
|
return {
|
|
164
154
|
...capabilities,
|
|
165
|
-
templates: [.../* @__PURE__ */ new Set(["
|
|
155
|
+
templates: [.../* @__PURE__ */ new Set(["chapterTitle", ...capabilities.templates])]
|
|
166
156
|
};
|
|
167
157
|
}
|
|
168
158
|
function validateVideoInput(input) {
|
|
@@ -190,16 +180,14 @@ function validateVideoInput(input) {
|
|
|
190
180
|
throw new Error(`Video response supplied media ${index} poster URL must be at most ${MAX_RETAINED_MEDIA_URL_LENGTH} characters`);
|
|
191
181
|
}
|
|
192
182
|
}
|
|
193
|
-
resolveVideoBrand(input.brand);
|
|
194
183
|
}
|
|
195
184
|
function buildInitialComposition(input, audio, snapshotRetention, closerReserveSec, getTemplatePacing) {
|
|
196
185
|
const openingText = typeof input.opening === "string" ? input.opening.trim() : void 0;
|
|
197
186
|
const openingScenes = openingText ? [{
|
|
198
187
|
id: "supplied-opening",
|
|
199
|
-
templateId: "
|
|
188
|
+
templateId: "chapterTitle",
|
|
200
189
|
variables: {
|
|
201
|
-
|
|
202
|
-
mediaType: "gradient"
|
|
190
|
+
title: openingText
|
|
203
191
|
},
|
|
204
192
|
timing: { fixedDuration: 3 }
|
|
205
193
|
}] : [];
|
|
@@ -223,7 +211,7 @@ function buildInitialComposition(input, audio, snapshotRetention, closerReserveS
|
|
|
223
211
|
warnings.push(...paced.warnings);
|
|
224
212
|
}
|
|
225
213
|
const meta = {
|
|
226
|
-
name:
|
|
214
|
+
name: "Video response"
|
|
227
215
|
};
|
|
228
216
|
if (snapshotRetention?.source) {
|
|
229
217
|
meta.source = input.input.trim().slice(0, MAX_RETAINED_SOURCE_LENGTH);
|
|
@@ -241,7 +229,6 @@ function buildInitialComposition(input, audio, snapshotRetention, closerReserveS
|
|
|
241
229
|
scenes,
|
|
242
230
|
...audio ? { audio } : {},
|
|
243
231
|
style: {
|
|
244
|
-
brand: resolveVideoBrand(input.brand),
|
|
245
232
|
density: input.style?.density ?? "normal",
|
|
246
233
|
motion: input.style?.motion ?? "normal",
|
|
247
234
|
defaultBackgroundEffect: input.style?.backgroundEffect ?? "static",
|
|
@@ -704,7 +691,7 @@ function createVideo(rawInput, options) {
|
|
|
704
691
|
position
|
|
705
692
|
}));
|
|
706
693
|
}
|
|
707
|
-
const systemPrompt = options.systemPrompt ?? (await import("./system-prompt-
|
|
694
|
+
const systemPrompt = options.systemPrompt ?? (await import("./system-prompt-SYRT5DWM.js")).createVideoSystemPrompt(input.knowledgeMode);
|
|
708
695
|
const context = { request, systemPrompt, userPrompt, initialConfig, signal: controller.signal };
|
|
709
696
|
attachGenerationLifecycleSink(context, lifecycle);
|
|
710
697
|
for await (const untrustedPart of options.generate(context)) {
|
package/dist/cli.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
3
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-OR52UMSF.js";
|
|
3
|
+
import "./chunk-PAJ44TFW.js";
|
|
4
4
|
import {
|
|
5
5
|
isTemplatePropertyFormatSupported,
|
|
6
6
|
validateTemplateSchemaValue
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EGVQODKU.js";
|
|
8
8
|
import {
|
|
9
9
|
getBuiltinTemplateMetadata,
|
|
10
10
|
listBuiltinTemplateMetadata
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LH4BPALA.js";
|
|
12
12
|
import "./chunk-3O7OMMMF.js";
|
|
13
13
|
import {
|
|
14
14
|
assertTemplateTransitionMetadata
|
|
15
15
|
} from "./chunk-2E6T633S.js";
|
|
16
16
|
import {
|
|
17
17
|
BUILTIN_TEMPLATE_MANIFEST
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-MXEYPK7M.js";
|
|
19
19
|
import {
|
|
20
20
|
externalVideoBackdropCapabilitySource
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-R3XAOMKP.js";
|
|
22
22
|
import {
|
|
23
23
|
getTemplateDefaults,
|
|
24
24
|
isMeaningfullyPresentTemplateValue,
|
|
@@ -1006,8 +1006,12 @@ function validateDiscoveredTemplate(template, cwd) {
|
|
|
1006
1006
|
validateSchema(metadata.schema);
|
|
1007
1007
|
if (metadata.timing !== void 0) {
|
|
1008
1008
|
if (!metadata.timing || typeof metadata.timing !== "object" || Array.isArray(metadata.timing)) throw new Error("timing must be an object");
|
|
1009
|
-
for (const key of Object.keys(metadata.timing)) if (!(/* @__PURE__ */ new Set(["contentFields", "contentUnit"])).has(key)) throw new Error(`timing.${key} is not supported`);
|
|
1010
|
-
if (!Array.isArray(metadata.timing.contentFields)
|
|
1009
|
+
for (const key of Object.keys(metadata.timing)) if (!(/* @__PURE__ */ new Set(["contentFields", "contentUnit", "revealSeconds", "holdSeconds", "exitSeconds"])).has(key)) throw new Error(`timing.${key} is not supported`);
|
|
1010
|
+
if (!Array.isArray(metadata.timing.contentFields)) throw new Error("timing.contentFields must be an array of schema properties");
|
|
1011
|
+
for (const key of ["revealSeconds", "holdSeconds", "exitSeconds"]) {
|
|
1012
|
+
const value = metadata.timing[key];
|
|
1013
|
+
if (value !== void 0 && (typeof value !== "number" || !Number.isFinite(value) || value < 0)) throw new Error(`timing.${key} must be a finite non-negative number`);
|
|
1014
|
+
}
|
|
1011
1015
|
const timingFields = /* @__PURE__ */ new Set();
|
|
1012
1016
|
for (const field of metadata.timing.contentFields) {
|
|
1013
1017
|
if (typeof field !== "string" || !Object.hasOwn(metadata.schema.properties, field)) throw new Error(`timing.contentFields references undeclared property ${JSON.stringify(field)}`);
|
|
@@ -1017,6 +1021,11 @@ function validateDiscoveredTemplate(template, cwd) {
|
|
|
1017
1021
|
if (!CONTENT_UNITS.has(metadata.timing.contentUnit)) throw new Error("timing.contentUnit contains an unsupported value");
|
|
1018
1022
|
}
|
|
1019
1023
|
const defaults = getTemplateDefaults(metadata.schema);
|
|
1024
|
+
const smokeVariables = { ...defaults };
|
|
1025
|
+
for (const field of metadata.schema.required ?? []) {
|
|
1026
|
+
const example = metadata.schema.properties[field]?.examples?.[0];
|
|
1027
|
+
if (!(field in smokeVariables) && example !== void 0) smokeVariables[field] = example;
|
|
1028
|
+
}
|
|
1020
1029
|
if (template.examples !== void 0 && !Array.isArray(template.examples)) throw new Error("examples must be an array");
|
|
1021
1030
|
const supplied = template.examples ?? [];
|
|
1022
1031
|
for (const [index, value] of supplied.entries()) {
|
|
@@ -1031,7 +1040,7 @@ function validateDiscoveredTemplate(template, cwd) {
|
|
|
1031
1040
|
name,
|
|
1032
1041
|
variables: { ...defaults, ...variables },
|
|
1033
1042
|
enforceRequiredAnyOf: true
|
|
1034
|
-
})) : [{ name: "defaults", variables:
|
|
1043
|
+
})) : [{ name: "defaults", variables: smokeVariables, enforceRequiredAnyOf: false }];
|
|
1035
1044
|
const names = /* @__PURE__ */ new Set();
|
|
1036
1045
|
for (const example of examples) {
|
|
1037
1046
|
if (typeof example.name !== "string" || !example.name.trim()) throw new Error("example names must be non-empty strings");
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
editorialFont,
|
|
3
|
+
editorialLabel,
|
|
4
|
+
fade
|
|
5
|
+
} from "./chunk-4YM2M62S.js";
|
|
6
|
+
|
|
7
|
+
// src/visual-system/scene-templates/comparison.tsx
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
function ComparisonScene({ variables, width, height, progress, motionProgress = progress, safeZone }) {
|
|
10
|
+
const portrait = height > width, u = Math.min(width, height);
|
|
11
|
+
const side = Math.max(width * 0.12, safeZone.left, safeZone.right);
|
|
12
|
+
const top = Math.max(height * 0.2, safeZone.top), bottom = height - Math.max(height * 0.23, safeZone.bottom);
|
|
13
|
+
const area = bottom - top, cy = (top + bottom) / 2, available = width - side * 2;
|
|
14
|
+
const entries = [{ label: String(variables.leftLabel ?? ""), text: String(variables.leftText ?? "") }, { label: String(variables.rightLabel ?? ""), text: String(variables.rightText ?? "") }];
|
|
15
|
+
const textWidth = portrait ? available : available * 0.39;
|
|
16
|
+
return /* @__PURE__ */ jsxs("div", { "data-template": "comparison", style: { position: "absolute", inset: 0, background: "#000", color: "#fff", fontFamily: editorialFont, overflow: "hidden" }, children: [
|
|
17
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { position: "absolute", left: portrait ? width * 0.32 : width / 2, top: portrait ? cy : top + area * 0.18, width: portrait ? width * 0.36 : u * 1e-3, height: portrait ? u * 1e-3 : area * 0.64, background: "#fff", opacity: 0.22 * fade((motionProgress - 0.16) / 0.18) } }),
|
|
18
|
+
entries.map((entry, i) => /* @__PURE__ */ jsxs("div", { "data-comparison-side": i === 0 ? "left" : "right", style: { position: "absolute", left: portrait ? side : side + available * (i === 0 ? 0.055 : 0.555), top: portrait ? top + area * (i === 0 ? 0.25 : 0.75) : cy, width: textWidth, transform: "translateY(-50%)", textAlign: "center", opacity: fade((motionProgress - 0.04 - i * 0.22) / 0.2) }, children: [
|
|
19
|
+
entry.label && /* @__PURE__ */ jsx("div", { style: { ...editorialLabel(u), marginBottom: u * 0.028 }, children: entry.label }),
|
|
20
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: u * 0.058, fontWeight: 500, lineHeight: 1.22, letterSpacing: "-.025em", textWrap: "balance", overflowWrap: "anywhere" }, children: entry.text })
|
|
21
|
+
] }, i))
|
|
22
|
+
] });
|
|
23
|
+
}
|
|
24
|
+
var ComparisonSceneTemplate = ComparisonScene;
|
|
25
|
+
export {
|
|
26
|
+
ComparisonSceneTemplate
|
|
27
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createVideo
|
|
3
|
+
} from "./chunk-ZDJNFA52.js";
|
|
4
|
+
import "./chunk-E7CL7UPB.js";
|
|
5
|
+
import "./chunk-RXTN2CW6.js";
|
|
6
|
+
import "./chunk-7M56IUUX.js";
|
|
7
|
+
import "./chunk-AUPC6MDK.js";
|
|
8
|
+
import "./chunk-7NZOMTAL.js";
|
|
9
|
+
import "./chunk-3O7OMMMF.js";
|
|
10
|
+
export {
|
|
11
|
+
createVideo
|
|
12
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
editorialFont,
|
|
3
|
+
fade
|
|
4
|
+
} from "./chunk-4YM2M62S.js";
|
|
5
|
+
|
|
6
|
+
// src/visual-system/scene-templates/editorial-timeline.tsx
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var timelineTiming = (index) => ({ nodeStart: index === 0 ? 0.06 : 0.23 + (index - 1) * 0.11, lineStart: 0.14 + index * 0.11, lineDuration: 0.09, entranceDuration: 0.16 });
|
|
9
|
+
function TimelineScene({ variables, progress, motionProgress = progress, width, height, safeZone }) {
|
|
10
|
+
const events = (Array.isArray(variables.events) ? variables.events : []).slice(0, 5).map((e) => ({ label: String(e?.label ?? "") }));
|
|
11
|
+
const portrait = height > width, u = Math.min(width, height), n = Math.max(1, events.length);
|
|
12
|
+
const side = Math.max(width * 0.13, safeZone.left, safeZone.right), available = width - side * 2;
|
|
13
|
+
const top = Math.max(height * 0.2, safeZone.top), bottom = height - Math.max(height * 0.24, safeZone.bottom);
|
|
14
|
+
const slot = portrait ? (bottom - top) / n : available / n;
|
|
15
|
+
const points = events.map((_, i) => ({ x: portrait ? side : side + slot * (i + 0.5), y: portrait ? top + slot * (i + 0.5) : height * 0.43 }));
|
|
16
|
+
const radius = u * 45e-4;
|
|
17
|
+
return /* @__PURE__ */ jsxs("div", { "data-template": "timeline", style: { position: "absolute", inset: 0, overflow: "hidden", background: "#000", fontFamily: editorialFont, color: "#fff" }, children: [
|
|
18
|
+
points.slice(0, -1).map((point, i) => {
|
|
19
|
+
const next = points[i + 1], timing = timelineTiming(i), line = fade((motionProgress - timing.lineStart) / timing.lineDuration);
|
|
20
|
+
return /* @__PURE__ */ jsx("div", { "data-step-connector": "true", style: { position: "absolute", left: point.x, top: point.y, width: portrait ? u * 1e-3 : next.x - point.x, height: portrait ? next.y - point.y : u * 1e-3, background: "#fff", opacity: 0.3, transform: portrait ? `scaleY(${line})` : `scaleX(${line})`, transformOrigin: portrait ? "top" : "left" } }, `line-${i}`);
|
|
21
|
+
}),
|
|
22
|
+
points.map((point, i) => {
|
|
23
|
+
const timing = timelineTiming(i), event = events[i], opacity = fade((motionProgress - timing.nodeStart) / timing.entranceDuration);
|
|
24
|
+
const textW = portrait ? available - u * 0.055 : slot * 0.86;
|
|
25
|
+
return /* @__PURE__ */ jsxs("div", { "data-template-item": "steps", style: { opacity }, children: [
|
|
26
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { position: "absolute", left: point.x - radius, top: point.y - radius, width: radius * 2, height: radius * 2, borderRadius: "50%", background: "#fff" } }),
|
|
27
|
+
/* @__PURE__ */ jsx("div", { style: { position: "absolute", left: portrait ? point.x + u * 0.055 : point.x - textW / 2, top: portrait ? point.y : point.y + u * 0.05, width: textW, transform: portrait ? "translateY(-50%)" : void 0, textAlign: portrait ? "left" : "center" }, children: /* @__PURE__ */ jsx("div", { style: { fontSize: u * (portrait ? 0.052 : 0.041), fontWeight: 500, lineHeight: 1.22, letterSpacing: "-.025em", textWrap: "balance", overflowWrap: "anywhere" }, children: event.label }) })
|
|
28
|
+
] }, i);
|
|
29
|
+
})
|
|
30
|
+
] });
|
|
31
|
+
}
|
|
32
|
+
var TimelineSceneTemplate = TimelineScene;
|
|
33
|
+
export {
|
|
34
|
+
TimelineSceneTemplate,
|
|
35
|
+
timelineTiming
|
|
36
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as VideoOrientation, V as VideoStyle, c as Video, a as VideoCapabilities, d as VideoAudio, e as VideoScene, f as VIDEO_PROTOCOL_VERSION } from './types-
|
|
1
|
+
import { b as VideoOrientation, V as VideoStyle, c as Video, a as VideoCapabilities, d as VideoAudio, e as VideoScene, f as VIDEO_PROTOCOL_VERSION } from './types-DdZw4GRQ.js';
|
|
2
2
|
|
|
3
3
|
type VideoWarningCategory = "validation" | "readability" | "grounding" | "provider" | "media" | "protocol";
|
|
4
4
|
type VideoWarningCode = "scene_duration_adjusted" | "scene_omitted_unreadable" | "scene_omitted_for_closer" | "scene_variable_clipped" | "chart_scale_imbalance" | "plan_incomplete" | "plan_missing_closer" | "provider_warning" | "provider_diagnostics_unavailable" | "media_budget_reached";
|