---
title: Per-Slide Motion
description: Advanced - give each slide of a video post made through the API its own animations, transition and hold, with the video editor's presets and custom keyframes.
canonical: https://postnitro.ai/docs/embed/api/initiate/video-motion-advanced
---

# Per-Slide Motion

> **Advanced.** Most videos don't need this: they're [animated by default](https://postnitro.ai/docs/embed/api/initiate/video-motion), or take a built-in style, or a style or sequence saved in the editor, which gives the same control without writing it. Use `motion` when you want to write the animations yourself.

`videoSettings.motion` on [Generate](https://postnitro.ai/docs/embed/api/initiate/generate#video-posts) and [Import](https://postnitro.ai/docs/embed/api/initiate/import#video-posts) gives slides their own motion. It's a list with one entry per slide, in order. `null` leaves a slide to the style, or to the template's motion, or as it is.

## Example

A video in the Bold style, whose second slide has its own animations: the title types itself in, then the image fades in, then the button pulses until the slide ends. The slide arrives with a push upwards.

```json
"videoSettings": {
    "motionStyle": "bold",
    "motion": [
        null,
        {
            "steps": [
                { "element": "title", "preset": "typewriter" },
                { "element": "image", "preset": "fade" },
                { "element": "cta", "preset": "pulse", "repeat": "until-end" }
            ],
            "transition": { "type": "push", "direction": "up" }
        }
    ]
}
```

On generate, the AI decides how many slides there are and what's on them, so an entry for slide 3 may find no slide 3, or a slide without an image. Per-slide motion suits [Import](https://postnitro.ai/docs/embed/api/initiate/import), where you write the slides.

## Each entry

Each entry is an object with any of these fields:

| Field | Type | Description |
|-------|------|-------------|
| `steps` | array | The slide's animations, in the order they play: see [Steps](#steps). They replace the style's animations on this slide; `[]` keeps the slide still. |
| `transition` | object | How the slide arrives: see [Transitions](#transitions). |
| `hold` | number | Seconds the slide stays on screen after its animations, `0` to `30`. |

An entry changes only what it gives. With a style, `"transition": { "type": "none" }` on its own keeps the style's animations on that slide and only makes it cut in. A request with `motion` and no style isn't given the default style: the slides it leaves out keep the template's motion, or stay still.

## Steps

Entrances play in order, each after the one before unless it has `together`. An emphasis plays once its own element has come in, and an exit ends with the slide; neither holds the entrances up.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `element` | string | Yes | What moves: see [Elements](#elements). |
| `preset` | string | Yes | How it moves: see [Presets](#presets). |
| `kind` | string | No | `"enter"` (the default) brings the element in, `"emphasis"` (the default for `pulse`, `float`, `wiggle` and `kenburns`) plays while it stays, and `"exit"` takes it out, playing the preset backwards. In the editor these are **In**, **Emphasis** and **Out**. |
| `together` | boolean | No | Entrances only: start with the previous entrance instead of after it. |
| `delay` | number | No | Seconds, `0` to `30`: how long an entrance waits; how long after its element has come in an emphasis starts; how long before the slide's end an exit finishes. |
| `seconds` | number | No | How long it plays, `0.05` to `10`. For text played by line, word or letter, how long each part plays. Leave it out for the preset's own pace. |
| `split` | string | No | Text only: `"line"`, `"word"` or `"letter"`. |
| `direction` | string | No | The direction of travel: `"left"`, `"right"`, `"up"` or `"down"`. |
| `repeat` | number or string | No | Emphasis only: `1` to `50` times, or `"until-end"`, the default: until the element leaves, with its exit or at the end of the slide. |
| `keyframes` | array | With `custom` | The step's own motion: see [Keyframes](#keyframes). |

### Elements

| `element` | What it is |
|-----------|------------|
| `title` | The slide's heading (`heading` on import). |
| `subtitle` | The subtitle (`sub_heading`). |
| `description` | The description. |
| `cta` | The button (`cta_button`). |
| `image` | The slide's image. |
| `backgroundImage` | The background image (`background_image`). |
| `infographics` | An infographic, as one block. |
| `infographicHeader`, `infographicAndGridTitle`, `infographicAndGridDescription` | An infographic's column headers, item titles and item descriptions, one after another. |
| `avatar`, `name`, `handle` | Your brand's headshot, name and handle. |
| `slideCount`, `swipeIndicator`, `bookmark`, `backgroundPattern` | The template's slide number, swipe arrow, bookmark and background pattern. |

### Presets

`fade`, `rise`, `slide` (**Slide in** in the editor), `zoom`, `pop`, `bounce`, `spring`, `blur`, `rotate`, `flash`, `split` (**Converge**), `glitch`, `shimmer`, `typewriter`, `wave`, `jump`, `wipe`, `sweep` and `count` bring an element in or take it out. `sweep` draws a text's highlighted words in, its coloured or boxed words, like a marker, one after another; on text with nothing highlighted it's left out. `count` counts a text's numbers up from zero, in the form the text writes them ("1,250" counts as "625", then "1,250"), leaving years alone; on text with no numbers it's left out. `pulse`, `float` and `wiggle` are emphases: they loop until their element leaves (its exit, or the end of the slide) unless `repeat` says how many times. `kenburns` slowly zooms in on a picture or the background and drifts it in its `direction`, once, over the rest of its slide; on a picture it moves the picture inside its frame. `custom` plays the step's own [`keyframes`](#keyframes) instead of a preset's, for any `kind`.

### Keyframes

With `"preset": "custom"`, a step plays keyframes of its own: 2 to 12 points along it, each saying where the element is then.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `at` | number | Yes | Where in the step, from `0`, its start, to `1`, its end. The first is at `0` and the last at `1`, and each comes after the one before. |
| `opacity` | number | No | `0`, hidden, to `1`, as a share of the element's own opacity. |
| `x`, `y` | number | No | How far it has moved from where it rests, in the design's pixels: right and down are positive, up to `2000` either way. |
| `scale` | number | No | Its size, as a multiple of its own: `0` to `4`. |
| `rotate` | number | No | How far it has turned, in degrees, clockwise: up to `720` either way. |
| `blur` | number | No | Pixels of blur, `0` to `40`. |
| `easing` | string | No | How it moves on to the next keyframe: `"linear"`, `"ease"`, `"smooth"`, `"snappy"`, `"in-out"`, `"back"`, `"spring"` or `"bounce"`. Leave it out for the step's own. |

A property a keyframe leaves out is at rest: `opacity` `1`, `x` and `y` `0`, `scale` `1`, `rotate` `0` and `blur` `0`. An entrance is written as the element coming to rest, so its last keyframe sets nothing else, and an exit plays it backwards. An emphasis starts and ends at rest, so it can loop. `direction` doesn't apply.

```json
{
    "element": "title",
    "preset": "custom",
    "keyframes": [
        { "at": 0, "opacity": 0, "y": 60, "scale": 0.9 },
        { "at": 0.7, "y": -8, "easing": "back" },
        { "at": 1 }
    ]
}
```

## Transitions

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | string | Yes | `"none"` (a cut), `"fade"`, `"slide"`, `"push"`, `"zoom"`, `"wipe"` or `"blur"`. |
| `direction` | string | No | For `slide`, `push` and `wipe`: `"left"`, `"right"`, `"up"` or `"down"`. |
| `seconds` | number | No | How long it takes, up to `3`. Defaults to `0.5`. |

## With a style, a sequence or a template

`motion` comes last: it changes slides over the template's motion, the style and a [saved sequence](https://postnitro.ai/docs/embed/api/initiate/video-motion#saved-styles-and-sequences). An entry's steps replace the slide's animations, and a slide given its motion outright doesn't take the sequence.

## What's checked

The motion is checked when you make the request, before anything is generated. An unknown element or preset, a step whose `kind` doesn't suit its preset, keyframes that break the rules above, an unknown field or a value out of range returns a `422` that says where it is, such as `videoSettings.motion[1].steps.0.element: …`.

What depends on the slides can't be checked until they exist. A step for an element a slide doesn't show, such as an image on a slide without one, is left out, and so are entries past the last slide. The post still completes, and the `COMPOSE_MOTION` step in [Check Post Status](https://postnitro.ai/docs/embed/api/request-status) says what was left out.
