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.
- package/README.md +483 -61
- package/launch-videos/06-kawaii-fruits.tsx +93 -0
- package/launch-videos/07-ugc-weight-loss.tsx +132 -0
- package/launch-videos/08-talking-head-varg.tsx +107 -0
- package/launch-videos/09-girl.tsx +160 -0
- package/launch-videos/README.md +42 -0
- package/package.json +8 -4
- package/skills/varg-video-generation/SKILL.md +213 -0
- package/skills/varg-video-generation/references/templates.md +380 -0
- package/skills/varg-video-generation/scripts/setup.ts +265 -0
- package/src/ai-sdk/cache.ts +1 -1
- package/src/ai-sdk/middleware/wrap-image-model.ts +4 -21
- package/src/ai-sdk/middleware/wrap-music-model.ts +4 -16
- package/src/ai-sdk/middleware/wrap-video-model.ts +5 -17
- package/src/ai-sdk/providers/editly/index.ts +110 -53
- package/src/ai-sdk/providers/editly/types.ts +2 -0
- package/src/ai-sdk/providers/elevenlabs.ts +10 -2
- package/src/ai-sdk/providers/fal.ts +6 -1
- package/src/cli/commands/find.tsx +1 -0
- package/src/cli/commands/hello.ts +85 -0
- package/src/cli/commands/help.tsx +18 -30
- package/src/cli/commands/index.ts +9 -1
- package/src/cli/commands/init.tsx +412 -0
- package/src/cli/commands/list.tsx +1 -0
- package/src/cli/commands/render.tsx +292 -80
- package/src/cli/commands/run.tsx +1 -0
- package/src/cli/commands/studio.ts +47 -0
- package/src/cli/commands/which.tsx +1 -0
- package/src/cli/index.ts +20 -5
- package/src/cli/ui/components/Badge.tsx +1 -0
- package/src/cli/ui/components/DataTable.tsx +1 -0
- package/src/cli/ui/components/Header.tsx +1 -0
- package/src/cli/ui/components/HelpBlock.tsx +1 -0
- package/src/cli/ui/components/KeyValue.tsx +1 -0
- package/src/cli/ui/components/OptionRow.tsx +1 -0
- package/src/cli/ui/components/Separator.tsx +1 -0
- package/src/cli/ui/components/StatusBox.tsx +1 -0
- package/src/cli/ui/components/VargBox.tsx +1 -0
- package/src/cli/ui/components/VargProgress.tsx +1 -0
- package/src/cli/ui/components/VargSpinner.tsx +1 -0
- package/src/cli/ui/components/VargText.tsx +1 -0
- package/src/react/assets.ts +9 -0
- package/src/react/elements.ts +0 -5
- package/src/react/examples/branching.tsx +6 -4
- package/src/react/examples/character-video.tsx +13 -10
- package/src/react/examples/madi.tsx +13 -10
- package/src/react/examples/mcmeows.tsx +40 -0
- package/src/react/examples/music-defaults.tsx +24 -0
- package/src/react/examples/quickstart-test.tsx +97 -0
- package/src/react/index.ts +1 -2
- package/src/react/react.test.ts +10 -10
- package/src/react/renderers/clip.ts +13 -24
- package/src/react/renderers/context.ts +3 -0
- package/src/react/renderers/image.ts +4 -2
- package/src/react/renderers/index.ts +0 -1
- package/src/react/renderers/music.ts +3 -3
- package/src/react/renderers/progress.ts +1 -3
- package/src/react/renderers/render.ts +49 -63
- package/src/react/renderers/speech.ts +2 -2
- package/src/react/renderers/video.ts +46 -9
- package/src/react/types.ts +18 -14
- package/src/studio/stages.ts +4 -24
- package/src/studio/step-renderer.ts +0 -15
- package/test-sync-v2.ts +30 -0
- package/test-sync-v2.tsx +29 -0
- package/tsconfig.json +5 -3
- package/video.tsx +7 -0
- package/src/react/cli.ts +0 -52
- 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
|
|
159
|
+
description: "render to video (strict mode - fails on errors)",
|
|
9
160
|
},
|
|
10
|
-
args:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
description: "minimal output",
|
|
31
|
-
default: false,
|
|
188
|
+
{
|
|
189
|
+
command: "varg preview video.tsx",
|
|
190
|
+
description: "fast preview with placeholders",
|
|
32
191
|
},
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
description: "
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
+
}
|
package/src/cli/commands/run.tsx
CHANGED
|
@@ -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
|
+
});
|
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: "
|
|
98
|
-
version:
|
|
99
|
-
description: "ai video
|
|
108
|
+
name: "vargai",
|
|
109
|
+
version: pkg.version,
|
|
110
|
+
description: "ai video generation sdk",
|
|
100
111
|
},
|
|
101
112
|
subCommands: {
|
|
102
|
-
|
|
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,
|
package/src/react/elements.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
<
|
|
39
|
-
|
|
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 {
|
|
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
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
))}
|