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 Values | Result |
|---|---|
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).
| Mode | Description |
|---|---|
"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.
| Mode | Description |
|---|---|
"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 Content | Goal | Recommended Mode |
|---|---|---|
| 9:16 vertical | Fill region, no bars | "fill" |
| 9:16 vertical | Show all, allow bars | "fit" |
| 16:9 horizontal | Fill region height, crop sides | "fill-height" |
| 16:9 horizontal | Show 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:
| Format | Example |
|---|---|
| Hex with # | "#000000" |
| Hex without # | "000000" |
| Named colors | "black", "white", "red" |
API Reference
verticalStack(regions, options?)
| Parameter | Type | Description |
|---|---|---|
regions | VerticalStackRegion[] | Array of exactly 2 regions (top, bottom) |
options | VerticalStackOptions | Optional configuration |
VerticalStackRegion
| Property | Type | Description |
|---|---|---|
media | string | VideoOperation | ImageOperation | Media URL or generated content |
size | string | Height percentage (e.g., "50%") |
fillMode | "fill" | "fit" | "fill-height" | "fit-height" | How media fits region (default: "fill") |
main | boolean | Use this region's duration |
padding | number | Padding in pixels (equal on all sides) |
backgroundColor | string | Background color for padding (default: "black") |
VerticalStackOptions
| Property | Type | Description |
|---|---|---|
duration | number | Explicit output duration |
width | number | Output width (default: 1080) |
height | number | Output height (default: 1920) |
How is this guide?