vargai 0.4.0-alpha2 → 0.4.0-alpha21

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 (69) hide show
  1. package/README.md +483 -61
  2. package/launch-videos/06-kawaii-fruits.tsx +93 -0
  3. package/launch-videos/07-ugc-weight-loss.tsx +132 -0
  4. package/launch-videos/08-talking-head-varg.tsx +107 -0
  5. package/launch-videos/09-girl.tsx +160 -0
  6. package/launch-videos/README.md +42 -0
  7. package/package.json +8 -4
  8. package/skills/varg-video-generation/SKILL.md +213 -0
  9. package/skills/varg-video-generation/references/templates.md +380 -0
  10. package/skills/varg-video-generation/scripts/setup.ts +265 -0
  11. package/src/ai-sdk/cache.ts +1 -1
  12. package/src/ai-sdk/middleware/wrap-image-model.ts +4 -21
  13. package/src/ai-sdk/middleware/wrap-music-model.ts +4 -16
  14. package/src/ai-sdk/middleware/wrap-video-model.ts +5 -17
  15. package/src/ai-sdk/providers/editly/index.ts +110 -53
  16. package/src/ai-sdk/providers/editly/types.ts +2 -0
  17. package/src/ai-sdk/providers/elevenlabs.ts +10 -2
  18. package/src/ai-sdk/providers/fal.ts +6 -1
  19. package/src/cli/commands/find.tsx +1 -0
  20. package/src/cli/commands/hello.ts +85 -0
  21. package/src/cli/commands/help.tsx +18 -30
  22. package/src/cli/commands/index.ts +9 -1
  23. package/src/cli/commands/init.tsx +412 -0
  24. package/src/cli/commands/list.tsx +1 -0
  25. package/src/cli/commands/render.tsx +292 -80
  26. package/src/cli/commands/run.tsx +1 -0
  27. package/src/cli/commands/studio.ts +47 -0
  28. package/src/cli/commands/which.tsx +1 -0
  29. package/src/cli/index.ts +20 -5
  30. package/src/cli/ui/components/Badge.tsx +1 -0
  31. package/src/cli/ui/components/DataTable.tsx +1 -0
  32. package/src/cli/ui/components/Header.tsx +1 -0
  33. package/src/cli/ui/components/HelpBlock.tsx +1 -0
  34. package/src/cli/ui/components/KeyValue.tsx +1 -0
  35. package/src/cli/ui/components/OptionRow.tsx +1 -0
  36. package/src/cli/ui/components/Separator.tsx +1 -0
  37. package/src/cli/ui/components/StatusBox.tsx +1 -0
  38. package/src/cli/ui/components/VargBox.tsx +1 -0
  39. package/src/cli/ui/components/VargProgress.tsx +1 -0
  40. package/src/cli/ui/components/VargSpinner.tsx +1 -0
  41. package/src/cli/ui/components/VargText.tsx +1 -0
  42. package/src/react/assets.ts +9 -0
  43. package/src/react/elements.ts +0 -5
  44. package/src/react/examples/branching.tsx +6 -4
  45. package/src/react/examples/character-video.tsx +13 -10
  46. package/src/react/examples/madi.tsx +13 -10
  47. package/src/react/examples/mcmeows.tsx +40 -0
  48. package/src/react/examples/music-defaults.tsx +24 -0
  49. package/src/react/examples/quickstart-test.tsx +97 -0
  50. package/src/react/index.ts +1 -2
  51. package/src/react/react.test.ts +10 -10
  52. package/src/react/renderers/clip.ts +13 -24
  53. package/src/react/renderers/context.ts +3 -0
  54. package/src/react/renderers/image.ts +4 -2
  55. package/src/react/renderers/index.ts +0 -1
  56. package/src/react/renderers/music.ts +3 -3
  57. package/src/react/renderers/progress.ts +1 -3
  58. package/src/react/renderers/render.ts +49 -63
  59. package/src/react/renderers/speech.ts +2 -2
  60. package/src/react/renderers/video.ts +46 -9
  61. package/src/react/types.ts +18 -14
  62. package/src/studio/stages.ts +4 -24
  63. package/src/studio/step-renderer.ts +0 -15
  64. package/test-sync-v2.ts +30 -0
  65. package/test-sync-v2.tsx +29 -0
  66. package/tsconfig.json +5 -3
  67. package/video.tsx +7 -0
  68. package/src/react/cli.ts +0 -52
  69. package/src/react/renderers/animate.ts +0 -59
