LiveRender - The JSON Code Explained
When setting up a LiveRenders element, a JSON format is utilized to configure the behavior of the animation. Here’s a summary of the various sections within this JSON and their effects.
Top-level structure
{
element_type: "liverender",
caching: "CDN",
+ input_parameters: [ ... ],
+ animation: { ... },
+ no_animation_fallback: {...},
+ frames: [ ... ],
+ cache_policy: { ... }
}
Each JSON definition requires:
- element_type — LiveRender
- caching — "server" or "cdn". For 1:1 (or close), use server. In all other cases, use CDN. Server is expensive but fast. CDN is cheap but slower for 1:1 customization scenarios.
- input_parameters — This is an array of the parameters you need to read. It's important, for caching reasons, to only stipulate what you need. Parameters are referenced as dim and correspond to Custom fields defined on your environment. You can use numeric custom fields (to show progress for example) or text Custom fields (as overlay text for example).
- animation — The copyslide property specifies the total number of frames in the animation, with a fixed frame rate of 10 frames per second. For instance, 30 frames would result in an animation duration of 3 seconds.
The loop property determines whether the animation plays once upon opening the email or repeats continuously in a loop.
Note: More frames lead to a smoother animation transition. By default, this is set to 30 frames, which is optimized for email rendering. Fewer frames can result in quicker loading times for the animation.
- no_animation_fallback — You may need a fallback image for email clients that don't support animation in LiveRender. You can select the frame from your animation that will be displayed when this happens.
- frames — The frames node specifies how the frames in the animation are created.
- cache_policy — How the content should be cached. The granularity defines which values will all be served the same animation. For example, granularity 10 implies that openers with values from 0 to 9 will all receive the same animation, 10 to 19 will also receive the same animation.
Example:
In this example, parameter dim6 is used as input for the animation. This corresponds to the 6th Custom field created in the Account Settings.
Let's go a little more into detail for the different nodes in the JSON.
The animation node
"animation": {
"sourceframes": [
{
"copyslide": "20"
}
],
"loop": "false"
},
1. sourceframes — This is an array of objects. It defines how many times slide 1 should be copied, how many times slide 2 should be copied, etc. For example. [{"copyslide" : "20"},{"copyslide" : "50"},{"copyslide" : "10"}] means that we are going to copy the first slide 20 times, the second slide 50 times and the third slide 10 times to create an 80-frame animation. Each frame takes 1 millisecond, so 80 frames means an animation of 8 seconds.
Note: The number of slides copied must be equal to the total number of slides in your animation. Further down in the frame node, you will define the rendering of the different frames and the total of the frames there needs to match the total of the frames/slides defined in this node.
If you want to reference another Liveclicker element (such as a Livefeed, Livescrape or Livesocial), then you need to declare an element property instead of the copyslide property.
Each node in the element array must have the element_id, element_type, version_id of the target version as well as a copyslide property, which refers to how many times you want that slide to be copied.
- For Livefeed use "element_type": "feed"
- For Livescrape use "element_type": "webscrape"
- For Livesocial use "element_type": "livesocial"
Example:
Note: If you use other elements as source frames, you MUST declare an expire_after_seconds property.
2. loop — Does the animation loop or not? By default it is set to true.
3. smart_delay_on_first_frame_in_sec — Optional and only applies when the caching property is set to "server". This defines the delay on the first frame of the animation, in seconds. In 1:1 delivery scenarios, the delay will be adjusted to the generation time. For example, if set to 2 seconds, and the generation takes 0.8 seconds, the actual delay will be 1.2 seconds.
Note: When served from the cache, delay will be 2 seconds since the generation time is virtually 0.
The no_animation_fallback node
This is optional. By default, email clients that do not support animation will see the last frame of the animation as the fallback (not the first), which is always extracted as a separate file from the animation. You can change that by setting the no_animation_fallback property:
"no_animation_fallback" : {
"source": "animation", "frame": "last"
}
1. source — Currently it's only possible to define a frame from the animation. So it is always set to "animation".
2. frame — You can use last, first or an integer defining the frame number from the animation to be use.
The frames node
The frames node is an array of objects. Each object in the node will describe how the frames within that set of frames are generated and rendered. Often, there is only one object in the array, but for more complex animations, there can be multiple objects each with their own rendering properties.
The start and end property indicate at which frame the animation starts and at which frame it ends. If you chose to use 31 frames in your animation, these values will typically be 0 and 30.
Within the frame node there is a Render node, which defines the transformation to apply to the frames.
Example of using different renderings for different framesets:
Frame 0 to 10 will use an input value dim1 and will show only an image
Frame 11 to 20 will use input value dim1 and show an image with an overlay text
Frame 21 to 30 will use input value dim1 and show only an image
The render node
This node resides within the Frames node and will define how each of the frames is rendered. Here's what it looks like:
This is an array of transformations. Each transformation in the array applies to the frames identified at the upper level. You can have as many transformations as you want, for a given set of frames.
Supported Transformations
drawrectangle
This will draw a colored rectangle on a frame. Here is an example.
For a detailed explanation of the different parameters in this type of transformation, please check out the topic on using templates.
Example drawrectangle:
{
"type": "drawrectangle",
"x": 49,
"y": 68,
"h": 15,
"w": {
"easing": "linear",
"parameters": {
"input":
{"source": "dim2",
"min": 0,
"max": 3428
},
"output":
{"min": 0,
"max": 558
}
}
},
"color": "#2a6187",
"source": "dim2"
}
- type — The type of animation, in this case a rectangle is drawn, showing the progress.
- x — The horizontal starting position of the progress bar in the image, expressed in pixels.
- y — The vertical starting position of the progress bar, expressed in pixels.
- h — The height of the rectangle.
- w — The dynamic width of the rectangle.
- easing — How the transition is happening. In this case the transition will speed up towards the end.
- parameters — These are the parameters that define the dynamic width of the progress bar.
- source — The source value that will determine the width of the bar. In this case dim1, which corresponds to the first Custom field set up in the account settings.
- min —The minimum and maximum values that are accepted for this source field. In case of a progress bar the source needs to be a numeric field.
- output min — The minimum size in pixels of the dynamic bar.
max — The maximum size in pixels for the bar. If our image was 600 by 100, and the bar starts at pixel 24 and needs to stay also 23 pixels away from the right border of the image, there are 554 pixels available to show the progress bar. - color — The color given to the bar.
- opacity — If set to 1 it is completely opaque, if set to 0 it is transparent.
- source — The source value that determines the progress on the bar.
drawpie
This will draw a pie shaped animation. Here is an example.
Example drawpie:
{
"type": "drawpie",
"cx": 100,
"cy": 100,
"radius" : 126,
"angle_start" : -180,
"angle_end": {
"easing": "linear",
"parameters": {
"input": {"source": "dim2", "min": 0, "max": 100},
"output": {"offset" : -180, "min": 0, "max": 180}
}
},
"color": "#c70000",
"source": "dim2"
}
- cx and cy — The center of the pie chart .
- radius of the pie — The distance from the center to the edge of the pie.
- angle_start and angle_end — The portion to draw. The reference axis is vertical. The start is always at -180 degrees, but the end is dynamic.
- color — The color given to the pie.
- source — The source value that determines the progress on the gauge.
overlaytext
This transformation overlays text on a frame.
"type": "overlaytext",
"font": "droidttf",
"size": "70",
"alignment": "c",
"x_offset": "88",
"y_offset": "95",
"append": "%",
"prepend": "",
"force_text": {
"easing": "linear",
"parameters": {
"input": {
"source": "dim1",
"min": "0",
"max": "1000"
},
"output": {
"offset": 0,
"min": 0,
"max": 100}}}
- x_offset and y-offset — X and y coordinates for the text, in pixels, using the alignment as a reference point.
- append and prepend — The text to prepend or append to the value that will be displayed in this overlay text.
- font — (string) Use a font from the account, referenced by its filename.
- alignment — (string, optional) default is l (the letter L, lower-cased). Possible values are {l, c, r}
- l is for left align: x_offset and y_offset below are using a reference point that's top left corner.
- c is for center align: x_offset and y_offset below are using a reference point that's the center of the image.
- r is for right align: x_offset and y_offset below are using a reference point that's top right corner.
overlayimage
This transformation overlays an image on a frame.
Example overlayimage:
{
"type": "overlayimage",
"x": {
"easing": "linear",
"parameters": {
"input": {"source": "dim2", "min": 0, "max": 2954},
"output": {"offset": 18, "min": 0, "max": 560}
}
},
"y": 2,
"source": {"type": "slide", "id": 2}
}
- Takes as input x, y which are the coordinates of the top left corner of the image using the top left corner as the reference point.
- If one of the parameters above (x, y, etc) is dynamic, then the source should be defined (esp_dim1, dim5, etc).
- You can also use functions to dynamically define the parameters. See this topic on easing functions.
animated_gif_explode
This transformation is essential if you are trying to generate a personalized GIF animation. What it does is it takes one of the uploaded animated GIF and explodes it into separate frames. In the example below, frames 39 and 40 of the final animation are taken from frames 39 and 40 of the initial GIF animation then annotated with a personalized overlaytext.
Example: More sophisticated examples are possible. Let's say you have a base animation of 40 frames you'd like the personalize in frames 38, 39, 40. To do this, you should have something like this in your LiveRender JSON:
- start: 0 to end 37 animated_gif_explode (only)
- start 38 end 40 animated_gif_explode followed by overlaytext
{
"element_type": "liverender",
"caching": "cdn",
"input_parameters": [
"dim1"
],
"animation": {
"sourceframes": [
{
"copyslide": "40"
}
],
"loop": "false"
},
"no_animation_fallback": {
"source": "animation",
"frame": "last"
},
"frames": [
{
"start": "0",
"end": "37",
"render": [
{
"type": "animated_gif_explode",
"image_source": {
"id": 1
}
}
]
},
{
"start": "38",
"end": "40",
"render": [
{
"type": "animated_gif_explode",
"image_source": {
"id": 1
}
},
{
"type": "overlaytext",
"x_offset": "88",
"y_offset": "125",
"source": "dim1",
"font": "Roboto.ttf",
"color": "#666",
"alignment": "c",
"size": "24"
}
]
}
],
"cache_policy": {
"dim1": {
"granularity": "string"
}
}
}
ticker
This is a special type of object that has a few dependencies before you get started.
-
You need a background image (usually white).
-
You need a digits file. This is a PNG which contains all the digits. It's organized according to this specification: https://docs.google.com/spreadsheets/d/1Go-yKYMS3q4CBq87j6I-frzGCdrVlQkLJbxwH1N4Waw/edit?usp=sharing .
Following properties are listed:
-
digits_input defines anything that has to do with parsing the above digits file.
- image_source is a single property object, {id:n}, where n is the image number you want to use for the digits file. Assuming your LiveRender has this digits file uploaded as the second image, then {id:2} is to be used.
- image_format can only be set to "default" right now.
- width is the width of the digits in pixels. It's an integer.
- height is the height of the digits.
- separator_width defines the width of the comma or periods.
-
digits_output sets the presentation options for the ticker itself.
- align (left, center, right), x_position (integer) and y_position (integer) set the reference point where the digits will be placed. If align is set to left, then the reference point will be the top left corner of the ticker. If there to right, then the reference point corresponds to the top right corner. If set to center, then your x_position and y_position will define where the center of the ticker will be placed.
- padding (integer) is the space between each digit block.
- digit_count defines how many maximum digits.
- hide_left_zero is either set to true or false. If set to false, then you will see instances like these: 0001234 or 054536. If set to false, then only 1234 and 54536 will be displayed. Note that this setting is dependent upon digit_count above.
- use_empty_digits_for_left_zeros is optional and false by default. When this option is set to true, then any left zero will be replaced by an empty box. The empty box is always located at the lower right corner of your digits file. See example. Please note that this setting is independent from the hide_left_zero option above.
- prepend_character is by default false. If you set it to true, then the "$" sign will prepend the output. If you prefer to have a € instead (or something else) change your digits file.
- number_format will add the "," and ".".
If set to decimal_with_comma, then the input is divided - for example: 3020525 will display as 30,205.25
.
If set to integer_with_comma, then 3020525 will display as 3,020,525.
-
transition
-
type: there are three possibilities.
- flat (goes from 0 to N increasing gradually).
- jackpot (goes from RANDOM to N by setting the first digit, then second digit, etc).
- airport (essentially like flat except that there is a nice little animation to make it look like and airport information board.
-
-
freeze_on_digit_for_n_cycles is an integer that defines how long the key frames should be shown. In general, it's best to leave it at 1 for flat and jackpot animations, otherwise the animation will look slow. For airport, you should set it to 3 to 5.
Example ticker:
{
"type": "ticker",
"source": "dim2",
"digits_input": {
"image_source":{"id":2},
"image_format":"default",
"width":53,
"top_height":39,
"bottom_height":64,
"separator_width": 5
},
"digits_output" : {
"align" : "left",
"x_position" : 10,
"y_position" : 50,
"padding" : 4,
"digit_count": 7,
"hide_left_zeros": true,
"number_format" : "decimal_with_comma"
},
"transition" : {"type":"airport"},
"freeze_on_digit_for_n_cycles": 4
}
recallframe
This transformation allows you to chain two animations together. For example, if you have a ticker from frames 0 to 49, then on frame 50 start another ticker right underneath, then you should "recallframe" 49 before the second ticker frames 50 to 99.
{
"type" : "recallframe",
"frame_id" : 49
}
The recallframe transformation is chained with other transformations within the render command. It is important to think about the order of operations when you use recallframe. In the example below, first recall frame #49 THEN we draw a rectangle.
"render" : [{
"type" : "recallframe",
"frame_id" : 49
},{
"type": "drawrectangle",
"x": 20,
"y": 120,
"h": 15,
"w": {
"easing": "linear",
"parameters": {
"input": {"source": "dim3", "min": 0, "max": 1000},
"output": {"min": 0, "max": 300}
}
},
"color": "#2a6187",
"source": "dim3"
}]
The cache_policy node
This is extremely important, it defines the "grouping" policy for these animations based on input parameters. For example:
Means the following: given that dim5 is an integer, group the animations in increments of 50 for dim5. The values 0 to 49 will get the same animation, 50..99, 100..149 etc. This saves a ton of resources.