VideoCascadeLogo
VideoCascade

Adding Overlays

Complete examples for adding watermarks, logos, background music, and complex overlays

Learn how to enhance your videos with watermarks, logos, background music, picture-in-picture overlays, and animated GIFs. This guide provides production-ready examples for creating professional, branded video content.

Overview

Video overlays allow you to add:

  • Image overlays - Watermarks, logos, branding
  • Video overlays - Picture-in-picture, reactions
  • Audio overlays - Background music, sound effects
  • GIF overlays - Animated stickers, reactions
  • Multiple layers - Complex compositions with z-index

Adding a Watermark

The most common overlay: add a watermark logo to your video.

async function addWatermark(videoUrl, watermarkUrl) {
  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: videoUrl,
      elements: [
        {
          type: 'image',
          url: watermarkUrl,
          timing: { entireVideo: true },
          position: { anchor: 'bottom-right' },
          size: { width: '15%' },
          effects: { opacity: 0.7 },
          zIndex: 100
        }
      ]
    }),
  });

const data = await response.json();
return data.videoId;
}

// Usage
const videoId = await addWatermark(
'https://example.com/video.mp4',
'https://example.com/watermark.png'
);

const result = await waitForCompletion(videoId);
console.log('Watermarked video:', result.videoUrl);
def add_watermark(video_url, watermark_url):
    """Add watermark to video"""
    response = requests.post(
        'https://api.videocascade.com/v1/videos',
        headers={
            'Authorization': 'Bearer vca_your_api_key',
            'Content-Type': 'application/json',
        },
        json={
            'fileUrl': video_url,
            'elements': [
                {
                    'type': 'image',
                    'url': watermark_url,
                    'timing': {'entireVideo': True},
                    'position': {'anchor': 'bottom-right'},
                    'size': {'width': '15%'},
                    'effects': {'opacity': 0.7},
                    'zIndex': 100
                }
            ]
        }
    )

    response.raise_for_status()
    data = response.json()
    return data['videoId']

# Usage
video_id = add_watermark(
    'https://example.com/video.mp4',
    'https://example.com/watermark.png'
)

result = wait_for_completion(video_id)
print(f"Watermarked video: {result['videoUrl']}")
interface ImageElement {
  type: 'image';
  url: string;
  timing: { entireVideo: boolean };
  position: { anchor: string };
  size: { width: string };
  effects?: { opacity: number };
  zIndex?: number;
}

async function addWatermark(
videoUrl: string,
watermarkUrl: string
): Promise<string> {
const watermark: ImageElement = {
type: 'image',
url: watermarkUrl,
timing: { entireVideo: true },
position: { anchor: 'bottom-right' },
size: { width: '15%' },
effects: { opacity: 0.7 },
zIndex: 100
};

const response = await fetch('https://api.videocascade.com/v1/videos', {
method: 'POST',
headers: {
'Authorization': 'Bearer vca_your_api_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
fileUrl: videoUrl,
elements: [watermark]
}),
});

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();
return data.videoId;
}

// Usage
const videoId = await addWatermark(
'https://example.com/video.mp4',
'https://example.com/watermark.png'
);

const result = await waitForCompletion(videoId);
console.log('Watermarked video:', result.videoUrl);

Add a logo in different positions with precise control.

async function addPositionedLogo(videoUrl, logoUrl, position = 'top-right') {
  const positions = {
    'top-left': { anchor: 'top-left' },
    'top-right': { anchor: 'top-right' },
    'top-center': { anchor: 'top-center' },
    'bottom-left': { anchor: 'bottom-left' },
    'bottom-right': { anchor: 'bottom-right' },
    'bottom-center': { anchor: 'bottom-center' },
    'center': { anchor: 'center' }
  };

  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: videoUrl,
      elements: [
        {
          type: 'image',
          url: logoUrl,
          timing: { entireVideo: true },
          position: positions[position],
          size: { width: '12%' },
          effects: {
            opacity: 0.9,
            fadeIn: { duration: 0.5 }
          },
          zIndex: 100
        }
      ]
    }),
  });

  const data = await response.json();
  return data.videoId;
}

