OpenReels
API Reference

DirectorScore Schema

The DirectorScore JSON schema that drives the entire video generation pipeline.

The DirectorScore is the central data structure in OpenReels. Produced by the Creative Director agent, it is a complete plan for the video: emotional arc, visual style, music mood, and a sequence of scenes. Every downstream stage (TTS, visuals, assembly, critic) reads from this score.

The schema is defined in src/schema/director-score.ts using Zod.

Full Schema

interface DirectorScore {
  emotional_arc: string;    // e.g., "curiosity-to-wonder"
  archetype: string;        // visual style archetype name
  music_mood: MusicMood;    // music mood for the soundtrack
  scenes: Scene[];          // 3-16 scenes
}

Top-Level Fields

emotional_arc

A short description of the emotional journey the video takes the viewer through (e.g., "curiosity-to-wisdom", "tension-to-resolution"). This guides the pacing and tone of the visual and audio choices.

archetype

The name of the visual style archetype. Must match one of the 14 registered archetypes (see Archetypes). Controls caption style, art style, color palette, motion intensity, and scene pacing.

music_mood

One of the following enum values:

ValueDescription
epic_cinematicGrand orchestral, cinematic feel
tense_electronicHigh-energy electronic, suspenseful
chill_lofiRelaxed lo-fi beats
uplifting_popUpbeat, positive energy
mysterious_ambientAtmospheric, enigmatic
warm_acousticOrganic, warm instrumentation
dark_cinematicMoody, intense cinematic
dreamy_etherealSoft, floating, dreamlike

scenes

An array of 3 to 16 scene objects. The number of scenes is determined by the pacing tier:

  • Slow: fewer scenes, longer per scene
  • Standard: balanced scene count
  • Fast: more scenes, shorter per scene

Scene Object

Each scene describes one segment of the video.

interface Scene {
  visual_type: VisualType;        // what kind of visual to produce
  visual_prompt: string;          // prompt for visual generation
  motion: Motion;                 // camera motion effect
  script_line: string;            // voiceover text for this scene
  transition: TransitionType | null;  // how this scene transitions to the next
}

visual_type

Determines the visual generation strategy for the scene.

ValueDescription
ai_imageGenerated by the image provider (Gemini, OpenAI)
ai_videoGenerated by the video provider (Veo, Kling)
stock_imageSourced from stock photography (Pexels, Pixabay)
stock_videoSourced from stock video footage
text_cardTypography-based card with the script text

visual_prompt

The prompt used to generate or search for the visual asset. For AI-generated visuals, this is passed through the image-prompter agent for optimization. For stock assets, it is used as a search query (with adaptive query reformulation).

motion

The camera motion applied to the visual during playback.

ValueDescription
zoom_inSlow zoom into the visual
zoom_outSlow zoom out from the visual
pan_rightHorizontal pan to the right
pan_leftHorizontal pan to the left
staticNo motion

script_line

The voiceover text spoken during this scene. Passed to the TTS provider to generate audio with word-level timestamps for caption synchronization.

transition

Controls how this scene transitions into the next scene. Can be null, in which case the mapper cascade resolves it: scene value, then archetype default, then "none".

ValueDescription
noneHard cut (default)
crossfadeSmooth opacity blend
slide_leftNew scene slides in from the right
slide_rightNew scene slides in from the left
wipeHorizontal wipe
flip3D card flip

Validation Rules

The schema enforces several constraints beyond basic types:

Scene count

Minimum 3 scenes, maximum 16 scenes. Scores outside this range are rejected.

Golden Rule

No more than 2 consecutive scenes may have the same visual_type. This ensures visual variety. For example, three ai_image scenes in a row will fail validation:

// INVALID: 3 consecutive ai_image scenes
scenes: [
  { visual_type: "ai_image", ... },
  { visual_type: "ai_image", ... },
  { visual_type: "ai_image", ... },  // golden rule violation
  { visual_type: "stock_video", ... },
]

// VALID: 2 consecutive ai_image scenes (max allowed)
scenes: [
  { visual_type: "ai_image", ... },
  { visual_type: "ai_image", ... },
  { visual_type: "stock_video", ... },
  { visual_type: "text_card", ... },
]

Non-empty strings

emotional_arc, archetype, visual_prompt, and script_line must all be non-empty strings.


Example

A complete DirectorScore for a video about black holes:

{
  "emotional_arc": "curiosity-to-wonder",
  "archetype": "editorial_caricature",
  "music_mood": "mysterious_ambient",
  "scenes": [
    {
      "visual_type": "text_card",
      "visual_prompt": "Bold text: What happens when a star dies?",
      "motion": "zoom_in",
      "script_line": "What happens when a star dies?",
      "transition": "crossfade"
    },
    {
      "visual_type": "ai_image",
      "visual_prompt": "Massive star collapsing inward, layers peeling away, deep space background with nebula colors",
      "motion": "zoom_in",
      "script_line": "When a massive star runs out of fuel, gravity wins. The core collapses in milliseconds.",
      "transition": "slide_left"
    },
    {
      "visual_type": "stock_video",
      "visual_prompt": "space nebula timelapse stars",
      "motion": "static",
      "script_line": "The result is one of the most extreme objects in the universe: a black hole.",
      "transition": "crossfade"
    },
    {
      "visual_type": "ai_image",
      "visual_prompt": "Black hole with glowing accretion disk, warped spacetime grid lines bending around it",
      "motion": "zoom_out",
      "script_line": "Not even light can escape its gravitational pull.",
      "transition": null
    }
  ]
}

Programmatic Usage

You can validate a DirectorScore using the exported Zod schema:

import { DirectorScore } from './src/schema/director-score.js';

const result = DirectorScore.safeParse(myScoreData);

if (result.success) {
  console.log('Valid score with', result.data.scenes.length, 'scenes');
} else {
  console.error('Validation errors:', result.error.issues);
}