vargai 0.4.0-alpha4 → 0.4.0-alpha40

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 (114) hide show
  1. package/.env.example +6 -0
  2. package/README.md +483 -61
  3. package/assets/fonts/TikTokSans-Bold.ttf +0 -0
  4. package/examples/grok-imagine-test.tsx +155 -0
  5. package/launch-videos/06-kawaii-fruits.tsx +93 -0
  6. package/launch-videos/07-ugc-weight-loss.tsx +132 -0
  7. package/launch-videos/08-talking-head-varg.tsx +107 -0
  8. package/launch-videos/09-girl.tsx +160 -0
  9. package/launch-videos/README.md +42 -0
  10. package/package.json +10 -4
  11. package/pipeline/cookbooks/round-video-character.md +1 -1
  12. package/skills/varg-video-generation/SKILL.md +224 -0
  13. package/skills/varg-video-generation/references/templates.md +380 -0
  14. package/skills/varg-video-generation/scripts/setup.ts +265 -0
  15. package/src/ai-sdk/cache.ts +1 -3
  16. package/src/ai-sdk/examples/google-image.ts +62 -0
  17. package/src/ai-sdk/index.ts +10 -0
  18. package/src/ai-sdk/middleware/wrap-image-model.ts +4 -21
  19. package/src/ai-sdk/middleware/wrap-music-model.ts +4 -16
  20. package/src/ai-sdk/middleware/wrap-video-model.ts +5 -17
  21. package/src/ai-sdk/providers/CONTRIBUTING.md +457 -0
  22. package/src/ai-sdk/providers/editly/backends/index.ts +8 -0
  23. package/src/ai-sdk/providers/editly/backends/local.ts +94 -0
  24. package/src/ai-sdk/providers/editly/backends/types.ts +74 -0
  25. package/src/ai-sdk/providers/editly/editly.test.ts +49 -1
  26. package/src/ai-sdk/providers/editly/index.ts +164 -80
  27. package/src/ai-sdk/providers/editly/layers.ts +58 -6
  28. package/src/ai-sdk/providers/editly/rendi/editly-with-rendi-backend.test.ts +335 -0
  29. package/src/ai-sdk/providers/editly/rendi/index.ts +289 -0
  30. package/src/ai-sdk/providers/editly/rendi/rendi.test.ts +35 -0
  31. package/src/ai-sdk/providers/editly/types.ts +30 -0
  32. package/src/ai-sdk/providers/elevenlabs.ts +10 -2
  33. package/src/ai-sdk/providers/fal.test.ts +214 -0
  34. package/src/ai-sdk/providers/fal.ts +435 -40
  35. package/src/ai-sdk/providers/google.ts +423 -0
  36. package/src/ai-sdk/providers/together.ts +191 -0
  37. package/src/cli/commands/find.tsx +1 -0
  38. package/src/cli/commands/frame.tsx +616 -0
  39. package/src/cli/commands/hello.ts +85 -0
  40. package/src/cli/commands/help.tsx +18 -30
  41. package/src/cli/commands/index.ts +11 -2
  42. package/src/cli/commands/init.tsx +570 -0
  43. package/src/cli/commands/list.tsx +1 -0
  44. package/src/cli/commands/render.tsx +322 -76
  45. package/src/cli/commands/run.tsx +1 -0
  46. package/src/cli/commands/storyboard.tsx +1714 -0
  47. package/src/cli/commands/which.tsx +1 -0
  48. package/src/cli/index.ts +23 -4
  49. package/src/cli/ui/components/Badge.tsx +1 -0
  50. package/src/cli/ui/components/DataTable.tsx +1 -0
  51. package/src/cli/ui/components/Header.tsx +1 -0
  52. package/src/cli/ui/components/HelpBlock.tsx +1 -0
  53. package/src/cli/ui/components/KeyValue.tsx +1 -0
  54. package/src/cli/ui/components/OptionRow.tsx +1 -0
  55. package/src/cli/ui/components/Separator.tsx +1 -0
  56. package/src/cli/ui/components/StatusBox.tsx +1 -0
  57. package/src/cli/ui/components/VargBox.tsx +1 -0
  58. package/src/cli/ui/components/VargProgress.tsx +1 -0
  59. package/src/cli/ui/components/VargSpinner.tsx +1 -0
  60. package/src/cli/ui/components/VargText.tsx +1 -0
  61. package/src/definitions/actions/grok-edit.ts +133 -0
  62. package/src/definitions/actions/index.ts +16 -0
  63. package/src/definitions/actions/qwen-angles.ts +218 -0
  64. package/src/index.ts +1 -0
  65. package/src/providers/fal.ts +196 -0
  66. package/src/react/assets.ts +9 -0
  67. package/src/react/elements.ts +0 -5
  68. package/src/react/examples/branching.tsx +6 -4
  69. package/src/react/examples/character-video.tsx +13 -10
  70. package/src/react/examples/local-files-test.tsx +19 -0
  71. package/src/react/examples/ltx2-test.tsx +25 -0
  72. package/src/react/examples/madi.tsx +13 -10
  73. package/src/react/examples/mcmeows.tsx +40 -0
  74. package/src/react/examples/music-defaults.tsx +24 -0
  75. package/src/react/examples/quickstart-test.tsx +101 -0
  76. package/src/react/examples/qwen-angles-test.tsx +72 -0
  77. package/src/react/index.ts +3 -3
  78. package/src/react/layouts/grid.tsx +1 -1
  79. package/src/react/layouts/index.ts +2 -1
  80. package/src/react/layouts/slot.tsx +85 -0
  81. package/src/react/layouts/split.tsx +18 -0
  82. package/src/react/react.test.ts +60 -11
  83. package/src/react/renderers/burn-captions.ts +95 -0
  84. package/src/react/renderers/cache.test.ts +182 -0
  85. package/src/react/renderers/captions.ts +25 -6
  86. package/src/react/renderers/clip.ts +56 -25
  87. package/src/react/renderers/context.ts +5 -2
  88. package/src/react/renderers/image.ts +5 -2
  89. package/src/react/renderers/index.ts +0 -1
  90. package/src/react/renderers/music.ts +8 -3
  91. package/src/react/renderers/packshot/blinking-button.ts +413 -0
  92. package/src/react/renderers/packshot.ts +170 -8
  93. package/src/react/renderers/progress.ts +4 -3
  94. package/src/react/renderers/render.ts +127 -71
  95. package/src/react/renderers/speech.ts +2 -2
  96. package/src/react/renderers/split.ts +34 -13
  97. package/src/react/renderers/utils.test.ts +80 -0
  98. package/src/react/renderers/utils.ts +37 -1
  99. package/src/react/renderers/video.ts +47 -9
  100. package/src/react/types.ts +70 -17
  101. package/src/studio/stages.ts +40 -39
  102. package/src/studio/step-renderer.ts +14 -24
  103. package/src/studio/ui/index.html +2 -2
  104. package/src/tests/all.test.ts +4 -4
  105. package/src/tests/index.ts +1 -1
  106. package/test-slot-grid.tsx +19 -0
  107. package/test-slot-userland.tsx +30 -0
  108. package/test-sync-v2.ts +30 -0
  109. package/test-sync-v2.tsx +29 -0
  110. package/tsconfig.json +1 -1
  111. package/video.tsx +7 -0
  112. package/src/ai-sdk/providers/editly/ffmpeg.ts +0 -60
  113. package/src/react/renderers/animate.ts +0 -59
  114. /package/src/cli/commands/{studio.tsx → studio.ts} +0 -0
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "module": "src/index.ts",
4
4
  "type": "module",
