Text to Video with Intro Video and Outro Video

This example demonstrates how to create a video with an intro video scene and an outro video scene. This is perfect for adding branded video intros and outros to your videos.

Overview

This example covers:

  • Getting an access token
  • Adding an intro scene with video background
  • Adding an outro scene with video background
  • Understanding optional minimum durations for intro/outro scenes
  • Understanding how video duration is determined automatically
  • Understanding background-only scenes
  • Monitoring job status and retrieving the final video

Node.js Example

Prerequisites

npm install axios

Complete Code

import axios from "axios";

const API_BASE_URL = "https://api.pictory.ai/pictoryapis";
const CLIENT_ID = "YOUR_CLIENT_ID";
const CLIENT_SECRET = "YOUR_CLIENT_SECRET";

const STORY_TEXT =
  "AI is poised to significantly impact educators and course creators on social media. By automating tasks like content generation, visual design, and video editing, AI will save time and enhance consistency.";
const INTRO_VIDEO_URL = "https://pictory-static.pictorycontent.com/PictoryLogoINTRO.mp4";
const OUTRO_VIDEO_URL = "https://pictory-static.pictorycontent.com/PictoryLogoOUTRO.mp4";

async function createTextToVideoWithIntroOutro() {
  try {
    // Step 1: Get Access Token
    console.log("Step 1: Getting access token...");
    const tokenResponse = await axios.post(
      `${API_BASE_URL}/v1/oauth2/token`,
      {
        client_id: CLIENT_ID,
        client_secret: CLIENT_SECRET,
      },
      {
        headers: {
          "Content-Type": "application/json",
        },
      }
    );

    const accessToken = tokenResponse.data.access_token;
    console.log("Access token obtained successfully");
    console.log("Token expires in:", tokenResponse.data.expires_in, "seconds\n");

    // Step 2: Create Video with Intro Video and Outro Video
    console.log("Step 2: Creating video with intro and outro...");
    const storyboardResponse = await axios.post(
      `${API_BASE_URL}/v2/video/storyboard/render`,
      {
        videoName: "text_to_video_intro_outro",
        scenes: [
          // Intro scene with video background
          {
            background: {
              type: "video",
              visualUrl: INTRO_VIDEO_URL,
            },
            minimumDuration: 2, // Optional: 2 seconds intro
          },
          // Main content scene
          {
            story: STORY_TEXT,
            createSceneOnNewLine: true,
            createSceneOnEndOfSentence: true,
          },
          // Outro scene with video background
          {
            background: {
              type: "video",
              visualUrl: OUTRO_VIDEO_URL,
            },
            // minimumDuration not specified - will use the actual video duration
          },
        ],
      },
      {
        headers: {
          "Content-Type": "application/json",
          Authorization: accessToken,
        },
      }
    );

    const renderJobId = storyboardResponse.data.data.jobId;
    console.log("Video with intro and outro render job created");
    console.log("Job ID:", renderJobId, "\n");

    // Step 3: Monitor Job Status
    console.log("Step 3: Monitoring job status...");
    let jobCompleted = false;
    let jobResult = null;

    while (!jobCompleted) {
      const jobStatusResponse = await axios.get(`${API_BASE_URL}/v1/jobs/${renderJobId}`, {
        headers: {
          Authorization: accessToken,
        },
      });

      const status = jobStatusResponse.data.data.status;
      console.log("Current status:", status);

      if (status === "completed") {
        jobCompleted = true;
        jobResult = jobStatusResponse.data;
        console.log("\nVideo with intro and outro created successfully!");
        console.log("Video URL:", jobResult.data.videoURL);
      } else if (status === "failed") {
        throw new Error("Job failed: " + JSON.stringify(jobStatusResponse.data));
      } else {
        // Wait 5 seconds before checking again
        await new Promise(resolve => setTimeout(resolve, 5000));
      }
    }

    return jobResult;
  } catch (error) {
    console.error("Error:", error.response?.data || error.message);
    throw error;
  }
}

// Run the function
createTextToVideoWithIntroOutro();

Python Example

Prerequisites

pip install requests

Complete Code

