varg.ai-sdk 0.1.0 → 0.4.0-alpha.1

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 (236) hide show
  1. package/.claude/settings.local.json +1 -1
  2. package/.env.example +3 -0
  3. package/.github/workflows/ci.yml +23 -0
  4. package/.husky/README.md +102 -0
  5. package/.husky/commit-msg +6 -0
  6. package/.husky/pre-commit +9 -0
  7. package/.husky/pre-push +6 -0
  8. package/.size-limit.json +8 -0
  9. package/.test-hooks.ts +5 -0
  10. package/CLAUDE.md +10 -3
  11. package/CONTRIBUTING.md +150 -0
  12. package/LICENSE.md +53 -0
  13. package/README.md +56 -209
  14. package/SKILLS.md +26 -10
  15. package/biome.json +7 -1
  16. package/bun.lock +1286 -0
  17. package/commitlint.config.js +22 -0
  18. package/docs/index.html +1130 -0
  19. package/docs/prompting.md +326 -0
  20. package/docs/react.md +834 -0
  21. package/docs/sdk.md +812 -0
  22. package/ffmpeg/CLAUDE.md +68 -0
  23. package/package.json +48 -8
  24. package/pipeline/cookbooks/scripts/animate-frames-parallel.ts +84 -0
  25. package/pipeline/cookbooks/scripts/combine-scenes.sh +53 -0
  26. package/pipeline/cookbooks/scripts/generate-frames-parallel.ts +99 -0
  27. package/pipeline/cookbooks/scripts/still-to-video.sh +37 -0
  28. package/pipeline/cookbooks/text-to-tiktok.md +669 -0
  29. package/pipeline/cookbooks/trendwatching.md +156 -0
  30. package/plan.md +281 -0
  31. package/scripts/.gitkeep +0 -0
  32. package/src/ai-sdk/cache.ts +142 -0
  33. package/src/ai-sdk/examples/cached-generation.ts +53 -0
  34. package/src/ai-sdk/examples/duet-scene-4.ts +53 -0
  35. package/src/ai-sdk/examples/duet-scene-5-audio.ts +32 -0
  36. package/src/ai-sdk/examples/duet-video.ts +56 -0
  37. package/src/ai-sdk/examples/editly-composition.ts +63 -0
  38. package/src/ai-sdk/examples/editly-test.ts +57 -0
  39. package/src/ai-sdk/examples/editly-video-test.ts +52 -0
  40. package/src/ai-sdk/examples/fal-lipsync.ts +43 -0
  41. package/src/ai-sdk/examples/higgsfield-image.ts +61 -0
  42. package/src/ai-sdk/examples/music-generation.ts +19 -0
  43. package/src/ai-sdk/examples/openai-sora.ts +34 -0
  44. package/src/ai-sdk/examples/replicate-bg-removal.ts +52 -0
  45. package/src/ai-sdk/examples/simpsons-scene.ts +61 -0
  46. package/src/ai-sdk/examples/talking-lion.ts +55 -0
  47. package/src/ai-sdk/examples/video-generation.ts +39 -0
  48. package/src/ai-sdk/examples/workflow-animated-girl.ts +104 -0
  49. package/src/ai-sdk/examples/workflow-before-after.ts +114 -0
  50. package/src/ai-sdk/examples/workflow-character-grid.ts +112 -0
  51. package/src/ai-sdk/examples/workflow-slideshow.ts +161 -0
  52. package/src/ai-sdk/file-cache.ts +112 -0
  53. package/src/ai-sdk/file.ts +238 -0
  54. package/src/ai-sdk/generate-element.ts +92 -0
  55. package/src/ai-sdk/generate-music.ts +46 -0
  56. package/src/ai-sdk/generate-video.ts +165 -0
  57. package/src/ai-sdk/index.ts +72 -0
  58. package/src/ai-sdk/music-model.ts +110 -0
  59. package/src/ai-sdk/providers/editly/editly.test.ts +1108 -0
  60. package/src/ai-sdk/providers/editly/ffmpeg.ts +60 -0
  61. package/src/ai-sdk/providers/editly/index.ts +817 -0
  62. package/src/ai-sdk/providers/editly/layers.ts +776 -0
  63. package/src/ai-sdk/providers/editly/plan.md +144 -0
  64. package/src/ai-sdk/providers/editly/types.ts +328 -0
  65. package/src/ai-sdk/providers/elevenlabs-provider.ts +255 -0
  66. package/src/ai-sdk/providers/fal-provider.ts +512 -0
  67. package/src/ai-sdk/providers/higgsfield.ts +379 -0
  68. package/src/ai-sdk/providers/openai.ts +251 -0
  69. package/src/ai-sdk/providers/replicate.ts +16 -0
  70. package/src/ai-sdk/video-model.ts +185 -0
  71. package/src/cli/commands/find.tsx +137 -0
  72. package/src/cli/commands/help.tsx +85 -0
  73. package/src/cli/commands/index.ts +6 -0
  74. package/src/cli/commands/list.tsx +238 -0
  75. package/src/cli/commands/render.tsx +71 -0
  76. package/src/cli/commands/run.tsx +511 -0
  77. package/src/cli/commands/which.tsx +253 -0
  78. package/src/cli/index.ts +114 -0
  79. package/src/cli/quiet.ts +44 -0
  80. package/src/cli/types.ts +32 -0
  81. package/src/cli/ui/components/Badge.tsx +29 -0
  82. package/src/cli/ui/components/DataTable.tsx +51 -0
  83. package/src/cli/ui/components/Header.tsx +23 -0
  84. package/src/cli/ui/components/HelpBlock.tsx +44 -0
  85. package/src/cli/ui/components/KeyValue.tsx +33 -0
  86. package/src/cli/ui/components/OptionRow.tsx +81 -0
  87. package/src/cli/ui/components/Separator.tsx +23 -0
  88. package/src/cli/ui/components/StatusBox.tsx +108 -0
  89. package/src/cli/ui/components/VargBox.tsx +51 -0
  90. package/src/cli/ui/components/VargProgress.tsx +36 -0
  91. package/src/cli/ui/components/VargSpinner.tsx +34 -0
  92. package/src/cli/ui/components/VargText.tsx +56 -0
  93. package/src/cli/ui/components/index.ts +19 -0
  94. package/src/cli/ui/index.ts +12 -0
  95. package/src/cli/ui/render.ts +35 -0
  96. package/src/cli/ui/theme.ts +63 -0
  97. package/src/cli/utils.ts +78 -0
  98. package/src/core/executor/executor.ts +201 -0
  99. package/src/core/executor/index.ts +13 -0
  100. package/src/core/executor/job.ts +214 -0
  101. package/src/core/executor/pipeline.ts +222 -0
  102. package/src/core/index.ts +11 -0
  103. package/src/core/registry/index.ts +9 -0
  104. package/src/core/registry/loader.ts +149 -0
  105. package/src/core/registry/registry.ts +221 -0
  106. package/src/core/registry/resolver.ts +206 -0
  107. package/src/core/schema/helpers.ts +134 -0
  108. package/src/core/schema/index.ts +8 -0
  109. package/src/core/schema/shared.ts +102 -0
  110. package/src/core/schema/types.ts +279 -0
  111. package/src/core/schema/validator.ts +92 -0
  112. package/src/definitions/actions/captions.ts +261 -0
  113. package/src/definitions/actions/edit.ts +298 -0
  114. package/src/definitions/actions/image.ts +125 -0
  115. package/src/definitions/actions/index.ts +114 -0
  116. package/src/definitions/actions/music.ts +205 -0
  117. package/src/definitions/actions/sync.ts +128 -0
  118. package/{action/transcribe/index.ts → src/definitions/actions/transcribe.ts} +63 -90
  119. package/src/definitions/actions/upload.ts +111 -0
  120. package/src/definitions/actions/video.ts +163 -0
  121. package/src/definitions/actions/voice.ts +119 -0
  122. package/src/definitions/index.ts +23 -0
  123. package/src/definitions/models/elevenlabs.ts +50 -0
  124. package/src/definitions/models/flux.ts +56 -0
  125. package/src/definitions/models/index.ts +36 -0
  126. package/src/definitions/models/kling.ts +56 -0
  127. package/src/definitions/models/llama.ts +54 -0
  128. package/src/definitions/models/nano-banana-pro.ts +102 -0
  129. package/src/definitions/models/sonauto.ts +68 -0
  130. package/src/definitions/models/soul.ts +65 -0
  131. package/src/definitions/models/wan.ts +54 -0
  132. package/src/definitions/models/whisper.ts +44 -0
  133. package/src/definitions/skills/index.ts +12 -0
  134. package/src/definitions/skills/talking-character.ts +87 -0
  135. package/src/definitions/skills/text-to-tiktok.ts +97 -0
  136. package/src/index.ts +118 -0
  137. package/src/providers/apify.ts +269 -0
  138. package/src/providers/base.ts +264 -0
  139. package/src/providers/elevenlabs.ts +217 -0
  140. package/src/providers/fal.ts +392 -0
  141. package/src/providers/ffmpeg.ts +544 -0
  142. package/src/providers/fireworks.ts +193 -0
  143. package/src/providers/groq.ts +149 -0
  144. package/src/providers/higgsfield.ts +145 -0
  145. package/src/providers/index.ts +143 -0
  146. package/src/providers/replicate.ts +147 -0
  147. package/src/providers/storage.ts +206 -0
  148. package/src/react/cli.ts +52 -0
  149. package/src/react/elements.ts +146 -0
  150. package/src/react/examples/branching.tsx +66 -0
  151. package/src/react/examples/captions-demo.tsx +37 -0
  152. package/src/react/examples/character-video.tsx +84 -0
  153. package/src/react/examples/grid.tsx +53 -0
  154. package/src/react/examples/layouts-demo.tsx +57 -0
  155. package/src/react/examples/madi.tsx +60 -0
  156. package/src/react/examples/music-test.tsx +35 -0
  157. package/src/react/examples/onlyfans-1m/workflow.tsx +88 -0
  158. package/src/react/examples/orange-portrait.tsx +41 -0
  159. package/src/react/examples/split-element-demo.tsx +60 -0
  160. package/src/react/examples/split-layout-demo.tsx +60 -0
  161. package/src/react/examples/split.tsx +41 -0
  162. package/src/react/examples/video-grid.tsx +46 -0
  163. package/src/react/index.ts +43 -0
  164. package/src/react/layouts/grid.tsx +28 -0
  165. package/src/react/layouts/index.ts +2 -0
  166. package/src/react/layouts/split.tsx +20 -0
  167. package/src/react/react.test.ts +309 -0
  168. package/src/react/render.ts +21 -0
  169. package/src/react/renderers/animate.ts +59 -0
  170. package/src/react/renderers/captions.ts +297 -0
  171. package/src/react/renderers/clip.ts +248 -0
  172. package/src/react/renderers/context.ts +17 -0
  173. package/src/react/renderers/image.ts +109 -0
  174. package/src/react/renderers/index.ts +22 -0
  175. package/src/react/renderers/music.ts +60 -0
  176. package/src/react/renderers/packshot.ts +84 -0
  177. package/src/react/renderers/progress.ts +173 -0
  178. package/src/react/renderers/render.ts +243 -0
  179. package/src/react/renderers/slider.ts +69 -0
  180. package/src/react/renderers/speech.ts +53 -0
  181. package/src/react/renderers/split.ts +91 -0
  182. package/src/react/renderers/subtitle.ts +16 -0
  183. package/src/react/renderers/swipe.ts +75 -0
  184. package/src/react/renderers/title.ts +17 -0
  185. package/src/react/renderers/utils.ts +124 -0
  186. package/src/react/renderers/video.ts +127 -0
  187. package/src/react/runtime/jsx-dev-runtime.ts +43 -0
  188. package/src/react/runtime/jsx-runtime.ts +35 -0
  189. package/src/react/types.ts +232 -0
  190. package/src/studio/index.ts +26 -0
  191. package/src/studio/scanner.ts +102 -0
  192. package/src/studio/server.ts +554 -0
  193. package/src/studio/stages.ts +251 -0
  194. package/src/studio/step-renderer.ts +279 -0
  195. package/src/studio/types.ts +60 -0
  196. package/src/studio/ui/cache.html +303 -0
  197. package/src/studio/ui/index.html +1820 -0
  198. package/src/tests/all.test.ts +509 -0
  199. package/src/tests/index.ts +33 -0
  200. package/src/tests/unit.test.ts +403 -0
  201. package/tsconfig.cli.json +8 -0
  202. package/tsconfig.json +21 -3
  203. package/TEST_RESULTS.md +0 -122
  204. package/action/captions/SKILL.md +0 -170
  205. package/action/captions/index.ts +0 -227
  206. package/action/edit/SKILL.md +0 -235
  207. package/action/edit/index.ts +0 -493
  208. package/action/image/SKILL.md +0 -140
  209. package/action/image/index.ts +0 -112
  210. package/action/sync/SKILL.md +0 -136
  211. package/action/sync/index.ts +0 -187
  212. package/action/transcribe/SKILL.md +0 -179
  213. package/action/video/SKILL.md +0 -116
  214. package/action/video/index.ts +0 -135
  215. package/action/voice/SKILL.md +0 -125
  216. package/action/voice/index.ts +0 -201
  217. package/index.ts +0 -38
  218. package/lib/README.md +0 -144
  219. package/lib/ai-sdk/fal.ts +0 -106
  220. package/lib/ai-sdk/replicate.ts +0 -107
  221. package/lib/elevenlabs.ts +0 -382
  222. package/lib/fal.ts +0 -478
  223. package/lib/ffmpeg.ts +0 -467
  224. package/lib/fireworks.ts +0 -235
  225. package/lib/groq.ts +0 -246
  226. package/lib/higgsfield.ts +0 -176
  227. package/lib/remotion/SKILL.md +0 -823
  228. package/lib/remotion/cli.ts +0 -115
  229. package/lib/remotion/functions.ts +0 -283
  230. package/lib/remotion/index.ts +0 -19
  231. package/lib/remotion/templates.ts +0 -73
  232. package/lib/replicate.ts +0 -304
  233. package/output.txt +0 -1
  234. package/test-import.ts +0 -7
  235. package/test-services.ts +0 -97
  236. package/utilities/s3.ts +0 -147
