Import
/** @jsxImportSource vargai */
import {
Render, Clip,
Image, Video, Speech, Music,
Title, Subtitle, Captions,
Overlay, Split, Slider, Swipe, Grid,
TalkingHead, Packshot
} from "vargai/react"
import { createVarg } from "vargai/ai"
const varg = createVarg({ apiKey: process.env.VARG_API_KEY! })
Quick Reference
| Component | Purpose | Key Props |
|---|---|---|
<Render> | Root container | width, height, fps |
<Clip> | Time segment | duration, transition |
<Image> | AI or static image | prompt, src, zoom |
<Video> | AI or source video | prompt, src, volume |
<Speech> | Text-to-speech | voice, children |
<Music> | Background music | prompt, volume, loop |
<Title> | Text overlay | position, color |
<Captions> | Auto-generated subs | src, style |
<Overlay> | Positioned layer | left, top, width, height |
<Split> | Side-by-side | direction |
Container Components
Render
Root container for video composition. Required for all videos.<Render width={1080} height={1920} fps={30}>
{/* clips and media */}
</Render>
| Prop | Type | Default | Description |
|---|---|---|---|
width | number | 1080 | Video width in pixels |
height | number | 1920 | Video height in pixels |
fps | number | 30 | Frames per second |
| Platform | Resolution | Aspect Ratio |
|---|---|---|
| TikTok/Reels/Shorts | 1080x1920 | 9:16 |
| YouTube | 1920x1080 | 16:9 |
| Instagram Feed | 1080x1080 | 1:1 |
Clip
Time segment container. Clips play sequentially.<Clip duration={3} transition={{ name: "fade", duration: 0.5 }}>
<Video src="scene.mp4" />
</Clip>
| Prop | Type | Default | Description |
|---|---|---|---|
duration | number | Required | Duration in seconds |
transition | object | undefined | Transition to next clip |
cutFrom | number | 0 | Start time offset |
cutTo | number | undefined | End time offset |
transition={{ name: "fade", duration: 0.5 }}
transition={{ name: "crossfade", duration: 0.5 }}
transition={{ name: "wipeleft", duration: 0.5 }}
transition={{ name: "wiperight", duration: 0.5 }}
transition={{ name: "slideup", duration: 0.5 }}
transition={{ name: "slidedown", duration: 0.5 }}
transition={{ name: "cube", duration: 0.8 }}
transition={{ name: "pixelize", duration: 0.5 }}
Media Components
Image
AI-generated or static image.// AI generation
const cat = Image({
prompt: "cute orange cat, Pixar style",
model: varg.imageModel("nano-banana-pro"),
aspectRatio: "9:16",
})
// In composition with zoom
<Clip duration={3}>
<Image src={cat} zoom="in" />
</Clip>
// Static image
<Clip duration={3}>
<Image src="media/photo.jpg" zoom="out" />
</Clip>
| Prop | Type | Default | Description |
|---|---|---|---|
prompt | string | Required | Image description |
model | ImageModel | varg.imageModel("nano-banana-pro") | AI model |
aspectRatio | string | "1:1" | Output ratio |
| Prop | Type | Default | Description |
|---|---|---|---|
src | string or ImageRef | Required | Image source or reference |
zoom | "in" "out" "left" "right" | undefined | Ken Burns effect |
resize | "cover" or "contain" | "cover" | Resize mode |
Video
AI-generated or source video.// Image-to-video
const character = Image({ prompt: "robot character" })
<Clip duration={5}>
<Video
prompt={{ text: "robot waves hello", images: [character] }}
model={varg.videoModel("kling-v3")}
/>
</Clip>
// Text-to-video
<Clip duration={5}>
<Video
prompt="ocean waves crashing on beach"
model={varg.videoModel("kling-v3")}
/>
</Clip>
// Source video
<Clip duration={5}>
<Video src="media/clip.mp4" volume={0.5} />
</Clip>
// Lipsync (video + audio)
const animatedVideo = Video({ prompt: { ... } });
const voiceover = Speech({ ... });
<Video
prompt={{ video: animatedVideo, audio: voiceover }}
model={varg.videoModel("sync-v2-pro")}
/>
| Prop | Type | Default | Description |
|---|---|---|---|
prompt | string or object | - | Generation prompt |
src | string | - | Source video path |
model | VideoModel | varg.videoModel("kling-v3") | AI model |
volume | number | 1 | Audio volume (0-1) |
cutFrom | number | 0 | Start trim |
cutTo | number | - | End trim |
// Text only
prompt="waves on beach"
// Image-to-video
prompt={{ text: "waves crash", images: [imageRef] }}
// Lipsync
prompt={{ video: videoRef, audio: speechRef }}
Speech
Text-to-speech voiceover.const voiceover = Speech({
model: varg.speechModel("eleven_v3"),
voice: "rachel",
children: "Hello everyone! Welcome to my video.",
})
// Use in composition
<Captions src={voiceover} style="tiktok" />
| Prop | Type | Default | Description |
|---|---|---|---|
children | string | Required | Text to speak |
model | SpeechModel | varg.speechModel("eleven_v3") | TTS model |
voice | string | "rachel" | Voice name or ID |
volume | number | 1 | Audio volume |
rachel, adam, bella, josh, sam, antoni, elli, arnold, domi
Music
Background music generation.<Render>
<Music
prompt="upbeat electronic pop, energetic"
model={varg.musicModel()}
volume={0.2}
loop
/>
<Clip duration={5}>...</Clip>
<Clip duration={5}>...</Clip>
</Render>
| Prop | Type | Default | Description |
|---|---|---|---|
prompt | string | - | Music description |
src | string | - | Source audio file |
model | MusicModel | varg.musicModel() | Generation model |
volume | number | 1 | Audio volume (0.1-0.3 for background) |
loop | boolean | false | Loop audio |
ducking | number | undefined | Lower volume during speech |
Text Components
Title
Text overlay on video.<Clip duration={5}>
<Video src="scene.mp4" />
<Title position="top" color="#ffffff">My Video Title</Title>
</Clip>
| Prop | Type | Default | Description |
|---|---|---|---|
children | string | Required | Title text |
position | "top" "center" "bottom" | "center" | Position |
color | string | "#ffffff" | Text color |
start | number | 0 | Start time |
end | number | - | End time |
Captions
Auto-generated subtitles from speech.const voiceover = Speech({ children: "Hello everyone!" });
<Render>
<Clip duration={5}>
<Video src="talking.mp4" />
</Clip>
<Captions src={voiceover} style="tiktok" color="#ffffff" />
</Render>
| Prop | Type | Default | Description |
|---|---|---|---|
src | SpeechRef | Required | Speech reference for timing |
srt | string | - | Custom SRT file |
style | string | "tiktok" | Caption animation style |
color | string | "#ffffff" | Text color |
activeColor | string | - | Active word color |
| Style | Description |
|---|---|
tiktok | Word-by-word highlight |
karaoke | Fill left-to-right |
bounce | Words bounce in |
typewriter | Typing effect |
Layout Components
Overlay
Positioned layer on top of content.<Clip duration={5}>
<Video src="background.mp4" />
<Overlay left={50} top={100} width={200} height={200}>
<Image src="logo.png" />
</Overlay>
</Clip>
| Prop | Type | Default | Description |
|---|---|---|---|
left | number | 0 | X position |
top | number | 0 | Y position |
width | number | - | Width |
height | number | - | Height |
keepAudio | boolean | true | Keep overlay audio |
Split
Side-by-side layout.<Clip duration={5}>
<Split direction="horizontal">
<Video src="left.mp4" />
<Video src="right.mp4" />
</Split>
</Clip>
| Prop | Type | Default | Description |
|---|---|---|---|
direction | "horizontal" or "vertical" | "horizontal" | Split direction |
SplitLayout
Before/after comparison layout.<Clip duration={5}>
<SplitLayout
direction="horizontal"
left={beforeVideo}
right={afterVideo}
/>
</Clip>
Grid
Grid layout for multiple items.<Clip duration={5}>
<Grid columns={2}>
<Video src="1.mp4" />
<Video src="2.mp4" />
<Video src="3.mp4" />
<Video src="4.mp4" />
</Grid>
</Clip>
| Prop | Type | Default | Description |
|---|---|---|---|
columns | number | 2 | Number of columns |
Slider
Before/after reveal slider.<Clip duration={5}>
<Slider direction="horizontal">
<Image src="before.jpg" />
<Image src="after.jpg" />
</Slider>
</Clip>
Swipe
Tinder-style card swipe.<Clip duration={10}>
<Swipe direction="horizontal" interval={2}>
<Image src="card1.jpg" />
<Image src="card2.jpg" />
<Image src="card3.jpg" />
</Swipe>
</Clip>
| Prop | Type | Default | Description |
|---|---|---|---|
direction | "horizontal" or "vertical" | "horizontal" | Swipe direction |
interval | number | 2 | Seconds per card |
Special Components
TalkingHead
Complete talking character with automatic lipsync.const character = Image({ prompt: "friendly presenter" });
<Clip duration={10}>
<TalkingHead
character={character}
voice="rachel"
model={varg.videoModel("kling-v3")}
lipsyncModel={varg.videoModel("sync-v2-pro")}
>
Hello everyone! Welcome to my channel.
</TalkingHead>
</Clip>
| Prop | Type | Default | Description |
|---|---|---|---|
character | ImageRef | Required | Character image |
children | string | Required | Script text |
voice | string | "rachel" | Voice name |
model | VideoModel | - | Animation model |
lipsyncModel | VideoModel | - | Lipsync model |
Packshot
End card with call-to-action.<Clip duration={3}>
<Packshot
background="#000000"
logo="media/logo.png"
cta="Subscribe Now!"
blinkCta
/>
</Clip>
| Prop | Type | Default | Description |
|---|---|---|---|
background | string | "#000000" | Background color |
logo | string | - | Logo image path |
cta | string | - | Call-to-action text |
blinkCta | boolean | false | Animate CTA |
FFmpeg processing
Slice
Split a video into segments with automatic first-frame extraction. Returns an array of segments, each with a video URL, full-resolution first frame (JPEG), and 480px thumbnail (WebP).import { Slice } from "vargai/react";
import { createVarg } from "vargai/ai";
const varg = createVarg({ apiKey: process.env.VARG_API_KEY! });
// Split every 15 seconds
const { segments } = await Slice({ src: "https://example.com/video.mp4", every: 15 });
for (const seg of segments) {
console.log(seg.url); // segment video URL
console.log(seg.first_frame); // full-res JPEG of first frame
console.log(seg.thumbnail); // 480px WebP thumbnail
console.log(seg.start, seg.end, seg.duration);
}
// Split every N seconds
await Slice({ src: video, every: 10 });
// Split at specific timestamps
await Slice({ src: video, at: [5, 15, 30] });
// Split into N equal parts
await Slice({ src: video, count: 4 });
// Split at explicit ranges
await Slice({ src: video, ranges: [{ start: 0, end: 10 }, { start: 20, end: 30 }] });
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | File | VargElement | - | Source video (URL, File, or element) |
codec | "copy" | "reencode" | "copy" | copy for fast keyframe-aligned cuts, reencode for frame-accurate |
every | number | - | Split every N seconds |
at | number[] | - | Split at specific timestamps |
count | number | - | Split into N equal parts |
ranges | Array<{start, end}> | - | Explicit time ranges |
every, at, count, or ranges must be provided.
Segment properties
Each segment in the returned array has:
| Property | Type | Description |
|---|---|---|
url | string | CDN URL of the segment video |
file | File | File object for the segment |
duration | number | Segment duration in seconds |
index | number | 0-based segment index |
start | number | Start time in the source video (seconds) |
end | number | End time in the source video (seconds) |
first_frame | string | Full-resolution first frame (JPEG) |
thumbnail | string | 480px-wide thumbnail (WebP) |