import requests
import time
import json

API_BASE_URL = 'https://api.pictory.ai/pictoryapis'
CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'

STORY_TEXT = "AI is poised to significantly impact educators and course creators on social media. By automating tasks like content generation, visual design, and video editing, AI will save time and enhance consistency."
INTRO_VIDEO_URL = "https://pictory-static.pictorycontent.com/PictoryLogoINTRO.mp4"
OUTRO_VIDEO_URL = "https://pictory-static.pictorycontent.com/PictoryLogoOUTRO.mp4"

def create_text_to_video_with_intro_outro():
    try:
        # Step 1: Get Access Token
        print('Step 1: Getting access token...')
        token_response = requests.post(
            f'{API_BASE_URL}/v1/oauth2/token',
            json={
                'client_id': CLIENT_ID,
                'client_secret': CLIENT_SECRET
            },
            headers={
                'Content-Type': 'application/json'
            }
        )
        token_response.raise_for_status()

        access_token = token_response.json()['access_token']
        print('Access token obtained successfully')
        print(f"Token expires in: {token_response.json()['expires_in']} seconds\n")

        # Step 2: Create Video with Intro Video and Outro Video
        print('Step 2: Creating video with intro and outro...')
        storyboard_response = requests.post(
            f'{API_BASE_URL}/v2/video/storyboard/render',
            json={
                'videoName': 'text_to_video_intro_outro',
                'scenes': [
                    # Intro scene with video background
                    {
                        'background': {
                            'type': 'video',
                            'visualUrl': INTRO_VIDEO_URL
                        },
                        'minimumDuration': 2  # Optional: 2 seconds intro
                    },
                    # Main content scene
                    {
                        'story': STORY_TEXT,
                        'createSceneOnNewLine': True,
                        'createSceneOnEndOfSentence': True
                    },
                    # Outro scene with video background
                    {
                        'background': {
                            'type': 'video',
                            'visualUrl': OUTRO_VIDEO_URL
                        }
                        # minimumDuration not specified - will use the actual video duration
                    }
                ]
            },
            headers={
                'Content-Type': 'application/json',
                'Authorization': access_token
            }
        )
        storyboard_response.raise_for_status()

        render_job_id = storyboard_response.json()['data']['jobId']
        print('Video with intro and outro render job created')
        print(f'Job ID: {render_job_id}\n')

        # Step 3: Monitor Job Status
        print('Step 3: Monitoring job status...')
        job_completed = False
        job_result = None

        while not job_completed:
            job_status_response = requests.get(
                f'{API_BASE_URL}/v1/jobs/{render_job_id}',
                headers={
                    'Authorization': access_token
                }
            )
            job_status_response.raise_for_status()

            status = job_status_response.json()['data']['status']
            print(f'Current status: {status}')

            if status == 'completed':
                job_completed = True
                job_result = job_status_response.json()
                print('\nVideo with intro and outro created successfully!')
                print(f"Video URL: {job_result['data']['videoURL']}")
            elif status == 'failed':
                raise Exception(f"Job failed: {json.dumps(job_status_response.json())}")
            else:
                # Wait 5 seconds before checking again
                time.sleep(5)

        return job_result

    except requests.exceptions.RequestException as error:
        print(f'Error: {error}')
        if hasattr(error, 'response') and error.response is not None:
            print(f'Response: {error.response.text}')
        raise

# Run the function
if __name__ == '__main__':
    create_text_to_video_with_intro_outro()

Key Parameters

Background Object

  • background.type: Type of background
    • "video" - For video backgrounds (both intros and outros)
  • background.visualUrl: URL to the background video file

Minimum Duration

  • minimumDuration: Optional duration in seconds for background-only scenes
    • Optional - If not provided, the system will automatically determine the duration from the video file at runtime
    • When specified, ensures intro/outro scenes play for a specific time
    • If the video is shorter than minimumDuration, it may loop depending on the loop settings
    • If the video is longer, it will be trimmed to minimumDuration
    • If omitted, the full duration of the provided video will be used

Scene Structure

Background-Only Scene (Intro/Outro)