// Usage examples
await addPositionedLogo(videoUrl, logoUrl, 'top-right');    // Top right corner
await addPositionedLogo(videoUrl, logoUrl, 'bottom-left');  // Bottom left corner
await addPositionedLogo(videoUrl, logoUrl, 'center');       // Center of video
def add_positioned_logo(video_url, logo_url, position='top-right'):
    """Add logo at specified position"""
    positions = {
        'top-left': {'anchor': 'top-left'},
        'top-right': {'anchor': 'top-right'},
        'top-center': {'anchor': 'top-center'},
        'bottom-left': {'anchor': 'bottom-left'},
        'bottom-right': {'anchor': 'bottom-right'},
        'bottom-center': {'anchor': 'bottom-center'},
        'center': {'anchor': 'center'}
    }

    response = requests.post(
        'https://api.videocascade.com/v1/videos',
        headers={
            'Authorization': 'Bearer vca_your_api_key',
            'Content-Type': 'application/json',
        },
        json={
            'fileUrl': video_url,
            'elements': [
                {
                    'type': 'image',
                    'url': logo_url,
                    'timing': {'entireVideo': True},
                    'position': positions[position],
                    'size': {'width': '12%'},
                    'effects': {
                        'opacity': 0.9,
                        'fadeIn': {'duration': 0.5}
                    },
                    'zIndex': 100
                }
            ]
        }
    )

    response.raise_for_status()
    data = response.json()
    return data['videoId']

# Usage examples

add_positioned_logo(video_url, logo_url, 'top-right')
add_positioned_logo(video_url, logo_url, 'bottom-left')
add_positioned_logo(video_url, logo_url, 'center')
type Position = 'top-left' | 'top-right' | 'top-center' |
                'bottom-left' | 'bottom-right' | 'bottom-center' |
                'center';

async function addPositionedLogo(
  videoUrl: string,
  logoUrl: string,
  position: Position = 'top-right'
): Promise<string> {
  const positions: Record<Position, { anchor: string }> = {
    'top-left': { anchor: 'top-left' },
    'top-right': { anchor: 'top-right' },
    'top-center': { anchor: 'top-center' },
    'bottom-left': { anchor: 'bottom-left' },
    'bottom-right': { anchor: 'bottom-right' },
    'bottom-center': { anchor: 'bottom-center' },
    'center': { anchor: 'center' }
  };

  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: videoUrl,
      elements: [
        {
          type: 'image',
          url: logoUrl,
          timing: { entireVideo: true },
          position: positions[position],
          size: { width: '12%' },
          effects: {
            opacity: 0.9,
            fadeIn: { duration: 0.5 }
          },
          zIndex: 100
        }
      ]
    }),
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  const data = await response.json();
  return data.videoId;
}

// Usage examples
await addPositionedLogo(videoUrl, logoUrl, 'top-right');
await addPositionedLogo(videoUrl, logoUrl, 'bottom-left');
await addPositionedLogo(videoUrl, logoUrl, 'center');

Background Music

Add background music with volume control and fade effects.

async function addBackgroundMusic(videoUrl, musicUrl) {
  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: videoUrl,
      normalizeAudio: true,  // Balance music with original audio
      elements: [
        {
          type: 'audio',
          url: musicUrl,
          timing: { entireVideo: true },
          effects: {
            volume: 0.2,  // 20% volume (subtle background)
            fadeIn: { duration: 2, easing: 'ease-in' },
            fadeOut: { duration: 3, easing: 'ease-out' }
          },
          loop: true  // Loop if music is shorter than video
        }
      ]
    }),
  });

const data = await response.json();
return data.videoId;
}

// Usage with different music volumes
async function addMusicWithVolume(videoUrl, musicUrl, volume = 0.2) {
const response = await fetch('https://api.videocascade.com/v1/videos', {
method: 'POST',
headers: {
'Authorization': 'Bearer vca_your_api_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
fileUrl: videoUrl,
normalizeAudio: true,
elements: [
{
type: 'audio',
url: musicUrl,
timing: { entireVideo: true },
effects: {
volume,
fadeIn: { duration: 2 },
fadeOut: { duration: 3 }
},
loop: true
}
]
}),
});

return (await response.json()).videoId;
}

// Usage
await addMusicWithVolume(videoUrl, musicUrl, 0.15); // Subtle (15%)
await addMusicWithVolume(videoUrl, musicUrl, 0.3); // Moderate (30%)
await addMusicWithVolume(videoUrl, musicUrl, 0.5); // Prominent (50%)
def add_background_music(video_url, music_url):
    """Add background music to video"""
    response = requests.post(
        'https://api.videocascade.com/v1/videos',
        headers={
            'Authorization': 'Bearer vca_your_api_key',
            'Content-Type': 'application/json',
        },
        json={
            'fileUrl': video_url,
            'normalizeAudio': True,  # Balance music with original audio
            'elements': [
                {
                    'type': 'audio',
                    'url': music_url,
                    'timing': {'entireVideo': True},
                    'effects': {
                        'volume': 0.2,  # 20% volume
                        'fadeIn': {'duration': 2, 'easing': 'ease-in'},
                        'fadeOut': {'duration': 3, 'easing': 'ease-out'}
                    },
                    'loop': True
                }
            ]
        }
    )

    response.raise_for_status()
    data = response.json()
    return data['videoId']

