---
title: "Direct how a trailer beat's text (or a closing card) moves."
method: POST
path: "/trailers/{jobId}/storyboard/direct-text-motion"
tags: ["Trailer"]
---

# Direct how a trailer beat's text (or a closing card) moves.

`POST /trailers/{jobId}/storyboard/direct-text-motion`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/trailers/{jobId}/storyboard/direct-text-motion`
- Auth: HTTP bearer

Say in plain words how one beat's on-screen text should move — "type it out letter by letter, then draw an underline beneath it" — and it is compiled into the bounded motion spec the master draws for that beat (its look becomes `directed`). NOT metered and NOT confirmed: it costs no credits and renders nothing, and re-directing REPLACES the treatment rather than adding to it, so there is nothing a confirmation would protect. Your own words are saved beside the compiled spec, so the next direction is not authored blind. A rendered trailer's master is stitched again with it, free; watch it with GET …/beats/{beatIndex}/text-preview. In a product film a direction that breaks a product-film rule (nothing bounces, turns, glitches or sparkles) is refused (409) with the reason. A beat with nothing to move is refused with a 409 before anything is compiled — a beat that is footage only, or one whose caption is still empty — and the refusal names the fix. With a `closingElement` (quote, comingSoon, productionCredit) instead of a `beatIndex` it directs one of the closing sequence's cards, or puts it back in its own type with `clear: true`; the master draws the card, so a rendered trailer is stitched again with it (free). A trailer's closing sequence's words are directed in the writer's own words through the trailer's direct-text-motion call with a `closingElement` instead of a `beatIndex`: `quote`, `comingSoon` or `productionCredit` ("Coming Soon wide and slow, a faint vignette breathing behind it"). The same director compiles the sentence into a motion-text spec (face, colour, size, motion and a quiet background) and saves it with the sentence on the closing sequence (`textMotion`). The words stay the closing's: a direction says how they look, never what they say. `clear: true` puts a card back in its own type. Free: an LLM call, no credits; a rendered trailer's master is stitched again with it, and nothing else renders. Requires `Idempotency-Key`. Scope: `story:write`.

## Headers

- `Idempotency-Key` string, required

## Request body

- TrailerDirectTextMotionRequest: Say in plain words how one beat's on-screen text should move (`beatIndex` + `direction`) — or how one of the closing sequence's cards should look and move (`closingElement` + `direction`, or + `clear: true` to put it back in its own type). Exactly one of `beatIndex` and `closingElement`. Free — no `confirmed` field, because there is no spend to confirm. A trailer's closing sequence's words are directed in the writer's own words through the trailer's direct-text-motion call with a `closingElement` instead of a `beatIndex`: `quote`, `comingSoon` or `productionCredit` ("Coming Soon wide and slow, a faint vignette breathing behind it"). The same director compiles the sentence into a motion-text spec (face, colour, size, motion and a quiet background) and saves it with the sentence on the closing sequence (`textMotion`). The words stay the closing's: a direction says how they look, never what they say. `clear: true` puts a card back in its own type. Free: an LLM call, no credits; a rendered trailer's master is stitched again with it, and nothing else renders.
  - `beatIndex` integer: Zero-based index of the beat whose on-screen text should move.
  - `closingElement` 'quote' | 'comingSoon' | 'productionCredit': Instead of a beat: one of the closing sequence's cards — quote (with where it is from), comingSoon, or productionCredit.
  - `direction` string: How the text should move, in the writer's own words — e.g. "type it out letter by letter, then draw an underline beneath it". Required unless `clear` is true.
  - `clear` true: With `closingElement`: put the card back in its own type.

## Response `200`

The direction now on the beat.

- TrailerDirectTextMotionAck: The direction now on the beat (or on one of the closing sequence's cards). Nothing was rendered and nothing was charged; a beat's text layer is re-rendered to see it move; a closing card is drawn by the master, which a rendered trailer stitches again (free; `reassembling`).
  - `success` boolean, required
  - `beatIndex` integer: The beat directed (a beat direction).
  - `direction` string, nullable, required: The writer's own words, saved beside the compiled spec so the next direction is not authored blind; null when a closing card was put back in its own type.
  - `closingElement` 'quote' | 'comingSoon' | 'productionCredit': The closing card directed (a closing direction).
  - `look` string, nullable: What the master draws for a directed closing card, read from the stored spec. Null when it was put back in its own type.
  - `closingSequence` ClosingSequenceView: A deck's closing sequence ends its master, after the last chapter, and mirrors its title sequence: optionally a closing quote (`quote`: its words, quoted exactly, and where they are from, cited exactly — one that answers the opening's epigraph, often from the same source), then "Coming Soon" (`comingSoon`, up to 40 characters; "Coming Soon" when left out), then the production credit (`productionCredit`; "Sleeper Hit Studio" when left out), each quiet on black, faded in and out and held long enough to read. It ADDS to the deck's length: no chapter is shortened for it. When the title sequence cuts on its bell beat grid, each card starts on a beat of that same grid and the bell lane accents it. Across it the music (the score or the beds) and the bell lane fade out smoothly to silence on the master's last frame: what still sounds at the last chapter's cut plays on under the cards. A card with no direction of its own wears the opening's look (the quote the epigraph's, the credit the source credit's, "Coming Soon" the title's or the epigraph's background), so the deck is sandwiched by one style. It is free: nothing is rendered for it, and a rendered deck's master is stitched again with it. `enabled: false` keeps it without playing it. How its words look and move is directed separately (`closingElement` on the direct-text-motion call; read back as `textMotion`), and a save keeps those directions. THE LOGO CARD (`logoCard: true`, off when left out) ends the sequence on the project's brand logo, alone on black after the production credit, faded in and out and held 3 seconds. The logo is the project's (`brandLogoUrl` on the project, set on the site's Closing card, with the Story API project update's `brandLogo`, or on the CLI with `projects update --brand-logo-file`); a save that turns the card on while the project has no logo is refused, and the save copies the logo the project has at that moment (read back as `logoUrl`), so save the closing again after replacing the logo. Free like the rest of the sequence.
    - `enabled` boolean, required: Whether the deck or trailer ends on it. False keeps it without playing it.
    - `quote` object: A closing quote shown first, alone on black, held long enough to read (about 3 words a second, at least 4 s).
      - `text` string, required: Its words, exactly as the source gives them.
      - `attribution` string: Where the words are from, cited exactly.
    - `comingSoon` string, required: "Coming Soon" as the master sets it (the default when left out).
    - `productionCredit` string, required: The production credit as the master sets it (the studio's name when left out).
    - `logoCard` boolean, required: Whether it ends on the project's brand logo.
    - `endCard` ClosingEndCard: THE END CARD (`endCard`: `appName`, `reason` up to 70 characters, `url` (https), and optionally `line`, the call to action, and `label`, a small disclosure) is how every trailer of a PRODUCT project ends: the app's name drawn in the text beats' reveal style, why to try it, and the link (shown without https:// or a query), held at least 4.5 seconds, in place of "Coming Soon" and the production credit. Sleeper sets it when the video is planned, from the story film's brief (its call to action) or the product's own (its Series Bible call to action, its site); it can be edited on every surface but never removed or turned off on a product project (such an edit is refused, nothing saved). Free like the rest of the sequence.
      - `appName` string, required: The app's name, the card's largest words.
      - `reason` string, required: Why to try it, one short line.
      - `url` string, uri, required: Where to try it (https); shown without the https:// and without a query.
      - `line` string: The call to action beside the link.
      - `label` string: A small disclosure line under the link.
    - `logoUrl` string, nullable, required: The logo the logo card shows: the project's brand logo as it was when the closing was saved with the card on (null while the card is off).
    - `logo` object: The logo as stored on the closing (READ ONLY: copied from the project by the save that turns the logo card on).
      - `url` string, required
    - `playing` boolean, required: True when it plays in the master (enabled, and a chapter or beat before it).
    - `durationMs` integer, required: How long it runs in the master: what it adds to the deck's or trailer's length.
    - `startSeconds` number, nullable, required: Where it starts in the master (null while it does not play).
    - `onBeatGrid` boolean, required: Whether its cards keep the title sequence's bell beat grid (each starting on a beat).
    - `textMotion` object: How its cards look and move, as directed (absent for a card that wears the opening's look or its own type). Set by POST /pitch-decks/{jobId}/storyboard/direct-text-motion with a `closingElement`, never by a save (which keeps them). The closing sequence's words are directed like the title sequence's, in the writer's own words, through the same direct-text-motion call with a `closingElement` instead of a `chapterIndex`: `quote`, `comingSoon` or `productionCredit` ("the same candlelight and grain as the epigraph", "Coming Soon wide and slow, a faint vignette breathing behind it"). The same director compiles the sentence into a motion-text spec (face, colour, size, motion and a quiet background) and saves it with the sentence on the closing sequence (`textMotion`). The words stay the closing's: a direction says how they look, never what they say. `clear: true` puts a card back in the opening's look (or its own type). Free: an LLM call, no credits; a rendered deck's master is stitched again with it, and nothing else renders.
      - `quote` PitchDeckTitleTextMotion: One of the title sequence's words, directed: the writer's sentence and the motion-text spec compiled from it, which the master executes.
        - `direction` string, required: The writer's own words for how it looks and moves.
        - `spec` object, required: The motion-text spec: version, layers (each a text, atmosphere, particle… layer with its face, fit, colours and keyframed steps).
      - `comingSoon` PitchDeckTitleTextMotion: One of the title sequence's words, directed: the writer's sentence and the motion-text spec compiled from it, which the master executes.
        - `direction` string, required: The writer's own words for how it looks and moves.
        - `spec` object, required: The motion-text spec: version, layers (each a text, atmosphere, particle… layer with its face, fit, colours and keyframed steps).
      - `productionCredit` PitchDeckTitleTextMotion: One of the title sequence's words, directed: the writer's sentence and the motion-text spec compiled from it, which the master executes.
        - `direction` string, required: The writer's own words for how it looks and moves.
        - `spec` object, required: The motion-text spec: version, layers (each a text, atmosphere, particle… layer with its face, fit, colours and keyframed steps).
    - `cards` object[], required: Its cards in order: the quote (when it has one), "Coming Soon", the production credit, and the project's logo (when the logo card is on). A product video has its end card in place of "Coming Soon" and the credit.
      - `card` 'quote' | 'comingSoon' | 'productionCredit' | 'logo' | 'endCard', required
      - `endCard` ClosingEndCard: THE END CARD (`endCard`: `appName`, `reason` up to 70 characters, `url` (https), and optionally `line`, the call to action, and `label`, a small disclosure) is how every trailer of a PRODUCT project ends: the app's name drawn in the text beats' reveal style, why to try it, and the link (shown without https:// or a query), held at least 4.5 seconds, in place of "Coming Soon" and the production credit. Sleeper sets it when the video is planned, from the story film's brief (its call to action) or the product's own (its Series Bible call to action, its site); it can be edited on every surface but never removed or turned off on a product project (such an edit is refused, nothing saved). Free like the rest of the sequence.
        - `appName` string, required: The app's name, the card's largest words.
        - `reason` string, required: Why to try it, one short line.
        - `url` string, uri, required: Where to try it (https); shown without the https:// and without a query.
        - `line` string: The call to action beside the link.
        - `label` string: A small disclosure line under the link.
      - `text` string, required: Its words (empty on the logo card).
      - `attribution` string, nullable, required
      - `imageUrl` string, nullable, required: The image it shows: the project's logo on the logo card, else null.
      - `seconds` number, required: How long it is on screen, its fades included.
      - `startSeconds` number, nullable, required: Where it starts in the master (null while the closing does not play).
      - `beat` integer, nullable, required: The bell beat it starts on, on the grid (null off the grid).
      - `look` 'own' | 'opening' | 'null', nullable, required: `own`: its own direction; `opening`: the opening's look, borrowed; null: its own type on black.
      - `lookFrom` 'title' | 'epigraph' | 'sourceCredit' | 'nameSupers' | 'null', nullable, required: The opening element its look is borrowed from.
      - `backgroundOnly` boolean, required: True when only a background is borrowed: the card keeps its own type over it.
    - `fadeOut` object, nullable, required: Where the master fades the music (the score or the beds) and the bell lane out: from the closing's first frame to silence on the master's last (null while it does not play).
      - `fromSeconds` number, required
      - `toSeconds` number, required
  - `reassembling` boolean: True when the trailer's master is stitched again with it (a rendered trailer; free — no beat renders).
  - `masterHold` TrailerMasterHold: On a rendered trailer with no screenplay, a blank beat holds its video: nothing rebuilds it until each blank beat is a capture beat or a title card, or removed (then it is rebuilt, free); the answer's `masterHold` names the beats and the fix, and the export is refused with it (`trailer_capture_only`).
    - `blankBeats` integer[], required: The blank beats, numbered from 1.
    - `message` string, required: The sentence to show: the beats, that the video keeps playing, and the fix.

## Other responses

- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `404`: The named project or source does not exist or is owned by another account.
- `409`: This beat has no on-screen text for a motion direction to act on, and nothing was compiled or saved. Either the beat is footage only (give it a caption, or set it to text/both) or its caption is still empty. A 409 rather than a 400 because the request body is fine — the same call succeeds once the beat is put right — and the message says which of the two it is.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

## Changes

- **2026-10-20** `86e084144cef`: 1 warning, 2 info
  - added the new `endCard` enum value to the `closingSequence/allOf[#/components/schemas/ClosingSequenceView]/allOf[subschema #2]/cards/items/card` response property for the response status `200`
  - added the optional property `closingSequence/allOf[#/components/schemas/ClosingSequenceView]/allOf[#/components/schemas/ClosingSequence]/endCard` to the response with the `200` status
  - added the optional property `closingSequence/allOf[#/components/schemas/ClosingSequenceView]/allOf[subschema #2]/cards/items/endCard` to the response with the `200` status

[Operation history](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/changes/trailers/:jobId/storyboard/direct-text-motion/post.md)

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/86e084144cef?raw)
