motionrender 0.2.3 → 0.2.4
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/dist/cli.js +35 -9
- package/dist/types/packages/cli/src/templates.d.ts +2 -0
- package/dist/types/packages/jobs/src/env.d.ts +3 -0
- package/package.json +1 -1
- package/studio/assets/index-BGdqA-kT.js +10 -0
- package/studio/index.html +1 -1
- package/templates/product-card/composition.json +11 -4
- package/templates/product-card/template.json +3 -3
- package/templates/social-reel/composition.json +19 -12
- package/templates/social-reel/template.json +3 -3
- package/studio/assets/index-n3DJI_GV.js +0 -10
package/dist/cli.js
CHANGED
|
@@ -4430,6 +4430,13 @@ var init_template = __esm({
|
|
|
4430
4430
|
};
|
|
4431
4431
|
templatesFor = (templates, size) => templates.filter((template) => sameShape(template, size));
|
|
4432
4432
|
systemText = `You fill in ready-made video templates. Reply with JSON only: {"template": "<id>", "theme": "<theme id, only for templates that take a theme>", "values": {"<variable>": <value>, ...}}.
|
|
4433
|
+
Choose the template that best matches the story structure and topic of the brief (stories and stats -> story-tall; features and cards -> showcase-tall; tips and steps -> social-reel).
|
|
4434
|
+
For templates that take a theme, ALWAYS choose the theme that best matches the mood, industry, and visual tone of the brief:
|
|
4435
|
+
- "midnight": modern tech, SaaS, B2B, cloud, finance
|
|
4436
|
+
- "neon": gaming, nightlife, social apps, crypto, cutting-edge AI
|
|
4437
|
+
- "espresso": artisan craft, food & beverage, coffee, lifestyle, podcasts, warmth
|
|
4438
|
+
- "paper": clean editorial, education, publishing, thought leadership, light minimalist
|
|
4439
|
+
- "signal": high-impact, fitness, sports, breaking news, urgency
|
|
4433
4440
|
Picture variables (image, image2\u2026) take the id of one supplied picture, or "" for none; never invent ids. Examples only show the length and kind of text wanted: never reuse their wording (including labels like INTRODUCING); use the brief's own names, numbers and details, and prefer a concrete line over a generic one such as "Ready to start?". Rules: write the words viewers will read, never a description of the video; do not invent dates, prices or claims that are not in the brief; use only the listed variable names; write real copy for the brief, about as long as each example (never much longer); "color" values are hex like "#f4d58d"; list values are arrays of objects with the listed fields.
|
|
4434
4441
|
If no template suits the brief, reply {"template": "none"}.`;
|
|
4435
4442
|
}
|
|
@@ -5970,17 +5977,31 @@ var init_plan = __esm({
|
|
|
5970
5977
|
init_registry();
|
|
5971
5978
|
paths = ["template", "json", "react"];
|
|
5972
5979
|
allowedPaths = (options3) => (options3.paths ?? paths).filter((path) => path !== "react" || options3.allowReact);
|
|
5973
|
-
systemText2 = (options3) => `You are the production planner for Open Video Engine. Decide how the brief below should be produced, before anything is generated.
|
|
5980
|
+
systemText2 = (options3) => `You are the creative production planner for Open Video Engine. Decide how the brief below should be produced, before anything is generated.
|
|
5974
5981
|
Reply with ONE JSON object and nothing else:
|
|
5975
5982
|
{
|
|
5976
5983
|
"path": "template" | "json" | "react",
|
|
5977
|
-
"template": "<template id>", // only with "template": the one template that suits the brief
|
|
5984
|
+
"template": "<template id>", // only with "template": the one template that best suits the brief's structure and topic
|
|
5978
5985
|
"theme": "<theme id>", // optional, only with a template that takes a theme
|
|
5979
5986
|
"idea": "<what the video says, in one line>",
|
|
5980
5987
|
"beats": [{ "name": "Hook", "onScreen": "what is on screen, concretely", "seconds": 3, "motion": "how it moves in" }],
|
|
5981
5988
|
"reasons": ["why this path suits this brief"]
|
|
5982
5989
|
}
|
|
5983
|
-
Templates
|
|
5990
|
+
Templates provide proven layouts, but pick the template that specifically fits the brief's narrative style:
|
|
5991
|
+
- Testimonials, customer stories, quotes, metrics, or personal founder stories: choose "story-tall" or "quote-card".
|
|
5992
|
+
- Multi-feature tours, app UI cards, feature lists, and product showcases: choose "showcase-tall", "product-wide" or "product-card".
|
|
5993
|
+
- Quick tips, 3-step processes, how-to guides, and numbered reels: choose "social-reel".
|
|
5994
|
+
- Company keynotes, presentations, and product launch films: choose "keynote-wide", "launch-wide" or "case-study".
|
|
5995
|
+
- Choose "json" when the brief requires a bespoke kinetic video with custom motion graphics, camera moves, and scene architecture.
|
|
5996
|
+
- Choose "react" only when allowed: it writes React code for bespoke high-end motion graphics.
|
|
5997
|
+
|
|
5998
|
+
Themes: For templates that take a theme, ALWAYS choose the theme matching the tone and brand of the brief:
|
|
5999
|
+
- "midnight": modern tech, SaaS, B2B, cloud, finance (deep slate navy, sky blue).
|
|
6000
|
+
- "neon": gaming, nightlife, social apps, crypto, cutting-edge AI (dark violet, hot magenta, electric lime).
|
|
6001
|
+
- "espresso": artisan craft, food & beverage, coffee, lifestyle, podcasts, warmth (dark espresso, amber gold).
|
|
6002
|
+
- "paper": clean editorial, education, publishing, thought leadership (clean light aesthetic, deep ink).
|
|
6003
|
+
- "signal": high-impact, fitness, sports, breaking news, urgency (bold monochrome with alert red).
|
|
6004
|
+
Every beat needs a concrete picture, not a mood.
|
|
5984
6005
|
Reply with "path" set to one of: ${allowedPaths(options3).join(" | ")}.
|
|
5985
6006
|
Available capabilities:
|
|
5986
6007
|
${describeCapabilities(options3.registry, options3)}`;
|
|
@@ -6115,7 +6136,7 @@ async function cliRegistry() {
|
|
|
6115
6136
|
async function composeSmart(provider, options3, mode = {}) {
|
|
6116
6137
|
const needsFull = mode.full || !!options3.fields?.length || (options3.assets ?? []).some((asset) => asset.type !== "image");
|
|
6117
6138
|
let plan;
|
|
6118
|
-
if (!mode.noPlan) {
|
|
6139
|
+
if (!mode.noPlan && !mode.full && !mode.template) {
|
|
6119
6140
|
const registry = mode.registry ?? await cliRegistry();
|
|
6120
6141
|
try {
|
|
6121
6142
|
plan = await planBuild(provider, { ...options3, registry, maxAttempts: Math.min(options3.maxAttempts ?? 2, 2) });
|
|
@@ -6123,13 +6144,16 @@ async function composeSmart(provider, options3, mode = {}) {
|
|
|
6123
6144
|
options3.onProgress?.(`Planning skipped (${error.message.split("\n")[0]}); using the built-in routing.`);
|
|
6124
6145
|
}
|
|
6125
6146
|
}
|
|
6126
|
-
const templatePath = plan ? plan.path === "template" : !needsFull;
|
|
6147
|
+
const templatePath = (plan ? plan.path === "template" : !needsFull) || Boolean(mode.template);
|
|
6127
6148
|
if (templatePath && !needsFull) {
|
|
6128
6149
|
try {
|
|
6129
6150
|
const choices = await templateChoices();
|
|
6130
|
-
const
|
|
6131
|
-
const
|
|
6132
|
-
const
|
|
6151
|
+
const targetTemplateId = mode.template ?? plan?.template;
|
|
6152
|
+
const picked = targetTemplateId ? choices.filter((choice) => choice.id === targetTemplateId) : choices;
|
|
6153
|
+
const targetThemeId = mode.theme ?? plan?.theme;
|
|
6154
|
+
const allThemes = await listThemes();
|
|
6155
|
+
const themes = targetThemeId ? allThemes.filter((theme) => theme.id === targetThemeId) : allThemes;
|
|
6156
|
+
const filled2 = await composeFromTemplate(provider, picked.length ? picked : choices, { ...options3, themes: themes.length ? themes : allThemes });
|
|
6133
6157
|
if (filled2) {
|
|
6134
6158
|
const wanted = options3.durationSeconds;
|
|
6135
6159
|
const current = filled2.composition.durationFrames / filled2.composition.fps;
|
|
@@ -7188,7 +7212,9 @@ function createHandlers(env) {
|
|
|
7188
7212
|
maxAttempts: integerIn(input.maxAttempts, 3, "maxAttempts", 1, 10),
|
|
7189
7213
|
onProgress: (message2) => progress(message2)
|
|
7190
7214
|
};
|
|
7191
|
-
const
|
|
7215
|
+
const theme = typeof input.theme === "string" && input.theme.trim() ? input.theme.trim() : void 0;
|
|
7216
|
+
const template = typeof input.template === "string" && input.template.trim() ? input.template.trim() : void 0;
|
|
7217
|
+
const result = await capabilities.composeSmart(ai, options3, { full, theme, template });
|
|
7192
7218
|
let composition = result.composition;
|
|
7193
7219
|
let narration;
|
|
7194
7220
|
if (options3.narration) {
|
|
@@ -56,6 +56,8 @@ export declare function composeSmart(provider: AiProvider, options: ComposeOptio
|
|
|
56
56
|
full?: boolean;
|
|
57
57
|
noPlan?: boolean;
|
|
58
58
|
registry?: Registry;
|
|
59
|
+
theme?: string;
|
|
60
|
+
template?: string;
|
|
59
61
|
}): Promise<ComposeResult & {
|
|
60
62
|
template?: string;
|
|
61
63
|
source?: Record<string, unknown>;
|
|
@@ -30,6 +30,9 @@ export interface JobPaths {
|
|
|
30
30
|
export type JobCapabilities = {
|
|
31
31
|
composeSmart(provider: AiProvider, options: ComposeOptions, mode: {
|
|
32
32
|
full?: boolean;
|
|
33
|
+
noPlan?: boolean;
|
|
34
|
+
theme?: string;
|
|
35
|
+
template?: string;
|
|
33
36
|
}): Promise<ComposeResult & {
|
|
34
37
|
template?: string;
|
|
35
38
|
source?: Record<string, unknown>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "motionrender",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "JSON-first, frame-deterministic motion graphics video engine: render compositions to MP4, WebM, ProRes, GIF or PNG frames from Node or the command line.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|