Skip to main content

Overview

The Editor structure defines a complete video or image composition with multiple layers, channels, and segments. It provides frame-accurate control over timing, positioning, effects, and layering.
Video vs Image Output:
  • Video Rendering: Supports all segment types (video, audio, text, image, nested editors)
  • Image Rendering: Only supports text and image segments (renders a static frame at time 0)

Editor Configuration

Root Properties

PropertyTypeRequiredDescription
widthnumberCanvas width in pixels (e.g., 1080 for TikTok/Instagram)
heightnumberCanvas height in pixels (e.g., 1920 for vertical video)
fpsnumberFrames per second (typically 30 or 60)
durationnumberTotal duration in milliseconds (can be auto-calculated from segments)
channelsChannel[]Array of channels, each containing segments

Channel Structure

Channels are independent layers that can contain multiple segments. All segments within a channel play sequentially, while segments across different channels play simultaneously.
PropertyTypeRequiredDescription
idstringUnique channel identifier (e.g., "background", "text-layer")
segmentsSegment[]Array of segments in this channel

Segment Types

Base Segment Properties

All segment types inherit these properties:
PropertyTypeRequiredDescription
idstringUnique segment identifier
typestringSegment type: video, image, text, audio, or editor
sourcestringPublic URL to media file (empty "" for text segments)
ordernumberSequence order within channel (0-based)
offsetTimeValueDelay after previous segment starts
startTrimnumberTrim from start in milliseconds (default: 0)
endTrimnumberTrim from end in milliseconds (default: 0)
durationTimeValueOverride segment duration (auto-calculated if omitted)

Visual Segment Properties

Video, image, text, and editor segments include these positioning properties:
PropertyTypeDefaultDescription
xOffsetnumber0Horizontal position from left edge in pixels
yOffsetnumber0Vertical position from top edge in pixels
widthnumberRequiredWidth in pixels
heightnumberRequiredHeight in pixels
zIndexnumber0Stacking order (higher values appear on top)
scalenumber1Scale multiplier (1.0 = 100%, 2.0 = 200%)
rotationnumber0Rotation in degrees (clockwise)
opacitynumber100Opacity percentage (0 = transparent, 100 = opaque)

Video Segment

Displays video content with optional audio. Additional Properties:
PropertyTypeDefaultDescription
fit'cover' | 'contain' | 'fill''cover'How the video fits in the bounds
cover: Fill entire area, crop overflow
contain: Fit entire video, may have letterboxing
fill: Stretch to fill, may distort
speednumber1Playback speed multiplier (0.5 = half speed, 2.0 = double speed)
volumenumber100Audio volume percentage (0 = muted, 100 = full volume)
Example:
{
  "id": "main-video",
  "type": "video",
  "source": "https://example.com/video.mp4",
  "order": 0,
  "offset": { "type": "absolute", "value": 0 },
  "startTrim": 1000,
  "endTrim": 500,
  "xOffset": 0,
  "yOffset": 0,
  "width": 1080,
  "height": 1920,
  "zIndex": 0,
  "scale": 1,
  "rotation": 0,
  "fit": "cover",
  "speed": 1,
  "opacity": 100,
  "volume": 50
}

Image Segment

Displays static images or animated GIFs. Additional Properties:
PropertyTypeDefaultDescription
fit'cover' | 'contain' | 'fill''contain'How the image fits in the bounds
loopbooleanfalseLoop animated GIFs (only affects GIFs)
Example:
{
  "id": "logo",
  "type": "image",
  "source": "https://example.com/logo.png",
  "order": 0,
  "offset": { "type": "absolute", "value": 0 },
  "duration": { "type": "absolute", "value": 5000 },
  "xOffset": 90,
  "yOffset": 100,
  "width": 300,
  "height": 300,
  "zIndex": 5,
  "scale": 1,
  "rotation": 0,
  "fit": "contain",
  "opacity": 100
}

Text Segment

