> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pictory.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# AI Storyboard

> Let AI design every scene of your video with layouts, on-screen text, and color palettes, from a script or from a single idea

The AI Storyboard turns a script, an article, or a one-line idea into a designed video. Instead of the standard full-screen visual with subtitles, every scene gets its own layout, on-screen text elements, and a matching color palette: title cards, statistic callouts, checklists, two-column comparisons, quotes, and more. You enable it with a single field, `aiStoryboard`, on the same request you already use to render a video.

## What You'll Learn

<CardGroup cols={2}>
  <Card title="Designed Scenes" icon="table-layout">
    Every scene receives a layout, text elements, and colors chosen by AI
  </Card>

  <Card title="Script or Idea" icon="lightbulb">
    Start from your own narration or let AI write the script from a brief
  </Card>

  <Card title="Visual Control" icon="images">
    Keep using stock search, your own media, AI-generated visuals, or solid colors
  </Card>

  <Card title="Job Monitoring" icon="clock">
    Track the render and collect the video, audio, thumbnail, and subtitle files
  </Card>
</CardGroup>

## Before You Begin

Make sure you have:

* A [Pictory API key](https://app.pictory.ai/api-access)
* Node.js or Python installed on your machine
* The required packages installed

<CodeGroup>
  ```bash npm theme={null}
  npm install axios
  ```

  ```bash pip theme={null}
  pip install requests
  ```
</CodeGroup>

## How It Works

Set `aiStoryboard.enabled` to `true` on a [Render Storyboard Video](/api-reference/videos/render-storyboard-video) request. The AI then works in one of two modes, depending on the content you send:

| You provide                            | Mode        | What the AI does                                                                 |
| -------------------------------------- | ----------- | -------------------------------------------------------------------------------- |
| `scenes[].story` or `scenes[].blogUrl` | Script mode | Designs each scene around your narration. Your text is used word for word.       |
| A single `scenes[0].brief`             | Brief mode  | Writes the narration from your idea and designs the storyboard in the same pass. |

In both modes the rest of the request works as usual: voice-over, avatar, background music, branding, subtitle styles, and per-scene background settings are all applied to the designed scenes.

<Note>
  `aiStoryboard` is optional and must be set explicitly to `{ "enabled": true }`. Requests without it, or with `enabled: false`, are processed exactly as before.
</Note>

### What Happens Behind the Scenes

1. **Scene breakdown** - Your script is split into scenes (one per sentence by default) or, in brief mode, the AI decides how many scenes the video needs
2. **Design** - The AI chooses a layout for every scene, writes the on-screen text elements, and picks a color palette for the whole video
3. **Visual selection** - Each scene's visual is resolved from its `background` configuration and placed into the layout
4. **Narration and timing** - Voice-over, subtitles, and scene durations are generated from the narration
5. **Render** - The video is encoded and the download links are attached to the job

<Note>
  **Processing Time:** The design step adds 1–3 minutes to the usual rendering time. Poll the job status every 10–30 seconds.
</Note>

## Step-by-Step Guide

### Step 1: Render an AI Storyboard from a Script

Send your narration with `aiStoryboard` enabled:

<CodeGroup>
  ```javascript Node.js theme={null}
  import axios from "axios";

  const API_BASE_URL = "https://api.pictory.ai/pictoryapis";
  const API_KEY = "YOUR_API_KEY"; // Replace with your actual API key

  const SCRIPT =
    "Creating videos used to take hours. " +
    "Pictory turns a script into a finished video in minutes. " +
    "Paste your text, pick a voice, and let the AI handle the visuals. " +
    "Try it today and publish your first video before lunch.";

  async function renderAiStoryboard() {
    try {
      console.log("Rendering AI storyboard...");

      const response = await axios.post(
        `${API_BASE_URL}/v2/video/storyboard/render`,
        {
          videoName: "ai_storyboard_from_script",
          aiStoryboard: { enabled: true },
          aspectRatio: "16:9",
          voiceOver: {
            enabled: true,
            aiVoices: [{ speaker: "Brian", speed: 100 }],
          },
          scenes: [
            {
              story: SCRIPT,
              // Optional: one designed scene per sentence is the default
              createSceneOnEndOfSentence: true,
            },
          ],
        },
        {
          headers: {
            "Content-Type": "application/json",
            Authorization: API_KEY,
          },
        }
      );

      const jobId = response.data.data.jobId;
      console.log("Job ID:", jobId);
      return jobId;
    } catch (error) {
      console.error("Error:", error.response?.data || error.message);
      throw error;
    }
  }
  ```

  ```python Python theme={null}
  import requests
  import time

  API_BASE_URL = 'https://api.pictory.ai/pictoryapis'
  API_KEY = 'YOUR_API_KEY'  # Replace with your actual API key

  SCRIPT = (
      "Creating videos used to take hours. "
      "Pictory turns a script into a finished video in minutes. "
      "Paste your text, pick a voice, and let the AI handle the visuals. "
      "Try it today and publish your first video before lunch."
  )

  def render_ai_storyboard():
      print("Rendering AI storyboard...")

      response = requests.post(
          f'{API_BASE_URL}/v2/video/storyboard/render',
          json={
              'videoName': 'ai_storyboard_from_script',
              'aiStoryboard': {'enabled': True},
              'aspectRatio': '16:9',
              'voiceOver': {
                  'enabled': True,
                  'aiVoices': [{'speaker': 'Brian', 'speed': 100}]
              },
              'scenes': [
                  {
                      'story': SCRIPT,
                      # Optional: one designed scene per sentence is the default
                      'createSceneOnEndOfSentence': True
                  }
              ]
          },
          headers={
              'Content-Type': 'application/json',
              'Authorization': API_KEY
          }
      )
      response.raise_for_status()

      job_id = response.json()['data']['jobId']
      print(f'Job ID: {job_id}')
      return job_id
  ```
</CodeGroup>

### Step 2: Monitor Progress

Poll the job until it completes, then collect the video and the accompanying files:

<CodeGroup>
  ```javascript Node.js theme={null}
  async function waitForVideo(jobId) {
    console.log("\nMonitoring render...");

    while (true) {
      const statusResponse = await axios.get(`${API_BASE_URL}/v1/jobs/${jobId}`, {
        headers: { Authorization: API_KEY },
      });

      const data = statusResponse.data.data;
      console.log("Status:", data.status, "Progress:", data.progress);

      if (data.status === "completed") {
        console.log("\nVideo URL:", data.videoURL);
        console.log("Share URL:", data.videoShareURL);
        console.log("Duration (s):", data.videoDuration);
        return data;
      }
      if (data.status === "failed") {
        throw new Error("Render failed: " + JSON.stringify(statusResponse.data));
      }

      // Poll every 10-30 seconds
      await new Promise(resolve => setTimeout(resolve, 15000));
    }
  }

  // Run the complete workflow
  renderAiStoryboard()
    .then(jobId => waitForVideo(jobId))
    .then(() => console.log("\nDone!"))
    .catch(error => console.error("Error:", error));
  ```

  ```python Python theme={null}
  def wait_for_video(job_id):
      print("\nMonitoring render...")

      while True:
          response = requests.get(
              f'{API_BASE_URL}/v1/jobs/{job_id}',
              headers={'Authorization': API_KEY}
          )
          response.raise_for_status()

          data = response.json()['data']
          print(f"Status: {data['status']} Progress: {data.get('progress')}")

          if data['status'] == 'completed':
              print(f"\nVideo URL: {data['videoURL']}")
              print(f"Share URL: {data['videoShareURL']}")
              print(f"Duration (s): {data['videoDuration']}")
              return data
          if data['status'] == 'failed':
              raise Exception(f'Render failed: {response.json()}')

          # Poll every 10-30 seconds
          time.sleep(15)

  # Run the complete workflow
  if __name__ == '__main__':
      job_id = render_ai_storyboard()
      wait_for_video(job_id)
      print("\nDone!")
  ```
</CodeGroup>

## Start from an Idea (Brief Mode)

Do not have a script yet? Describe the video in a `brief` and the AI writes the narration and designs the storyboard together. A brief is a single scene; the AI decides how many scenes the video needs.

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await axios.post(
    `${API_BASE_URL}/v2/video/storyboard/render`,
    {
      aiStoryboard: { enabled: true },
      aspectRatio: "16:9",
      voiceOver: {
        enabled: true,
        aiVoices: [{ speaker: "Brian" }],
      },
      scenes: [
        {
          brief: {
            prompt: "Create a 1 minute explainer video that simplifies video creation for beginners.",
            videoGoal: "Explainer",
            tone: "friendly",
            duration: 60,
          },
        },
      ],
    },
    {
      headers: {
        "Content-Type": "application/json",
        Authorization: API_KEY,
      },
    }
  );

  console.log("Job ID:", response.data.data.jobId);
  ```

  ```python Python theme={null}
  response = requests.post(
      f'{API_BASE_URL}/v2/video/storyboard/render',
      json={
          'aiStoryboard': {'enabled': True},
          'aspectRatio': '16:9',
          'voiceOver': {
              'enabled': True,
              'aiVoices': [{'speaker': 'Brian'}]
          },
          'scenes': [
              {
                  'brief': {
                      'prompt': 'Create a 1 minute explainer video that simplifies video creation for beginners.',
                      'videoGoal': 'Explainer',
                      'tone': 'friendly',
                      'duration': 60
                  }
              }
          ]
      },
      headers={
          'Content-Type': 'application/json',
          'Authorization': API_KEY
      }
  )
  response.raise_for_status()

  print(f"Job ID: {response.json()['data']['jobId']}")
  ```
</CodeGroup>

The generated narration is available in the completed job's `txtFile` (plain text) and `srtFile`/`vttFile` (timed subtitles). If you omit `videoName`, the AI's own title is used as the project name.

<Note>
  Without `aiStoryboard`, a `brief` still generates a script and builds a standard storyboard from it. See the [AI Brief to Video guide](/guides/story-copilot/ai-story-generation).
</Note>

## Understanding the Parameters

### aiStoryboard Object

| Parameter              | Type    | Required | Description                                                                                                     |
| ---------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `aiStoryboard.enabled` | boolean | Yes      | Set to `true` to have the AI design the storyboard. Omit the object or set `false` for the standard storyboard. |

### brief Object

| Parameter         | Type    | Required | Description                                                                                                                               |
| ----------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `brief.prompt`    | string  | Yes      | The idea or description of the video. Up to 3900 characters with `aiStoryboard`.                                                          |
| `brief.videoGoal` | string  | No       | `Explainer` (default), `Marketing`, `Internal Communication`, `Tutorial`, or `Product`.                                                   |
| `brief.tone`      | string  | No       | `professional`, `casual`, `friendly`, `informative`, `persuasive`, `exciting`, `educational`, `humorous`, `serious`, or `conversational`. |
| `brief.duration`  | integer | No       | Target length in seconds, 8–500 with `aiStoryboard`. Omit it to let the AI choose.                                                        |
| `brief.platform`  | string  | No       | Target platform used for script generation without `aiStoryboard`; the AI Storyboard does not use it.                                     |

### Scene Control in Script Mode

* A `story` scene without `createSceneOnNewLine` or `createSceneOnEndOfSentence` is split into one designed scene per sentence.
* Each designed scene can hold at most 1500 characters of narration. A scene that cannot be split (for example, one that uses `caption`) and exceeds this limit is rejected with a `400` response; a single sentence longer than the limit fails the job.
* A video can have at most 250 designed scenes.
* `createSceneOnNewLine` and `createSceneOnEndOfSentence` are not allowed on a `brief` scene; the AI decides the scenes.

## Choosing Visuals

Each scene's `background` configuration works the same way it does for a standard video. The AI Storyboard places the resulting visual into the layout it designed for that scene, and fills any additional media slots in the layout from the same search.

| `background` configuration | Result                                                                                                                                                                                  |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Not set, or `searchFilter` | A stock visual matching the narration (and your filters) fills the scene's main visual slot                                                                                             |
| `visualUrl`                | Your own image or video is kept as the scene's main visual and the layout is designed around it                                                                                         |
| `aiVisual`                 | An AI-generated visual fills the main slot. AI Credits are charged per generated visual at the model's rate. See [AI-Generated Visuals](/guides/ai-generated-visuals/background-images) |
| `color`                    | The scene background becomes your solid color; the layout's text elements are drawn on top                                                                                              |

<Warning>
  In brief mode there is only one scene in the request, so its `background` configuration applies to every scene the AI creates. A `brief` with `aiVisual` generates one visual per designed scene and charges AI Credits for each of them.
</Warning>

## Subtitles, Branding, Voice, and Avatar

* **Subtitle styles:** the AI chooses a subtitle style that fits each layout. Your `subtitleStyle`, `subtitleStyleId`, or `subtitleStyleName` overrides its font, size, and colors; the AI's placement is kept unless your style sets a position. Brand text styles apply the same way.
* **Subtitles on designed scenes:** where the narration is shown as an on-screen text element, subtitles are hidden for that scene. Set `hideSubtitles: false` on a scene to force them on.
* **Voice-over and music:** applied as usual. Scene durations follow the narration.
* **Avatar:** the avatar you configure is used; the AI positions it scene by scene to fit each layout. Scene-level `avatar` overrides in your request still take precedence.
* **Brand intro and outro:** added as usual around the designed scenes.

## What Is Not Supported

The AI Storyboard is a text-to-video feature. With `aiStoryboard` enabled, a scene must use `story`, `brief`, or `blogUrl`, and the following are rejected with a `400` response:

| Field                                                                                                                                                                        | Message                                                                                                                        |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `scenes[].pptUrl`, `scenes[].audioUrl`, `scenes[].videoUrl`                                                                                                                  | `aiStoryboard is only supported with blogUrl, story and brief; scenes[0].pptUrl is not supported`                              |
| `templateId`, `variables`, `smartLayoutName`, `smartLayoutId`                                                                                                                | `<field> is not supported with aiStoryboard`, for example `templateId is not supported with aiStoryboard`                      |
| `aspectRatio: "4:5"`                                                                                                                                                         | `aiStoryboard supports aspectRatio 16:9, 9:16, 1:1 only`                                                                       |
| `scenes[].transcript`, `mediaRepurposeSettings`, `audioLanguage`, `animatePPT`, `useSpeakerNotes`, `isSSMLStory`, `backgroundBrolls`, `backgroundCorpus`, `templateOverride` | `scenes[0].<field> is not supported with aiStoryboard`, for example `scenes[0].isSSMLStory is not supported with aiStoryboard` |

Scene `elements` remain supported and are added on top of the AI's design.

## Understanding the Response

### Initial Response (Job Created)

```json theme={null}
{
  "success": true,
  "data": {
    "jobId": "abc123def456"
  }
}
```

### Completed Response

```json theme={null}
{
  "job_id": "abc123def456",
  "success": true,
  "data": {
    "status": "completed",
    "progress": 100,
    "videoURL": "https://cdn.pictory.ai/videos/ai_storyboard_from_script.mp4",
    "videoShareURL": "https://video.pictory.ai/share/abc123def456",
    "videoEmbedURL": "https://video.pictory.ai/embed/abc123def456",
    "audioURL": "https://cdn.pictory.ai/audio/ai_storyboard_from_script.mp3",
    "thumbnail": "https://cdn.pictory.ai/images/ai_storyboard_from_script.jpg",
    "srtFile": "https://cdn.pictory.ai/subtitles/ai_storyboard_from_script.srt",
    "txtFile": "https://cdn.pictory.ai/subtitles/ai_storyboard_from_script.txt",
    "vttFile": "https://cdn.pictory.ai/subtitles/ai_storyboard_from_script.vtt",
    "videoDuration": 21.6,
    "encodingDuration": 313
  }
}
```

| Field                | Description                                                         |
| -------------------- | ------------------------------------------------------------------- |
| `status`             | `in-progress`, `completed`, or `failed`                             |
| `progress`           | Render progress, 0–100                                              |
| `videoURL`           | Download link for the rendered MP4                                  |
| `videoShareURL`      | Shareable player page for the video                                 |
| `videoEmbedURL`      | Player URL for embedding the video in an iframe                     |
| `audioURL`           | The narration and music track as MP3                                |
| `thumbnail`          | Thumbnail image of the video                                        |
| `srtFile`, `vttFile` | Timed subtitles; in brief mode they contain the generated narration |
| `txtFile`            | The full narration as plain text                                    |
| `videoDuration`      | Length of the video in seconds                                      |
| `encodingDuration`   | Time spent encoding, in seconds                                     |

## Troubleshooting

<AccordionGroup>
  <Accordion title="400 - Field Is Not Supported With aiStoryboard">
    **Cause:** The request uses a source or option the AI Storyboard cannot design, such as `pptUrl`, `audioUrl`, `videoUrl`, `templateId`, or a smart layout.

    **Resolution:**

    1. Use `story`, `brief`, or `blogUrl` as the scene source
    2. Remove the field named in the message, or
    3. Remove `aiStoryboard` to render a standard video with that field
  </Accordion>

  <Accordion title="400 - Provide Exactly One Scene When Using Brief">
    **Cause:** A `brief` was combined with other scenes.

    **Resolution:**

    1. Send the `brief` as the only scene; the AI decides how many scenes the video needs
    2. To combine your own narration with generated content, render the brief first, take the narration from `txtFile`, and submit an edited version as `story` scenes
  </Accordion>

  <Accordion title="400 - Scene Text Exceeds 1500 Characters">
    **Cause:** A scene that cannot be split (for example, one that uses `caption`) holds more narration than one designed scene can show.

    **Resolution:**

    1. Enable `createSceneOnEndOfSentence` or `createSceneOnNewLine` on the scene, or
    2. Split the text into several scenes yourself
  </Accordion>

  <Accordion title="Job Failed With an AI_STORYBOARD Error Code">
    **Cause:** The design step could not complete, for example the AI produced an invalid design or the service was temporarily unavailable. There is no fallback to a standard video.

    **Resolution:**

    1. Retry the request; the design is generated fresh on every attempt
    2. Shorten very long scripts (the limit is 250 designed scenes)
    3. If the error persists, [contact support](https://pictory.ai/contact) with the job ID
  </Accordion>

  <Accordion title="Different Design on Each Render">
    **Cause:** The AI generates a new design on every request, so rendering the same script twice can produce different layouts.

    **Resolution:**

    1. Use `saveProject: true` to keep the designed project in your Pictory account and render it again from there with [Render Project](/api-reference/videos/render-project)
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Add AI Voice-Over" icon="microphone" href="/guides/text-to-video/ai-voiceover">
    Choose a voice for the narration
  </Card>

  <Card title="AI-Generated Visuals" icon="image" href="/guides/ai-generated-visuals/background-images">
    Generate unique visuals for the designed scenes
  </Card>

  <Card title="Apply Brand Settings" icon="palette" href="/guides/branding-customization/brand-settings">
    Add your logo, fonts, and colors on top of the AI design
  </Card>

  <Card title="Video with Avatar" icon="user" href="/guides/video-with-avatar/create-avatar-video">
    Present the designed scenes with an AI avatar
  </Card>
</CardGroup>

## API Reference

<CardGroup cols={2}>
  <Card title="Render Storyboard Video" icon="video" href="/api-reference/videos/render-storyboard-video">
    Full request reference for the render endpoint
  </Card>

  <Card title="aiStoryboard and brief Objects" icon="book" href="/api-reference/videos/create-storyboard-preview#aistoryboard-object">
    Field-level reference for the aiStoryboard and brief objects
  </Card>

  <Card title="Get Video Render Job" icon="clock" href="/api-reference/jobs/get-video-render-job-by-id">
    Poll the render job and collect the output files
  </Card>

  <Card title="Render Project" icon="folder-open" href="/api-reference/videos/render-project">
    Render a saved AI storyboard project again
  </Card>
</CardGroup>