@@ -1,94 +1,306 @@
1
+ /** @jsxImportSource react */
2
+
3
+ import { existsSync, mkdirSync } from "node:fs";
4
+ import { resolve } from "node:path";
1
5
  import { defineCommand } from "citty";
6
+ import { Box, Text } from "ink";
2
7
  import { render } from "../../react/render";
3
- import type { RenderMode, VargElement } from "../../react/types";
8
+ import type { DefaultModels, RenderMode, VargElement } from "../../react/types";
9
+ import { Header, HelpBlock, VargBox, VargText } from "../ui/index.ts";
10
+ import { renderStatic } from "../ui/render.ts";
11
+
12
+ const AUTO_IMPORTS = `/** @jsxImportSource vargai */
13
+ import { Captions, Clip, Image, Music, Overlay, Packshot, Render, Slider, Speech, Split, Subtitle, Swipe, TalkingHead, Title, Video, Grid, SplitLayout } from "vargai/react";
14
+ import { fal, elevenlabs, replicate } from "vargai/ai";
15
+ `;
16
+
17
+ async function detectDefaultModels(): Promise<DefaultModels | undefined> {
18
+ const defaults: DefaultModels = {};
19
+
20
+ if (process.env.FAL_KEY) {
21
+ const { fal } = await import("../../ai-sdk/providers/fal");
22
+ defaults.image = fal.imageModel("flux-schnell");
23
+ defaults.video = fal.videoModel("wan-2.5");
24
+ }
25
+
26
+ if (process.env.ELEVENLABS_API_KEY) {
27
+ const { elevenlabs } = await import("../../ai-sdk/providers/elevenlabs");
28
+ defaults.speech = elevenlabs.speechModel("eleven_multilingual_v2");
29
+ defaults.music = elevenlabs.musicModel("music_v1");
30
+ }
31
+
32
+ return Object.keys(defaults).length > 0 ? defaults : undefined;
33
+ }
34
+
35
+ async function loadComponent(filePath: string): Promise<VargElement> {
36
+ const resolvedPath = resolve(filePath);
37
+ const source = await Bun.file(resolvedPath).text();
38
+
39
+ const hasAnyImport = source.includes(" from ");
40
+ const hasVargaiImport =
41
+ source.includes("from 'vargai") ||
42
+ source.includes('from "vargai') ||
43
+ source.includes("from '@vargai") ||
44
+ source.includes('from "@vargai');
45
+
46
+ const hasJsxPragma =
47
+ source.includes("@jsxImportSource") || source.includes("@jsx ");
48
+
49
+ // file has imports (relative or absolute) - import directly to preserve paths
50
+ if (hasAnyImport) {
51
+ const mod = await import(resolvedPath);
52
+ return mod.default;
53
+ }
54
+
55
+ // no imports - inject auto-imports and jsx pragma
56
+ const pkgDir = new URL("../../..", import.meta.url).pathname;
57
+ const tmpDir = `${pkgDir}/.cache/varg-render`;
58
+ if (!existsSync(tmpDir)) {
59
+ mkdirSync(tmpDir, { recursive: true });
60
+ }
61
+
62
+ const tmpFile = `${tmpDir}/${Date.now()}.tsx`;
63
+ await Bun.write(tmpFile, AUTO_IMPORTS + source);
64
+
65
+ try {
66
+ const mod = await import(tmpFile);
67
+ return mod.default;
68
+ } finally {
69
+ (await Bun.file(tmpFile).exists()) && (await Bun.write(tmpFile, ""));
70
+ }
71
+ }
72
+
73
+ const sharedArgs = {
74
+ file: {
75
+ type: "positional" as const,
76
+ description: "component file (.tsx)",
77
+ required: true,
78
+ },
79
+ output: {
80
+ type: "string" as const,
81
+ alias: "o",
82
+ description: "output path",
83
+ },
84
+ cache: {
85
+ type: "string" as const,
86
+ alias: "c",
87
+ description: "cache directory",
88
+ default: ".cache/ai",
89
+ },
90
+ quiet: {
91
+ type: "boolean" as const,
92
+ alias: "q",
93
+ description: "minimal output",
94
+ default: false,
95
+ },
96
+ "no-cache": {
97
+ type: "boolean" as const,
98
+ description: "disable cache (don't read or write)",
99
+ default: false,
100
+ },
101
+ verbose: {
102
+ type: "boolean" as const,
103
+ alias: "v",
104
+ description: "show ffmpeg commands",
105
+ default: false,
106
+ },
107
+ };
108
+
109
+ async function runRender(
110
+ args: Record<string, unknown>,
111
+ mode: RenderMode,
112
+ commandName: string,
113
+ ) {
114
+ const file = args.file as string;
115
+
116
+ if (!file) {
117
+ console.error(`usage: varg ${commandName} <component.tsx> [-o output.mp4]`);
118
+ process.exit(1);
119
+ }
120
+
121
+ const component = await loadComponent(file);
122
+
123
+ if (!component || component.type !== "render") {
124
+ console.error("error: default export must be a <Render> element");
125
+ process.exit(1);
126
+ }
127
+
128
+ const basename = file
129
+ .replace(/\.tsx?$/, "")
130
+ .split("/")
131
+ .pop();
132
+ const outputPath = (args.output as string) ?? `output/${basename}.mp4`;
133
+
134
+ if (!args.quiet) {
135
+ const modeLabel = mode === "preview" ? " (fast)" : "";
136
+ console.log(`rendering ${file} → ${outputPath}${modeLabel}`);
137
+ }
138
+
139
+ const useCache = !args["no-cache"] && mode !== "preview";
140
+
141
+ const defaults = await detectDefaultModels();
142
+
143
+ const buffer = await render(component, {
144
+ output: outputPath,
145
+ cache: useCache ? (args.cache as string) : undefined,
146
+ mode,
147
+ defaults,
148
+ verbose: args.verbose as boolean,
149
+ });
150
+
151
+ if (!args.quiet) {
152
+ console.log(`done! ${buffer.byteLength} bytes → ${outputPath}`);
153
+ }
154
+ }
4
155
 