Rich text overlays with full typography and styling control. Typography Properties:
PropertyTypeDefaultDescription
textstringRequiredThe text content (supports emojis)
fontType'arial' | 'tiktok' | 'apple''tiktok'Font family
fontSizenumber40Font size in pixels
fontWeight'normal' | 'bold''normal'Font weight
lineHeightnumber1.2Line height multiplier
letterSpacingnumber0Letter spacing in pixels
Alignment Properties:
PropertyTypeDefaultDescription
alignment'left' | 'center' | 'right' | 'justify''left'Horizontal text alignment
verticalAlign'top' | 'middle' | 'bottom''top'Vertical alignment within bounds
direction'ltr' | 'rtl''ltr'Text direction (left-to-right or right-to-left)
paddingnumber0Inner padding in pixels
Text Wrapping Properties:
PropertyTypeDefaultDescription
textWrap'word' | 'char' | 'none''word'How text wraps to new lines
wordBreak'normal' | 'break-all' | 'break-word''normal'How words break across lines
hyphenation'none' | 'auto''none'Automatic hyphenation
maxLinesnumber0Maximum lines (0 = unlimited)
textOverflow'clip' | 'ellipsis''clip'How overflow is handled
ellipsisstring'...'Ellipsis string for overflow
Color Properties:
PropertyTypeDefaultDescription
colorstring'#FFFFFF'Text color in hex format (e.g., #FF0000 for red)
backgroundColorstring'transparent'Background color with optional alpha (e.g., #00000080 for 50% black)
strokeColorstringundefinedText outline color (e.g., #000000 for black outline)
strokeWidthnumber0Outline width in pixels
Example:
{
  "id": "title-text",
  "type": "text",
  "source": "",
  "order": 0,
  "offset": { "type": "absolute", "value": 500 },
  "duration": { "type": "absolute", "value": 4000 },
  "xOffset": 90,
  "yOffset": 800,
  "width": 900,
  "height": 320,
  "zIndex": 10,
  "text": "Hello World! 🎉",
  "alignment": "center",
  "verticalAlign": "middle",
  "direction": "ltr",
  "padding": 20,
  "fontType": "tiktok",
  "fontSize": 80,
  "fontWeight": "bold",
  "lineHeight": 1.2,
  "letterSpacing": 0,
  "textWrap": "word",
  "wordBreak": "break-word",
  "hyphenation": "none",
  "maxLines": 0,
  "textOverflow": "clip",
  "ellipsis": "...",
  "color": "#FFFFFF",
  "backgroundColor": "#00000080",
  "strokeColor": "#000000",
  "strokeWidth": 4,
  "scale": 1,
  "rotation": 0,
  "opacity": 100
}

Audio Segment

Background audio or music tracks. Audio segments don’t have visual properties. Properties:
PropertyTypeDefaultDescription
(base properties)All base segment properties apply
volumenumber100Audio volume percentage (0 = muted, 100 = full)
Example:
{
  "id": "background-music",
  "type": "audio",
  "source": "https://example.com/music.mp3",
  "order": 0,
  "offset": { "type": "absolute", "value": 0 },
  "startTrim": 0,
  "endTrim": 0,
  "duration": { "type": "absolute", "value": 5000 },
  "volume": 80
}

Editor Segment (Nested Composition)

Nest entire editor configurations within segments for complex compositions. Additional Properties:
PropertyTypeDescription
editorEditorComplete nested editor configuration
(all visual properties)Same as video segments
Example:
{
  "id": "nested-composition",
  "type": "editor",
  "source": "",
  "order": 0,
  "offset": { "type": "absolute", "value": 1000 },
  "editor": {
    "width": 540,
    "height": 960,
    "fps": 30,
    "duration": 3000,
    "channels": [/* nested channels */]
  },
  "xOffset": 270,
  "yOffset": 480,
  "width": 540,
  "height": 960,
  "zIndex": 5,
  "fit": "contain",
  "opacity": 100,
  "speed": 1,
  "volume": 100
}

Time Value Format

Time values can be specified as absolute (milliseconds) or relative (percentage):
// Absolute - exact time in milliseconds
{
  "type": "absolute",
  "value": 500  // 500ms
}

// Relative - percentage of total duration
{
  "type": "relative",
  "value": 0.25  // 25% of total duration
}
Usage Examples:
  • Offset: { type: "absolute", value: 1000 } = start 1 second after previous segment
  • Duration: { type: "relative", value: 0.5 } = last for 50% of total video duration

Timing & Duration Calculation

How Segment Timing Works

  1. Sequential within channels: Segments in the same channel play one after another
  2. Parallel across channels: Segments in different channels play simultaneously
  3. Offset delays: Each segment can delay relative to the previous one

Duration Calculation Rules

// Segment duration is calculated as:
const segmentDuration = 
  mediaDuration - startTrim - endTrim + (duration override if specified)

// Segment start time is calculated as:
const startTime = 
  previousSegmentStartTime + offset.value

Example Timeline

{
  "channels": [
    {
      "id": "channel1",
      "segments": [
        {
          "id": "seg1",
          "offset": { "type": "absolute", "value": 0 },
          // Starts at 0ms
        },
        {
          "id": "seg2",
          "offset": { "type": "absolute", "value": 1000 },
          // Starts at 1000ms (1 second after seg1 starts)
        },
        {
          "id": "seg3",
          "offset": { "type": "absolute", "value": 500 },
          // Starts at 1500ms (500ms after seg2 starts)
        }
      ]
    }
  ]
}

Positioning & Transform Properties

Position

PropertyDescriptionExample
xOffsetDistance from left edge in pixels540 centers a 1080px-wide element in a 1920px canvas
yOffsetDistance from top edge in pixels0 places at the top

Size

PropertyDescriptionNotes
widthElement width in pixelsCombined with fit mode for media
heightElement height in pixelsCombined with fit mode for media

Transforms

PropertyRangeDescription
scale0.1 - 10Size multiplier (1 = original size, 2 = 200%, 0.5 = 50%)
rotation0 - 360Rotation in degrees (clockwise)
opacity0 - 100Transparency (0 = invisible, 100 = fully opaque)
zIndexany integerLayer order (higher numbers appear on top)

Fit Modes

Controls how media (video/image) fits within specified width/height bounds.

cover (Default for video)

  • Behavior: Fills entire area, crops overflow
  • Use case: Full-screen backgrounds
  • Aspect ratio: Maintained
  • Example: 16:9 video in 9:16 canvas → sides cropped

contain (Default for image)

  • Behavior: Fits entire media, may have letterboxing
  • Use case: Logos, overlays that must be fully visible
  • Aspect ratio: Maintained
  • Example: Square image in rectangular area → bars on sides or top/bottom

fill

  • Behavior: Stretches to fill entire area
  • Use case: Rare - usually avoid as it distorts
  • Aspect ratio: Not maintained
  • Example: Any aspect ratio → stretched to match bounds exactly

Text Styling Reference

Font Options

fontTypeDescription
'tiktok'TikTok Sans font family (default, recommended)
'apple'SF Pro font (Apple system font)
'arial'Arial fallback font

Font Weight Options

fontWeightRendering
'normal'Regular weight
'bold'Bold weight

Text Alignment

alignmentEffect
'left'Align to left edge
'center'Center horizontally
'right'Align to right edge
'justify'Justify text (stretch to fill width)
verticalAlignEffect
'top'Align to top edge
'middle'Center vertically
'bottom'Align to bottom edge

Text Wrapping Modes

textWrapBehavior
'word'Break at word boundaries (recommended)
'char'Break at any character
'none'No wrapping, text may overflow
wordBreakBehavior
'normal'Break at normal word boundaries
'break-all'Break between any two characters
'break-word'Break long words if necessary

Color Format

All colors use hex format with optional alpha channel:
"#RRGGBB"      // RGB (e.g., "#FF0000" = red)
"#RRGGBBAA"    // RGBA (e.g., "#FF000080" = 50% transparent red)
Examples:
  • #FFFFFF - White
  • #000000 - Black
  • #FF0000 - Red
  • #00000080 - 50% transparent black
  • #FFFFFF00 - Fully transparent white

Complete Example: Multi-Layer Video

{
  "width": 1080,
  "height": 1920,
  "fps": 30,
  "duration": 10000,
  "channels": [
    {
      "id": "background",
      "segments": [
        {
          "id": "bg-video",
          "type": "video",
          "source": "https://example.com/background.mp4",
          "order": 0,
          "offset": { "type": "absolute", "value": 0 },
          "startTrim": 0,
          "endTrim": 0,
          "xOffset": 0,
          "yOffset": 0,
          "width": 1080,
          "height": 1920,
          "zIndex": 0,
          "scale": 1,
          "rotation": 0,
          "fit": "cover",
          "speed": 1,
          "opacity": 100,
          "volume": 30
        }
      ]
    },
    {
      "id": "overlay-images",
      "segments": [
        {
          "id": "logo",
          "type": "image",
          "source": "https://example.com/logo.png",
          "order": 0,
          "offset": { "type": "absolute", "value": 0 },
          "duration": { "type": "absolute", "value": 10000 },
          "xOffset": 50,
          "yOffset": 50,
          "width": 200,
          "height": 200,
          "zIndex": 5,
          "fit": "contain",
          "opacity": 90
        }
      ]
    },
    {
      "id": "text-overlays",
      "segments": [
        {
          "id": "intro-text",
          "type": "text",
          "source": "",
          "order": 0,
          "offset": { "type": "absolute", "value": 500 },
          "duration": { "type": "absolute", "value": 3000 },
          "xOffset": 90,
          "yOffset": 800,
          "width": 900,
          "height": 320,
          "zIndex": 10,
          "text": "Welcome! 👋",
          "alignment": "center",
          "verticalAlign": "middle",
          "fontType": "tiktok",
          "fontSize": 80,
          "fontWeight": "bold",
          "color": "#FFFFFF",
          "backgroundColor": "#00000080",
          "strokeColor": "#000000",
          "strokeWidth": 4,
          "padding": 20,
          "opacity": 100
        },
        {
          "id": "cta-text",
          "type": "text",
          "source": "",
          "order": 1,
          "offset": { "type": "absolute", "value": 4000 },
          "duration": { "type": "absolute", "value": 2500 },
          "xOffset": 90,
          "yOffset": 1400,
          "width": 900,
          "height": 200,
          "zIndex": 10,
          "text": "Follow for more! 🚀",
          "alignment": "center",
          "verticalAlign": "middle",
          "fontType": "tiktok",
          "fontSize": 60,
          "fontWeight": "bold",
          "color": "#FFD700",
          "strokeColor": "#000000",
          "strokeWidth": 3,
          "opacity": 100
        }
      ]
    },
    {
      "id": "audio-layer",
      "segments": [
        {
          "id": "background-music",
          "type": "audio",
          "source": "https://example.com/music.mp3",
          "order": 0,
          "offset": { "type": "absolute", "value": 0 },
          "duration": { "type": "absolute", "value": 10000 },
          "volume": 50
        }
      ]
    }
  ]
}

Complete Example: Static Image

{
  "width": 1080,
  "height": 1920,
  "fps": 30,
  "duration": 1000,
  "channels": [
    {
      "id": "background",
      "segments": [
        {
          "id": "bg-image",
          "type": "image",
          "source": "https://example.com/background.jpg",
          "order": 0,
          "offset": { "type": "absolute", "value": 0 },
          "xOffset": 0,
          "yOffset": 0,
          "width": 1080,
          "height": 1920,
          "zIndex": 0,
          "fit": "cover"
        }
      ]
    },
    {
      "id": "text-layer",
      "segments": [
        {
          "id": "title",
          "type": "text",
          "source": "",
          "order": 0,
          "offset": { "type": "absolute", "value": 0 },
          "xOffset": 90,
          "yOffset": 800,
          "width": 900,
          "height": 320,
          "zIndex": 10,
          "text": "Thumbnail Title",
          "alignment": "center",
          "verticalAlign": "middle",
          "fontType": "tiktok",
          "fontSize": 100,
          "fontWeight": "bold",
          "color": "#FFFFFF",
          "strokeColor": "#000000",
          "strokeWidth": 5
        }
      ]
    }
  ]
}

Best Practices

Layering

  • Use zIndex to control stacking order
  • Background elements: zIndex: 0
  • Mid-layer elements: zIndex: 5
  • Text/overlays: zIndex: 10+
  • Keep zIndex values spaced for easy insertion

Performance

  • Limit segments: < 50 per composition
  • Optimize source media: compress before upload
  • Use appropriate resolutions:
    • TikTok/Instagram: 1080x1920 (9:16)
    • YouTube Shorts: 1080x1920 (9:16)
    • Square: 1080x1080 (1:1)

Timing

  • Use offset for staggered animations
  • Combine absolute and relative times for flexibility
  • Test edge cases (segment boundaries, overlaps)

Text Rendering

  • Readability: Use high contrast (white text on dark bg or vice versa)
  • Stroke: Add strokeWidth: 3-5 for text on video backgrounds
  • Font size: Minimum 40px for mobile readability
  • Line count: Keep under 3 lines for best engagement
  • Emojis: Fully supported, render correctly

Color Selection

  • Text on video: White with black stroke (color: "#FFFFFF", strokeColor: "#000000")
  • Backgrounds: Use semi-transparent (#00000080 for 50% black)
  • Highlights: Brand colors with full opacity
  • Test: Verify colors on different screens/backgrounds

Media Sources

  • URLs must be publicly accessible: No auth required
  • Supported formats:
    • Video: MP4, MOV, WebM
    • Image: PNG, JPEG, GIF, WebP
    • Audio: MP3, WAV, OGG
  • HTTPS required: All source URLs must use HTTPS
  • CORS: Ensure proper CORS headers on your media server

Common Patterns

Full-Screen Video Background

{
  "xOffset": 0,
  "yOffset": 0,
  "width": 1080,
  "height": 1920,
  "fit": "cover",
  "zIndex": 0
}

Centered Logo Overlay

{
  "xOffset": 440,
  "yOffset": 860,
  "width": 200,
  "height": 200,
  "fit": "contain",
  "zIndex": 5
}

Bottom-Third Text Banner

{
  "xOffset": 90,
  "yOffset": 1400,
  "width": 900,
  "height": 200,
  "alignment": "center",
  "verticalAlign": "middle",
  "zIndex": 10
}

Fade In Effect (Manual)

// Show multiple text segments with increasing opacity
[
  { "opacity": 0, "duration": 100 },
  { "opacity": 25, "duration": 100 },
  { "opacity": 50, "duration": 100 },
  { "opacity": 75, "duration": 100 },
  { "opacity": 100, "duration": 3000 }
]

Troubleshooting

Text Not Appearing

  • Check zIndex - must be higher than background elements
  • Verify opacity is > 0
  • Ensure color contrasts with background
  • Check timing - verify segment is active during playback

Media Not Loading

  • Verify URL is publicly accessible (test in browser)
  • Check CORS headers on media server
  • Ensure HTTPS (not HTTP)
  • Verify file format is supported

Unexpected Timing

  • Review offset values - they’re relative to previous segment
  • Check startTrim and endTrim values
  • Verify duration overrides if specified
  • Remember: segments in same channel are sequential, different channels are parallel

Quality Issues

  • Use higher resolution source media
  • Avoid over-scaling (scale > 2.0)
  • Use fit: 'contain' instead of fill to avoid distortion
  • Ensure FPS matches source media (typically 30fps)