def add_music_with_volume(video_url, music_url, volume=0.2):
    """Add music with custom volume"""
    response = requests.post(
        'https://api.videocascade.com/v1/videos',
        headers={
            'Authorization': 'Bearer vca_your_api_key',
            'Content-Type': 'application/json',
        },
        json={
            'fileUrl': video_url,
            'normalizeAudio': True,
            'elements': [
                {
                    'type': 'audio',
                    'url': music_url,
                    'timing': {'entireVideo': True},
                    'effects': {
                        'volume': volume,
                        'fadeIn': {'duration': 2},
                        'fadeOut': {'duration': 3}
                    },
                    'loop': True
                }
            ]
        }
    )

    response.raise_for_status()
    return response.json()['videoId']

# Usage
add_music_with_volume(video_url, music_url, 0.15)  # Subtle
add_music_with_volume(video_url, music_url, 0.3)   # Moderate
add_music_with_volume(video_url, music_url, 0.5)   # Prominent
interface AudioElement {
  type: 'audio';
  url: string;
  timing: { entireVideo: boolean };
  effects: {
    volume: number;
    fadeIn?: { duration: number; easing?: string };
    fadeOut?: { duration: number; easing?: string };
  };
  loop: boolean;
}

async function addBackgroundMusic(
videoUrl: string,
musicUrl: string
): Promise<string> {
const music: AudioElement = {
type: 'audio',
url: musicUrl,
timing: { entireVideo: true },
effects: {
volume: 0.2,
fadeIn: { duration: 2, easing: 'ease-in' },
fadeOut: { duration: 3, easing: 'ease-out' }
},
loop: true
};

const response = await fetch('https://api.videocascade.com/v1/videos', {
method: 'POST',
headers: {
'Authorization': 'Bearer vca_your_api_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
fileUrl: videoUrl,
normalizeAudio: true,
elements: [music]
}),
});

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();
return data.videoId;
}

async function addMusicWithVolume(
videoUrl: string,
musicUrl: string,
volume: number = 0.2
): Promise<string> {
const music: AudioElement = {
type: 'audio',
url: musicUrl,
timing: { entireVideo: true },
effects: {
volume,
fadeIn: { duration: 2 },
fadeOut: { duration: 3 }
},
loop: true
};

const response = await fetch('https://api.videocascade.com/v1/videos', {
method: 'POST',
headers: {
'Authorization': 'Bearer vca_your_api_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
fileUrl: videoUrl,
normalizeAudio: true,
elements: [music]
}),
});

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return (await response.json()).videoId;
}

// Usage
await addMusicWithVolume(videoUrl, musicUrl, 0.15); // Subtle
await addMusicWithVolume(videoUrl, musicUrl, 0.3); // Moderate
await addMusicWithVolume(videoUrl, musicUrl, 0.5); // Prominent

Picture-in-Picture Video Overlay

Add a webcam or reaction video in the corner.

async function addPictureInPicture(mainVideoUrl, pipVideoUrl) {
  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: mainVideoUrl,
      elements: [
        {
          type: 'video',
          url: pipVideoUrl,
          timing: { entireVideo: true },
          position: { anchor: 'bottom-right' },
          size: {
            width: '25%',  // 1/4 of main video width
            fit: 'cover'
          },
          effects: {
            fadeIn: { duration: 0.5 },
            fadeOut: { duration: 0.5 }
          },
          zIndex: 10,
          loop: false  // Don't loop the PiP video
        }
      ]
    }),
  });

  const data = await response.json();
  return data.videoId;
}

// Usage: Add webcam overlay to screen recording
const videoId = await addPictureInPicture(
  'https://example.com/screen-recording.mp4',
  'https://example.com/webcam.mp4'
);

// Advanced: PiP with timing control
async function addTimedPiP(mainVideoUrl, pipVideoUrl, startTime, endTime) {
  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: mainVideoUrl,
      elements: [
        {
          type: 'video',
          url: pipVideoUrl,
          timing: { startTime, endTime },  // Show only during this time
          position: { anchor: 'bottom-right' },
          size: { width: '25%', fit: 'cover' },
          effects: {
            fadeIn: { duration: 0.5 },
            fadeOut: { duration: 0.5 }
          },
          zIndex: 10
        }
      ]
    }),
  });

  return (await response.json()).videoId;
}

// Show PiP only from 30s to 90s
await addTimedPiP(mainVideoUrl, pipVideoUrl, 30, 90);
def add_picture_in_picture(main_video_url, pip_video_url):
    """Add picture-in-picture video overlay"""
    response = requests.post(
        'https://api.videocascade.com/v1/videos',
        headers={
            'Authorization': 'Bearer vca_your_api_key',
            'Content-Type': 'application/json',
        },
        json={
            'fileUrl': main_video_url,
            'elements': [
                {
                    'type': 'video',
                    'url': pip_video_url,
                    'timing': {'entireVideo': True},
                    'position': {'anchor': 'bottom-right'},
                    'size': {
                        'width': '25%',
                        'fit': 'cover'
                    },
                    'effects': {
                        'fadeIn': {'duration': 0.5},
                        'fadeOut': {'duration': 0.5}
                    },
                    'zIndex': 10,
                    'loop': False
                }
            ]
        }
    )

    response.raise_for_status()
    data = response.json()
    return data['videoId']

def add_timed_pip(main_video_url, pip_video_url, start_time, end_time):
"""Add PiP with timing control"""
response = requests.post(
'https://api.videocascade.com/v1/videos',
headers={
'Authorization': 'Bearer vca_your_api_key',
'Content-Type': 'application/json',
},
json={
'fileUrl': main_video_url,
'elements': [
{
'type': 'video',
'url': pip_video_url,
'timing': {'startTime': start_time, 'endTime': end_time},
'position': {'anchor': 'bottom-right'},
'size': {'width': '25%', 'fit': 'cover'},
'effects': {
'fadeIn': {'duration': 0.5},
'fadeOut': {'duration': 0.5}
},
'zIndex': 10
}
]
}
)

    response.raise_for_status()
    return response.json()['videoId']

# Usage

video_id = add_picture_in_picture(
'https://example.com/screen-recording.mp4',
'https://example.com/webcam.mp4'
)

# Show PiP only from 30s to 90s

add_timed_pip(main_video_url, pip_video_url, 30, 90)
interface VideoElement {
  type: 'video';
  url: string;
  timing: { entireVideo?: boolean; startTime?: number; endTime?: number };
  position: { anchor: string };
  size: { width: string; fit: string };
  effects?: {
    fadeIn?: { duration: number };
    fadeOut?: { duration: number };
  };
  zIndex: number;
  loop?: boolean;
}

async function addPictureInPicture(
  mainVideoUrl: string,
  pipVideoUrl: string
): Promise<string> {
  const pipElement: VideoElement = {
    type: 'video',
    url: pipVideoUrl,
    timing: { entireVideo: true },
    position: { anchor: 'bottom-right' },
    size: {
      width: '25%',
      fit: 'cover'
    },
    effects: {
      fadeIn: { duration: 0.5 },
      fadeOut: { duration: 0.5 }
    },
    zIndex: 10,
    loop: false
  };

  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: mainVideoUrl,
      elements: [pipElement]
    }),
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  const data = await response.json();
  return data.videoId;
}

async function addTimedPiP(
  mainVideoUrl: string,
  pipVideoUrl: string,
  startTime: number,
  endTime: number
): Promise<string> {
  const pipElement: VideoElement = {
    type: 'video',
    url: pipVideoUrl,
    timing: { startTime, endTime },
    position: { anchor: 'bottom-right' },
    size: { width: '25%', fit: 'cover' },
    effects: {
      fadeIn: { duration: 0.5 },
      fadeOut: { duration: 0.5 }
    },
    zIndex: 10
  };

  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: mainVideoUrl,
      elements: [pipElement]
    }),
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return (await response.json()).videoId;
}

// Usage
const videoId = await addPictureInPicture(
  'https://example.com/screen-recording.mp4',
  'https://example.com/webcam.mp4'
);

// Show PiP only from 30s to 90s
await addTimedPiP(mainVideoUrl, pipVideoUrl, 30, 90);

Multiple Overlays with Z-Index

Layer multiple overlays with proper stacking order.

async function addMultipleOverlays(videoUrl) {
  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: videoUrl,
      elements: [
        // Background watermark (bottom layer)
        {
          type: 'image',
          url: 'https://example.com/background-pattern.png',
          timing: { entireVideo: true },
          position: { anchor: 'center' },
          size: { width: '100%' },
          effects: { opacity: 0.1 },
          zIndex: 1
        },
        // Main logo (middle layer)
        {
          type: 'image',
          url: 'https://example.com/logo.png',
          timing: { entireVideo: true },
          position: { anchor: 'top-right' },
          size: { width: '12%' },
          effects: { opacity: 0.9 },
          zIndex: 50
        },
        // Watermark text (top layer)
        {
          type: 'image',
          url: 'https://example.com/watermark-text.png',
          timing: { entireVideo: true },
          position: { anchor: 'bottom-right' },
          size: { width: '15%' },
          effects: { opacity: 0.7 },
          zIndex: 100
        },
        // Opening title card (temporary, highest layer)
        {
          type: 'image',
          url: 'https://example.com/title-card.png',
          timing: { startTime: 0, endTime: 5 },
          position: { anchor: 'center' },
          size: { width: '60%' },
          effects: {
            fadeIn: { duration: 0.5 },
            fadeOut: { duration: 0.5 }
          },
          zIndex: 200
        },
        // Background music
        {
          type: 'audio',
          url: 'https://example.com/background-music.mp3',
          timing: { entireVideo: true },
          effects: {
            volume: 0.2,
            fadeIn: { duration: 2 },
            fadeOut: { duration: 3 }
          },
          loop: true
        }
      ]
    }),
  });

const data = await response.json();
return data.videoId;
}

// Usage
const videoId = await addMultipleOverlays('https://example.com/video.mp4');
console.log('Processing video with multiple overlays:', videoId);
def add_multiple_overlays(video_url):
    """Add multiple layered overlays"""
    response = requests.post(
        'https://api.videocascade.com/v1/videos',
        headers={
            'Authorization': 'Bearer vca_your_api_key',
            'Content-Type': 'application/json',
        },
        json={
            'fileUrl': video_url,
            'elements': [
                # Background watermark (bottom layer)
                {
                    'type': 'image',
                    'url': 'https://example.com/background-pattern.png',
                    'timing': {'entireVideo': True},
                    'position': {'anchor': 'center'},
                    'size': {'width': '100%'},
                    'effects': {'opacity': 0.1},
                    'zIndex': 1
                },
                # Main logo (middle layer)
                {
                    'type': 'image',
                    'url': 'https://example.com/logo.png',
                    'timing': {'entireVideo': True},
                    'position': {'anchor': 'top-right'},
                    'size': {'width': '12%'},
                    'effects': {'opacity': 0.9},
                    'zIndex': 50
                },
                # Watermark text (top layer)
                {
                    'type': 'image',
                    'url': 'https://example.com/watermark-text.png',
                    'timing': {'entireVideo': True},
                    'position': {'anchor': 'bottom-right'},
                    'size': {'width': '15%'},
                    'effects': {'opacity': 0.7},
                    'zIndex': 100
                },
                # Opening title card (temporary, highest layer)
                {
                    'type': 'image',
                    'url': 'https://example.com/title-card.png',
                    'timing': {'startTime': 0, 'endTime': 5},
                    'position': {'anchor': 'center'},
                    'size': {'width': '60%'},
                    'effects': {
                        'fadeIn': {'duration': 0.5},
                        'fadeOut': {'duration': 0.5}
                    },
                    'zIndex': 200
                },
                # Background music
                {
                    'type': 'audio',
                    'url': 'https://example.com/background-music.mp3',
                    'timing': {'entireVideo': True},
                    'effects': {
                        'volume': 0.2,
                        'fadeIn': {'duration': 2},
                        'fadeOut': {'duration': 3}
                    },
                    'loop': True
                }
            ]
        }
    )

    response.raise_for_status()
    data = response.json()
    return data['videoId']

# Usage
video_id = add_multiple_overlays('https://example.com/video.mp4')
print(f"Processing video with multiple overlays: {video_id}")
type Element = ImageElement | AudioElement;

async function addMultipleOverlays(videoUrl: string): Promise<string> {
const elements: Element[] = [
// Background watermark (bottom layer)
{
type: 'image',
url: 'https://example.com/background-pattern.png',
timing: { entireVideo: true },
position: { anchor: 'center' },
size: { width: '100%' },
effects: { opacity: 0.1 },
zIndex: 1
},
// Main logo (middle layer)
{
type: 'image',
url: 'https://example.com/logo.png',
timing: { entireVideo: true },
position: { anchor: 'top-right' },
size: { width: '12%' },
effects: { opacity: 0.9 },
zIndex: 50
},
// Watermark text (top layer)
{
type: 'image',
url: 'https://example.com/watermark-text.png',
timing: { entireVideo: true },
position: { anchor: 'bottom-right' },
size: { width: '15%' },
effects: { opacity: 0.7 },
zIndex: 100
},
// Opening title card (temporary, highest layer)
{
type: 'image',
url: 'https://example.com/title-card.png',
timing: { startTime: 0, endTime: 5 },
position: { anchor: 'center' },
size: { width: '60%' },
effects: {
fadeIn: { duration: 0.5 },
fadeOut: { duration: 0.5 }
},
zIndex: 200
},
// Background music
{
type: 'audio',
url: 'https://example.com/background-music.mp3',
timing: { entireVideo: true },
effects: {
volume: 0.2,
fadeIn: { duration: 2 },
fadeOut: { duration: 3 }
},
loop: true
}
];

const response = await fetch('https://api.videocascade.com/v1/videos', {
method: 'POST',
headers: {
'Authorization': 'Bearer vca_your_api_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
fileUrl: videoUrl,
elements
}),
});

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();
return data.videoId;
}

// Usage
const videoId = await addMultipleOverlays('https://example.com/video.mp4');
console.log('Processing video with multiple overlays:', videoId);

Animated GIF Reactions

Add animated GIF stickers and reactions at specific moments.

async function addGifReaction(videoUrl, gifUrl, startTime, duration = 3) {
  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: videoUrl,
      elements: [
        {
          type: 'gif',
          url: gifUrl,
          timing: {
            startTime,
            endTime: startTime + duration
          },
          position: { anchor: 'center' },
          size: { width: '30%' },
          effects: {
            fadeIn: { duration: 0.3 },
            fadeOut: { duration: 0.3 }
          },
          zIndex: 50,
          loop: true
        }
      ]
    }),
  });

  const data = await response.json();
  return data.videoId;
}

// Add multiple GIF reactions at different times
async function addMultipleGifReactions(videoUrl) {
  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: videoUrl,
      elements: [
        // Celebration at 15 seconds
        {
          type: 'gif',
          url: 'https://example.com/celebration.gif',
          timing: { startTime: 15, endTime: 18 },
          position: { anchor: 'top-center' },
          size: { width: '25%' },
          effects: {
            fadeIn: { duration: 0.3 },
            fadeOut: { duration: 0.3 }
          },
          zIndex: 50,
          loop: true
        },
        // Thumbs up at 45 seconds
        {
          type: 'gif',
          url: 'https://example.com/thumbs-up.gif',
          timing: { startTime: 45, endTime: 48 },
          position: { anchor: 'bottom-right' },
          size: { width: '20%' },
          effects: {
            fadeIn: { duration: 0.3 },
            fadeOut: { duration: 0.3 }
          },
          zIndex: 50,
          loop: true
        },
        // Fire emoji at 60 seconds
        {
          type: 'gif',
          url: 'https://example.com/fire.gif',
          timing: { startTime: 60, endTime: 63 },
          position: { anchor: 'center' },
          size: { width: '35%' },
          effects: {
            fadeIn: { duration: 0.3 },
            fadeOut: { duration: 0.3 }
          },
          zIndex: 50,
          loop: true
        }
      ]
    }),
  });

  return (await response.json()).videoId;
}

// Usage
await addGifReaction(videoUrl, 'https://example.com/celebration.gif', 30);
await addMultipleGifReactions(videoUrl);
def add_gif_reaction(video_url, gif_url, start_time, duration=3):
    """Add animated GIF reaction"""
    response = requests.post(
        'https://api.videocascade.com/v1/videos',
        headers={
            'Authorization': 'Bearer vca_your_api_key',
            'Content-Type': 'application/json',
        },
        json={
            'fileUrl': video_url,
            'elements': [
                {
                    'type': 'gif',
                    'url': gif_url,
                    'timing': {
                        'startTime': start_time,
                        'endTime': start_time + duration
                    },
                    'position': {'anchor': 'center'},
                    'size': {'width': '30%'},
                    'effects': {
                        'fadeIn': {'duration': 0.3},
                        'fadeOut': {'duration': 0.3}
                    },
                    'zIndex': 50,
                    'loop': True
                }
            ]
        }
    )

    response.raise_for_status()
    data = response.json()
    return data['videoId']

def add_multiple_gif_reactions(video_url):
"""Add multiple GIF reactions at different times"""
response = requests.post(
'https://api.videocascade.com/v1/videos',
headers={
'Authorization': 'Bearer vca_your_api_key',
'Content-Type': 'application/json',
},
json={
'fileUrl': video_url,
'elements': [

# Celebration at 15 seconds

{
'type': 'gif',
'url': 'https://example.com/celebration.gif',
'timing': {'startTime': 15, 'endTime': 18},
'position': {'anchor': 'top-center'},
'size': {'width': '25%'},
'effects': {
'fadeIn': {'duration': 0.3},
'fadeOut': {'duration': 0.3}
},
'zIndex': 50,
'loop': True
},

# Thumbs up at 45 seconds

{
'type': 'gif',
'url': 'https://example.com/thumbs-up.gif',
'timing': {'startTime': 45, 'endTime': 48},
'position': {'anchor': 'bottom-right'},
'size': {'width': '20%'},
'effects': {
'fadeIn': {'duration': 0.3},
'fadeOut': {'duration': 0.3}
},
'zIndex': 50,
'loop': True
},

# Fire emoji at 60 seconds

{
'type': 'gif',
'url': 'https://example.com/fire.gif',
'timing': {'startTime': 60, 'endTime': 63},
'position': {'anchor': 'center'},
'size': {'width': '35%'},
'effects': {
'fadeIn': {'duration': 0.3},
'fadeOut': {'duration': 0.3}
},
'zIndex': 50,
'loop': True
}
]
}
)

    response.raise_for_status()
    return response.json()['videoId']

