Export vertical video designs for social media platforms with the correct dimensions, formats, and quality settings. Configure video exports with appropriate resolution, framerate, and bitrate optimized for Instagram Reels, TikTok, and YouTube Shorts.
Short-form vertical video has become the dominant format for social media. Instagram Reels, TikTok, and YouTube Shorts all use the 9:16 aspect ratio at 1080×1920 pixels. This guide demonstrates how to create and export vertical video content with the correct settings for these platforms.
This guide covers creating a vertical video scene, exporting with resolution, framerate, and bitrate settings, and tracking export progress.
Creating a Scene#
Create a video scene and pin its design unit to pixels so the page dimensions you set match the platform requirements exactly. Add a page sized 1080×1920 (9:16), the standard resolution for Instagram Reels, TikTok, and YouTube Shorts.
let scene = try engine.scene.createVideo()try engine.scene.setDesignUnit(.px)let page = try engine.block.create(.page)try engine.block.appendChild(to: scene, child: page)try engine.block.setWidth(page, value: 1080)try engine.block.setHeight(page, value: 1920)engine.scene.createVideo() returns the new scene block and switches the engine into video mode. setDesignUnit(.px) makes subsequent setWidth/setHeight calls operate in pixels regardless of the scene’s previous unit.
Adding a Video#
Fill the page with a video clip so the export has visible content. Create a graphic block with a rectangle shape, attach a video fill backed by a remote URL, append the block to the page, and call fillParent so it covers the full 1080×1920 frame.
let videoBlock = try engine.block.create(.graphic)try engine.block.setShape(videoBlock, shape: engine.block.createShape(.rect))let videoFill = try engine.block.createFill(.video)try engine.block.setString( videoFill, property: "fill/video/fileURI", // swiftlint:disable:next line_length value: "https://cdn.img.ly/packages/imgly/cesdk-swift/1.76.0/assets/ly.img.video/videos/pexels-drone-footage-of-a-surfer-barrelling-a-wave-12715991.mp4",)try engine.block.setFill(videoBlock, fill: videoFill)try engine.block.appendChild(to: page, child: videoBlock)try engine.block.fillParent(videoBlock)try await engine.block.forceLoadAVResource(videoFill)forceLoadAVResource(videoFill) blocks until the remote video is downloaded and parsed. Calling it before export keeps the export pipeline from waiting on resource I/O while frames are being encoded.
Configuring Export Options#
VideoExportOptions controls resolution, framerate, and bitrate. For Instagram Reels, TikTok, and YouTube Shorts, render to 1080×1920 at 30 frames per second with an 8 Mbps video bitrate.
let options = VideoExportOptions( videoBitrate: 8_000_000, // 8 Mbps framerate: 30, targetWidth: 1080, targetHeight: 1920,)Key video export settings:
- targetWidth / targetHeight: Output resolution (1080×1920 for vertical)
- framerate: 30 frames per second (standard for social media)
- videoBitrate: 8 Mbps balances quality and upload speed for short-form video
Higher bitrates produce better quality but larger files. Pass 0 to either bitrate field to let the engine pick a value automatically based on the H.264 profile and level.
Exporting Videos#
engine.block.exportVideo(_:mimeType:options:) returns an AsyncThrowingStream<VideoExport, Error> that yields progress events while the export runs and a final .finished(video:) event carrying the encoded MP4 as a Blob (a typealias for Data). Use MIMEType.mp4 for broad platform compatibility.
var exportedVideo: Blob?for try await event in try await engine.block.exportVideo( page, mimeType: .mp4, options: options,) { switch event { case let .progress(renderedFrames, encodedFrames, totalFrames): let percent = totalFrames == 0 ? 0 : Int((Double(encodedFrames) / Double(totalFrames)) * 100) print("Export \(percent)% – rendered \(renderedFrames), encoded \(encodedFrames) of \(totalFrames)") case let .finished(video: blob): exportedVideo = blob }}guard let videoData = exportedVideo else { return }The for try await loop drains the stream until the export completes. Capture the final blob in an optional and unwrap it before saving so an interrupted export doesn’t write a zero-byte file.
Tracking Export Progress#
The .progress case fires repeatedly during the export and reports three frame counts:
- renderedFrames – Frames the engine has rendered so far.
- encodedFrames – Frames the encoder has written to the output stream.
- totalFrames – Total frames the export will produce.
case let .progress(renderedFrames, encodedFrames, totalFrames): let percent = totalFrames == 0 ? 0 : Int((Double(encodedFrames) / Double(totalFrames)) * 100) print("Export \(percent)% – rendered \(renderedFrames), encoded \(encodedFrames) of \(totalFrames)")Encoding trails rendering slightly. Drive a progress indicator from encodedFrames / totalFrames for an accurate completion percentage. totalFrames can be 0 for the first event or two — guard against division by zero before computing a percentage.
Saving the Exported Video#
The .finished case yields a Blob containing the MP4 bytes. Write it to a file with Data.write(to:) to hand it off to a share sheet, an upload pipeline, or the photo library.
let outputURL = FileManager.default.temporaryDirectory .appendingPathComponent("vertical-video-1080x1920.mp4")try videoData.write(to: outputURL)For uploads, pass the Blob directly to your networking layer instead of writing it to disk first.
API Reference#
| Method | Purpose |
|---|---|
engine.scene.createVideo() | Create a video scene |
engine.scene.setDesignUnit(_:) | Pin the scene’s design unit (.px, .mm, .in) |
engine.block.fillParent(_:) | Resize a block to fill its parent |
engine.block.forceLoadAVResource(_:) | Wait for a video fill’s source to load |
engine.block.exportVideo(_:mimeType:options:) | Export a block as a video stream |
Export Options (Videos)#
| Option | Type | Description |
|---|---|---|
targetWidth | Float | Output width in design units |
targetHeight | Float | Output height in design units |
framerate | Float | Frames per second (default 30) |
videoBitrate | Int32 | Video bitrate in bits per second (0 = auto) |
audioBitrate | Int32 | Audio bitrate in bits per second (0 = auto) |
h264Profile | H264Profile | Encoder feature set: .baseline, .extended, .main (default), .high |
h264Level | Int32 | H.264 level × 10 (default 52 = level 5.2) |
timeOffset | Double | Start time in seconds (default 0) |
duration | Double | Output duration in seconds (0 = full scene) |
Next Steps#
- Export Overview - Complete export options including H.264 profiles and advanced settings