Skip to content

Instantly share code, notes, and snippets.

@SecurityQQ
Last active March 10, 2026 04:34
Show Gist options
  • Select an option

  • Save SecurityQQ/0901cbed66ec1c272a321b654884484f to your computer and use it in GitHub Desktop.

Select an option

Save SecurityQQ/0901cbed66ec1c272a321b654884484f to your computer and use it in GitHub Desktop.
varg + Claude Code Quickstart - Generate AI videos with natural language

Legend Biography Video Templates -- Quickstart

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)

Setup (2 minutes)

# 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
EOF

Get your keys:

Render a Video

# Amy Winehouse biography
bun run render templates/legend-amy.tsx

# Kurt Cobain biography
bun run render templates/legend-kurt.tsx

Output lands in output/. First run takes a few minutes (AI generation). Subsequent runs are instant (cached).

Preview in Studio

bun run studio templates/legend-amy.tsx

Opens a visual editor at localhost:8282 where you can preview the timeline.

How It Works

Each template follows the same pattern:

Reference Photo --> 8 AI Images --> 8 AI Videos --> Composed Timeline
                                                   + Voiceover
                                                   + Music
                                                   + Captions

The Pipeline

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>
);

Make Your Own Legend

To create a biography for a different person:

  1. Get a reference photo -- upload to https://s3.varg.ai/ or use any public URL
  2. Copy a template -- cp templates/legend-amy.tsx templates/legend-yourperson.tsx
  3. Edit 4 things:
    • REF -- your reference image URL
    • STYLE -- 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
  4. Render -- bun run render templates/legend-yourperson.tsx

Use with Claude Code

# Install the varg skill
npx add-skill vargHQ/skills

# Start Claude Code in the templates directory
claude

Then 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.

Key Details

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

Full Examples

legend-amy.tsx

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>
);

legend-kurt.tsx

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>
);

Links

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment