How To Turn Images Into Interactive Slideshow Videos With Node.js & Shotstack API
Tags: javascript, tutorial, node, api
Published: 2022-07-14 03:14:30

A basic slideshow is a sequence of still images that change at regular time intervals. With modern video editing 
software you can go beyond the classical definition by adding motion effects and transitions to capture your audience's 
interest.

The possibilities with video slideshows are infinite. They are perfectly suited for for storytelling, showcasing a 
product, highlighting aspects of physical locations (real estate tours, venues etc), step-by-step tutorials or different
albums such as personal or event photography.

One of the most common effects you can add to your video slideshows is the 
[Ken Burns effect](https://en.wikipedia.org/wiki/Ken_Burns_effect) - a simple, elegant 
transition effect that gives the illusion of motion on static images by zooming and panning around an image.

In this article we'll go through the basis of creating video slideshows using Node.js and the Shotstack cloud video 
editing API and then add some effects to keep the viewers engaged, similar to the Ken Burns effect.

### Prerequisites

- Shotstack Free Developer Account:
The [Shotstack API](https://shotstack.io/) allows you to render tens of thousands of videos in the cloud, and personalise each individual video with the [Node.js SDK](https://shotstack.io/product/sdk/node/). With API capable of rendering hundreds videos concurrently in the cloud, you can automate generation hundreds of similar videos. After registering just log in to receive your API key. 

- [Node.js:](https://nodejs.org/)
We'll be using Node.js to build our application. No fancy routing, just the basics.


### Getting started

In order to help you get started quickly, we prepared a Shotstack Node.js demo project which is open source and publicly 
available on GitHub.

Checkout the [shotstack/node-demos](https://github.com/shotstack/node-demos) project:

```bash
git clone https://github.com/shotstack/node-demos.git
```

Install the dependencies including the Shotstack [Node.js video editor SDK](/product/sdk/node/):

```bash
npm install
```

Set your API key as an environment variable (Linux/Mac):

```bash
export SHOTSTACK_KEY=your_key_here
```

or, if using Windows:

```bash
set SHOTSTACK_KEY=your_key_here
```

Replace `your_key_here` with your provided sandbox API key which is free for testing and development.

### Creating a simple video slideshow using code

We are going to generate the slideshow video below using Node.js and the built in video editing API functionality.

<video id="player" playsinline controls>
  <source src="https://d1uej6xx5jo4cd.cloudfront.net/basic-slideshow-nodejs.mp4" type="video/mp4" />
</video>

First, open the file [examples/images.js][images-repo-file] from the demo project. This simple Node.js script takes an 
array of images, loops through them to create video clip and prepares an a JSON payload. Finally the payload is sent to 
the Shotstack API to be rendered.

We will use the Shotstack Node.js SDK which help us configure the API client and interact with the API features using 
models, getter and setter functions.

#### Configure the API client

The first few lines setup the client with the the API url and key, making sure the `SHOTSTACK_KEY` was set correctly in 
the previous step.

```javascript
const Shotstack = require('shotstack-sdk');

const defaultClient = Shotstack.ApiClient.instance;
const DeveloperKey = defaultClient.authentications['DeveloperKey'];
const api = new Shotstack.EditApi();

let apiUrl = 'https://api.shotstack.io/stage';

if (!process.env.SHOTSTACK_KEY) {
    console.log('API Key is required. Set using: export SHOTSTACK_KEY=your_key_here');
    process.exit(1);
}

if (process.env.SHOTSTACK_HOST) {
    apiUrl = process.env.SHOTSTACK_HOST;
}

defaultClient.basePath = apiUrl;
DeveloperKey.apiKey = process.env.SHOTSTACK_KEY;
```

#### Defining the slideshow images

We need to define an array of images to use in our slideshow, the images need to be hosted somewhere online and be
accessible via a public or signed URL. For this tutorial we are using some photos we downloaded from the 
[Pexels](https://www.pexels.com/) stock photo library.

```javascript
const images = [
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-712850.jpeg',
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-867452.jpeg',
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-752036.jpeg',
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-572487.jpeg',
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-114977.jpeg',
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-347143.jpeg',
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-206290.jpeg',
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-940301.jpeg',
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-266583.jpeg',
    'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-539432.jpeg'
];
``` 

#### Basic config

We will now define an empty array holder for our clips, in Shotstack a clip defines the type of asset, when it starts 
playing and how long it plays for:

```javascript
let clips = [];
```

We need to control the duration of each slide and the time when it starts. We'll set default duration to 
**1.5 seconds**. 

```javascript
let start = 0;
const length = 1.5;
```

We will come back to these setting in one of the next steps.

#### Adding audio to the slideshow

A stunning slideshow should not miss an audio track - it can be music you like, some specific sounds that help the 
visuals or even a voice-over. We use the SDK's `Shotstack.Soundtrack` model to set the audio file URL and a 
`fadeInFadeOut` volume effect.

```javascript
let soundtrack = new Shotstack.Soundtrack;
soundtrack
    .setSrc('https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/music/gangsta.mp3')
    .setEffect('fadeInFadeOut');
```

#### Creating video clips from each image

Let's now use our `images` to create [clips][api-clip]. We will iterate over the `images` array and create clips, defining the start 
time, length and a default effect. We use the `Shotstack.ImageAsset` model to set the image URL and the 
`Shotstack.Clip` model to create the clip playback properties and add them to our `clips` array we set up earlier.

```javascript
images.forEach((image) => {
    let imageAsset = new Shotstack.ImageAsset;
    imageAsset
        .setSrc(image);

    let clip = new Shotstack.Clip;
    clip
        .setAsset(imageAsset)
        .setStart(start)
        .setLength(length)
        .setEffect('zoomIn');

    start = start + length;
    clips.push(clip);
});

```

Each slide starts immediately after the previous one ends. For the first image we default the `start` to **0** so it starts 
playing right away. We then add the `length` which we defined as **1.5 seconds**, so each image will appear in the video
for that duration.

Here is the full list of motion effects you can use to enhance your video slideshows:

* **zoomIn** - slow zoom in
* **zoomOut** - slow zoom out
* **slideLeft** - slow slide (pan) left
* **slideRight** - slow slide (pan) right
* **slideUp** - slow slide (pan) up
* **slideDown** - slow slide (pan) down

#### Adding the clips to the timeline

Shotstack API uses a [timeline][api-timeline], which is like a container for multiple video clips which play over time.
The timeline contains [tracks][api-track] which allow us to layer clips over one another.

In our case, the clips we just created are added to a track and then we add the track to the timeline, along
with the soundtrack. We use the `Shotstack.Track` from the SDK and the `Shotstack.Timeline`:

```javascript
let track = new Shotstack.Track;
track
    .setClips(clips);

let timeline = new Shotstack.Timeline;
timeline
    .setBackground('#000000')
    .setSoundtrack(soundtrack)
    .setTracks([track]);
```

#### Configuring the output video

Finally we configure the [output][api-output] format and add the timeline 
and output to create an [edit](/docs/api/#tocs_edit). Using the SDK again we use the 
`Shotstack.Output` and `Shotstack.Edit` models. 

```javascript
let output = new Shotstack.Output;
output
    .setFormat('mp4')
    .setResolution('sd')
    .setFps(30);

let edit = new Shotstack.Edit;
edit
    .setTimeline(timeline)
    .setOutput(output);
```

#### Sending the edit to the Shotstack API

The final step in our script is to send the data to the video editing API for processing and rendering. The Shotstack 
SDK takes care of converting our objects to JSON, adding our key to the request header and sending everything to the
API.

```javascript
api.postRender(edit).then((data) => {
    let message = data.response.message;
    let id = data.response.id
    
    console.log(message + '\n');
    console.log('>> Now check the progress of your render by running:');
    console.log('>> node examples/status.js ' + id);

}, (error) => {
    console.error('Request failed: ', error);
    process.exit(1);
});
```

#### Running the script

To run the script use the node command from the root folder of the project:

```bash
node examples/images.js
```

If the render request is successful, the API will return the render id which we can use to retrieve the status of the 
render.

For this, you can run a different script included in our sample repo:

```bash
node examples/status.js {renderId}
```

Replace `{renderId}` with the ID returned from the first command.

Re-run the status.js script every 4-5 seconds until either a video URL is returned or there is an error message.

#### Recreating the Ken Burns effect using code

If you want to have a Ken Burs style effect with random transition between the slides, we can define an array to hold 
the pool of effects we want to use and use a randomizer function.

You can add the code below before defining the `image` constant:

```javascript
const effects = ['zoomIn', 'zoomOut', 'slideLeft', 'slideRight', 'slideUp', 'slideDown'];

const getRandomEffect = () => {
    return effects[Math.floor(Math.random() * effects.length)]
}

const images = [
    ...
]
```

All we need to do is replace the `zoomIn` effect in the clip creation code with the call to the `getRandomEffect`
method.

```javascript
images.forEach((image) => {
    let imageAsset = new Shotstack.ImageAsset;
    imageAsset
        .setSrc(image);

    let clip = new Shotstack.Clip;
    clip
        .setAsset(imageAsset)
        .setStart(start)
        .setLength(length)
        .setEffect(getRandomEffect());

    start = start + length;
    clips.push(clip);
});
```

Our randomised Ken Burns style slideshow video will look something like the video below.

<video id="player" playsinline controls>
  <source src="https://d1uej6xx5jo4cd.cloudfront.net/random-slideshow-nodejs.mp4" type="video/mp4" />
</video>

#### Controlling the motion effect for each image

If you want to have more control on each of the slides, you can configure the duration and effect individually when 
defining the `images` constant and use an array of objects instead:

```javascript
const images = [
    {
        src: 'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-712850.jpeg',
        length: 2,
        effect: 'zoomIn'
    },
    {
        src: 'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-867452.jpeg',
        length: 5,
        effect: 'slideLeft'
    },
    {
        src: 'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-752036.jpeg',
        length: 1.5,
        effect: 'slideDown'
    },
    {
        src: 'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-572487.jpeg',
        length: 2,
        effect: 'slideRight'
    }
];
```

We now need to alter the clip creation code; we'll ignore the default `length` constant we defined in the first part 
and instead use the value defined for each object in the array: 

```javascript
images.forEach((image) => {
    let imageAsset = new Shotstack.ImageAsset;
    imageAsset
        .setSrc(image.src);

    let clip = new Shotstack.Clip;
    clip
        .setAsset(imageAsset)
        .setStart(start)
        .setLength(image.length)
        .setEffect(image.effect);

    start = start + image.length;
    clips.push(clip);
});
```

Our final programmatically generated slideshow video looks like below.

<video id="player" playsinline controls>
  <source src="https://d1uej6xx5jo4cd.cloudfront.net/controlled-slideshow-nodejs.mp4" type="video/mp4" />
</video>

### Final thoughts

I hope this tutorial has given you a basic understanding of how to use the Shotstack
[video editing API](/product/video-editing-api/) to automatically generate a video slideshow using code, in this case
Node.js. The same demo code is also available in 
[PHP](https://github.com/shotstack/php-demos/blob/main/examples/images.php) and 
[Ruby](https://github.com/shotstack/ruby-demos/blob/main/examples/images.rb).

You can also build out from this example and create out an entire application that uses images from different sources 
such as user uploaded images or user generated content, image scraping or integrate with an image hosting service like
Google Photos, Google Drive, Drop Box or Microsoft OneDrive.

[api-track]: /docs/api/#tocs_track
[api-timeline]: /docs/api/#tocs_timeline
[api-output]: /docs/api/#tocs_output
[api-clip]: /docs/api/#tocs_clip
[images-repo-file]: https://github.com/shotstack/node-demos/blob/main/examples/images.js
[yt]: https://www.youtube.com/watch?v=3OTv1AGwmYM&ab_channel=Shotstack

Follow [Shotstack ](https://dev.to/shotstack) to get similar  articles about programmable videos and applications. Start with our [learn resources](https://shotstack.io/learn/) to learn to start programmable videos. Sign up for free to start building awesome video applications.