Synthome Docs
Operations

Vertical Stack

Split a vertical video into top/bottom regions with configurable sizes

verticalStack()

Split a 9:16 vertical video screen into two regions (top/bottom) with configurable sizes and fill modes.

import { compose, verticalStack } from "@synthome/sdk";

const execution = await compose(
  verticalStack([
    { media: "https://example.com/image.jpg", size: "50%" },
    { media: "https://example.com/video.mp4", size: "50%", main: true },
  ]),
).execute();

Basic Usage

50/50 Split

verticalStack([
  { media: "https://example.com/top.jpg", size: "50%" },
  { media: "https://example.com/bottom.mp4", size: "50%", main: true },
]);

30/70 Split

verticalStack([
  { media: "https://example.com/header.jpg", size: "30%" },
  { media: "https://example.com/content.mp4", size: "70%", main: true },
]);

40/60 Split

verticalStack([
  { media: "https://example.com/image.png", size: "40%" },
  { media: "https://example.com/video.mp4", size: "60%", main: true },
]);

Size Options

Sizes are specified as percentages. They are automatically normalized if they don't add up to 100%.

Size ValuesResult
50%, 50%Equal split
30%, 70%30/70 split
40%, 60%40/60 split
25%, 75%25/75 split

Auto-Normalization

If your percentages don't add up to 100%, they are automatically normalized:

// 30% + 50% = 80%, so normalized to 37.5% + 62.5%
verticalStack([
  { media: "https://example.com/top.jpg", size: "30%" },
  { media: "https://example.com/bottom.mp4", size: "50%", main: true },
]);

Fill Modes

Control how media fits within each region. There are two categories of modes:

Width-Priority Modes (Best for 9:16 Content)

These modes scale based on width first. Best when your source content is already vertical (9:16).

ModeDescription
"fill"Scale to cover width, crop height if needed (no empty space)
"fit"Scale to fit width, add black bars on top/bottom (letterbox)

Height-Priority Modes (Best for 16:9 Content)

These modes scale based on height first. Best when your source content is horizontal (16:9) and you want to fill the vertical region height.

ModeDescription
"fill-height"Scale to cover height, crop width if needed (no empty space)
"fit-height"Scale to fit height, add black bars on left/right (pillarbox)

fill (default)

Width-priority fill. Scales to cover the full width, crops height if the content is taller than the region.

verticalStack([
  { media: "https://example.com/image.jpg", size: "50%", fillMode: "fill" },
  {
    media: "https://example.com/video.mp4",
    size: "50%",
    fillMode: "fill",
    main: true,
  },
]);

fit

Width-priority fit. Scales to fit the width, adds black bars (letterbox) on top/bottom if needed.

verticalStack([
  { media: "https://example.com/image.jpg", size: "50%", fillMode: "fit" },
  {
    media: "https://example.com/video.mp4",
    size: "50%",
    fillMode: "fit",
    main: true,
  },
]);

fill-height

Height-priority fill. Scales to cover the full height of the region, crops width if the content is wider. Perfect for 16:9 horizontal content in vertical regions.

// 16:9 video filling vertical region by height, sides cropped
verticalStack([
  {
    media: "https://example.com/horizontal-image.jpg",
    size: "50%",
    fillMode: "fill-height",
  },
  {
    media: "https://example.com/horizontal-video.mp4",
    size: "50%",
    fillMode: "fill-height",
    main: true,
  },
]);

fit-height

Height-priority fit. Scales to fit the height of the region, adds black bars (pillarbox) on left/right if needed.

// 16:9 video fitting vertical region by height, with side bars
verticalStack([
  {
    media: "https://example.com/horizontal-image.jpg",
    size: "50%",
    fillMode: "fit-height",
  },
  {
    media: "https://example.com/horizontal-video.mp4",
    size: "50%",
    fillMode: "fit-height",
    main: true,
  },
]);

Choosing the Right Mode

Source ContentGoalRecommended Mode
9:16 verticalFill region, no bars"fill"
9:16 verticalShow all, allow bars"fit"
16:9 horizontalFill region height, crop sides"fill-height"
16:9 horizontalShow all, allow side bars"fit-height"

Duration Control

Main Region

Mark a region as the duration reference (typically the video region):

verticalStack([
  { media: "https://example.com/image.jpg", size: "50%" },
  { media: "https://example.com/video.mp4", size: "50%", main: true }, // Duration from this
]);

If no region is marked as main, the first video region is used automatically.

Explicit Duration

verticalStack(
  [
    { media: "https://example.com/image.jpg", size: "50%" },
    { media: "https://example.com/video.mp4", size: "50%" },
  ],
  { duration: 10 }, // 10 second output
);

Output Dimensions

Default output is 1080x1920 (9:16 vertical). You can customize:

verticalStack(
  [
    { media: "https://example.com/image.jpg", size: "50%" },
    { media: "https://example.com/video.mp4", size: "50%", main: true },
  ],
  { width: 1080, height: 1920 },
);

With Generated Content

Generated Image + Video

import {
  verticalStack,
  generateImage,
  generateVideo,
  imageModel,
  videoModel,
} from "@synthome/sdk";

verticalStack([
  {
    media: generateImage({
      model: imageModel("black-forest-labs/flux-schnell", "replicate"),
      prompt: "A beautiful sunset landscape",
    }),
    size: "40%",
    fillMode: "fill",
  },
  {
    media: generateVideo({
      model: videoModel("bytedance/seedance-1-pro", "replicate"),
      prompt: "Ocean waves crashing on rocks",
    }),
    size: "60%",
    fillMode: "fill",
    main: true,
  },
]);

Two Generated Videos

verticalStack([
  {
    media: generateVideo({
      model: videoModel("minimax/video-01", "replicate"),
      prompt: "Aerial view of mountains",
    }),
    size: "50%",
    fillMode: "fill",
  },
  {
    media: generateVideo({
      model: videoModel("bytedance/seedance-1-pro", "replicate"),
      prompt: "Forest path in autumn",
    }),
    size: "50%",
    fillMode: "fill",
    main: true,
  },
]);

Use Cases

Social Media Split Screen

Show a product image at top with demo video below:

verticalStack([
  {
    media: "https://example.com/product-photo.jpg",
    size: "40%",
    fillMode: "fill",
  },
  {
    media: "https://example.com/demo-video.mp4",
    size: "60%",
    fillMode: "fill",
    main: true,
  },
]);

Comparison Videos

Show before/after or two perspectives:

verticalStack([
  { media: "https://example.com/before.mp4", size: "50%", fillMode: "fill" },
  {
    media: "https://example.com/after.mp4",
    size: "50%",
    fillMode: "fill",
    main: true,
  },
]);

Header + Content Layout

Static header image with main video content:

verticalStack([
  {
    media: "https://example.com/header-banner.png",
    size: "20%",
    fillMode: "fill",
  },
  {
    media: "https://example.com/main-content.mp4",
    size: "80%",
    fillMode: "fill",
    main: true,
  },
]);

16:9 Videos in Vertical Stack

Use fill-height when stacking horizontal (16:9) videos in a vertical format:

verticalStack([
  {
    media: "https://example.com/horizontal-clip-1.mp4",
    size: "50%",
    fillMode: "fill-height", // Fills height, crops sides
  },
  {
    media: "https://example.com/horizontal-clip-2.mp4",
    size: "50%",
    fillMode: "fill-height",
    main: true,
  },
]);

Padding

Add equal padding around media to create a bordered/framed look. The padding area is filled with the background color.

Basic Padding

verticalStack([
  {
    media: "https://example.com/image.jpg",
    size: "50%",
    padding: 40, // 40px padding on all sides
  },
  {
    media: "https://example.com/video.mp4",
    size: "50%",
    main: true,
  },
]);

With Custom Background Color

verticalStack([
  {
    media: "https://example.com/image.jpg",
    size: "50%",
    padding: 40,
    backgroundColor: "#1a1a1a", // Dark gray background
  },
  {
    media: "https://example.com/video.mp4",
    size: "50%",
    main: true,
  },
]);

Padding with Fill Modes

Padding works with all fill modes. The media is scaled to fit the inner area (after padding is applied):

verticalStack([
  {
    media: "https://example.com/horizontal-image.jpg",
    size: "50%",
    padding: 30,
    fillMode: "fill-height", // Scale to fill inner height, crop width
    backgroundColor: "black",
  },
  {
    media: "https://example.com/video.mp4",
    size: "50%",
    main: true,
  },
]);

Color Formats

The backgroundColor option supports multiple formats:

FormatExample
Hex with #"#000000"
Hex without #"000000"
Named colors"black", "white", "red"

API Reference

verticalStack(regions, options?)

ParameterTypeDescription
regionsVerticalStackRegion[]Array of exactly 2 regions (top, bottom)
optionsVerticalStackOptionsOptional configuration

VerticalStackRegion

PropertyTypeDescription
mediastring | VideoOperation | ImageOperationMedia URL or generated content
sizestringHeight percentage (e.g., "50%")
fillMode"fill" | "fit" | "fill-height" | "fit-height"How media fits region (default: "fill")
mainbooleanUse this region's duration
paddingnumberPadding in pixels (equal on all sides)
backgroundColorstringBackground color for padding (default: "black")

VerticalStackOptions

PropertyTypeDescription
durationnumberExplicit output duration
widthnumberOutput width (default: 1080)
heightnumberOutput height (default: 1920)

How is this guide?

On this page