5
5
  "bin": {
6
- "varg": "./src/cli/index.ts"
6
+ "vargai": "./src/cli/index.ts"
7
7
  },
8
8
  "scripts": {
9
9
  "check": "biome check . && tsc --noEmit",
@@ -34,14 +34,18 @@
34
34
  },
35
35
  "peerDependencies": {
36
36
  "typescript": "^5",
37
- "ai": "^6.0.0"
37
+ "ai": "^6.0.0",
38
+ "zod": "^3.25.76 || ^4.1.8"
38
39
  },
39
40
  "dependencies": {
40
41
  "@ai-sdk/fal": "^1.0.23",
41
42
  "@ai-sdk/fireworks": "^2.0.16",
42
43
  "@ai-sdk/groq": "^3.0.12",
44
+ "@ai-sdk/google": "^3.0.13",
43
45
  "@ai-sdk/openai": "^3.0.9",
46
+ "@google/genai": "^1.0.0",
44
47
  "@ai-sdk/provider": "^3.0.2",
48
+ "@ai-sdk/provider-utils": "^4.0.4",
45
49
  "@ai-sdk/replicate": "^2.0.5",
46
50
  "@aws-sdk/client-s3": "^3.937.0",
47
51
  "@aws-sdk/s3-request-presigner": "^3.937.0",
@@ -61,9 +65,10 @@
61
65
  "react-dom": "^19.2.0",
62
66
  "remotion": "^4.0.377",
63
67
  "replicate": "^1.4.0",
68
+ "sharp": "^0.34.5",
64
69
  "zod": "^4.2.1"
65
70
  },
