Search Docs
Loading...
Skip to content

Lottie Fills

Play a Lottie animation as the fill of a block, with the images and fonts that it references by URL.

6 mins
estimated time
Download
StackBlitz
GitHub

A video fill plays a Lottie .json file or a dotLottie .lottie archive. The block shows the whole animation, and its layers stay out of reach. To edit the layers, import the Lottie as blocks instead.

This guide covers how to give a Lottie document a URI, how to set it as a fill, how to wait for the Lottie and its references, which references the engine loads, how to export a frame, and the errors to expect.

Creating the Scene#

The example starts the headless engine and creates a page of 3 seconds, the length of the animation.

// Initialize the headless Creative Engine
const engine = await CreativeEngine.init({
baseURL: process.env.IMGLY_LOCAL_ASSETS_URL
// license: process.env.CESDK_LICENSE
});
try {
// Create a scene with a 3 second page
const scene = engine.scene.create('DepthStack');
const page = engine.block.create('page');
engine.block.setWidth(page, 1000);
engine.block.setHeight(page, 1000);
engine.block.appendChild(scene, page);
engine.block.setDuration(page, 3);

Writing a Lottie Document#

The example writes its Lottie in code, so it runs without a hosted file. The document runs for 90 frames at 30 frames per second. Its image layer fades in a photo and zooms into it. The image asset names the photo by an absolute URL.

// A 3 second Lottie at 30 frames per second. Its image layer fades in a
// photo and zooms into it. The asset names the photo by an absolute URL.
const lottie = {
v: '5.7.0',
fr: 30,
ip: 0,
op: 90,
w: 1000,
h: 1000,
assets: [
{
id: 'photo',
w: 2500,
h: 1667,
u: '',
p: 'https://img.ly/static/ubq_samples/sample_1.jpg',
e: 0
}
],
layers: [
{
ty: 2,
refId: 'photo',
ip: 0,
op: 90,
st: 0,
ks: {
a: { a: 0, k: [1250, 833] },
p: { a: 0, k: [500, 500] },
s: {
a: 1,
k: [
{ t: 0, s: [60, 60] },
{ t: 90, s: [80, 80] }
]
},
o: {
a: 1,
k: [
{ t: 0, s: [0] },
{ t: 30, s: [100] }
]
}
}
}
]
};

Storing the Document in a Buffer#

engine.editor.createBuffer() returns a buffer:// URI, and engine.editor.setBufferData() writes the document into it. A buffer has no directory, so a document in a buffer names its images by absolute URL. The Buffers guide explains buffers in detail.

// A buffer holds the document in memory and gives it a URI
const lottieURI = engine.editor.createBuffer();
const bytes = new TextEncoder().encode(JSON.stringify(lottie));
engine.editor.setBufferData(lottieURI, 0, bytes);

Setting the Lottie as a Fill#

engine.block.createFill('video') creates the fill, and its fill/video/fileURI property takes the URI of the Lottie. For a hosted file, set its https URL the same way. engine.block.setFill() gives the fill to a graphic block.

// A video fill plays the Lottie. Set a hosted .json or .lottie URL the same way.
const block = engine.block.create('graphic');
engine.block.setShape(block, engine.block.createShape('rect'));
engine.block.setWidth(block, 1000);
engine.block.setHeight(block, 1000);
const fill = engine.block.createFill('video');
engine.block.setString(fill, 'fill/video/fileURI', lottieURI);
engine.block.setFill(block, fill);
engine.block.appendChild(page, block);
engine.block.setDuration(block, 3);

Loading the Lottie and Its References#

engine.block.forceLoadAVResource() finishes when the Lottie and every image and font that it references are loaded. engine.block.getAVResourceTotalDuration() then returns the duration in seconds, the frame count divided by the frame rate.

// The load finishes when the Lottie and the images it references are loaded
await engine.block.forceLoadAVResource(fill);
console.log(engine.block.getAVResourceTotalDuration(fill)); // 3

Referenced Images and Fonts#

A Lottie can reference files instead of embedding them. An image asset names its file with its u directory and its p file name. A font names its file in fonts.list[].fPath. An asset with e: 1 or a data: URI is embedded and loads with the document.

A relative reference resolves against the URL of the Lottie. In https://example.com/anims/intro.json, an asset with u: 'images/' and p: 'photo.png' loads https://example.com/anims/images/photo.png.

The engine loads these references:

  • http and https URLs
  • bundle:// URIs
  • relative references that stay in the directory of the Lottie
  • a file:// path in the directory of a local Lottie file

The engine refuses a path that starts with /, a .. that leaves the directory of the Lottie, a backslash and a buffer:// URI. The Lottie then draws without that image or font, and the engine logs a warning that names the reference. A reference that fails to load has the same result. The engine loads at most 256 different references of one Lottie. It draws without the others and logs a warning with their number. The export and the forced load wait for each reference before they finish. A URI resolver receives each reference after it resolves against the Lottie URL.

Exporting a Frame#

engine.block.setPlaybackTime() seeks the page to 1.5 seconds, after the fade-in. engine.block.export() exports that frame as a PNG file.

// Seek the page to 1.5 seconds and export that frame
engine.block.setPlaybackTime(page, 1.5);
const frame = await engine.block.export(page, { mimeType: 'image/png' });
mkdirSync('output', { recursive: true });
writeFileSync(
'output/lottie-frame.png',
Buffer.from(await frame.arrayBuffer())
);
console.log('Frame saved to output/lottie-frame.png');

Handling Errors#

A file that is neither a Lottie nor a video does not load, and engine.block.forceLoadAVResource() rejects with EDITOR.RESOURCE_LOAD_FAILED. The example destroys the fill and its buffer afterwards.

// A file that is not a Lottie or a video does not load
const brokenURI = engine.editor.createBuffer();
engine.editor.setBufferData(
brokenURI,
0,
new TextEncoder().encode('not a Lottie')
);
const brokenFill = engine.block.createFill('video');
engine.block.setString(brokenFill, 'fill/video/fileURI', brokenURI);
try {
await engine.block.forceLoadAVResource(brokenFill);
} catch (error) {
// Engine errors carry a stable catalog id in `code`
const { code } = error as { code?: string };
console.log(code); // 'EDITOR.RESOURCE_LOAD_FAILED'
}
engine.block.destroy(brokenFill);
engine.editor.destroyBuffer(brokenURI);

Cleaning Up#

The example disposes of the engine in a finally block, so the engine frees its resources also after an error.

// Always dispose of the engine to free resources
engine.dispose();

Troubleshooting#

  • An image or a font is missing: the engine logs a warning that names the reference. Check that the reference is an http, https or bundle:// URI, or a relative path inside the directory of the Lottie. A Lottie with more than 256 different references draws without the rest.
  • A document in a buffer draws without its images: a relative reference has no directory to resolve against. Name each image by an absolute URL.
  • A .lottie archive does not load: an archive must be a valid dotLottie file within the engine limits: at most 1,024 entries, 128 MiB uncompressed and 32 MiB for the animation JSON. Otherwise engine.block.forceLoadAVResource() rejects with SCENE.LOTTIE_ARCHIVE_INVALID, SCENE.LOTTIE_ARCHIVE_TOO_MANY_ENTRIES, SCENE.LOTTIE_ARCHIVE_TOO_LARGE or SCENE.LOTTIE_ARCHIVE_UNSAFE_PATH.

API Reference#

Method Description
editor.createBuffer() Create a buffer and return its URI
editor.setBufferData(uri, offset, data) Write the Lottie document into the buffer
editor.destroyBuffer(uri) Free a buffer
block.createFill('video') Create a video fill
block.setString(fill, 'fill/video/fileURI', uri) Set the Lottie file of the fill
block.setFill(block, fill) Give the block the fill
block.forceLoadAVResource(fill) Load the Lottie and its references
block.getAVResourceTotalDuration(fill) Read the duration of the animation in seconds
block.setPlaybackTime(page, time) Seek the page
block.export(page, options) Export a frame

Next Steps#