Loading and changing content
loadTemplate, setSource, getSource, getElements, findElement, setModifications, applyModifications, cacheAsset
Everything the preview shows is RenderScript, the JSON format templates are made of.
Loading a template or a source
loadTemplate(templateId), setSource(source)
The SDK can load a video in two ways. The easiest is loadTemplate: it points to a template in your project, and the SDK fetches it by its ID with the public token. You design the template in the editor, mark the elements your users may change as dynamic, and fill them in from your app with setModifications, as explained below.
Using loadTemplate is the easiest way to get started with the Preview SDK. It can be limiting, however, when you want to make more complex edits, such as building a video from data or changing its structure, where a template and its modifications get in the way. For those, setSource takes the RenderScript directly, from wherever your app has it: a video your code assembled, the video a user edited earlier that you saved with getSource, or the JSON of a template you fetched through the API. A template is just RenderScript stored in your project, so either way the preview shows the same thing. Start with loadTemplate and the modifications system, and move to RenderScript when you want to work on the video itself.
Both methods take a second argument, createUndoPoint. Loading normally resets the undo history, as you'd want for a fresh start. Set it to true when loading is itself something the user may want to undo, such as restoring a saved version.
Reading the video back
getSource(), getElements(), findElement(predicate)
Your app often needs to know what is in the video: the names of its dynamic elements, or which element the user selected. getSource() returns the whole video as JSON and getElements() every element as a flat array, nested ones included. findElement returns the first element for which your predicate is true:
1const title = preview.findElement((element) => element.source.name === 'Title');An element's timing in the video isn't in its JSON; it's in the state.
Changing content with modifications
setModifications(modifications)
Once a template is loaded, the usual change is to its content: a different text in the headline, another photo in an image element. setModifications makes those changes without changing the template. It takes an object of modifications in the same format the API uses: the element's name as the key, the new content as the value. The preview then shows the template with those values in place of its own:
1await preview.setModifications({
2 Title: 'Summer sale',
3 Photo: 'https://example.com/photo.jpg',
4});Keeping the changes separate from the template is what keeps this simple. The same object goes to your server for the final render, together with the template ID; your app never handles the video's JSON. Leaving an element out restores the template's own content; clearing a field needs no special case. And the design can change in the editor at any time without a change to your app.
Changing the video itself
applyModifications(modifications), setSource(source)
Sometimes a change should become part of the video rather than sit on top of it: the user moves a headline and expects it to stay there, or adds a slide to a slideshow. What they end up with is a new video, and that video is what you save and render. Two methods make such changes. applyModifications takes the same format as setModifications but writes the change into the video, as an undo step:
1await preview.applyModifications({ 'Title.fill_color': '#ff0000' });For a change in structure, such as a new scene, edit the JSON itself: take the video with getSource, change it, and load it back with setSource. Because elements on the same track play one after the other, a scene added on track 1 plays after the scenes already there:
1const source = preview.getSource();
2
3source.elements.push({
4 type: 'composition',
5 name: 'Slide-3',
6 track: 1,
7 duration: 4,
8 elements: [
9 { type: 'text', text: 'A new slide', y: '50%', width: '80%', x_alignment: '50%', fill_color: '#ffffff' },
10 ],
11});
12
13await preview.setSource(source, true); // true: as an undo stepThe two kinds of change also decide how the final render is requested. Content changed with setModifications is rendered from the template; a changed video is rendered from its source, as explained under Rendering the final video.
Showing an uploaded file at once
cacheAsset(url, blob)
When the user picks a photo from their device, they expect to see it in the video at once. The preview, however, loads images, videos, and audio by URL, exactly as the API does, and the file has no URL until it has been uploaded. cacheAsset bridges that gap: it tells the preview to use the local file wherever a given URL is referenced, so you can set the modification immediately and upload in the background:
1const url = 'https://storage.example.com/uploads/photo.jpg'; // where the file will be
2
3await preview.cacheAsset(url, file); // show it now
4await preview.setModifications({ Photo: url });
5await uploadFile(file, url); // upload in the backgroundBecause the final render fetches every file from its URL, start it only once the upload is done.
When a file can't be loaded
When the preview can't load a file, it throws an error through the function that submitted the change. Therefore, make sure to surround your calls to setModifications, setSource, and the like with a try-catch, and let the user know the file couldn't be used:
1try {
2 await preview.setModifications({ Photo: url });
3} catch (error) {
4 // Tell the user, and ask for another file
5}A common load issue is caused by cross-origin resource sharing (CORS), a browser safety mechanism that stops a web page from reading files hosted on another domain unless that domain allows it. The preview has to read the files it draws, so every image, video, and audio file must come from a host that allows it. To solve this, the server hosting the file should send the Access-Control-Allow-Origin header in its responses, allowing https://creatomate.com, the domain the preview runs in, or *. Most storage services and CDNs have a CORS setting for this.
To check a file's host, request the file with the origin the preview uses and look at the response headers:
$ curl -s -D - -o /dev/null -H "Origin: https://creatomate.com" https://example.com/uploads/photo.jpg
A host that allows the preview answers with the header:
1HTTP/2 200
2content-type: image/jpeg
3access-control-allow-origin: https://creatomate.comWithout that header, the browser refuses the file and the preview can't load it.
Next step
How the video plays, and why an app seeks to what the user is editing: Controlling playback.