# Shotstack Documentation (Full)
This file is generated from markdown docs visible in the sidebar for high-recall agent retrieval.
Use `llms.txt` for lightweight navigation.
---
## What is Shotstack?
- Markdown URL: https://shotstack.io/docs/guide/what-is-shotstack.md
- Web URL: https://shotstack.io/docs/guide/
- Description: Shotstack is a platform for editing videos using code that enables marketers, developers and designers to automate the generation of videos at scale.
# What is Shotstack?
[Shotstack](https://shotstack.io/) is a platform for editing videos, using code, that enables developers, marketers, and
designers to automate the generation of videos at scale.
Shotstack uses a REST based API hosted in the cloud that uses JSON data describing the arrangement of a video edit.
JSON is used to arrange, trim and animate assets including images, video, titles and audio. It also
includes a number of built in motion effects, transitions and filters to rapidly edit a professional looking
video.
The cloud based API provides the infrastructure to allow thousands of videos to be rendered concurrently in a matter of
minutes allowing for mass personalization and customization of content.
The API can also be used to generate images and audio only files.
---
## Edit Videos Using Code
- Markdown URL: https://shotstack.io/docs/guide/getting-started/core-concepts.md
- Web URL: https://shotstack.io/docs/guide/getting-started/core-concepts/
- Description: Learn the basics of how a video edit is put together using JSON
# Edit Videos Using Code
Shotstack is a cloud based [video editing API](https://shotstack.io). Unlike traditional desktop video editing
applications like Adobe Premiere or After Effects, Shotstack is purely code based - you create an edit using code. The
API uses a REST architectural style using JSON to describe how the video should be edited.
Although code based, the API follows many of the principles of desktop editing software such as a timeline, tracks and
clips. If you have used with Adobe Premiere, After Effects or even Flash some of these concepts should be familiar, all
be it without a graphical user interface.
These core concepts and principles are described below:
### Edit
An edit encompasses everything about the video that you want to create and is made of two components - the `timeline`
which describes the assets \(videos, images and titles\) that you want use and how they are arranged \(edited\) and the
`output` format \(gif or mp4\) and resolution \(HD, SD, mobile, etc..\).
```json
{
"timeline": {...}, // the main video edit description
"output": {...} // the output format and resolution
}
```
:::info
The Edit is the JSON payload that you POST to the _render_ endpoint to create your video.
:::
### Timeline
The timeline represents the time that the video will play for, using seconds and starting from 0. A timeline is made up
of `tracks` which are like layers that contain clips.
```json
{
"timeline": {
"tracks": [{...}] // array of tracks
},
...
}
```
### Tracks
Tracks are like layers within the timeline which span the entire length of the timeline, a track contains one or more
`clips` Tracks can be visualized as layers that can be placed one on top of another. Clips on the top most track will
obscure those on tracks below it. This can be useful for when you want to layer a title over a video clip or you want to
fade between clips.
Tracks also help to logically organize different types of content, for example a title track which plays over the top of
a video and a watermark track that plays over the top of everything.
Tracks are an array within the timeline, the first element is the top track and the last element is the bottom most
track:
```json
{
"timeline": {
"tracks": [
{
... // top track
},
{
... // bottom track
}
]
},
...
}
```
### Clips
Clips are where you select the asset \(video, image or title\) you want to display within a track on the timeline, when
it starts, how long it plays for and what effects, transitions and filters you want to apply.
Clips are placed on a track at a specific `start` time, for example a clip with a `start` time of 3 will appear in
the video after three seconds have played. Clips also have a `length` which determines how long the clip will play for
in seconds.
You can choose to set the `start` or `length` property automatically by setting it to `auto` or `end`. See the
[smart clips](/docs/guide/architecting-an-application/smart-clips) section for all options.
Each `asset` type has a specific set of options and features but you must specify the `type` of asset and also the
`content` of the asset such a URL `src` to a video or image file or for titles a `text` string.
```json
{
"timeline": {
"tracks": [
{
"clips": [
{
// place an image at the very start of the track/timeline that plays for 4 seconds.
"asset":{
"type": "image",
"src": "https://s3-ap-southeast-2.amazonaws.com/my-bucket/photo.jpg",
},
"start": 0,
"length": 4
},
{
// place a video that starts on the fourth second of the track/timeline ("start": 4) that has
// the first two seconds trimmed ("trim": 2) and plays for 6 seconds ("length": 6).
"asset":{
"type": "video",
"src": "https://s3-ap-southeast-2.amazonaws.com/my-bucket/footage.mp4",
"trim": 2
},
"start": 4,
"length": 6
}
]
},
]
},
...
}
```
:::danger
Do not place clips on a track so that their start or end times overlap. This will result in the clips
flickering because the API does not know which clip to display.
:::
A clip can also have transitions, effects and filters applied to them. A clip may look something like this when more
options are applied:
```json
{
"asset":{
"type": "video",
"src": "https://s3-ap-southeast-2.amazonaws.com/my-bucket/footage.mp4",
"trim": 2,
"volume": 0.5
},
"start": 0,
"length": 4,
"transition": {
"in": "fade",
"out": "fade"
},
"filter": "boost",
"effect": "slideRight"
}
```
From these basic building blocks you should be able to assemble a sophisticated, reusable template to create videos.
Assets can be replaced or clips added using loops, conditions and other coding constructs allowing you to build a range
of video based applications.
---
## Request API Keys
- Markdown URL: https://shotstack.io/docs/guide/getting-started/request-api-keys.md
- Web URL: https://shotstack.io/docs/guide/getting-started/request-api-keys/
- Description: Before you can use the API you need to register and receive your API keys
# Request API Keys
[Sign up](https://dashboard.shotstack.io/register) to the Shotstack service to generate API keys. Keys for both a
staging sandbox and a live production environment are available in the dashboard.
Find your keys in the menu under your account name (top right hand corner):

Click on the **API Keys** item in the menu to open the keys page:

Keys are a random 40 character string that look something like:
```text
HBHjHylztJqjEeIFQxNJWB5g2mPa4lI40wX8oNVD
```
Staging sandbox and production URL's are:
| Sandbox URL | Production URL |
| :------------------------------| :-------------------------- |
| https://api.shotstack.io/stage | https://api.shotstack.io/v1 |
:::tip
Use the sandbox environment for testing. Only AI assetes get charged. Videos are watermarked.
:::
:::caution
Using your production key will use up your credits and may result in being [charged](https://shotstack.io/pricing/).
:::
---
## Hello World
- Markdown URL: https://shotstack.io/docs/guide/getting-started/hello-world-using-curl.md
- Web URL: https://shotstack.io/docs/guide/getting-started/hello-world-using-curl/
- Description: Create your first video in 5 minutes using the command line and Curl
# Hello World
This Hello World guide should provide you with a basic understanding of how quick and easy it is to create a simple
video using styled text, a soundtrack and a simple fade transition.
Before you begin ensure you have registered and received your [API keys](./request-api-keys.md).
### Requirements
This tutorial uses Curl to create your first 'Hello World' video. Curl is a cross platform command line utility that can
be used to POST data to an API.
### Create the Hello World edit
We'll use a text file to define the JSON data so that it is easy to edit and format. Open your preferred text editor and
copy and paste the following JSON, save the file as **hello.json**:
```json
{
"timeline": {
"soundtrack": {
"src": "https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/music/moment.mp3",
"effect": "fadeOut"
},
"tracks": [
{
"clips": [
{
"asset": {
"type": "text",
"text": "HELLO WORLD",
"font": {
"family": "Montserrat ExtraBold",
"color": "#ffffff",
"size": 32
},
"alignment": {
"horizontal": "left"
}
},
"start": 0,
"length": 5,
"transition": {
"in": "fade",
"out": "fade"
}
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1024,
"height": 576
}
}
}
```
### POST the edit to the Shotstack API
You can now go ahead and POST the **hello.json** edit data to the API for rendering, to do this we'll use the **render**
endpoint. From the same directory as the **hello.json** file, run the following Curl command:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-H "x-api-key: ptmpOiyKgGYMnnONwvXH7FHzDGOazrIjaEDUS7Cf" \
-d @hello.json \
https://api.shotstack.io/edit/stage/render
```
:::info
Replace the **x-api-key** value with your own sandbox (stage) API key.
:::
You should receive a 201 response code and payload similar to:
```json
{
"success":true,
"message":"Created",
"response":{
"message":"Render Successfully Queued",
"id":"d2b46ed6-998a-4d6b-9d91-b8cf0193a655"
}
}
```
:::info
Take a note of the **id**, it will be different from the example above, you will need this in the next step.
You should keep track of **id** in your own database as there is currently no way to retrieve a list of render id's.
:::
### Poll the API to check the render status
Your video is now either waiting in a queue to be rendered or is being processed. To check the status and know when
rendering is complete and the video file is ready we need to poll the API.
Using the **id** noted in the previous step and your own key, call the staging API using the following command:
```bash
curl -X GET \
-H "Content-Type: application/json" \
-H "x-api-key: ptmpOiyKgGYMnnONwvXH7FHzDGOazrIjaEDUS7Cf" \
https://api.shotstack.io/edit/stage/render/d2b46ed6-998a-4d6b-9d91-b8cf0193a655
```
:::info
Replace the UUID at the end of the render URL with the **id** output in the previous step.
:::
In less than one minute you should receive a 200 response code and payload similar to the output below. The status
parameter tells you what stage the render is at, **done** means the video is ready for download. Other status are
queued, fetching, rendering, saving and failed.
```json
{
"success": true,
"message": "OK",
"response": {
"id": "d2b46ed6-998a-4d6b-9d91-b8cf0193a655",
"owner": "5ca6hu7s9k",
"plan": "free",
"status": "done",
"url": "https://shotstack-api-stage-output.s3-ap-southeast-2.amazonaws.com/5ca6hu7s9k/d2b46ed6-998a-4d6b-9d91-b8cf0193a655.mp4",
"data": {
"output": {
...
},
"timeline": {
...
}
},
"created": "2024-01-16T12:02:42.148Z",
"updated": "2024-01-16T12:02:51.867Z"
}
}
```
:::caution Warning
If the status is **failed** then there has been an error and the render will not continue. Attempt to resolve the issue
based on the error message then try again. If the problem persists contact us for support.
:::
### Hosting and serving the rendered video
When the status returned from polling equals **done**, then the video is ready for
[hosting](/docs/guide/serving-assets/hosting) or downloading.
By default all videos are automatically sent to our
[video hosting and CDN service](/docs/guide/serving-assets/hosting). After a few seconds the video should be available
at the following locations:
| Staging | Production |
| :--------------------------------- | :------------------------------ |
| **https://cdn.shotstack.io/au/stage/** | **https://cdn.shotstack.io/au/v1/** |
The video created in this guide would be available at:
```
https://cdn.shotstack.io/au/stage/5ca6hu7s9k/d2b46ed6-998a-4d6b-9d91-b8cf0193a655.mp4
```
The [Serve API](/docs/guide/serving-assets/serve-api) provides more information on the status and availability of hosted
files.
### Transferring the video to your own hosting service
If you use your own hosting solution, you can [opt-out](/docs/guide/serving-assets/self-host) from the Shotstack hosting
service and transfer the file to the location of your choice.
Videos are stored temporarily for a 24 hour period at the following locations:
| Staging | Production |
| :------------------------------------------------------------------ | :------------------------------------------------------------------ |
| **https://shotstack-api-stage-output.s3-ap-southeast-2.amazonaws.com/** | **https://shotstack-api-v1-output.s3-ap-southeast-2.amazonaws.com/** |
Download or transfer the video using the URL returned in the get render status response:
```bash
curl -O https://shotstack-api-stage-output.s3-ap-southeast-2.amazonaws.com/5ca6hu7s9k/d2b46ed6-998a-4d6b-9d91-b8cf0193a655.mp4
```
:::warning Danger
Do not serve the temporary URLs from your application as the file will be deleted after 24 hours. Check the
[Hosting and Serving Assets](/docs/guide/serving-assets/hosting) guide for the correct way to serve assets generated by
the video editing API.
:::
### Conclusion
You will now have a basic understanding of the key steps needed to create a simple edit:
1. Prepare the edit data
2. POST the edit data to the API
3. Poll the API and wait for the render to complete
4. Serve the video from the Shotstack CDN
5. Download or transfer the video to your own storage
---
## Editing Videos, Images and Audio
- Markdown URL: https://shotstack.io/docs/guide/architecting-an-application/guidelines.md
- Web URL: https://shotstack.io/docs/guide/architecting-an-application/guidelines/
- Description: Guidelines on how to create an application incorporating the Shotstack API.
# Editing Videos, Images and Audio
Shotstack provides a framework to automate the editing process for your videos, images and audio and the heavy lifting
of rendering thousands of videos concurrently.
Shotstack is useful is in building media based applications and automating workflows where a template can be used and
assets created in batches or large volumes.
## Key steps to editing media
### Prepare JSON using the Studio
An edit in Shotstack is defined using JSON which specifies when different assets (images, videos, titles) will appear
and play on a timeline. In order to create a video you first need to prepare the JSON data so that it contains the
correct assets arranged on the timeline.
You can use the Shotstack Studio to help create this JSON data.
### Post JSON to API render endpoint
Once your have prepared an edit using the Studio you POST the data to the _**render** endpoint of our API.
### Poll render endpoint
The render process takes approximately 10 seconds for a 30-second video.
Your application needs to poll the API on a regular basis to check the status of the video render by calling the
_**render**_ endpoint with the **id** of the current render. When the status is `done` you can proceed to downloading or
transferring the video to your application.
:::info Tip
We recommend [using webhooks](webhooks.md) to reduce the number of calls to the API and receive a notification as
soon as rendering completes.
:::
### Hosting and serving video
Once a video is finished rendering, it is available at a temporary URL as well as automatically transferred to the
[Shotstack hosting service](/docs/guide/serving-assets/hosting).
### Download or transfer the video
Instead of using the Shotstack hosting service, the video can be fetched from our servers \(S3\) and transferred to your
own application for further processing and hosting.
You may wish to transfer the video to your own S3 or storage service, upload it Google Drive, Vimeo or any of our other
destinations.
:::danger Warning
If you are not using our hosting service, we will store the video on our servers for 24 hours only. After that time they
will be deleted.
:::
---
## Rich Text
- Markdown URL: https://shotstack.io/docs/guide/architecting-an-application/rich-text.md
- Web URL: https://shotstack.io/docs/guide/architecting-an-application/rich-text/
- Description: Create advanced animated text with gradients, shadows, and effects
# Rich Text
The rich-text asset provides advanced text rendering capabilities with support for animations, gradients, shadows, strokes, and custom styling. It's ideal for creating professional titles, animated text effects, and stylized typography.
## Common rich-text patterns
Before diving into individual properties, here are solutions to common text needs:
### Animated title
Create an eye-catching title with a word-by-word ascend animation, a custom font and a linear gradient:
```json
{
"timeline": {
"fonts": [
{
"src": "https://shotstack-assets.s3.amazonaws.com/fonts/Oswald-VariableFont.ttf"
}
],
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "Evening Night",
"font": {
"family": "Oswald",
"size": 125,
"weight": 900
},
"style": {
"letterSpacing": 8,
"gradient": {
"type": "linear",
"stops": [
{
"offset": 0,
"color": "#005AA7"
},
{
"offset": 1,
"color": "#FFFDE4"
}
]
}
},
"animation": {
"preset": "ascend",
"duration": 1
}
},
"start": 0,
"length": 5,
"width": 1000,
"height": 300
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```
### Bold call-to-action text
Create impactful text with stroke outline and shadow for maximum visibility:
```json
{
"timeline": {
"background": "#000000",
"fonts": [
{
"src": "https://shotstack-assets.s3.amazonaws.com/fonts/SpecialElite-Regular.ttf"
}
],
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "SUBSCRIBE NOW",
"font": {
"family": "Montserrat",
"size": 64,
"weight": 800,
"color": "#ffd700"
},
"style": {
"letterSpacing": 4,
"textTransform": "uppercase"
},
"stroke": {
"width": 4,
"color": "#000000",
"opacity": 1
},
"shadow": {
"offsetX": 6,
"offsetY": 6,
"blur": 12,
"color": "#000000",
"opacity": 0.7
},
"background": {
"color": "#FF5962",
"borderRadius": 25
},
"animation": {
"preset": "shift",
"duration": 2,
"style": "character",
"direction": "up"
},
"align": {
"horizontal": "center"
}
},
"start": 0,
"length": 5,
"width": 800,
"height": 200
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```
### Typewriter subtitle effect
Create text that appears character by character:
```json
{
"timeline": {
"background": "#000000",
"fonts": [
{
"src": "https://shotstack-assets.s3.amazonaws.com/fonts/SpecialElite-Regular.ttf"
}
],
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "Let me tell you a story...",
"font": {
"family": "SpecialElite-Regular",
"size": 42,
"color": "#ffffff"
},
"animation": {
"preset": "typewriter",
"duration": 1.5,
"style": "character"
}
},
"start": 0,
"length": 5,
"width": 900,
"height": 150
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```
## Basic usage
A simple rich-text element requires only text, dimensions, and font properties:
```json
{
"asset": {
"type": "rich-text",
"text": "Welcome to Shotstack",
"font": {
"family": "Roboto",
"size": 48,
"color": "#ffffff"
}
},
"start": 0,
"length": 5,
"width": 800,
"height": 400
}
```
This creates white Roboto text at 48px within an 800×400 pixel container. The `width` and `height` define the text's maximum area, and text is centered by default. The clip appears at the beginning of the timeline and lasts 5 seconds.
## Fonts
The font properties control the core typography of your text. Choose from built-in fonts or load custom fonts to match your brand. Font styling is broken down into seven properties:
1. `font`
2. `style`
3. `stroke`
4. `shadow`
5. `align`
6. `animation`
### Font properties
Customize the appearance of your text with font styling options:
```json
{
"asset": {
"type": "rich-text",
"text": "Styled Text",
"font": {
"family": "Roboto",
"size": 64,
"weight": 800,
"color": "#ff6b6b",
"opacity": 0.9
}
},
"start": 0,
"length": 5,
"width": 800,
"height": 400
}
```
This creates bold italic text using Roboto (weight 800) at 64px with a coral red color at 90% opacity.
**Font options:**
- `family` - Font name (default: "Roboto")
- `size` - Font size in pixels, 12-200 (default: 48)
- `weight` - Font weight: 100-900 or "normal", "bold" (default: "400")
- `color` - Hex color code (default: "#ffffff")
- `opacity` - Text opacity, 0-1 (default: 1)
### Available fonts
Built-in fonts:
- Roboto
- Montserrat
- Open Sans
- Work Sans
- Uni Neue
- Arapey
- Clear Sans
- Didact Gothic
- Movie Letter
- Permanent Marker
- Sue Ellen Francisco
### Custom fonts
Use your own fonts by providing a URL to an OTF or TTF font file:
```json
{
"timeline": {
"background": "#FFD166",
"fonts": [
{
"src": "https://shotstack-assets.s3.amazonaws.com/fonts/PressStart2P-Regular.ttf"
}
],
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "GAME OVER",
"font": {
"family": "Press Start 2P",
"size": 60,
"color": "#EF476F"
}
},
"start": 0,
"length": 5,
"width": 1000,
"height": 400
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```

:::info
The font file must be publicly accessible. The `family` property can be set using either:
1. **The font's embedded name** (recommended) — use the font's real family name as stored in the font file, e.g. `"Press Start 2P"` for `PressStart2P-Regular.ttf`. This is the name you would see when installing the font on your computer.
2. **The filename** — use the filename without the extension, e.g. `"PressStart2P-Regular"` for `PressStart2P-Regular.ttf`.
:::
### International fonts
Shotstack supports everything from Arabic calligraphy to Devanagari ligatures, as long as the font provides the necessary glyphs.
#### Hindi
```json
{
"timeline": {
"background": "#015C37",
"fonts": [
{
"src": "https://shotstack-assets.s3.amazonaws.com/fonts/Hind-Regular.ttf"
}
],
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "जहाँ चाह, वहाँ राह।",
"font": {
"family": "Hind",
"size": 60,
"color": "#FFFFFF"
}
},
"start": 0,
"length": 5,
"width": 1000,
"height": 400
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```

#### Chinese (Simplified)
```json
{
"timeline": {
"background": "#CD071E",
"fonts": [
{
"src": "https://shotstack-assets.s3.amazonaws.com/fonts/NotoSansTC-VariableFont_wght.ttf"
}
],
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "千里之行,始于足下。",
"font": {
"family": "NotoSansTC-VariableFont_wght",
"size": 75,
"color": "#FABC3C"
}
},
"start": 0,
"length": 5,
"width": 1000,
"height": 400
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```

## Text styling
Beyond fonts, text styling properties control spacing, transformations, and decorations. These properties help create modern, spacious layouts and emphasize important text.
### Letter spacing and line height
Adjust text layout with spacing and transformation options:
```json
{
"timeline": {
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "Spaced Out Text",
"font": {
"family": "Roboto",
"size": 48,
"color": "#ffffff"
},
"style": {
"letterSpacing": 35,
"lineHeight": 1.5,
"textTransform": "uppercase",
"textDecoration": "underline"
}
},
"start": 0,
"length": 5,
"width": 1000,
"height": 400
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```

This adds 35 pixels between characters, increases line height to 2× the font size (more space between lines), converts text to uppercase, and adds an underline.
**Style options:**
- `letterSpacing` - Space between characters in pixels (default: 0)
- `lineHeight` - Relative line height, 0-10 (default: 1.2)
- `textTransform` - "none", "uppercase", "lowercase", "capitalize" (default: "none")
- `textDecoration` - "none", "underline", "line-through" (default: "none")
## Gradients
Gradients add visual interest by transitioning between colors. Use linear gradients for modern, directional effects, or radial gradients for spotlight and glow effects. Gradients work best with bold, large text and override the font color property.
### Linear gradient
Create text with a smooth color transition from one color to another:
```json
{
"timeline": {
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "MILKSHAKE",
"font": {
"family": "Montserrat",
"size": 125,
"weight": 800
},
"style": {
"gradient": {
"type": "linear",
"angle": 45,
"stops": [
{
"offset": 0,
"color": "#C6FFDD"
},
{
"offset": 0.5,
"color": "#FBD786"
},
{
"offset": 1,
"color": "#f7797d"
}
]
}
}
},
"start": 0,
"length": 5,
"width": 900,
"height": 400
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```

A three-color gradient transition at a 45-degree diagonal. The `angle` controls the direction (0° is left to right, 90° is top to bottom), and `stops` define colors at specific positions (0 is start, 0.5 is middle and 1 is end).
### Radial gradient
Create text with a color that radiates from the center outward:
```json
{
"timeline": {
"background": "#FFFFFF",
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "NOVA",
"font": {
"family": "Montserrat",
"size": 200,
"weight": 800
},
"style": {
"gradient": {
"type": "radial",
"stops": [
{
"offset": 0,
"color": "#ffd89b"
},
{
"offset": 0.5,
"color": "#f6416c"
},
{
"offset": 1,
"color": "#2d3561"
}
]
}
}
},
"start": 0,
"length": 5,
"width": 900,
"height": 400
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```

The gradient radiates from yellow at the center through pink at the midpoint to dark blue at the edges. Radial gradients create a spotlight or glow effect and work best with centered text.
**Gradient options:**
- `type` - "linear" or "radial" (default: "linear")
- `angle` - Gradient angle in degrees, 0-360 (default: 0, only for linear)
- `stops` - Array of color stops (minimum 2 required)
- `offset` - Position of stop, 0-1 (required)
- `color` - Hex color code (required)
:::info
Gradients require at least 2 color stops. Use 2-4 stops for smooth, professional gradients. More stops can create banding effects. When using gradients, the gradient fill overrides the `font.color` property.
:::
## Stroke
Add a bold outline around text for visibility and impact:
```json
{
"asset": {
"type": "rich-text",
"text": "Outlined Text",
"font": {
"family": "Permanent Marker",
"size": 72,
"color": "#ffffff"
},
"stroke": {
"width": 4,
"color": "#000000",
"opacity": 1
}
},
"start": 0,
"length": 5,
"width": 800,
"height": 400
}
```

The 4-pixel black stroke creates a bold outline that makes white text readable over any background. Stroke width of 3-6 pixels works well for most text sizes. Combine stroke with shadow for maximum visibility.
**Stroke options:**
- `width` - Stroke width in pixels (default: 0)
- `color` - Hex color code (default: "#000000")
- `opacity` - Stroke opacity, 0-1 (default: 1)
## Shadow
Add depth and improve readability with drop shadows:
```json
{
"timeline": {
"background": "#F9DB6A",
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "MONDAY",
"font": {
"family": "Montserrat",
"size": 175,
"color": "#432963",
"weight": 900
},
"shadow": {
"offsetX": 8,
"offsetY": 8,
"blur": 6,
"color": "#77E6F0",
"opacity": 0.8
}
},
"start": 0,
"length": 5,
"width": 1000,
"height": 400
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```

The shadow appears 8 pixels down and to the right with an 6-pixel blur, creating a soft depth effect. Lower opacity (0.5-0.8) creates subtle shadows, while higher opacity (0.9-1.0) creates dramatic shadows.
**Shadow options:**
- `offsetX` - Horizontal offset in pixels (default: 0)
- `offsetY` - Vertical offset in pixels (default: 0)
- `blur` - Blur radius in pixels (default: 0)
- `color` - Hex color code (default: "#000000")
- `opacity` - Shadow opacity, 0-1 (default: 0.5)
## Background
Add a colored background box behind text:
```json
{
"asset": {
"type": "rich-text",
"text": "Background Text",
"font": {
"family": "Roboto",
"size": 48,
"color": "#ffffff"
},
"background": {
"color": "#3498db",
"opacity": 0.8,
"borderRadius": 20
}
},
"start": 0,
"length": 5,
"width": 600,
"height": 200
}
```

By default, the background fills the entire clip container (600×200 pixels) with a semi-transparent blue color. The rounded corners (`borderRadius: 20`) soften the edges.
### Wrapping the background to the text
When the text length is unknown at template-authoring time — merge fields, user input, transcribed names — a fixed-width background looks awkward. Short text leaves a wide empty bar; long text overflows or feels cramped against the edges. Set `background.wrap` to `true` and the background shrinks to fit the rendered text plus the asset's padding (and stroke width, if present), producing a pill that hugs whatever the runtime value turns out to be.
The render below uses an identical template for three different names. Without wrap (left), the background is always the full clip width. With wrap (right), the pill resizes to each name:
```json
{
"asset": {
"type": "rich-text",
"text": "Alexandra Wellington",
"font": {
"family": "Montserrat",
"size": 48,
"color": "#ffffff",
"weight": 600
},
"padding": 18,
"background": {
"color": "#ef4444",
"borderRadius": 60,
"wrap": true
}
},
"start": 0,
"length": 2,
"width": 600,
"height": 100
}
```
The clip stays 600×100, but the red pill only wraps the text plus 18 pixels of padding on each side. The text stays positioned within the clip per its `align` settings; the pill follows the text. Combined with `border`, the border tracks the wrapped pill in the same way.
**Background options:**
- `color` - Hex color code (optional)
- `opacity` - Background opacity, 0-1 (default: 1)
- `borderRadius` - Border radius in pixels (default: 0)
- `wrap` - When `true`, the background shrinks to fit the rendered text plus padding instead of filling the clip (default: false)
## Alignment
Position text within its container using horizontal and vertical alignment:
```json
{
"timeline": {
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "\"The mystery of human existence lies not in just staying alive, but in finding something to live for.\" \n \n- Fyodor Dostoevsky",
"font": {
"family": "Open Sans",
"size": 48
},
"align": {
"horizontal": "left",
"vertical": "top"
}
},
"start": 0,
"length": 5,
"width": 500,
"height": 600
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```

This positions text in the top-left corner of the 500x600 container. Text is centered both horizontally and vertically by default.
**Alignment options:**
- `horizontal` - "left", "center", "right" (default: "center")
- `vertical` - "top", "middle", "bottom" (default: "middle")
## Animations
Text animations bring your text to life. Choose from preset animations like typewriter, fade-in, slide-in, and more. Control animation speed and duration to match your video's pacing. Animations are perfect for intros, subtitles, and attention-grabbing titles.
### Example: Fade-in animation
Create text that smoothly fades into view:
```json
{
"timeline": {
"tracks": [
{
"clips": [
{
"asset": {
"type": "rich-text",
"text": "Ascend while others stay idle",
"font": {
"family": "Roboto",
"size": 60,
"color": "#ffffff"
},
"animation": {
"preset": "typewriter",
"duration": 2,
"style": "word"
}
},
"start": 0,
"length": 5,
"width": 800,
"height": 400
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```
The text fades in over 2 seconds. The optional `duration` parameter controls how long the animation takes, with the default being set to the length of the clip. The animation starts when the clip begins.
### Available animation presets
#### fadeIn
```json
"animation": {
"preset": "fadeIn", // Animation type
"duration": 2, // Animation length (default: full clip)
"style": "character" // "word", "character", or "full" (default)
}
```
**typewriter**
```json
"animation": {
"preset": "typewriter", // Animation type
"duration": 2, // Animation length (default: full clip)
"style": "character" // "word" or "character" (default: character)
}
```
**slideIn**
```json
"animation": {
"preset": "slideIn", // Animation type
"duration": 2, // Animation length (default: full clip)
"style": "character", // "word" or "character" (default)
"direction": "left" // "left" (default), "right", "up", "down"
}
```
**ascend**
```json
"animation": {
"preset": "ascend", // Animation type
"duration": 2, // Animation length (default: full clip)
"direction": "up" // "up" (default), "down"
}
```
**shift** - Text shifts from a direction with fade
```json
"animation": {
"preset": "shift", // Animation type
"duration": 2, // Animation length (default: full clip)
"style": "character", // "word" or "character" (default)
"direction": "left" // "left" (default), "right", "up", "down"
}
```
## Related topics
- [Animations](/docs/guide/architecting-an-application/animations) - Animate clip properties over time
- [Positioning](/docs/guide/architecting-an-application/positioning) - Position and scale rich-text assets
---
## Positioning
- Markdown URL: https://shotstack.io/docs/guide/architecting-an-application/positioning.md
- Web URL: https://shotstack.io/docs/guide/architecting-an-application/positioning/
- Description: Position assets precisely on the video canvas using position, offset, fit, and scale properties
# Positioning
Positioning controls where assets appear in your video. Because source assets vary in size and aspect ratio, Shotstack provides multiple properties that work together to give you precise control over placement and sizing.
## Common positioning patterns
Before diving into how each property works, here are solutions to common positioning needs:
### Consistent sizing for variable images
When using images of different sizes or aspect ratios (common in templates with user-provided content), set fixed dimensions with the appropriate fit mode to ensure consistent layout:
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/images/woods1.jpg"
},
"start": 0,
"length": 5,
"width": 400,
"height": 400,
"fit": "contain"
}
```

By setting fixed `width` and `height` values, every image—regardless of its original dimensions—will occupy exactly 800x450 pixels in your video. This is critical when working with user-provided content where source image sizes vary unpredictably.
The `fit` property determines how the source image fills this fixed area:
- `fit: "contain"` (shown above) - Scales the image proportionally to fit entirely within the 800x450 area. Maintains aspect ratio but may add letterboxing. Best when you must show the complete image.
- `fit: "crop"` - Fills the 800x450 area by cropping the source image. Centers the crop region.
- `fit: "cover"` - Scales the image to completely fill the 800x450 area. Does not aintain aspect ratio and may distort the image.
### Logo in corner
Places a logo in the top-right corner with margin:
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/logos/shotstack/small/logo-mono-white.png"
},
"start": 0,
"length": 5,
"fit": "crop", // Default setting. Can be ommitted.
"scale": 0.07,
"position": "topRight",
"offset": {
"x": -0.05,
"y": -0.05
}
}
```

The `offset` property adds spacing from the corner anchor point, while the `fit` properties value of `crop` crops the image to the size of the viewport. The `scale` property resizes the clip to 7% of the viewport size.
### Full-bleed background
Fills the entire canvas with an image, cropping edges if needed:
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/images/woods1.jpg"
},
"start": 0,
"length": 5,
"fit": "crop", // Default setting. Can be omitted.
"position": "center" // Default setting. Can be omitted.
}
```

The `"fit": "crop"` property scales the image to fill the clip area while maintaining aspect ratio.
## The coordinate system
Shotstack uses normalized coordinates that work regardless of your output resolution. The viewport center is `(0, 0)`, edges extend from `-1` to `1` in both directions.
This means the same positioning values work identically for 720p, 1080p, or 4K videos—no need to recalculate for different resolutions.

## Position property
The `position` property anchors your asset to one of nine points on the viewport:
- `center` (default)
- `top`, `bottom`, `left`, `right`
- `topLeft`, `topRight`, `bottomLeft`, `bottomRight`
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/logos/shotstack/small/logo-mono-white.png"
},
"start": 0,
"length": 5,
"fit": "none",
"position": "topLeft"
}
```

Use `position` when you want to align content to standard locations like corners or edges.
:::info
Make sure you are using the correct `fit` property. The default `"fit": "crop"` will scale the asset to the viewport, allowing you to control how the asset is cropped.
:::
## Offset property
The `offset` property fine-tunes placement from the `position` anchor point, relative to the total width and height of the viewport. Values range from `-1` to `1`:
- `x`: Negative moves left, positive moves right
- `y`: Negative moves down, positive moves up
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/logos/shotstack/small/logo-mono-white.png"
},
"start": 0,
"length": 5,
"fit": "none",
"position": "topLeft",
"offset":{
"x": 0.05,
"y": -0.05
}
}
```

This example positions the asset at `bottomLeft`, then moves it right by 10% of width of the viewport, and up by 10% of the height of the viewport, creating margin from the edges.
:::info
Offset values use a relative `-1` to `1` range, based on the `width` and `height` selected in the `output`. Values > 1 will move the image offscreen.
:::
## Fit property
The `fit` property controls how assets scale to fit the clip:
### Crop
Scales the asset to fill the clip bounds while maintaining aspect ratio. This may crop the asset if aspect ratio doesn't match the viewport size:
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/images/mountain-mist-lrg.jpg"
},
"start": 0,
"length": 5,
"fit": "crop"
}
```

### Cover
Scales the asset to fill the clip area. This does not maintain the aspect ratio and may distort the asset if the viewport aspect ratio doesn't match:
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/images/mountain-mist-lrg.jpg"
},
"start": 0,
"length": 5,
"fit": "cover"
}
```

### Contain
Scales the asset to fit within the clip bounds while maintaining aspect ratio, but may add letterboxing if aspect ratios don't match:
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/images/mountain-mist-lrg.jpg"
},
"start": 0,
"length": 5,
"fit": "contain"
}
```

### None
No scaling applied. Asset uses its original dimensions:
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/images/mountain-mist-lrg.jpg"
},
"start": 0,
"length": 5,
"fit": "none"
}
```

Use when you want exact control over sizing, typically combined with `scale`.
:::info
If no `fit` property is specified, the default behavior is `crop`, which will crop assets to fill the frame.
:::
## Width & Height
Clips are set to the width and height of the viewport by default, unless you explicitly set its dimensions.
:::info
The `width` and `height` properties are not currently available in Shotstack Studio. These properties are only available when using the Shotstack API directly.
:::
### Implicit dimensions
When `width` and `height` are **not** explicitly set the clip will assume the dimensions of the viewport as set in the `output` property.
### Explicit dimensions
You can set the exact pixel dimensions for a clip. This is helpful if you want to make sure your assets are contained within a fixed boundary:
```json
{
"asset": {
"type": "video",
"src": "https://shotstack-assets.s3.amazonaws.com/footage/city.mp4"
},
"start": 0,
"length": 5,
"width": 480,
"height": 270,
"position": "bottomRight",
"offset": {
"x": -0.1,
"y": -0.1
}
}
```

This creates a picture-in-picture effect with a fixed-size video overlay.
:::info
Fixed size clips are particularly useful if you are using UGC or other assets from which you cannot guarantee the size and/or aspect ratio.
:::
## Scale
The `scale` property resizes assets proportionally. A value of `1` is normal size, `0.5` is half size, `2` is double size:
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/images/woods1.jpg"
},
"start": 0,
"length": 5,
"scale": 0.2
}
```

Use `scale` when you want proportional resizing. Use `width` and `height` when you need exact dimensions.
:::info
The `scale` property is applied to the `clip` **after** `fit` scaling is applied to the asset.
:::
## How properties work together
Properties are applied in this order:
1. **Width/Height** - Sets explicit dimensions of the clip
2. **Fit** - Scales asset to the clip
3. **Position** - Anchors to grid point
4. **Offset** - Fine-tunes from anchor relative to viewport
5. **Scale** - Final size multiplier
Example using multiple properties:
```json
{
"asset": {
"type": "image",
"src": "https://shotstack-assets.s3.amazonaws.com/images/woods1.jpg"
},
"start": 0,
"length": 5,
"fit": "contain",
"position": "topLeft",
"width": 500,
"height": 500,
"offset": {
"x": 0.1,
"y": -0.1
},
"scale": 0.8
}
```

This example:
1. The clip container is explicitly set to 500px by 500px.
2. The asset is resized to fit within the 500px by 500px container without cropping the image, potentially with letterboxing.
3. Anchors the clip to the top-left corner of the viewport (`topLeft`)
4. Adds 10% margins margings (relative to the width and height of the viewport) from the corner
5. Scales the clip down by 80% to 400px by 400px.
## Related topics
- [Animations](/docs/guide/architecting-an-application/animations) - Animate position and offset over time
---
## SVG
- Markdown URL: https://shotstack.io/docs/guide/architecting-an-application/svg.md
- Web URL: https://shotstack.io/docs/guide/architecting-an-application/svg/
- Description: Create scalable vector graphics using raw SVG markup
# SVG
The SVG asset lets you add scalable vector graphics to your videos using raw SVG markup. Unlike the [shape asset](/docs/guide/architecting-an-application/shapes) which is limited to basic rectangles, circles, and lines, the SVG asset supports complex paths, polygons, and custom shapes defined using standard [SVG 2 markup](https://www.w3.org/TR/SVG2/).
## Common SVG patterns
Before diving into individual properties, here are solutions to common SVG needs:
### Circle with fill color
Create a simple filled circle:

```json
{
"timeline": {
"background": "#1a1a2e",
"tracks": [
{
"clips": [
{
"asset": {
"type": "svg",
"src": ""
},
"start": 0,
"length": 5
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```
### Rectangle with stroke
Create a rectangle with a colored border and fill:

```json
{
"timeline": {
"background": "#000000",
"tracks": [
{
"clips": [
{
"asset": {
"type": "svg",
"src": ""
},
"start": 0,
"length": 5
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```
### Path-based custom shape
Create a custom star shape using a path:

```json
{
"timeline": {
"background": "#1a1a2e",
"tracks": [
{
"clips": [
{
"asset": {
"type": "svg",
"src": ""
},
"start": 0,
"length": 5
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}
```
## Basic usage
A minimal SVG asset requires the `type` set to `svg` and a `src` property containing the raw SVG markup as a string:
```json
{
"asset": {
"type": "svg",
"src": ""
},
"start": 0,
"length": 5
}
```
The `src` property accepts any valid SVG markup as a string. The outer `