A scene with only a background (no story text) requires:

  1. A background object with type and visualUrl
  2. Optionally, a minimumDuration to specify how long the scene should display
    • If minimumDuration is not provided, the system will automatically use the actual duration of the video file
    • If minimumDuration is provided, the video will be trimmed or looped to match that duration

Regular Content Scene

A scene with story text:

  1. Has a story field with text content
  2. Duration is calculated based on text length and voice-over
  3. Can optionally have a background as well

Use Cases

Intro Video Scenes

  • Animated company logo
  • Channel branding with motion graphics
  • Title animations
  • Episode intros with movement
  • Series branding with video effects

Outro Video Scenes

  • Animated subscribe/follow calls-to-action
  • Social media links with animations
  • Next episode teasers with clips
  • Animated credits
  • Thank you animations

Advanced Examples

Intro with Text Overlay

{
  background: {
    type: "video",
    visualUrl: "https://pictory-static.pictorycontent.com/PictoryLogoINTRO.mp4"
  },
  story: "Welcome to our channel",
  minimumDuration: 3  // Optional: override video duration
}

Intro without minimumDuration (Auto-detect)

{
  background: {
    type: "video",
    visualUrl: "https://pictory-static.pictorycontent.com/PictoryLogoINTRO.mp4"
  }
  // minimumDuration omitted - will use the actual video duration
}

Multiple Outros

scenes: [
  { story: "Main content..." },
  {
    background: {
      type: "video",
      visualUrl: "https://pictory-static.pictorycontent.com/PictoryLogoOUTRO.mp4",
    },
    // No minimumDuration - uses actual video duration
  },
  {
    background: {
      type: "image",
      visualUrl: "https://example.com/thankyou.png",
    },
    minimumDuration: 3, // Required for images
  },
];

Video Background Settings

You can control video background behavior:

background: {
  type: "video",
  visualUrl: OUTRO_VIDEO_URL,
  settings: {
    mute: true,   // Mute the outro video audio
    loop: false   // Don't loop the video
  }
}

Best Practices

  1. Intro Duration: Keep intros short (2-5 seconds) to maintain viewer engagement
  2. Outro Duration: Outros can be longer (5-10 seconds) for calls-to-action
  3. Video Format: Use MP4 format for best compatibility
  4. Video Resolution: Use high-resolution videos (1920x1080)
  5. Auto-Duration: For custom video URLs, omit minimumDuration to use the actual video length automatically
  6. Video Length: If using minimumDuration, ensure video files are close to that duration to avoid excessive looping or trimming
  7. Audio: Consider muting background videos if you have voice-over or music
  8. Branding: Use consistent intro/outro videos across your video series

Common Intro/Outro Durations

  • Quick Intro: 2-3 seconds
  • Standard Intro: 4-5 seconds
  • Detailed Intro: 6-8 seconds
  • Short Outro: 3-5 seconds
  • Standard Outro: 5-8 seconds
  • Long Outro: 10-15 seconds

Response

The API returns a job ID for monitoring the video creation progress. Once completed, you'll receive a video URL with intro and outro video scenes included.

Notes

  • Replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with your actual API credentials
  • Video files must be accessible via public URLs
  • minimumDuration is optional - If not provided, the system automatically detects the video duration at runtime for custom video URLs (non-stock library videos)
  • When minimumDuration is specified, it ensures scenes play for at least the specified time
  • If the background video is shorter than minimumDuration, it may loop (unless loop is set to false)
  • If the background video is longer than minimumDuration, it will be trimmed
  • For image backgrounds, minimumDuration is required as images don't have inherent duration
  • You can add background music to intro/outro scenes
  • You can add voice-over to intro/outro scenes by including a story field
  • Both intro and outro videos will be processed and included in the final rendered video

Duration Behavior Summary

ScenariominimumDurationBehavior
Custom video URLNot providedUses actual video duration (auto-detected at runtime)
Custom video URLProvided (e.g., 5s)Video is trimmed or looped to match 5 seconds
Stock library videoProvidedVideo is trimmed or looped to match specified duration
Image backgroundRequiredMust specify duration as images have no inherent duration