# Usage

add_gif_reaction(video_url, 'https://example.com/celebration.gif', 30)
add_multiple_gif_reactions(video_url)
interface GifElement {
  type: 'gif';
  url: string;
  timing: { startTime: number; endTime: number };
  position: { anchor: string };
  size: { width: string };
  effects?: {
    fadeIn?: { duration: number };
    fadeOut?: { duration: number };
  };
  zIndex: number;
  loop: boolean;
}

async function addGifReaction(
  videoUrl: string,
  gifUrl: string,
  startTime: number,
  duration: number = 3
): Promise<string> {
  const gifElement: GifElement = {
    type: 'gif',
    url: gifUrl,
    timing: {
      startTime,
      endTime: startTime + duration
    },
    position: { anchor: 'center' },
    size: { width: '30%' },
    effects: {
      fadeIn: { duration: 0.3 },
      fadeOut: { duration: 0.3 }
    },
    zIndex: 50,
    loop: true
  };

  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: videoUrl,
      elements: [gifElement]
    }),
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  const data = await response.json();
  return data.videoId;
}

async function addMultipleGifReactions(videoUrl: string): Promise<string> {
  const gifs: GifElement[] = [
    // Celebration at 15 seconds
    {
      type: 'gif',
      url: 'https://example.com/celebration.gif',
      timing: { startTime: 15, endTime: 18 },
      position: { anchor: 'top-center' },
      size: { width: '25%' },
      effects: {
        fadeIn: { duration: 0.3 },
        fadeOut: { duration: 0.3 }
      },
      zIndex: 50,
      loop: true
    },
    // Thumbs up at 45 seconds
    {
      type: 'gif',
      url: 'https://example.com/thumbs-up.gif',
      timing: { startTime: 45, endTime: 48 },
      position: { anchor: 'bottom-right' },
      size: { width: '20%' },
      effects: {
        fadeIn: { duration: 0.3 },
        fadeOut: { duration: 0.3 }
      },
      zIndex: 50,
      loop: true
    },
    // Fire emoji at 60 seconds
    {
      type: 'gif',
      url: 'https://example.com/fire.gif',
      timing: { startTime: 60, endTime: 63 },
      position: { anchor: 'center' },
      size: { width: '35%' },
      effects: {
        fadeIn: { duration: 0.3 },
        fadeOut: { duration: 0.3 }
      },
      zIndex: 50,
      loop: true
    }
  ];

  const response = await fetch('https://api.videocascade.com/v1/videos', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vca_your_api_key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileUrl: videoUrl,
      elements: gifs
    }),
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return (await response.json()).videoId;
}

// Usage
await addGifReaction(videoUrl, 'https://example.com/celebration.gif', 30);
await addMultipleGifReactions(videoUrl);

Real-World Use Case: Social Media Branding

Complete example for automatically branding social media content.