5
156
  export const renderCmd = defineCommand({
6
157
  meta: {
7
158
  name: "render",
8
- description: "render a react component to video",
159
+ description: "render to video (strict mode - fails on errors)",
9
160
  },
10
- args: {
11
- file: {
12
- type: "positional",
13
- description: "component file (.tsx)",
14
- required: true,
15
- },
16
- output: {
17
- type: "string",
18
- alias: "o",
19
- description: "output path",
161
+ args: sharedArgs,
162
+ async run({ args }) {
163
+ await runRender(args, "strict", "render");
164
+ },
165
+ });
166
+
167
+ export const previewCmd = defineCommand({
168
+ meta: {
169
+ name: "preview",
170
+ description: "render with all placeholders (no generation)",
171
+ },
172
+ args: sharedArgs,
173
+ async run({ args }) {
174
+ await runRender(args, "preview", "preview");
175
+ },
176
+ });
177
+
178
+ function RenderHelpView() {
179
+ const examples = [
180
+ {
181
+ command: "varg render video.tsx",
182
+ description: "render component to output/video.mp4",
20
183
  },
21
- cache: {
22
- type: "string",
23
- alias: "c",
24
- description: "cache directory",
25
- default: ".cache/ai",
184
+ {
185
+ command: "varg render video.tsx -o my-video.mp4",
186
+ description: "custom output path",
26
187
  },
27
- quiet: {
28
- type: "boolean",
29
- alias: "q",
30
- description: "minimal output",
31
- default: false,
188
+ {
189
+ command: "varg preview video.tsx",
190
+ description: "fast preview with placeholders",
32
191
  },
33
- strict: {
34
- type: "boolean",
35
- description: "fail on provider errors (no fallback)",
36
- default: false,
192
+ ];
193
+
194
+ return (
195
+ <VargBox title="varg render">
196
+ <Box marginBottom={1}>
197
+ <Text>
198
+ render jsx components to video. the react engine for ai video.
199
+ </Text>
200
+ </Box>
201
+
202
+ <Header>USAGE</Header>
203
+ <Box paddingLeft={2} marginBottom={1}>
204
+ <VargText variant="accent">
205
+ varg render {"<file.tsx>"} [options]
206
+ </VargText>
207
+ </Box>
208
+
209
+ <Header>OPTIONS</Header>
210
+ <Box flexDirection="column" paddingLeft={2} marginBottom={1}>
211
+ <Text>
212
+ <VargText variant="accent">-o, --output </VargText>output path
213
+ (default: output/{"<name>"}.mp4)
214
+ </Text>
215
+ <Text>
216
+ <VargText variant="accent">-c, --cache </VargText>cache directory
217
+ (default: .cache/ai)
218
+ </Text>
219
+ <Text>
220
+ <VargText variant="accent">--no-cache </VargText>disable cache
221
+ </Text>
222
+ <Text>
223
+ <VargText variant="accent">-q, --quiet </VargText>minimal output
224
+ </Text>
225
+ <Text>
226
+ <VargText variant="accent">-v, --verbose </VargText>show ffmpeg
227
+ commands
228
+ </Text>
229
+ </Box>
230
+
231
+ <Header>COMPONENTS</Header>
232
+ <Box flexDirection="column" paddingLeft={2} marginBottom={1}>
233
+ <Text>{"<Render>"} root container (width, height, fps)</Text>
234
+ <Text>{"<Clip>"} time segment with duration</Text>
235
+ <Text>{"<Video>"} ai-generated or source video</Text>
236
+ <Text>{"<Image>"} ai-generated or static image</Text>
237
+ <Text>{"<Speech>"} text-to-speech audio</Text>
238
+ <Text>{"<Music>"} background music</Text>
239
+ <Text>{"<Captions>"} auto-generated subtitles</Text>
240
+ </Box>
241
+
242
+ <Header>EXAMPLES</Header>
243
+ <Box marginTop={1}>
244
+ <HelpBlock examples={examples} />
245
+ </Box>
246
+ </VargBox>
247
+ );
248
+ }
249
+
250
+ function PreviewHelpView() {
251
+ const examples = [
252
+ {
253
+ command: "varg preview video.tsx",
254
+ description: "quick test without ai calls",
37
255
  },
38
- preview: {
39
- type: "boolean",
40
- description: "skip all generation, use placeholders only",
41
- default: false,
256
+ {
257
+ command: "varg preview video.tsx -o test.mp4",
258
+ description: "preview to custom path",
42
259
  },
43
- },
44
- async run({ args }) {
45
- const file = args.file as string;
260
+ ];
46
261
 
47
- if (!file) {
48
- console.error("usage: varg render <component.tsx> [-o output.mp4]");
49
- process.exit(1);
50
- }
262
+ return (
263
+ <VargBox title="varg preview">
264
+ <Box marginBottom={1}>
265
+ <Text>
266
+ fast preview mode - uses placeholders instead of ai generation.
267
+ </Text>
268
+ </Box>
51
269
 
52
- const resolvedPath = Bun.resolveSync(file, process.cwd());
53
- const mod = await import(resolvedPath);
54
- const component: VargElement = mod.default;
55
-
56
- if (!component || component.type !== "render") {
57
- console.error("error: default export must be a <Render> element");
58
- process.exit(1);
59
- }
60
-
61
- const outputPath =
62
- args.output ??
63
- `output/${file
64
- .replace(/\.tsx?$/, "")
65
- .split("/")
66
- .pop()}.mp4`;
67
-
68
- const mode: RenderMode = args.strict
69
- ? "strict"
70
- : args.preview
71
- ? "preview"
72
- : "default";
73
-
74
- if (!args.quiet) {
75
- const modeLabel =
76
- mode === "preview"
77
- ? " (preview)"
78
- : mode === "strict"
79
- ? " (strict)"
80
- : "";
81
- console.log(`rendering ${file} → ${outputPath}${modeLabel}`);
82
- }
83
-
84
- const buffer = await render(component, {
85
- output: outputPath,
86
- cache: args.cache,
87
- mode,
88
- });
89
-
90
- if (!args.quiet) {
91
- console.log(`done! ${buffer.byteLength} bytes → ${outputPath}`);
92
- }
93
- },
94
- });
270
+ <Header>USAGE</Header>
271
+ <Box paddingLeft={2} marginBottom={1}>
272
+ <VargText variant="accent">
273
+ varg preview {"<file.tsx>"} [options]
274
+ </VargText>
275
+ </Box>
276
+
277
+ <Header>OPTIONS</Header>
278
+ <Box flexDirection="column" paddingLeft={2} marginBottom={1}>
279
+ <Text>
280
+ <VargText variant="accent">-o, --output </VargText>output path
281
+ (default: output/{"<name>"}.mp4)
282
+ </Text>
283
+ <Text>
284
+ <VargText variant="accent">-q, --quiet </VargText>minimal output
285
+ </Text>
286
+ <Text>
287
+ <VargText variant="accent">-v, --verbose </VargText>show ffmpeg
288
+ commands
289
+ </Text>
290
+ </Box>
291
+
292
+ <Header>EXAMPLES</Header>
293
+ <Box marginTop={1}>
294
+ <HelpBlock examples={examples} />
295
+ </Box>
296
+ </VargBox>
297
+ );
298
+ }
299
+
300
+ export function showRenderHelp() {
301
+ renderStatic(<RenderHelpView />);
302
+ }
303
+
304
+ export function showPreviewHelp() {
305
+ renderStatic(<PreviewHelpView />);
306
+ }
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * varg run command
3
4
  * Ink-based execution with live status updates
@@ -0,0 +1,47 @@
1
+ import { resolve } from "node:path";
2
+ import { defineCommand } from "citty";
3
+ import { createStudioServer } from "../../studio/server";
4
+
5
+ export const studioCmd = defineCommand({
6
+ meta: {
7
+ name: "studio",
8
+ description: "launch varg studio - visual editor for workflows",
9
+ },
10
+ args: {
11
+ file: {
12
+ type: "positional",
13
+ description: "initial file to open",
14
+ required: false,
15
+ },
16
+ cache: {
17
+ type: "string",
18
+ description: "cache directory",
19
+ default: ".cache/ai",
20
+ },
21
+ port: {
22
+ type: "string",
23
+ description: "port to run on",
24
+ default: "8282",
25
+ },
26
+ },
27
+ run: async ({ args }) => {
28
+ const initialFile = args.file ? resolve(args.file) : undefined;
29
+ const cacheDir = args.cache;
30
+ const port = Number.parseInt(args.port, 10);
31
+
32
+ console.log("varg studio starting...");
33
+ console.log(`cache folder: ${cacheDir}`);
34
+ if (initialFile) {
35
+ console.log(`initial file: ${initialFile}`);
36
+ }
37
+
38
+ const server = createStudioServer({ cacheDir, initialFile, port });
39
+
40
+ console.log(`\nopen http://localhost:${server.port}`);
41
+ console.log(" /editor - code editor");
42
+ console.log(" /cache - cache viewer");
43
+
44
+ // Keep process alive
45
+ await new Promise(() => {});
46
+ },
47
+ });
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * varg which command
3
4
  * Ink-based inspection view
package/src/cli/index.ts CHANGED
@@ -13,16 +13,23 @@ import { registry } from "../core/registry";
13
13
  import { allDefinitions } from "../definitions";
14
14
  import {
15
15
  findCmd,
16
+ helloCmd,
16
17
  helpCmd,
18
+ initCmd,
17
19
  listCmd,
20
+ previewCmd,
18
21
  renderCmd,
19
22
  runCmd,
20
23
  showFindHelp,
21
24
  showHelp,
25
+ showInitHelp,
22
26
  showListHelp,
27
+ showPreviewHelp,
28
+ showRenderHelp,
23
29
  showRunHelp,
24
30
  showTargetHelp,
25
31
  showWhichHelp,
32
+ studioCmd,
26
33
  whichCmd,
27
34
  } from "./commands";
28
35
 
@@ -44,9 +51,11 @@ for (const provider of providers.all()) {
44
51
  const args = process.argv.slice(2);
45
52
  const hasHelp = args.includes("--help") || args.includes("-h");
46
53
 
47
- // Map subcommands to their help functions
48
54
  const subcommandHelp: Record<string, () => void> = {
49
55
  run: showRunHelp,
56
+ render: showRenderHelp,
57
+ preview: showPreviewHelp,
58
+ init: showInitHelp,
50
59
  list: showListHelp,
51
60
  ls: showListHelp,
52
61
  find: showFindHelp,
@@ -92,15 +101,21 @@ if (hasHelp) {
92
101
  }
93
102
  }
94
103
 
104
+ const pkg = await import("../../package.json");
105
+
95
106
  const main = defineCommand({
96
107
  meta: {
97
- name: "varg",
98
- version: "0.3.0",
99
- description: "ai video infrastructure from your terminal",
108
+ name: "vargai",
109
+ version: pkg.version,
110
+ description: "ai video generation sdk",
100
111
  },
101
112
  subCommands: {
102
- run: runCmd,
113
+ hello: helloCmd,
114
+ init: initCmd,
103
115
  render: renderCmd,
116
+ preview: previewCmd,
117
+ studio: studioCmd,
118
+ run: runCmd,
104
119
  list: listCmd,
105
120
  ls: listCmd,
106
121
  find: findCmd,
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * Badge - Type indicator badge
3
4
  * Shows [model] [action] [skill] with appropriate styling
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * DataTable - Table display component
3
4
  * Clean text-based table for listing items
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * Header - Section header component
3
4
  * Bold dimmed text for section titles
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * HelpBlock - Command help and examples
3
4
  * Displays usage patterns and command examples
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * KeyValue - Label-value pair display
3
4
  * Aligned key-value pairs with optional required marker
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * OptionRow - CLI option display with better spacing
3
4
  * Shows option name, description, type hints, defaults, and enums
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * Separator - Horizontal divider line
3
4
  * Minimal visual separator between sections
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * StatusBox - Execution status display
3
4
  * Shows running/done/error state with params and results
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * VargBox - Container component
3
4
  * Luxury minimal styled box with optional title and borders
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * VargProgress - Progress bar component
3
4
  * Elegant thin progress visualization
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * VargSpinner - Animated loading indicator
3
4
  * Elegant braille spinner with label
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * VargText - Typography component
3
4
  * Provides semantic text variants for consistent styling
@@ -0,0 +1,9 @@
1
+ export const assets = {
2
+ characters: {
3
+ orangeGirl: "https://s3.varg.ai/uploads/images/1_0475e227.png",
4
+ },
5
+ backgrounds: {
6
+ orangeGradient:
7
+ "https://s3.varg.ai/uploads/images/xyearp51qvve-zi3nrcve-zbno2hfgt5gergjrof_995f553d.png",
8
+ },
9
+ } as const;
@@ -1,5 +1,4 @@
1
1
  import type {
2
- AnimateProps,
3
2
  CaptionsProps,
4
3
  ClipProps,
5
4
  ImageProps,
@@ -71,10 +70,6 @@ export function Video(props: VideoProps): VargElement<"video"> {
71
70
  return createElement("video", props as Record<string, unknown>, undefined);
72
71
  }
73
72
 
74
- export function Animate(props: AnimateProps): VargElement<"animate"> {
75
- return createElement("animate", props as Record<string, unknown>, undefined);
76
- }
77
-
78
73
  export function Speech(props: SpeechProps): VargElement<"speech"> {
79
74
  return createElement(
80
75
  "speech",
@@ -1,6 +1,6 @@
1
1
  import { elevenlabs } from "../../ai-sdk/providers/elevenlabs";
2
2
  import { fal } from "../../ai-sdk/providers/fal";
3
- import { Animate, Clip, Image, Render, Speech, Title } from "..";
3
+ import { Clip, Image, Render, Speech, Title, Video } from "..";
4
4
 
5
5
  // Non-linear tree: multiple clips with independent branches
6
6
  // Clip 1: TalkingHead (Image -> Animate + Speech)
@@ -35,10 +35,12 @@ export default (
35
35
  <Render width={1080} height={1920}>
36
36
  {/* Clip 1: Talking head intro */}
37
37
  <Clip duration={5}>
38
- <Animate
39
- image={character}
38
+ <Video
39
+ prompt={{
40
+ text: "talking naturally, slight head movements, friendly expression",
41
+ images: [character],
42
+ }}
40
43
  model={fal.videoModel("wan-2.5")}
41
- motion="talking naturally, slight head movements, friendly expression"
42
44
  />
43
45
  <Speech voice="adam" model={elevenlabs.speechModel("turbo")}>
44
46
  Hey everyone! Today we're looking at the biggest smartphone upgrade of
@@ -1,6 +1,6 @@
1
1
  import { elevenlabs } from "../../ai-sdk/providers/elevenlabs";
2
2
  import { fal } from "../../ai-sdk/providers/fal";
3
- import { Animate, Clip, Image, Music, Render, render } from "..";
3
+ import { Clip, Image, Music, Render, render, Video } from "..";
4
4
 
5
5
  const MADI_REF =
6
6
  "https://s3.varg.ai/fellowers/madi/character_shots/madi_shot_03_closeup.png";
@@ -54,16 +54,19 @@ async function main() {
54
54
 
55
55
  {SCENES.map((scene) => (
56
56
  <Clip key={scene.prompt} duration={2}>
57
- <Animate
58
- image={Image({
59
- prompt: { text: scene.prompt, images: [MADI_REF] },
60
- model: fal.imageModel("nano-banana-pro/edit"),
61
- aspectRatio: "9:16",
62
- resize: "cover",
63
- })}
64
- motion={scene.motion}
57
+ <Video
58
+ prompt={{
59
+ text: scene.motion,
60
+ images: [
61
+ Image({
62
+ prompt: { text: scene.prompt, images: [MADI_REF] },
63
+ model: fal.imageModel("nano-banana-pro/edit"),
64
+ aspectRatio: "9:16",
65
+ resize: "cover",
66
+ }),
67
+ ],
68
+ }}
65
69
  model={fal.videoModel("wan-2.5")}
66
- duration={5}
67
70
  />
68
71
  </Clip>
69
72
  ))}