66
- "version": "0.4.0-alpha4",
71
+ "version": "0.4.0-alpha40",
67
72
  "exports": {
68
73
  ".": "./src/index.ts",
69
74
  "./ai": "./src/ai-sdk/index.ts",
@@ -73,6 +78,7 @@
73
78
  "./react": "./src/react/index.ts",
74
79
  "./studio": "./src/studio/index.ts",
75
80
  "./jsx-runtime": "./src/react/runtime/jsx-runtime.ts",
76
- "./jsx-dev-runtime": "./src/react/runtime/jsx-dev-runtime.ts"
81
+ "./jsx-dev-runtime": "./src/react/runtime/jsx-dev-runtime.ts",
82
+ "./editly": "./src/ai-sdk/providers/editly/index.ts"
77
83
  }
78
84
  }
@@ -321,7 +321,7 @@ see all voices: `bun run lib/elevenlabs.ts voices`
321
321
  ```bash
322
322
  # required api keys
323
323
  export ELEVENLABS_API_KEY="your_key"
324
- export FAL_KEY="your_key" # for wan-25 and image generation
324
+ export FAL_API_KEY="your_key" # for wan-25 and image generation (or set FAL_KEY)
325
325
  ```
326
326
 
327
327
  ## changelog
@@ -0,0 +1,224 @@
1
+ ---
2
+ name: varg-video-generation
3
+ description: Generate AI videos using varg SDK React engine. Use when creating videos, animations, talking characters, slideshows, or social media content.
4
+ license: MIT
5
+ metadata:
6
+ author: vargHQ
7
+ version: "1.0.0"
8
+ compatibility: Requires bun runtime. FAL_KEY required. Optional ELEVENLABS_API_KEY, REPLICATE_API_TOKEN, GROQ_API_KEY
9
+ allowed-tools: Bash(bun:*) Bash(cat:*) Read Write Edit
10
+ ---
11
+
12
+ # Video Generation with varg React Engine
13
+
14
+ Generate AI videos using declarative JSX syntax with automatic caching and parallel generation.
15
+
16
+ ## Quick Setup
17
+
18
+ Initialize a new project:
19
+
20
+ ```bash
21
+ bunx vargai init
22
+ ```
23
+
24
+ Or just create hello.tsx starter:
25
+
26
+ ```bash
27
+ bunx vargai hello
28
+ ```
29
+
30
+ Check existing API keys:
31
+
32
+ ```bash
33
+ cat .env 2>/dev/null | grep -E "^(FAL_KEY|ELEVENLABS_API_KEY)=" || echo "No API keys found"
34
+ ```
35
+
36
+ ## Required API Keys
37
+
38
+ ### FAL_KEY (Required)
39
+
40
+ | Detail | Value |
41
+ |--------|-------|
42
+ | Provider | Fal.ai |
43
+ | Get it | https://fal.ai/dashboard/keys |
44
+ | Free tier | Yes (limited credits) |
45
+ | Used for | Image generation (Flux), Video generation (Wan 2.5, Kling) |
46
+
47
+ If user doesn't have `FAL_KEY`:
48
+ 1. Direct them to https://fal.ai/dashboard/keys
49
+ 2. Create account and generate API key
50
+ 3. Add to `.env` file: `FAL_KEY=fal_xxxxx`
51
+
52
+ ### Optional Keys
53
+
54
+ | Feature | Key | Provider | URL |
55
+ |---------|-----|----------|-----|
56
+ | Music/Voice | `ELEVENLABS_API_KEY` | ElevenLabs | https://elevenlabs.io/app/settings/api-keys |
57
+ | Lipsync | `REPLICATE_API_TOKEN` | Replicate | https://replicate.com/account/api-tokens |
58
+ | Transcription | `GROQ_API_KEY` | Groq | https://console.groq.com/keys |
59
+
60
+ **Warn user about missing optional keys but continue with available features.**
61
+
62
+ ## Available Features by API Key
63
+
64
+ **FAL_API_KEY only:**
65
+ - Image generation (Flux models)
66
+ - Image-to-video animation (Wan 2.5, Kling)
67
+ - Text-to-video generation
68
+ - Slideshows with transitions
69
+ - Ken Burns zoom effects
70
+
71
+ **FAL + ELEVENLABS:**
72
+ - All above, plus:
73
+ - AI-generated background music
74
+ - Text-to-speech voiceovers
75
+ - Talking character videos
76
+
77
+ **All keys:**
78
+ - Full production pipeline with lipsync and auto-captions
79
+
80
+ ## Quick Templates
81
+
82
+ ### Simple Slideshow (FAL only)
83
+
84
+ ```tsx
85
+ /** @jsxImportSource vargai */
86
+ import { Render, Clip, Image } from "vargai/react";
87
+
88
+ const SCENES = ["sunset over ocean", "mountain peaks", "city at night"];
89
+
90
+ export default (
91
+ <Render width={1080} height={1920}>
92
+ {SCENES.map((prompt, i) => (
93
+ <Clip key={i} duration={3} transition={{ name: "fade", duration: 0.5 }}>
94
+ <Image prompt={prompt} zoom="in" />
95
+ </Clip>
96
+ ))}
97
+ </Render>
98
+ );
99
+ ```
100
+
101
+ ### Animated Video (FAL + ElevenLabs)
102
+
103
+ ```tsx
104
+ /** @jsxImportSource vargai */
105
+ import { Render, Clip, Image, Video, Music } from "vargai/react";
106
+ import { fal, elevenlabs } from "vargai/ai";
107
+
108
+ const cat = Image({ prompt: "cute cat on windowsill" });
109
+
110
+ export default (
111
+ <Render width={1080} height={1920}>
112
+ <Music prompt="upbeat electronic" model={elevenlabs.musicModel()} />
113
+ <Clip duration={5}>
114
+ <Video
115
+ prompt={{ text: "cat turns head, blinks slowly", images: [cat] }}
116
+ model={fal.videoModel("wan-2.5")}
117
+ />
118
+ </Clip>
119
+ </Render>
120
+ );
121
+ ```
122
+
123
+ ### Talking Character
124
+
125
+ ```tsx
126
+ /** @jsxImportSource vargai */
127
+ import { Render, Clip, Image, Video, Speech, Captions } from "vargai/react";
128
+ import { fal, elevenlabs } from "vargai/ai";
129
+
130
+ const robot = Image({ prompt: "friendly robot, blue metallic", aspectRatio: "9:16" });
131
+
132
+ const voiceover = Speech({
133
+ model: elevenlabs.speechModel("eleven_multilingual_v2"),
134
+ voice: "adam",
135
+ children: "Hello! I'm your AI assistant. Let's create something amazing!",
136
+ });
137
+
138
+ export default (
139
+ <Render width={1080} height={1920}>
140
+ <Clip duration={5}>
141
+ <Video
142
+ prompt={{ text: "robot talking, subtle head movements", images: [robot] }}
143
+ model={fal.videoModel("wan-2.5")}
144
+ />
145
+ </Clip>
146
+ <Captions src={voiceover} style="tiktok" />
147
+ </Render>
148
+ );
149
+ ```
150
+
151
+
152
+
153
+ ## Running Videos
154
+
155
+ ```bash
156
+ bunx vargai render your-video.tsx
157
+ ```
158
+
159
+ ## Key Components
160
+
161
+ | Component | Purpose | Required Key |
162
+ |-----------|---------|--------------|
163
+ | `<Render>` | Root container | - |
164
+ | `<Clip>` | Sequential segment | - |
165
+ | `<Image>` | AI image | FAL |
166
+ | `<Animate>` | Image-to-video | FAL |
167
+ | `<Music>` | Background music | ElevenLabs |
168
+ | `<Speech>` | Text-to-speech | ElevenLabs |
169
+
170
+ ## Common Patterns
171
+
172
+ ### Character Consistency
173
+
174
+ ```tsx
175
+ const character = Image({ prompt: "blue robot" });
176
+ // Reuse same reference = same generated image
177
+ <Animate image={character} motion="waving" />
178
+ <Animate image={character} motion="dancing" />
179
+ ```
180
+
181
+ ### Transitions
182
+
183
+ ```tsx
184
+ <Clip transition={{ name: "fade", duration: 0.5 }}>
185
+ // Options: fade, crossfade, wipeleft, cube, slideup, etc.
186
+ ```
187
+
188
+ ### Aspect Ratios
189
+
190
+ - `9:16` - TikTok, Reels, Shorts (vertical)
191
+ - `16:9` - YouTube (horizontal)
192
+ - `1:1` - Instagram (square)
193
+
194
+ ### Zoom Effects
195
+
196
+ ```tsx
197
+ <Image prompt="landscape" zoom="in" /> // Zoom in
198
+ <Image prompt="landscape" zoom="out" /> // Zoom out
199
+ <Image prompt="landscape" zoom="left" /> // Pan left
200
+ ```
201
+
202
+ ## Troubleshooting
203
+
204
+ ### "FAL_KEY not found"
205
+ - Check `.env` file exists in project root
206
+ - Ensure no spaces around `=` sign
207
+ - Restart terminal after adding keys
208
+
209
+ ### "Rate limit exceeded"
210
+ - Free tier has limited credits
211
+ - Wait or upgrade plan
212
+ - Use caching to avoid regenerating
213
+
214
+ ### "Video generation failed"
215
+ - Check prompt doesn't violate content policy
216
+ - Try simpler motion descriptions
217
+ - Reduce video duration
218
+
219
+ ## Next Steps
220
+
221
+ 1. Run `bunx vargai init` to initialize project
222
+ 2. Add your FAL_KEY to `.env`
223
+ 3. Run `bunx vargai render hello.tsx`
224
+ 4. Or ask the agent: "create a 10 second tiktok video about cats"
@@ -0,0 +1,380 @@
1
+ # Video Generation Templates
2
+
3
+ Complete code templates for common video generation patterns.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Simple Slideshow](#simple-slideshow)
8
+ 2. [Animated Video with Music](#animated-video-with-music)
9
+ 3. [Talking Character](#talking-character)
10
+ 4. [TikTok Multi-Clip](#tiktok-multi-clip)
11
+ 5. [Character with Consistent Style](#character-with-consistent-style)
12
+ 6. [Split Screen Comparison](#split-screen-comparison)
13
+
14
+ ---
15
+
16
+ ## Simple Slideshow
17
+
18
+ **Requirements:** FAL_API_KEY only
19
+
20
+ Basic image slideshow with transitions and zoom effects.
21
+
22
+ ```tsx
23
+ // slideshow.tsx
24
+ import { render, Render, Clip, Image } from "vargai/react";
25
+
26
+ const SCENES = [
27
+ "sunset over ocean, cinematic golden hour",
28
+ "mountain peaks at dawn, misty atmosphere",
29
+ "city skyline at night, neon lights",
30
+ "forest path in autumn, fallen leaves",
31
+ ];
32
+
33
+ async function main() {
34
+ await render(
35
+ <Render width={1080} height={1920}>
36
+ {SCENES.map((prompt, i) => (
37
+ <Clip
38
+ key={i}
39
+ duration={3}
40
+ transition={{ name: "fade", duration: 0.5 }}
41
+ >
42
+ <Image prompt={prompt} zoom="in" />
43
+ </Clip>
44
+ ))}
45
+ </Render>,
46
+ { output: "output/slideshow.mp4" }
47
+ );
48
+
49
+ console.log("Done! output/slideshow.mp4");
50
+ }
51
+
52
+ main();
53
+ ```
54
+
55
+ Run: `bun run slideshow.tsx`
56
+
57
+ ---
58
+
59
+ ## Animated Video with Music
60
+
61
+ **Requirements:** FAL_API_KEY + ELEVENLABS_API_KEY
62
+
63
+ Video with AI-generated animation and background music.
64
+
65
+ ```tsx
66
+ // animated-video.tsx
67
+ import { render, Render, Clip, Image, Animate, Music } from "vargai/react";
68
+ import { fal, elevenlabs } from "vargai/ai";
69
+
70
+ async function main() {
71
+ await render(
72
+ <Render width={1080} height={1920}>
73
+ <Music
74
+ prompt="upbeat electronic pop, energetic, modern tiktok vibe"
75
+ model={elevenlabs.musicModel()}
76
+ duration={10}
77
+ volume={0.7}
78
+ />
79
+
80
+ <Clip duration={5}>
81
+ <Animate
82
+ image={Image({
83
+ prompt: "cute cat sitting on windowsill, golden hour lighting",
84
+ model: fal.imageModel("flux-schnell")
85
+ })}
86
+ motion="cat slowly turns head, blinks, tail swishes gently"
87
+ model={fal.videoModel("wan-2.5")}
88
+ duration={5}
89
+ />
90
+ </Clip>
91
+
92
+ <Clip duration={5} transition={{ name: "fade", duration: 0.5 }}>
93
+ <Animate
94
+ image={Image({
95
+ prompt: "same cat stretching on windowsill, yawning"
96
+ })}
97
+ motion="cat stretches, yawns widely, settles back down"
98
+ model={fal.videoModel("wan-2.5")}
99
+ duration={5}
100
+ />
101
+ </Clip>
102
+ </Render>,
103
+ { output: "output/cat-video.mp4" }
104
+ );
105
+ }
106
+
107
+ main();
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Talking Character
113
+
114
+ **Requirements:** FAL_API_KEY + ELEVENLABS_API_KEY
115
+
116
+ Character that speaks with animated movement.
117
+
118
+ ```tsx
119
+ // talking-character.tsx
120
+ import { render, Render, Clip, Image, Animate, Speech } from "vargai/react";
121
+ import { fal, elevenlabs } from "vargai/ai";
122
+
123
+ const CHARACTER = "friendly cartoon robot, blue metallic body, expressive LED eyes, studio background";
124
+
125
+ const SCRIPT = `
126
+ Hello! I'm your AI assistant.
127
+ Today I'm going to show you something amazing.
128
+ Let's create some videos together!
129
+ `;
130
+
131
+ async function main() {
132
+ await render(
133
+ <Render width={1080} height={1920}>
134
+ <Clip duration="auto">
135
+ <Animate
136
+ image={Image({
137
+ prompt: CHARACTER,
138
+ aspectRatio: "9:16",
139
+ model: fal.imageModel("flux-schnell")
140
+ })}
141
+ motion="robot talking naturally, subtle head movements, eyes blink occasionally, friendly gestures"
142
+ model={fal.videoModel("wan-2.5")}
143
+ />
144
+ <Speech
145
+ voice="adam"
146
+ model={elevenlabs.speechModel("turbo")}
147
+ >
148
+ {SCRIPT}
149
+ </Speech>
150
+ </Clip>
151
+ </Render>,
152
+ { output: "output/talking-robot.mp4" }
153
+ );
154
+ }
155
+
156
+ main();
157
+ ```
158
+
159
+ **Available voices:** `adam`, `rachel`, `bella`, `sam`, `josh`
160
+
161
+ ---
162
+
163
+ ## TikTok Multi-Clip
164
+
165
+ **Requirements:** FAL_API_KEY + ELEVENLABS_API_KEY
166
+
167
+ Multi-scene TikTok-style video with varied camera angles.
168
+
169
+ ```tsx
170
+ // tiktok-video.tsx
171
+ import { render, Render, Clip, Image, Animate, Music, Title } from "vargai/react";
172
+ import { fal, elevenlabs } from "vargai/ai";
173
+
174
+ const CHARACTER = "confident young woman, casual style, bright smile, modern apartment";
175
+
176
+ const SCENES = [
177
+ {
178
+ prompt: "extreme close-up face, surprised expression, wide eyes",
179
+ motion: "eyes widen in surprise, eyebrows raise, subtle gasp"
180
+ },
181
+ {
182
+ prompt: "medium shot, laughing genuinely, hand on chest",
183
+ motion: "head tilts back slightly, genuine laugh, shoulders shake"
184
+ },
185
+ {
186
+ prompt: "close-up, knowing smirk, raised eyebrow",
187
+ motion: "slow smile forms, eyebrow raises, subtle head nod"
188
+ },
189
+ {
190
+ prompt: "medium shot, waving at camera, bright smile",
191
+ motion: "waves energetically at camera, bright smile, slight bounce"
192
+ },
193
+ ];
194
+
195
+ async function main() {
196
+ await render(
197
+ <Render width={1080} height={1920}>
198
+ <Music
199
+ prompt="trendy tiktok music, upbeat, catchy hook, viral sound"
200
+ model={elevenlabs.musicModel()}
201
+ duration={8}
202
+ volume={0.6}
203
+ />
204
+
205
+ {SCENES.map((scene, i) => (
206
+ <Clip
207
+ key={i}
208
+ duration={2}
209
+ transition={{ name: "fade", duration: 0.3 }}
210
+ >
211
+ <Animate
212
+ image={Image({
213
+ prompt: `${CHARACTER}, ${scene.prompt}`,
214
+ aspectRatio: "9:16",
215
+ model: fal.imageModel("flux-schnell")
216
+ })}
217
+ motion={scene.motion}
218
+ model={fal.videoModel("wan-2.5")}
219
+ duration={5}
220
+ />
221
+ {i === 0 && (
222
+ <Title position="bottom">POV: When it actually works</Title>
223
+ )}
224
+ </Clip>
225
+ ))}
226
+ </Render>,
227
+ { output: "output/tiktok-video.mp4" }
228
+ );
229
+ }
230
+
231
+ main();
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Character with Consistent Style
237
+
238
+ **Requirements:** FAL_API_KEY
239
+
240
+ Reuse the same character reference for visual consistency across clips.
241
+
242
+ ```tsx
243
+ // consistent-character.tsx
244
+ import { render, Render, Clip, Image, Animate } from "vargai/react";
245
+ import { fal } from "vargai/ai";
246
+
247
+ async function main() {
248
+ // Define character once - same reference = same generated image
249
+ const character = Image({
250
+ prompt: "cute cartoon fox, orange fur, big eyes, friendly expression",
251
+ model: fal.imageModel("flux-schnell"),
252
+ aspectRatio: "9:16"
253
+ });
254
+
255
+ await render(
256
+ <Render width={1080} height={1920}>
257
+ <Clip duration={3}>
258
+ <Animate
259
+ image={character}
260
+ motion="fox waves hello, tail wagging"
261
+ model={fal.videoModel("wan-2.5")}
262
+ duration={3}
263
+ />
264
+ </Clip>
265
+
266
+ <Clip duration={3} transition={{ name: "fade", duration: 0.5 }}>
267
+ <Animate
268
+ image={character}
269
+ motion="fox dances happily, spinning around"
270
+ model={fal.videoModel("wan-2.5")}
271
+ duration={3}
272
+ />
273
+ </Clip>
274
+
275
+ <Clip duration={3} transition={{ name: "fade", duration: 0.5 }}>
276
+ <Animate
277
+ image={character}
278
+ motion="fox blows a kiss at camera, winks"
279
+ model={fal.videoModel("wan-2.5")}
280
+ duration={3}
281
+ />
282
+ </Clip>
283
+ </Render>,
284
+ { output: "output/fox-video.mp4" }
285
+ );
286
+ }
287
+
288
+ main();
289
+ ```
290
+
291
+ ---
292
+
293
+ ## Split Screen Comparison
294
+
295
+ **Requirements:** FAL_API_KEY
296
+
297
+ Side-by-side comparison layout.
298
+
299
+ ```tsx
300
+ // split-screen.tsx
301
+ import { render, Render, Clip, Image, Animate, Split, Title } from "vargai/react";
302
+ import { fal } from "vargai/ai";
303
+
304
+ async function main() {
305
+ const before = Image({
306
+ prompt: "messy room, clothes everywhere, unmade bed",
307
+ aspectRatio: "3:4"
308
+ });
309
+
310
+ const after = Image({
311
+ prompt: "clean organized room, made bed, tidy shelves",
312
+ aspectRatio: "3:4"
313
+ });
314
+
315
+ await render(
316
+ <Render width={1080} height={1920}>
317
+ <Clip duration={5}>
318
+ <Split direction="horizontal">
319
+ <Animate
320
+ image={before}
321
+ motion="camera slowly pans across messy room"
322
+ model={fal.videoModel("wan-2.5")}
323
+ />
324
+ <Animate
325
+ image={after}
326
+ motion="camera slowly pans across clean room"
327
+ model={fal.videoModel("wan-2.5")}
328
+ />
329
+ </Split>
330
+ <Title position="bottom">
331
+ BEFORE AFTER
332
+ </Title>
333
+ </Clip>
334
+ </Render>,
335
+ { output: "output/split-comparison.mp4" }
336
+ );
337
+ }
338
+
339
+ main();
340
+ ```
341
+
342
+ ---
343
+
344
+ ## Component Reference
345
+
346
+ | Component | Props | Description |
347
+ |-----------|-------|-------------|
348
+ | `<Render>` | `width`, `height`, `fps` | Root container |
349
+ | `<Clip>` | `duration`, `transition` | Sequential segment |
350
+ | `<Image>` | `prompt`, `src`, `model`, `aspectRatio`, `zoom` | AI or static image |
351
+ | `<Animate>` | `image`, `motion`, `model`, `duration` | Image-to-video |
352
+ | `<Video>` | `src`, `prompt`, `model`, `keepAudio` | Video file or generated |
353
+ | `<Music>` | `prompt`, `model`, `duration`, `volume`, `loop` | Background music |
354
+ | `<Speech>` | `voice`, `model`, `children` | Text-to-speech |
355
+ | `<Title>` | `position`, `color`, `start`, `end` | Text overlay |
356
+ | `<Split>` | `direction` | Side-by-side layout |
357
+
358
+ ## Transitions
359
+
360
+ Available transition effects:
361
+
362
+ - `fade` - Simple fade
363
+ - `crossfade` - Cross dissolve
364
+ - `wipeleft`, `wiperight`, `wipeup`, `wipedown` - Directional wipes
365
+ - `slideleft`, `slideright`, `slideup`, `slidedown` - Slides
366
+ - `cube` - 3D cube rotation
367
+ - `pixelize` - Pixelation effect
368
+
369
+ ```tsx
370
+ <Clip transition={{ name: "cube", duration: 0.8 }}>
371
+ ```
372
+
373
+ ## Aspect Ratios
374
+
375
+ | Ratio | Use Case | Dimensions |
376
+ |-------|----------|------------|
377
+ | `9:16` | TikTok, Reels, Shorts | 1080x1920 |
378
+ | `16:9` | YouTube, Twitter | 1920x1080 |
379
+ | `1:1` | Instagram posts | 1080x1080 |
380
+ | `4:5` | Instagram portrait | 1080x1350 |