AI-generated biography videos in TikTok/Reels format. Each template creates a 16-second vertical video with 8 cinematic scenes, voiceover, captions, and background music -- all from a single reference photo.
Included templates:
legend-amy.tsx-- Amy Winehouse (warm jazz/soul, vintage 2000s aesthetic)legend-kurt.tsx-- Kurt Cobain (cool grunge, 1990s blue tones)
# 1. Clone the templates repo
git clone --recursive https://github.com/vargHQ/templates.git
cd templates
# 2. Install dependencies
bun install
# 3. Add your API keys to .env
cat > .env << 'EOF'
FAL_KEY=fal_xxx
ELEVENLABS_API_KEY=xxx
EOFGet your keys:
- FAL_KEY (required) -- https://fal.ai/dashboard/keys
- ELEVENLABS_API_KEY (required for voice/music) -- https://elevenlabs.io/app/settings/api-keys
# Amy Winehouse biography
bun run render templates/legend-amy.tsx
# Kurt Cobain biography
bun run render templates/legend-kurt.tsxOutput lands in output/. First run takes a few minutes (AI generation). Subsequent runs are instant (cached).
bun run studio templates/legend-amy.tsxOpens a visual editor at localhost:8282 where you can preview the timeline.
Each template follows the same pattern:
Reference Photo --> 8 AI Images --> 8 AI Videos --> Composed Timeline
+ Voiceover
+ Music
+ Captions
import { fal, elevenlabs } from "vargai/ai";
import { Clip, Image, Render, Video, Music, Speech, Captions } from "vargai/react";
// 1. Reference photo for character consistency
const REF = "https://your-reference-image.png";
// 2. Style constants
const STYLE = "vintage color photograph, film grain, warm tones";
const CHARACTER = "same person from reference, key visual traits";
// 3. Generate scene images from the reference
const img1 = Image({
prompt: { text: `Close-up portrait, ${CHARACTER}, jazz club, ${STYLE}`, images: [REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
// 4. Animate each image to video
const vid1 = Video({
prompt: { text: "person singing, gentle movement", images: [img1] },
model: fal.videoModel("kling-v2.5"),
duration: 10,
});
// 5. Voiceover
const speech = Speech({
voice: "rachel",
model: elevenlabs.speechModel("turbo"),
children: "Your narration script here.",
});
// 6. Compose the final video
export default (
<Render width={1080} height={1920}>
<Music prompt="genre-appropriate instrumental" model={elevenlabs.musicModel()}
volume={0.15} loop ducking duration={16} />
<Clip duration={2} cutFrom={0.3} cutTo={2.3}>
{vid1}
</Clip>
{/* ...more clips with fade transitions... */}
<Captions src={speech} style="tiktok" position="bottom" />
</Render>
);To create a biography for a different person:
- Get a reference photo -- upload to
https://s3.varg.ai/or use any public URL - Copy a template --
cp templates/legend-amy.tsx templates/legend-yourperson.tsx - Edit 4 things:
REF-- your reference image URLSTYLE-- visual aesthetic (e.g. "1970s disco, warm golden tones")CHARACTER-- key visual traits ("same man from reference, afro, wide smile, bell-bottoms")speech.children-- your narration script
- Render --
bun run render templates/legend-yourperson.tsx
# Install the varg skill
npx add-skill vargHQ/skills
# Start Claude Code in the templates directory
claudeThen ask:
> Create a legend biography video for Freddie Mercury using this reference: https://example.com/freddie.jpg
> Make a biography template for Billie Holiday in warm sepia jazz tones
> Modify the Kurt template to use a 30-second narration instead
Claude Code knows the full varg component API and will generate working .tsx files.
| What | Value |
|---|---|
| Output format | 1080x1920 (9:16 vertical) |
| Duration | ~16 seconds (8 clips x 2s each) |
| Scenes | 8 (4 performance + 4 emotional close-ups) |
| Transitions | Fade (0.15s between clips) |
| Cut trim | 0.2-0.3s trimmed from clip edges (removes AI artifacts) |
| Image model | nano-banana-pro/edit (reference-based generation) |
| Video model | kling-v2.5 (10s for main scenes, 5s for cutaways) |
| Voice model | ElevenLabs turbo |
| Music | ElevenLabs music model, 15% volume, ducking enabled |
import { fal, elevenlabs } from "vargai/ai";
import { Clip, Image, Render, Video, Music, Speech, Captions } from "vargai/react";
// --- REFERENCES ---
const AMY_REF = "https://uu.varg.ai/1773114162387_kurylgk1.png";
// --- STYLE ---
const STYLE = "vintage color photograph, film grain texture, warm vintage tones, 2000s retro aesthetic, elegant moody lighting, soulful atmosphere, no sepia, no border";
const CHARACTER = "same woman from reference, dark hair in beehive style, red lips, striking eyes, vintage fashion, tattooed arms";
const CHARACTER_SPEAKING = `${CHARACTER}, lips slightly parted, speaking`;
// --- ORIGINAL 4 SCENE IMAGES ---
const img1 = Image({
prompt: { text: `Medium close-up portrait, ${CHARACTER_SPEAKING}, in a retro jazz club setting, soft spotlight, emotional expression, vintage microphone, ${STYLE}`, images: [AMY_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img2 = Image({
prompt: { text: `Close-up portrait, ${CHARACTER_SPEAKING}, on stage with microphone, confident powerful gaze, warm stage lighting, passionate soul voice, ${STYLE}`, images: [AMY_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img3 = Image({
prompt: { text: `Medium shot, ${CHARACTER}, performing with arms raised, powerful stance, retro stage setting, elegant movement, vintage dress, ${STYLE}`, images: [AMY_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img4 = Image({
prompt: { text: `Portrait, ${CHARACTER}, in quiet vulnerable pose, looking downward, soft warm light, delicate fragile expression, introspective mood, ${STYLE}`, images: [AMY_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
// --- NEW SCENES ---
const img5 = Image({
prompt: { text: `Close-up of woman's soulful face, ${CHARACTER}, eyes glistening with emotion, vulnerable expression, dramatic warm lighting, inner pain visible, ${STYLE}`, images: [AMY_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img6 = Image({
prompt: { text: `Close-up hands holding microphone, ${CHARACTER} singing, tattooed arms visible, expressive hand movement, intimate moment, warm vintage light, ${STYLE}`, images: [AMY_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img7 = Image({
prompt: { text: `Medium shot from below, ${CHARACTER} on stage in vintage dress, performing with passion, crowd energy, spotlight, powerful presence, ${STYLE}`, images: [AMY_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img8 = Image({
prompt: { text: `Wide shot, ${CHARACTER} alone in dimly lit room, sitting alone, melancholic expression, warm soft light, isolated vulnerability, ${STYLE}`, images: [AMY_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
// --- ANIMATE TO VIDEO ---
const vid1 = Video({
prompt: { text: "woman singing with deep emotion, gentle head movement, soulful gaze, warm intimate expression", images: [img1] },
model: fal.videoModel("kling-v2.5"),
duration: 10
});
const vid2 = Video({
prompt: { text: "woman on stage, confident powerful presence, holding microphone, raw emotional delivery, soul-filled voice", images: [img2] },
model: fal.videoModel("kling-v2.5"),
duration: 10
});
const vid3 = Video({
prompt: { text: "woman performing, elegant movement, arms graceful, powerful stage presence, vintage style", images: [img3] },
model: fal.videoModel("kling-v2.5"),
duration: 10
});
const vid4 = Video({
prompt: { text: "woman in quiet vulnerable pose, soft downward gaze, delicate fragile moment, gentle breath", images: [img4] },
model: fal.videoModel("kling-v2.5"),
duration: 10
});
const vid5 = Video({
prompt: { text: "woman's eyes glisten with emotion, eyebrows furrow, vulnerable soulful expression, pain and beauty", images: [img5] },
model: fal.videoModel("kling-v2.5"),
duration: 5
});
const vid6 = Video({
prompt: { text: "hands hold microphone, fingers expressive, singing with passion, intimate musical moment", images: [img6] },
model: fal.videoModel("kling-v2.5"),
duration: 5
});
const vid7 = Video({
prompt: { text: "woman on stage singing passionately, body sways with music, powerful vocal energy, elegant presence", images: [img7] },
model: fal.videoModel("kling-v2.5"),
duration: 5
});
const vid8 = Video({
prompt: { text: "woman sits alone in dim light, slow melancholic movement, introspective vulnerable mood", images: [img8] },
model: fal.videoModel("kling-v2.5"),
duration: 5
});
// --- VOICEOVER ---
const speech = Speech({
voice: "rachel",
model: elevenlabs.speechModel("turbo"),
children: "Amy Winehouse was pure soul. Her voice dripped with vulnerability and strength. Jazz reborn through her. A once-in-a-generation talent. Though she fought her demons hard, her legacy lives forever. In every note."
});
// --- BUILD RENDER ---
export default (
<Render width={1080} height={1920}>
<Music
prompt="vintage jazz soul instrumental, retro 1960s influence, soulful horns, warm vintage vibes, 2000s soul music"
model={elevenlabs.musicModel()}
volume={0.15}
loop={true}
ducking={true}
duration={16}
/>
<Clip duration={2} cutFrom={0.3} cutTo={2.3}>
{vid1}
</Clip>
<Clip duration={2} cutFrom={0.3} cutTo={2.3} transition={{ name: "fade", duration: 0.15 }}>
{vid2}
</Clip>
<Clip duration={2} cutFrom={0.2} cutTo={2.2} transition={{ name: "fade", duration: 0.15 }}>
{vid5}
</Clip>
<Clip duration={2} cutFrom={0.2} cutTo={2.2} transition={{ name: "fade", duration: 0.15 }}>
{vid6}
</Clip>
<Clip duration={2} cutFrom={0.3} cutTo={2.3} transition={{ name: "fade", duration: 0.15 }}>
{vid3}
</Clip>
<Clip duration={2} cutFrom={0.2} cutTo={2.2} transition={{ name: "fade", duration: 0.15 }}>
{vid7}
</Clip>
<Clip duration={2} cutFrom={0.3} cutTo={2.3} transition={{ name: "fade", duration: 0.15 }}>
{vid4}
</Clip>
<Clip duration={2} cutFrom={0.2} cutTo={2.2} transition={{ name: "fade", duration: 0.15 }}>
{vid8}
</Clip>
<Captions src={speech} style="tiktok" position="bottom" />
</Render>
);import { fal, elevenlabs } from "vargai/ai";
import { Clip, Image, Render, Video, Music, Speech, Captions } from "vargai/react";
// --- REFERENCES ---
const KURT_REF = "https://uu.varg.ai/1773109560573_gbz0buz0.jpg";
// --- STYLE ---
const STYLE = "vintage color photograph, film grain texture, cool blue tones, 1990s grunge aesthetic, moody atmospheric lighting, soft focus, no sepia, no border";
const CHARACTER = "same man from reference, long blonde hair, pale complexion, introspective gaze, worn expression";
const CHARACTER_SPEAKING = `${CHARACTER}, lips slightly parted, speaking`;
// --- ORIGINAL 4 SCENE IMAGES ---
const img1 = Image({
prompt: { text: `Medium close-up portrait, ${CHARACTER_SPEAKING}, in a basement or garage setting, holding an acoustic guitar, dim lamp light, melancholic expression, ${STYLE}`, images: [KURT_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img2 = Image({
prompt: { text: `Close-up portrait, ${CHARACTER_SPEAKING}, in a recording studio, microphone visible, focused intensity, cool studio lighting, raw emotional expression, ${STYLE}`, images: [KURT_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img3 = Image({
prompt: { text: `Medium shot, ${CHARACTER}, on stage with guitar, powerful performance stance, stage lights and smoke, wild energy, hair flying, ${STYLE}`, images: [KURT_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img4 = Image({
prompt: { text: `Portrait, ${CHARACTER}, in quiet contemplative pose, looking downward, soft diffused light, vulnerable and fragile expression, ${STYLE}`, images: [KURT_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
// --- NEW SCENES ---
const img5 = Image({
prompt: { text: `Close-up of man's anguished face, ${CHARACTER}, eyes filled with pain, brow furrowed, emotional turmoil visible, moody dark lighting, ${STYLE}`, images: [KURT_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img6 = Image({
prompt: { text: `Close-up hands on guitar strings, ${CHARACTER} playing, fingers on fretboard, worn hands, intimate creative moment, dim candlelit atmosphere, ${STYLE}`, images: [KURT_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img7 = Image({
prompt: { text: `Medium shot from below, ${CHARACTER} on stage with guitar raised, intense performance, crowd energy, stage lights, raw power, ${STYLE}`, images: [KURT_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
const img8 = Image({
prompt: { text: `Wide shot, ${CHARACTER} alone in empty room, sitting isolated, looking haunted, pale blue light through window, solitary melancholy, ${STYLE}`, images: [KURT_REF] },
model: fal.imageModel("nano-banana-pro/edit"),
aspectRatio: "9:16",
});
// --- ANIMATE TO VIDEO ---
const vid1 = Video({
prompt: { text: "man holding guitar, fingers moving gently on strings, sad contemplative gaze, quiet intensity", images: [img1] },
model: fal.videoModel("kling-v2.5"),
duration: 10
});
const vid2 = Video({
prompt: { text: "man in studio, raw emotional expression, voice trembling slightly, intense focus, vulnerability", images: [img2] },
model: fal.videoModel("kling-v2.5"),
duration: 10
});
const vid3 = Video({
prompt: { text: "man on stage with guitar, explosive energy, body swaying with music, wild passionate performance", images: [img3] },
model: fal.videoModel("kling-v2.5"),
duration: 10
});
const vid4 = Video({
prompt: { text: "man in quiet pose, head slightly tilted, troubled gaze, gentle defeated movement", images: [img4] },
model: fal.videoModel("kling-v2.5"),
duration: 10
});
const vid5 = Video({
prompt: { text: "man's jaw clenches, eyes show deep pain, brow furrows, emotional anguish expression", images: [img5] },
model: fal.videoModel("kling-v2.5"),
duration: 5
});
const vid6 = Video({
prompt: { text: "fingers playing guitar strings, hand movement, strings vibrating, intimate musical moment", images: [img6] },
model: fal.videoModel("kling-v2.5"),
duration: 5
});
const vid7 = Video({
prompt: { text: "man thrashing on stage with guitar, intense movement, powerful performance, crowd energy", images: [img7] },
model: fal.videoModel("kling-v2.5"),
duration: 5
});
const vid8 = Video({
prompt: { text: "man sits alone in empty room, slow movement, withdrawn isolated pose, melancholic atmosphere", images: [img8] },
model: fal.videoModel("kling-v2.5"),
duration: 5
});
// --- VOICEOVER ---
const speech = Speech({
voice: "adam",
model: elevenlabs.speechModel("turbo"),
children: "Kurt Cobain came from nowhere. His pain became a generation's anthem. Raw, authentic, unfiltered. Nirvana changed everything. Though he burned too bright, too fast. His voice echoes forever."
});
// --- BUILD RENDER ---
export default (
<Render width={1080} height={1920}>
<Music
prompt="dark melancholic grunge rock instrumental, distorted guitar, 1990s alternative rock, heavy sad atmosphere"
model={elevenlabs.musicModel()}
volume={0.15}
loop={true}
ducking={true}
duration={16}
/>
<Clip duration={2} cutFrom={0.3} cutTo={2.3}>
{vid1}
</Clip>
<Clip duration={2} cutFrom={0.3} cutTo={2.3} transition={{ name: "fade", duration: 0.15 }}>
{vid2}
</Clip>
<Clip duration={2} cutFrom={0.2} cutTo={2.2} transition={{ name: "fade", duration: 0.15 }}>
{vid5}
</Clip>
<Clip duration={2} cutFrom={0.2} cutTo={2.2} transition={{ name: "fade", duration: 0.15 }}>
{vid6}
</Clip>
<Clip duration={2} cutFrom={0.3} cutTo={2.3} transition={{ name: "fade", duration: 0.15 }}>
{vid3}
</Clip>
<Clip duration={2} cutFrom={0.2} cutTo={2.2} transition={{ name: "fade", duration: 0.15 }}>
{vid7}
</Clip>
<Clip duration={2} cutFrom={0.3} cutTo={2.3} transition={{ name: "fade", duration: 0.15 }}>
{vid4}
</Clip>
<Clip duration={2} cutFrom={0.2} cutTo={2.2} transition={{ name: "fade", duration: 0.15 }}>
{vid8}
</Clip>
<Captions src={speech} style="tiktok" position="bottom" />
</Render>
);