class SocialMediaBrander {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://api.videocascade.com/v1';
  }

  async brandVideoForPlatform(videoUrl, platform, brandAssets) {
    const platformConfigs = {
      youtube: {
        aspectRatio: '16:9',
        logoSize: '10%',
        logoPosition: 'top-right',
        watermarkSize: '12%',
        musicVolume: 0.15,
      },
      instagram: {
        aspectRatio: '1:1',
        logoSize: '12%',
        logoPosition: 'top-center',
        watermarkSize: '15%',
        musicVolume: 0.2,
      },
      tiktok: {
        aspectRatio: '9:16',
        logoSize: '15%',
        logoPosition: 'top-center',
        watermarkSize: '18%',
        musicVolume: 0.25,
      },
      twitter: {
        aspectRatio: '16:9',
        logoSize: '10%',
        logoPosition: 'top-right',
        watermarkSize: '12%',
        musicVolume: 0.15,
      },
    };

    const config = platformConfigs[platform];

    const elements = [
      // Logo
      {
        type: 'image',
        url: brandAssets.logoUrl,
        timing: { entireVideo: true },
        position: { anchor: config.logoPosition },
        size: { width: config.logoSize },
        effects: {
          opacity: 0.9,
          fadeIn: { duration: 0.5 },
        },
        zIndex: 100,
      },
      // Watermark
      {
        type: 'image',
        url: brandAssets.watermarkUrl,
        timing: { entireVideo: true },
        position: { anchor: 'bottom-right' },
        size: { width: config.watermarkSize },
        effects: { opacity: 0.7 },
        zIndex: 90,
      },
    ];

    // Add background music if provided
    if (brandAssets.musicUrl) {
      elements.push({
        type: 'audio',
        url: brandAssets.musicUrl,
        timing: { entireVideo: true },
        effects: {
          volume: config.musicVolume,
          fadeIn: { duration: 2 },
          fadeOut: { duration: 3 },
        },
        loop: true,
      });
    }

    // Add intro card if provided
    if (brandAssets.introCardUrl) {
      elements.push({
        type: 'image',
        url: brandAssets.introCardUrl,
        timing: { startTime: 0, endTime: 3 },
        position: { anchor: 'center' },
        size: { width: '70%' },
        effects: {
          fadeIn: { duration: 0.5 },
          fadeOut: { duration: 0.5 },
        },
        zIndex: 200,
      });
    }

    // Add outro card if provided
    if (brandAssets.outroCardUrl) {
      // Get video duration first (requires separate API call)
      const metadata = await this.getVideoMetadata(videoUrl);
      elements.push({
        type: 'image',
        url: brandAssets.outroCardUrl,
        timing: {
          startTime: metadata.duration - 5,
          endTime: metadata.duration,
        },
        position: { anchor: 'center' },
        size: { width: '70%' },
        effects: {
          fadeIn: { duration: 0.5 },
          fadeOut: { duration: 0.5 },
        },
        zIndex: 200,
      });
    }

    const response = await fetch(`${this.baseUrl}/videos`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        fileUrl: videoUrl,
        aspectRatio: config.aspectRatio,
        resizeMode: 'cover',
        normalizeAudio: true,
        compressionQuality: 95,
        elements,
        webhookUrl: `https://yourapp.com/webhooks/branded-video/${platform}`,
      }),
    });

    return await response.json();
  }

  async getVideoMetadata(videoUrl) {
    // Placeholder - implement actual metadata fetching
    return { duration: 120 };
  }
}

// Usage
const brander = new SocialMediaBrander('vca_your_api_key');

const brandAssets = {
  logoUrl: 'https://example.com/brand/logo.png',
  watermarkUrl: 'https://example.com/brand/watermark.png',
  musicUrl: 'https://example.com/brand/background-music.mp3',
  introCardUrl: 'https://example.com/brand/intro-card.png',
  outroCardUrl: 'https://example.com/brand/outro-card.png',
};

// Brand for different platforms
await brander.brandVideoForPlatform(videoUrl, 'youtube', brandAssets);
await brander.brandVideoForPlatform(videoUrl, 'instagram', brandAssets);
await brander.brandVideoForPlatform(videoUrl, 'tiktok', brandAssets);
await brander.brandVideoForPlatform(videoUrl, 'twitter', brandAssets);

Best Practices

1. Optimize Overlay Assets

Prepare assets for best performance:

// Good practices
- Use PNG with transparency for logos/watermarks
- Compress images (TinyPNG, ImageOptim)
- Use appropriate resolution (don't use 4K for 10% overlay)
- Test opacity levels (0.7-0.9 works well for most cases)

// Image size recommendations
- Logos: 500-800px width
- Watermarks: 300-500px width
- Title cards: 1920px width (16:9) or 1080px (1:1)
- Background patterns: Match video resolution

2. Layer with Z-Index Spacing

Leave room for future additions:

// Good: Spaced out z-indexes
elements: [
  { zIndex: 10 }, // Background layer
  { zIndex: 50 }, // Middle layer
  { zIndex: 100 }, // Top layer
  { zIndex: 200 }, // Temporary overlays
];

// Bad: Sequential z-indexes
elements: [{ zIndex: 1 }, { zIndex: 2 }, { zIndex: 3 }, { zIndex: 4 }];

3. Balance Audio Levels

Set appropriate volumes:

// Recommended volumes
{
  volume: 0.15; // Subtle background music
  volume: 0.25; // Moderate background music
  volume: 0.4; // Prominent background music
  volume: 0.6; // Dominant audio overlay
}

// Always normalize when adding audio
normalizeAudio: true; // Balances all audio tracks

4. Use Fade Effects

Professional transitions:

// Always fade in/out temporary elements
{
  effects: {
    fadeIn: { duration: 0.5, easing: 'ease-in' },
    fadeOut: { duration: 0.5, easing: 'ease-out' }
  }
}

// Longer fades for audio
{
  effects: {
    fadeIn: { duration: 2 },
    fadeOut: { duration: 3 }
  }
}

5. Mobile-Friendly Positioning

Test on different aspect ratios:

// Safe positioning
position: {
  anchor: 'bottom-right';
} // Clear, predictable
size: {
  width: '15%';
} // Responsive percentage

// Avoid edge positioning for important content
// Keep 5-10% margin from edges for mobile safety

Next Steps