package/docs/sdk.md ADDED
@@ -0,0 +1,812 @@
1
+ # varg sdk
2
+
3
+ typescript sdk for ai video generation, built on vercel ai sdk patterns.
4
+
5
+ ## installation
6
+
7
+ ```bash
8
+ # core sdk
9
+ npm install @varg/sdk ai
10
+
11
+ # providers (install what you need)
12
+ npm install @varg/fal # fal.ai (kling, nano-banana, lipsync)
13
+ npm install @varg/elevenlabs # elevenlabs (tts, music)
14
+ npm install @varg/higgsfield # higgsfield (soul, characters)
15
+ npm install @varg/heygen # heygen (talking heads)
16
+ npm install @varg/openai # openai (sora, gpt-image, dall-e)
17
+ npm install @varg/replicate # replicate (birefnet, any model)
18
+ ```
19
+
20
+ ## quick start
21
+
22
+ ```typescript
23
+ import { generateImage, generateVideo } from "ai";
24
+ import { fal } from "@varg/fal";
25
+
26
+ const { image } = await generateImage({
27
+ model: fal.imageModel("nano-banana-pro"),
28
+ prompt: "woman in red dress on beach at sunset",
29
+ aspectRatio: "9:16",
30
+ });
31
+
32
+ const { video } = await generateVideo({
33
+ model: fal.videoModel("kling-v2.5"),
34
+ prompt: {
35
+ images: [image.uint8Array],
36
+ text: "woman walking along shoreline, hair blowing in wind",
37
+ },
38
+ duration: 5,
39
+ });
40
+ ```
41
+
42
+ ---
43
+
44
+ ## core concepts
45
+
46
+ ### files
47
+
48
+ load media from disk, urls, or buffers:
49
+
50
+ ```typescript
51
+ import { File } from "@varg/sdk";
52
+
53
+ // from disk
54
+ const file = File.fromPath("media/portrait.jpg");
55
+
56
+ // from url
57
+ const file = await File.fromUrl("https://example.com/video.mp4");
58
+
59
+ // from buffer
60
+ const file = File.fromBuffer(uint8Array, "image/png");
61
+
62
+ // get contents
63
+ const buffer = await file.arrayBuffer();
64
+ const base64 = await file.base64();
65
+ ```
66
+
67
+ ### providers
68
+
69
+ each provider is a separate package:
70
+
71
+ ```typescript
72
+ import { fal } from "@varg/fal";
73
+ import { elevenlabs } from "@varg/elevenlabs";
74
+ import { heygen } from "@varg/heygen";
75
+ import { higgsfield } from "@varg/higgsfield";
76
+ import { openai } from "@varg/openai";
77
+ import { replicate } from "@varg/replicate";
78
+ ```
79
+
80
+ ---
81
+
82
+ ## image generation
83
+
84
+ ### text to image
85
+
86
+ ```typescript
87
+ import { generateImage } from "ai";
88
+ import { fal } from "@varg/fal";
89
+ import { higgsfield } from "@varg/higgsfield";
90
+
91
+ // fal nano-banana - options on model or in providerOptions
92
+ const { image } = await generateImage({
93
+ model: fal.imageModel("nano-banana-pro", { resolution: "1K" }),
94
+ prompt: "cyberpunk cityscape at night, neon lights",
95
+ aspectRatio: "16:9",
96
+ n: 1,
97
+ });
98
+
99
+ // higgsfield soul - options on model
100
+ const { image } = await generateImage({
101
+ model: higgsfield.imageModel("soul", {
102
+ style: "realism",
103
+ enhancePrompt: true,
104
+ quality: "1080p",
105
+ }),
106
+ prompt: "portrait of young woman, soft lighting",
107
+ aspectRatio: "1:1",
108
+ });
109
+ ```
110
+
111
+ ### image to image (editing)
112
+
113
+ ```typescript
114
+ const { image } = await generateImage({
115
+ model: fal.imageModel("nano-banana-pro/edit"),
116
+ prompt: {
117
+ images: [referenceImage1, referenceImage2],
118
+ text: "combine these two people in a coffee shop scene",
119
+ },
120
+ aspectRatio: "4:5",
121
+ });
122
+ ```
123
+
124
+ ### with element reference (characters, items, styles)
125
+
126
+ generate reusable elements for consistent generation:
127
+
128
+ ```typescript
129
+ import { generateImage, generateVideo } from "ai";
130
+ import { generateElement, scene, File } from "@varg/sdk";
131
+ import { fal } from "@varg/fal";
132
+
133
+ // create character element
134
+ const { element: ralph } = await generateElement({
135
+ model: fal.imageModel("nano-banana-pro/edit"),
136
+ type: "character",
137
+ prompt: {
138
+ text: "ralph wiggum from the simpsons, yellow skin, blue shorts, red shirt",
139
+ images: [await File.fromPath("media/ralph.jpg").arrayBuffer()],
140
+ },
141
+ });
142
+ console.log(`ralph: ${ralph.images.length} images`);
143
+
144
+ // create item element
145
+ const { element: blackboard } = await generateElement({
146
+ model: fal.imageModel("nano-banana-pro"),
147
+ type: "item",
148
+ prompt: "green chalkboard from simpsons intro, white chalk text",
149
+ });
150
+
151
+ // compose elements with scene`` tagged template
152
+ const { image: firstFrame } = await generateImage({
153
+ model: fal.imageModel("nano-banana-pro/edit"),
154
+ prompt: scene`${ralph} writes on the ${blackboard}`,
155
+ });
156
+
157
+ // use element.text in video prompts
158
+ const { video } = await generateVideo({
159
+ model: fal.videoModel("wan-2.5"),
160
+ prompt: {
161
+ text: `${ralph.text} writes on the ${blackboard.text}`,
162
+ images: [firstFrame.base64],
163
+ },
164
+ duration: 5,
165
+ });
166
+ ```
167
+
168
+ element structure:
169
+ ```typescript
170
+ interface Element {
171
+ images: Uint8Array[]; // generated reference images
172
+ text: string; // text description for prompts
173
+ type: "character" | "item" | "style";
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ ## video generation
180
+
181
+ ### image to video
182
+
183
+ ```typescript
184
+ import { generateVideo } from "ai";
185
+ import { fal } from "@varg/fal";
186
+
187
+ const { video } = await generateVideo({
188
+ model: fal.videoModel("kling-v2.5"),
189
+ prompt: {
190
+ images: [frameImage],
191
+ text: "person slowly turns head and smiles",
192
+ },
193
+ duration: 5, // 5 or 10 seconds
194
+ });
195
+ ```
196
+
197
+ ### text to video
198
+
199
+ ```typescript
200
+ const { video } = await generateVideo({
201
+ model: fal.videoModel("kling-v2.5"),
202
+ prompt: "aerial shot of ocean waves crashing on rocks",
203
+ duration: 10,
204
+ });
205
+ ```
206
+
207
+ ### talking head from photo
208
+
209
+ ```typescript
210
+ import { generateTalkingHead } from "@varg/sdk";
211
+ import { heygen } from "@varg/heygen";
212
+
213
+ const { video } = await generateTalkingHead({
214
+ model: heygen.talkingHeadModel("avatar-iv"),
215
+ image: File.fromPath("media/portrait.jpg"),
216
+ script: "hello! welcome to our product demo.",
217
+ voice: "rachel",
218
+ motionPrompt: "friendly, subtle hand gestures",
219
+ });
220
+ ```
221
+
222
+ ---
223
+
224
+ ## audio generation
225
+
226
+ ### text to speech (voiceover)
227
+
228
+ ```typescript
229
+ import { generateSpeech } from "ai";
230
+ import { elevenlabs } from "@varg/elevenlabs";
231
+
232
+ const { audio } = await generateSpeech({
233
+ model: elevenlabs.speechModel("eleven-turbo-v2"),
234
+ text: "this is an amazing new product that will change your life.",
235
+ voice: "rachel",
236
+ providerOptions: {
237
+ elevenlabs: {
238
+ stability: 0.5,
239
+ similarityBoost: 0.75,
240
+ },
241
+ },
242
+ });
243
+
244
+ await Bun.write("output/voiceover.mp3", audio.uint8Array);
245
+ ```
246
+
247
+ ### music generation
248
+
249
+ ```typescript
250
+ import { generateMusic } from "@varg/sdk";
251
+ import { elevenlabs } from "@varg/elevenlabs";
252
+
253
+ const { audio } = await generateMusic({
254
+ model: elevenlabs.musicModel("sound-generation"),
255
+ prompt: "upbeat electronic music, energetic, modern, 120 bpm",
256
+ duration: 15, // up to 22 seconds
257
+ });
258
+ ```
259
+
260
+ ---
261
+
262
+ ## lipsync
263
+
264
+ sync video to audio:
265
+
266
+ ```typescript
267
+ import { generateLipsync } from "@varg/sdk";
268
+ import { fal } from "@varg/fal";
269
+
270
+ const { video } = await generateLipsync({
271
+ model: fal.lipsyncModel("sync-v2-pro"),
272
+ video: File.fromPath("media/talking-head.mp4"),
273
+ audio: File.fromPath("media/voiceover.mp3"),
274
+ syncMode: "cut_off", // "cut_off" | "loop" | "bounce" | "silence"
275
+ });
276
+ ```
277
+
278
+ ---
279
+
280
+ ## video editing
281
+
282
+ use [editly](https://github.com/mifi/editly) directly for video composition. we provide `File.toTemp()` to bridge ai outputs to editly.
283
+
284
+ ### bridging ai outputs to editly
285
+
286
+ ```typescript
287
+ import editly from "editly";
288
+ import { generateVideo, generateImage } from "ai";
289
+ import { File } from "@varg/sdk";
290
+ import { fal } from "@varg/fal";
291
+
292
+ // generate with ai
293
+ const { video } = await generateVideo({
294
+ model: fal.videoModel("kling-v2.5"),
295
+ prompt: "woman walking on beach",
296
+ duration: 5,
297
+ });
298
+
299
+ const { image } = await generateImage({
300
+ model: fal.imageModel("nano-banana-pro"),
301
+ prompt: "product shot on white background",
302
+ });
303
+
304
+ // save to temp files for editly
305
+ const videoPath = await File.toTemp(video);
306
+ const imagePath = await File.toTemp(image);
307
+
308
+ // use editly directly
309
+ await editly({
310
+ outPath: "./output.mp4",
311
+ width: 1080,
312
+ height: 1920,
313
+ clips: [
314
+ {
315
+ duration: 5,
316
+ layers: [{ type: "video", path: videoPath, resizeMode: "contain-blur" }],
317
+ },
318
+ {
319
+ duration: 3,
320
+ transition: { name: "fade", duration: 0.5 },
321
+ layers: [{ type: "image", path: imagePath }],
322
+ },
323
+ ],
324
+ audioTracks: [
325
+ { path: "./music.mp3", mixVolume: 0.3 },
326
+ ],
327
+ audioNorm: { enable: true }, // audio ducking
328
+ });
329
+ ```
330
+
331
+ ### editly features
332
+
333
+ - 67 gl-transitions (fade, crossfade, cube, pixelize, glitch, etc.)
334
+ - blur background resize (`resizeMode: "contain-blur"`)
335
+ - picture-in-picture (positioned overlays)
336
+ - audio mixing with ducking (`audioNorm`)
337
+ - ken burns on images (`zoomDirection: "in" | "out"`)
338
+ - custom canvas/fabric.js layers
339
+
340
+ see [editly docs](https://github.com/mifi/editly) for full api.
341
+
342
+ ---
343
+
344
+ ### add captions
345
+
346
+ ```typescript
347
+ import { addCaptions } from "@varg/sdk";
348
+
349
+ // tiktok-style word-by-word captions
350
+ const { video } = await addCaptions({
351
+ video: File.fromPath("media/video.mp4"),
352
+ captions: [
353
+ { text: "this is amazing", start: 0, end: 2 },
354
+ { text: "watch until the end", start: 2, end: 4 },
355
+ ],
356
+ style: "tiktok", // animated bounce effect
357
+ position: "center",
358
+ font: {
359
+ family: "Montserrat",
360
+ size: 48,
361
+ color: "#ffffff",
362
+ strokeColor: "#000000",
363
+ strokeWidth: 2,
364
+ },
365
+ });
366
+ ```
367
+
368
+ ### add music to video
369
+
370
+ ```typescript
371
+ import { addMusic } from "@varg/sdk";
372
+
373
+ const { video } = await addMusic({
374
+ video: File.fromPath("media/video.mp4"),
375
+ music: File.fromPath("media/background-music.mp3"),
376
+ volume: 0.3,
377
+ ducking: {
378
+ enabled: true,
379
+ threshold: -20, // duck when voice detected
380
+ reduction: 0.2,
381
+ },
382
+ });
383
+ ```
384
+
385
+ ### add voiceover to video
386
+
387
+ ```typescript
388
+ import { addVoiceover } from "@varg/sdk";
389
+ import { elevenlabs } from "@varg/elevenlabs";
390
+
391
+ const { video } = await addVoiceover({
392
+ video: File.fromPath("media/video.mp4"),
393
+ text: "here's what you need to know about this amazing product",
394
+ voice: elevenlabs.voice("rachel"),
395
+ mixWithOriginal: false,
396
+ });
397
+ ```
398
+
399
+ ---
400
+
401
+ ## video transformations
402
+
403
+ ### resize with blur (aspect ratio conversion)
404
+
405
+ convert 9:16 to 4:5 with blurred sides:
406
+
407
+ ```typescript
408
+ import { resizeVideo } from "@varg/sdk";
409
+
410
+ const { video } = await resizeVideo({
411
+ video: File.fromPath("media/vertical-video.mp4"),
412
+ targetAspect: "4:5", // "1:1" | "4:5" | "9:16" | "16:9" | "4:3" | "21:9"
413
+ background: "blur", // blurred version of video fills sides
414
+ blurStrength: 60,
415
+ });
416
+ ```
417
+
418
+ ### crop to aspect ratio
419
+
420
+ ```typescript
421
+ import { cropVideo } from "@varg/sdk";
422
+
423
+ const { video } = await cropVideo({
424
+ video: File.fromPath("media/landscape.mp4"),
425
+ targetAspect: "9:16",
426
+ gravity: "center", // "center" | "top" | "bottom" | "left" | "right"
427
+ });
428
+ ```
429
+
430
+ ### picture in picture
431
+
432
+ ```typescript
433
+ import { createPiP } from "@varg/sdk";
434
+
435
+ const { video } = await createPiP({
436
+ background: File.fromPath("media/background.mp4"),
437
+ overlay: File.fromPath("media/speaker.mp4"),
438
+ position: "bottom-right", // "bottom-right" | "bottom-left" | "top-right" | "top-left" | "center"
439
+ size: 0.3, // 30% of frame
440
+ padding: 20,
441
+ borderRadius: 16,
442
+ });
443
+ ```
444
+
445
+ ---
446
+
447
+ ## transitions & effects
448
+
449
+ ### split screen (before/after)
450
+
451
+ ```typescript
452
+ import { createSplitScreen } from "@varg/sdk";
453
+
454
+ const { video } = await createSplitScreen({
455
+ left: File.fromPath("media/before.mp4"),
456
+ right: File.fromPath("media/after.mp4"),
457
+ style: "rounded", // "stretch" | "rounded"
458
+ dividerWidth: 4,
459
+ dividerColor: "#ffffff",
460
+ });
461
+ ```
462
+
463
+ ### before/after slider
464
+
465
+ animated slider revealing transformation:
466
+
467
+ ```typescript
468
+ import { createSlider } from "@varg/sdk";
469
+
470
+ const { video } = await createSlider({
471
+ before: File.fromPath("media/before.jpg"),
472
+ after: File.fromPath("media/after.jpg"),
473
+ direction: "left-to-right",
474
+ duration: 4,
475
+ style: "center-stop", // stops at 50%
476
+ glowColor: [100, 255, 100],
477
+ });
478
+ ```
479
+
480
+ ### push transition
481
+
482
+ card-push transition between media:
483
+
484
+ ```typescript
485
+ import { createPushTransition } from "@varg/sdk";
486
+
487
+ const { video } = await createPushTransition({
488
+ before: File.fromPath("media/slide-1.jpg"),
489
+ after: File.fromPath("media/slide-2.jpg"),
490
+ direction: "left-to-right",
491
+ duration: 3,
492
+ parallax: true,
493
+ });
494
+ ```
495
+
496
+ ### tinder swipe
497
+
498
+ card swipe animation through multiple images:
499
+
500
+ ```typescript
501
+ import { createSwipeAnimation } from "@varg/sdk";
502
+
503
+ const { video } = await createSwipeAnimation({
504
+ images: [
505
+ File.fromPath("media/card-1.jpg"),
506
+ File.fromPath("media/card-2.jpg"),
507
+ File.fromPath("media/card-3.jpg"),
508
+ ],
509
+ direction: "right",
510
+ style: "stack", // "simple" | "stack" | "fade"
511
+ durationPerSwipe: 0.8,
512
+ pauseDuration: 0.5,
513
+ cornerRadius: 20,
514
+ shadow: true,
515
+ });
516
+ ```
517
+
518
+ ### slideshow with transitions
519
+
520
+ ```typescript
521
+ import { createSlideshow } from "@varg/sdk";
522
+
523
+ const { video } = await createSlideshow({
524
+ images: [
525
+ File.fromPath("media/photo-1.jpg"),
526
+ File.fromPath("media/photo-2.jpg"),
527
+ File.fromPath("media/photo-3.jpg"),
528
+ ],
529
+ durationPerSlide: 3,
530
+ transition: "crossfade", // "crossfade" | "fade" | "none"
531
+ transitionDuration: 0.5,
532
+ kenBurns: true, // subtle zoom/pan effect
533
+ });
534
+ ```
535
+
536
+ ### zoom effects
537
+
538
+ ```typescript
539
+ import { applyZoom } from "@varg/sdk";
540
+
541
+ const { video } = await applyZoom({
542
+ video: File.fromPath("media/video.mp4"),
543
+ type: "in", // "in" | "out"
544
+ intensity: 1.2, // 120% zoom
545
+ easing: "ease-in-out",
546
+ });
547
+ ```
548
+
549
+ ---
550
+
551
+ ## video composition
552
+
553
+ ### concatenate videos
554
+
555
+ ```typescript
556
+ import { concatenateVideos } from "@varg/sdk";
557
+
558
+ const { video } = await concatenateVideos({
559
+ videos: [
560
+ File.fromPath("media/intro.mp4"),
561
+ File.fromPath("media/main.mp4"),
562
+ File.fromPath("media/outro.mp4"),
563
+ ],
564
+ transition: "crossfade",
565
+ transitionDuration: 0.5,
566
+ });
567
+ ```
568
+
569
+ ### create packshot (end card)
570
+
571
+ ```typescript
572
+ import { createPackshot } from "@varg/sdk";
573
+
574
+ const { video } = await createPackshot({
575
+ background: File.fromPath("media/product.jpg"),
576
+ title: "shop now",
577
+ subtitle: "limited time offer",
578
+ ctaButton: {
579
+ text: "buy now",
580
+ color: "#ff0000",
581
+ pulse: true,
582
+ },
583
+ duration: 3,
584
+ });
585
+ ```
586
+
587
+ ### composite (layered video)
588
+
589
+ ```typescript
590
+ import { compositeVideos } from "@varg/sdk";
591
+
592
+ const { video } = await compositeVideos({
593
+ layers: [
594
+ { video: File.fromPath("media/background.mp4"), opacity: 1 },
595
+ { video: File.fromPath("media/overlay.mp4"), opacity: 0.8, position: "center" },
596
+ { video: File.fromPath("media/logo.png"), opacity: 1, position: "top-right", size: 0.1 },
597
+ ],
598
+ });
599
+ ```
600
+
601
+ ---
602
+
603
+ ## image processing
604
+
605
+ ### remove background
606
+
607
+ ```typescript
608
+ import { removeBackground } from "@varg/sdk";
609
+ import { replicate } from "@varg/replicate";
610
+
611
+ const { image } = await removeBackground({
612
+ model: replicate.imageModel("birefnet"),
613
+ image: File.fromPath("media/portrait.jpg"),
614
+ });
615
+ ```
616
+
617
+ ---
618
+
619
+ ## complete pipeline example
620
+
621
+ full video ad creation:
622
+
623
+ ```typescript
624
+ import { generateImage, generateVideo, generateSpeech } from "ai";
625
+ import {
626
+ generateMusic,
627
+ addCaptions,
628
+ addMusic,
629
+ addVoiceover,
630
+ resizeVideo,
631
+ createPackshot,
632
+ concatenateVideos,
633
+ File,
634
+ } from "@varg/sdk";
635
+ import { fal } from "@varg/fal";
636
+ import { elevenlabs } from "@varg/elevenlabs";
637
+ import { higgsfield } from "@varg/higgsfield";
638
+
639
+ async function createVideoAd() {
640
+ // 1. generate character image
641
+ const { image: characterImage } = await generateImage({
642
+ model: higgsfield.imageModel("soul"),
643
+ prompt: "confident woman in her 30s, natural makeup, warm smile",
644
+ aspectRatio: "9:16",
645
+ });
646
+
647
+ // 2. animate to video
648
+ const { video: mainVideo } = await generateVideo({
649
+ model: fal.videoModel("kling-v2.5"),
650
+ prompt: {
651
+ images: [characterImage.uint8Array],
652
+ text: "woman speaking to camera, friendly gestures, nodding",
653
+ },
654
+ duration: 10,
655
+ });
656
+
657
+ // 3. generate voiceover
658
+ const { audio: voiceover } = await generateSpeech({
659
+ model: elevenlabs.speechModel("eleven-turbo-v2"),
660
+ text: "discover the secret to radiant skin with our new formula",
661
+ voice: "rachel",
662
+ });
663
+
664
+ // 4. generate background music
665
+ const { audio: music } = await generateMusic({
666
+ model: elevenlabs.musicModel("sound-generation"),
667
+ prompt: "soft inspiring background music, gentle piano",
668
+ duration: 15,
669
+ });
670
+
671
+ // 5. add voiceover with captions
672
+ let { video } = await addVoiceover({
673
+ video: mainVideo,
674
+ audio: voiceover,
675
+ });
676
+
677
+ ({ video } = await addCaptions({
678
+ video,
679
+ captions: [
680
+ { text: "discover the secret", start: 0, end: 2 },
681
+ { text: "to radiant skin", start: 2, end: 4 },
682
+ { text: "with our new formula", start: 4, end: 6 },
683
+ ],
684
+ style: "tiktok",
685
+ }));
686
+
687
+ // 6. add background music with ducking
688
+ ({ video } = await addMusic({
689
+ video,
690
+ music,
691
+ volume: 0.2,
692
+ ducking: { enabled: true },
693
+ }));
694
+
695
+ // 7. create packshot
696
+ const { video: packshot } = await createPackshot({
697
+ background: File.fromPath("media/product.jpg"),
698
+ title: "shop now",
699
+ ctaButton: { text: "buy now", pulse: true },
700
+ duration: 3,
701
+ });
702
+
703
+ // 8. concatenate main video + packshot
704
+ const { video: finalVideo } = await concatenateVideos({
705
+ videos: [video, packshot],
706
+ transition: "crossfade",
707
+ });
708
+
709
+ // 9. export multiple aspect ratios
710
+ const { video: video_9x16 } = finalVideo; // already 9:16
711
+
712
+ const { video: video_4x5 } = await resizeVideo({
713
+ video: finalVideo,
714
+ targetAspect: "4:5",
715
+ background: "blur",
716
+ });
717
+
718
+ const { video: video_1x1 } = await resizeVideo({
719
+ video: finalVideo,
720
+ targetAspect: "1:1",
721
+ background: "blur",
722
+ });
723
+
724
+ // save all formats
725
+ await Bun.write("output/ad_9x16.mp4", video_9x16.uint8Array);
726
+ await Bun.write("output/ad_4x5.mp4", video_4x5.uint8Array);
727
+ await Bun.write("output/ad_1x1.mp4", video_1x1.uint8Array);
728
+
729
+ console.log("done! exported 3 formats");
730
+ }
731
+
732
+ createVideoAd();
733
+ ```
734
+
735
+ ---
736
+
737
+ ## provider reference
738
+
739
+ ### fal
740
+
741
+ | model type | models |
742
+ |---|---|
743
+ | `imageModel` | `nano-banana-pro`, `nano-banana-pro/edit` |
744
+ | `videoModel` | `kling-v2.5`, `kling-v2.5-pro` |
745
+ | `lipsyncModel` | `sync-v2-pro` |
746
+
747
+ ### higgsfield
748
+
749
+ | model type | models |
750
+ |---|---|
751
+ | `imageModel` | `soul` |
752
+
753
+ ### elevenlabs
754
+
755
+ | model type | models |
756
+ |---|---|
757
+ | `speechModel` | `eleven-turbo-v2`, `eleven-multilingual-v2` |
758
+ | `musicModel` | `sound-generation` |
759
+ | `voice` | `rachel`, `adam`, `bella`, ... |
760
+
761
+ ### heygen
762
+
763
+ | model type | models |
764
+ |---|---|
765
+ | `talkingHeadModel` | `avatar-iv` |
766
+
767
+ ### openai
768
+
769
+ | model type | models |
770
+ |---|---|
771
+ | `imageModel` | `gpt-image-1`, `dall-e-3`, `dall-e-2` |
772
+ | `videoModel` | `sora-2`, `sora-2-pro` |
773
+
774
+ ### replicate
775
+
776
+ | model type | models |
777
+ |---|---|
778
+ | `imageModel` | `birefnet` (background removal), any replicate model |
779
+
780
+ ---
781
+
782
+ ## types
783
+
784
+ ```typescript
785
+ interface File {
786
+ arrayBuffer(): Promise<ArrayBuffer>;
787
+ base64(): Promise<string>;
788
+ uint8Array: Uint8Array;
789
+ mimeType: string;
790
+ }
791
+
792
+ interface GenerateImageResult {
793
+ image: File;
794
+ revisedPrompt?: string;
795
+ }
796
+
797
+ interface GenerateVideoResult {
798
+ video: File;
799
+ duration: number;
800
+ }
801
+
802
+ interface GenerateSpeechResult {
803
+ audio: File;
804
+ duration: number;
805
+ }
806
+
807
+ type AspectRatio = "1:1" | "4:5" | "9:16" | "16:9" | "4:3" | "21:9" | "3:2" | "2:3";
808
+
809
+ type CaptionStyle = "tiktok" | "subtitle" | "minimal";
810
+
811
+ type TransitionType = "crossfade" | "fade" | "none";
812
+ ```