Serialization
Etro movies can be serialized to plain JSON and reconstructed later. This is useful for saving a project to disk or a database, sending a movie over the network, or duplicating one in memory.
Serializing a Movie
A Movie, along with all of its layers and effects, implements toJSON(), so you can serialize an entire movie with the built-in JSON.stringify():
const data = JSON.stringify(movie);
localStorage.setItem("my-project", data);
Calling movie.toJSON() directly returns the plain object that describes the movie:
const json = movie.toJSON();
// {
// type: "movie",
// canvas: { width: 1920, height: 1080 },
// background: { type: "Color", r: 0, g: 0, b: 0, a: 1 },
// repeat: false,
// layers: [
// {
// type: "layer.Text",
// x: 0,
// y: 0,
// width: null,
// height: null,
// background: null,
// border: null,
// opacity: 1,
// text: "Hello World",
// font: "10px sans-serif",
// color: { type: "Color", r: 255, g: 0, b: 0, a: 1 },
// textX: 0,
// textY: 0,
// maxWidth: null,
// textAlign: "start",
// textBaseline: "top",
// textDirection: "ltr",
// textStroke: null,
// enabled: true,
// startTime: 0,
// duration: 10,
// effects: [{ type: "effect.Brightness", enabled: true, brightness: 2 }],
// },
// ],
// effects: [{ type: "effect.Grayscale", enabled: true }],
// }
Each layer is tagged with a layer.<ClassName> type and each effect with an effect.<ClassName> type so that they can be reconstructed later.
The output above is complete, not abbreviated. toJSON() writes out every public property of each layer and effect, including the ones you never set (which fall back to their defaults, such as opacity: 1 or textAlign: "start") and the enabled flag that every layer and effect carries. Properties whose default is undefined — for example an unset sourceWidth on an Image layer — are the exception: they are omitted, since JSON has no undefined.
Deserializing a Movie
Use the static etro.Movie.fromJSON() method to rebuild a movie from its serialized form:
const data = localStorage.getItem("my-project");
const movie = etro.Movie.fromJSON(JSON.parse(data));
fromJSON() accepts the following arguments:
json(required): the parsed movie object (not a JSON string).canvas: the HTML<canvas>element to render to. If omitted, a new canvas is created using the serializedwidthandheight.actx: the audio context to play audio layers through. If omitted, a new one is used.
const movie = etro.Movie.fromJSON(json, document.querySelector("canvas"));
A full round trip looks like this:
// Save
const saved = JSON.stringify(movie);
// Load
const restored = etro.Movie.fromJSON(JSON.parse(saved), canvas);
What Gets Serialized
The movie's background and repeat options, along with every layer and effect and their dynamic properties, are serialized.
Etro's built-in value types round-trip automatically:
etro.Color→{ type: "Color", r, g, b, a }etro.Font→{ type: "Font", size, sizeUnit, family, ... }etro.KeyFrame→{ type: "KeyFrame", value, interpolationKeys }, where each keyframe's interpolation is stored as"linear"or"cosine".
etro.Movie.fromJSON() restores these for you, so there is no need to convert them by hand.
Limitations
Not everything can be represented as JSON. Keep the following in mind:
- Functions are not serialized. Dynamic properties that are plain functions are dropped. Only constant values and keyframe animations survive a round trip.
- Custom keyframe interpolation is not preserved. Only the built-in
etro.linearInterpandetro.cosineInterpfunctions are saved; other interpolation functions are lost. - The canvas is not fully serialized. Only its
widthandheightare stored, not the element or its drawing context. - The audio context is not serialized. Pass an
actxtoetro.Movie.fromJSON()if your movie has audio layers. - Media layers store their source URL. Image, video and audio layers are serialized using their
srcURL, so a revoked object URL will not reload. - Only built-in layers and effects can be restored.
fromJSON()strips thelayer.oreffect.prefix from eachtypeand resolves the rest against Etro's built-inetro.layerandetro.effectnamespaces. A built-in such aslayer.Textresolves toetro.layer.Text, but a custom subclass serialized as, say,layer.Stickerhas no match and throwsUnknown layer type: Sticker. Custom layer and effect subclasses are not restored.