> ## Documentation Index
> Fetch the complete documentation index at: https://docs.videodb.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Trailer Narration

> Create dramatic trailers with automated narration

<a href="https://colab.research.google.com/github/video-db/videodb-cookbook/blob/main/examples/Automated_Trailer_Voiceover.ipynb" target="_blank">
  <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" noZoom />
</a>

## Introduction

Narration is the heartbeat of trailers, injecting excitement and intrigue into every frame. With **VideoDB**, adding narration becomes a seamless, creative process.

In this tutorial, we will:

1. **Analyze** a movie trailer to understand its scenes.
2. **Generate** a dramatic script using VideoDB's text generation.
3. **Synthesize** a deep, trailer-style voiceover using VideoDB's voice generation.
4. **Edit** the narration into specific time slots to match the video's pacing.
5. **Overlay** a movie poster at the end.

All using a single SDK.

Here's an example of weaving a thrilling storyline from a reel of unrelated, but valuable cinematic shots:

<iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/sldlSP_aSmQ" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

## Setup

### Installing VideoDB

```
!pip install videodb
```

### API Keys

<Note>
  You only need your VideoDB API Key. Get your API key from [VideoDB Console](https://console.videodb.io). Free for first 50 uploads, no credit card required.
</Note>

## Step 1: Connect to VideoDB

Establish a connection to your VideoDB project.

<CodeGroup>
  ```python Python theme={null}
  import videodb

  # Set your API key
  api_key = "your_api_key"

  # Connect to VideoDB
  conn = videodb.connect(api_key=api_key)
  coll = conn.get_collection()
  ```

  ```javascript Node.js theme={null}
  import { connect } from 'videodb';

  // Connect to VideoDB
  const conn = await connect({ apiKey: process.env.VIDEO_DB_API_KEY });
  const coll = await conn.getCollection();
  ```
</CodeGroup>

## Step 2: Upload the Trailer

We'll upload a sample movie trailer (Chase) to VideoDB. This creates the base video asset we will edit.

<CodeGroup>
  ```python Python theme={null}
  video = coll.upload(url='https://www.youtube.com/watch?v=WQmGwmc-XUY')
  ```

  ```javascript Node.js theme={null}
  const video = await coll.uploadURL({ url: 'https://www.youtube.com/watch?v=WQmGwmc-XUY' });
  ```
</CodeGroup>

## Step 3: Analyze Scenes

We need to understand the visual pacing of the trailer to write a good script. `index_scenes()` will generate descriptions and timestamps for every shot.

<CodeGroup>
  ```python Python theme={null}
  video_scenes_id = video.index_scenes()
  ```

  ```javascript Node.js theme={null}
  const videoScenesId = await video.indexScenes();
  ```
</CodeGroup>

Let's view the description of first scene from the video

<CodeGroup>
  ```python Python theme={null}
  video_scenes = video.get_scene_index(video_scenes_id)

  import json
  print(json.dumps(video_scenes[0], indent=2))
  ```

  ```javascript Node.js theme={null}
  const videoScenes = await video.getSceneIndex(videoScenesId);

  console.log(JSON.stringify(videoScenes[0], null, 2));
  ```
</CodeGroup>

**Output:**

```json theme={null}
{
  "description": "The scene is engulfed in a vast, tumultuous blaze, with vibrant yellow and fiery orange flames swirling and dancing across the entire frame. The intense heat radiating from the inferno creates a mesmerizing, dynamic spectacle, casting a reddish-brown glow that fills the atmosphere. Darker, smoky elements are intermittently visible through the brilliant light, suggesting objects being consumed within the heart of this powerful, destructive force. The fire is alive, constantly shifting and reaching, conveying both destructive power and captivating motion.",
  "end": 1.043,
  "metadata": {},
  "scene_metadata": {},
  "start": 0.0
}
```

## Step 4: Generate Narration Script

We'll use VideoDB's `generate_text` to write a dramatic script. We feed the scene descriptions into the prompt to ensure the narration matches the visual action.

<CodeGroup>
  ```python Python theme={null}
  # Construct prompt with scene context
  scene_context = "\n".join([f"- {scene['description']}" for scene in video_scenes])

  prompt = f"""
  Craft a dynamic, dramatic narration script for a movie trailer based on these visual descriptions:
  {scene_context}

  Requirements:
  - Style: Intense, gritty, like a blockbuster action movie trailer.
  - Output: Only provide the script for direct voice generation, no stage directions or narration.
  """

  script_response = coll.generate_text(
      prompt=prompt,
      model_name="pro")

  script_text = script_response["output"]

  print("--- Generated Script ---")
  print(script_text)
  ```

  ```javascript Node.js theme={null}
  // Construct prompt with scene context
  const sceneContext = videoScenes.map(scene => `- ${scene.description}`).join('\n');

  const prompt = `
  Craft a dynamic, dramatic narration script for a movie trailer based on these visual descriptions:
  ${sceneContext}

  Requirements:
  - Style: Intense, gritty, like a blockbuster action movie trailer.
  - Output: Only provide the script for direct voice generation, no stage directions or narration.
  `;

  const scriptResponse = await coll.generateText(
      prompt,
      "pro"
  );

  const scriptText = scriptResponse.output;

  console.log("--- Generated Script ---");
  console.log(scriptText);
  ```
</CodeGroup>

You can refine the narration script prompt to ensure synchronization with timestamps in the scene index, optimizing the storytelling experience.

## Step 5: Generate Voiceover Audio

Now we synthesize the audio.

<CodeGroup>
  ```python Python theme={null}
  # Generate speech directly as an Audio Asset
  audio = coll.generate_voice(
      text=script_text,
      voice_name="Brian")

  print(f"Generated Audio ID: {audio.id}")
  ```

  ```javascript Node.js theme={null}
  // Generate speech directly as an Audio Asset
  const audio = await coll.generateVoice(
      scriptText,
      "Brian"
  );

  console.log(`Generated Audio ID: ${audio.id}`);
  ```
</CodeGroup>

## Step 6: Edit the Timeline

Now we combine the video and audio.

<CodeGroup>
  ```python Python theme={null}
  from videodb.editor import Timeline, Track, Clip, VideoAsset, AudioAsset

  timeline = Timeline(conn)

  # --- 1. Main Video Track ---
  main_track = Track()
  video_asset = VideoAsset(id=video.id, volume=0.5)
  video_clip = Clip(asset=video_asset, duration=float(video.length))
  main_track.add_clip(0, video_clip)
  timeline.add_track(main_track)

  # --- 2. Narration Track---
  audio_track = Track()
  audio_asset1 = AudioAsset(id=audio.id, start=0, volume=2.0)
  audio_clip1 = Clip(asset=audio_asset1, duration=float(audio.length))
  audio_track.add_clip(4, audio_clip1)

  timeline.add_track(audio_track)
  ```

  ```javascript Node.js theme={null}
  import { EditorTimeline, Track, Clip, EditorVideoAsset, EditorAudioAsset } from 'videodb';

  const timeline = new EditorTimeline(conn);

  // --- 1. Main Video Track ---
  const mainTrack = new Track();
  const videoAsset = new EditorVideoAsset({ id: video.id, volume: 0.5 });
  const videoClip = new Clip({ asset: videoAsset, duration: parseFloat(video.length) });
  mainTrack.addClip(0, videoClip);
  timeline.addTrack(mainTrack);

  // --- 2. Narration Track ---
  const audioTrack = new Track();
  const audioAsset1 = new EditorAudioAsset({ id: audio.id, start: 0, volume: 2.0 });
  const audioClip1 = new Clip({ asset: audioAsset1, duration: parseFloat(audio.length) });
  audioTrack.addClip(4, audioClip1);

  timeline.addTrack(audioTrack);
  ```
</CodeGroup>

## Step 8: Review and Share

Preview the trailer with the integrated narration to ensure it aligns with your vision. Once satisfied, share the trailer with others to experience the enhanced storytelling.

<CodeGroup>
  ```python Python theme={null}
  from videodb import play_stream

  stream_url = timeline.generate_stream()
  play_stream(stream_url)
  ```

  ```javascript Node.js theme={null}
  const streamUrl = await timeline.generateStream();
  console.log(streamUrl);
  ```
</CodeGroup>

## Bonus - Add Movie Poster

Let's add a "Coming Soon" style movie poster at the very end of the trailer. We'll upload an image URL and overlay it on the video.

<CodeGroup>
  ```python Python theme={null}
  from videodb import MediaType

  # Upload movie poster
  poster_url = "https://img.freepik.com/free-photo/darkly-atmospheric-retail-environment-rendering_23-2151153755.jpg"
  image = coll.upload(url=poster_url, media_type=MediaType.image)
  ```

  ```javascript Node.js theme={null}
  import { MediaType } from 'videodb';

  // Upload movie poster
  const posterUrl = "https://img.freepik.com/free-photo/darkly-atmospheric-retail-environment-rendering_23-2151153755.jpg";
  const image = await coll.uploadURL({ url: posterUrl, mediaType: MediaType.image });
  ```
</CodeGroup>

<CodeGroup>
  ```python Python theme={null}
  from videodb.editor import ImageAsset

  # Create an overlay track for the poster
  image_track = Track()

  # Show poster at the 10 seconds of the trailer
  image_asset = ImageAsset(id=image.id)
  image_clip = Clip(
      asset=image_asset,
      duration=10.0,
      fit="contain")

  image_track.add_clip(float(video.length) - 10, image_clip)
  timeline.add_track(image_track)

  stream_url = timeline.generate_stream()
  play_stream(stream_url)
  ```

  ```javascript Node.js theme={null}
  import { EditorImageAsset } from 'videodb';

  // Create an overlay track for the poster
  const imageTrack = new Track();

  // Show poster at the 10 seconds of the trailer
  const imageAsset = new EditorImageAsset({ id: image.id });
  const imageClip = new Clip({
      asset: imageAsset,
      duration: 10.0,
      fit: "contain"
  });

  imageTrack.addClip(parseFloat(video.length) - 10, imageClip);
  timeline.addTrack(imageTrack);

  const finalStreamUrl = await timeline.generateStream();
  console.log(finalStreamUrl);
  ```
</CodeGroup>

## Conclusion

You’ve successfully built a sophisticated video editing workflow:

* **Analysis:** Automated scene understanding.
* **Generation:** AI Scripting and Voice synthesis.
* **Composition:** Non-linear editing with multi-track audio and image overlays.

<iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/KMqtcMzOmW8" title="Enhanced Trailer with Narration" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

Here's another interesting experiment to generate automatic voiceovers for silent footages. In this example, we've added the classic David Attenborough styled documentary narration to this footage of the underwater world. Check out the complete tutorial [here](/examples-and-tutorials/content-factory/voiceovers)

<iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/gsU14KgORgg" title="David Attenborough Style Documentary Narration" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

<Card icon="notebook" title="Explore Full Notebook" href="https://colab.research.google.com/github/video-db/videodb-cookbook/blob/main/examples/Automated_Trailer_Voiceover.ipynb">
  Open the complete implementation in Google Colab with all code examples.
</Card>

## Related Tutorials

<CardGroup cols={2}>
  <Card title="AI Voiceovers" icon="mic" href="/examples-and-tutorials/content-factory/voiceovers">
    Add professional narration to silent footage
  </Card>

  <Card title="Voice Cloning" icon="copy" href="/examples-and-tutorials/content-factory/voice-cloning">
    Clone voices for consistent brand audio
  </Card>
</CardGroup>
