Generators
A generator is a picture the engine draws from a description, with no media to decode: a color or gradient, a shape layer, a text, or a layout. This page covers the first three; Layout covers the fourth. After reading it you can make backgrounds, motion graphics and titles from JSON alone.
Where generators go
Section titled “Where generators go”A Generator appears in three places:
- as the
generatorof a source with"kind": "generated", which clips show like any other source; - as a composition’s
generatornode; - through a composition’s
medianode that names a generated source.
A generated picture is the size of the canvas. Positions are fractions, (0, 0) top-left to (1, 1) bottom-right, and lengths are fractions of the canvas’s shorter side, so the picture is the same at any render resolution.
A fill never changes over time. Text changes only through its animators. Shapes and layouts may animate any value, keyed in picture time: the source time the clip selects (see Animation).
Fill and paint
Section titled “Fill and paint”{ "type": "fill", "paint": ... } covers the picture with a Paint:
| Paint | Fields |
|---|---|
solid |
color |
linear_gradient |
start, end, stops, spread (pad, repeat or reflect) |
radial_gradient |
center, radius (a fraction of the shorter side), stops, spread |
conic_gradient |
center, angle_degrees (where offset 0 lies, clockwise from straight up), stops |
A gradient has 2 to 8 stops, each an offset in 0..1 and a color. Gradients interpolate premultiplied stops in linear light, so a gradient between two colors passes through their physical mix, and a stop fading to transparent does not darken its neighbour. Wherever a paint is read, a bare color is read as a solid paint.
This project shows the four paints one after another, a second each:
[ { "id": "solid", "kind": "generated", "generator": { "type": "fill", "paint": { "type": "solid", "color": { "red": 0.17, "green": 0.36, "blue": 0.99, "alpha": 1 } } } }, { "id": "linear", "kind": "generated", "generator": { "type": "fill", "paint": { "type": "linear_gradient", "start": { "x": 0, "y": 0.5 }, "end": { "x": 1, "y": 0.5 }, "stops": [ { "offset": 0, "color": { "red": 0.98, "green": 0.45, "blue": 0.1, "alpha": 1 } }, { "offset": 1, "color": { "red": 0.17, "green": 0.36, "blue": 0.99, "alpha": 1 } } ] } } }, { "id": "radial", "kind": "generated", "generator": { "type": "fill", "paint": { "type": "radial_gradient", "center": { "x": 0.5, "y": 0.5 }, "radius": 0.6, "stops": [ { "offset": 0, "color": { "red": 0.98, "green": 0.45, "blue": 0.1, "alpha": 1 } }, { "offset": 1, "color": { "red": 0.17, "green": 0.36, "blue": 0.99, "alpha": 1 } } ] } } }, { "id": "conic", "kind": "generated", "generator": { "type": "fill", "paint": { "type": "conic_gradient", "center": { "x": 0.5, "y": 0.5 }, "stops": [ { "offset": 0, "color": { "red": 0.98, "green": 0.45, "blue": 0.1, "alpha": 1 } }, { "offset": 0.5, "color": { "red": 0.17, "green": 0.36, "blue": 0.99, "alpha": 1 } }, { "offset": 1, "color": { "red": 0.98, "green": 0.45, "blue": 0.1, "alpha": 1 } } ] } } }]Shapes
Section titled “Shapes”{ "type": "shapes", "items": [...] } draws an ordered content tree, as an After Effects or Lottie shape layer does. Each ShapeItem is one of:
- Geometry:
rectangle(withcorner_radius),ellipse,polystar(a polygon or star),path(Bezier subpaths). - Paints:
fillpaints the inside of the geometry listed before it in its group;strokeoutlines it, withwidth,cap,join,miter_limitanddash. - Modifiers:
trimkeeps part of the geometry before it, by length, fromstarttoend, shifted byoffset. group: items drawn together through onetransformand opacity.
The tree reads front first: a fill or stroke paints the geometry before it in the same group, nested groups included, and earlier paints draw on top of later ones.
Units follow the picture: a center is a position, a size is per axis (x a fraction of the width, y of the height, so { "x": 0.5, "y": 0.5 } is round only on a square canvas), and radii and stroke widths are fractions of the shorter side.
This star draws itself on with a keyframed trim while it turns:
{ "type": "shapes", "items": [ { "type": "group", "items": [ { "type": "polystar", "kind": "star", "center": { "mode": "constant", "value": { "x": 0.5, "y": 0.5 } }, "points": { "mode": "constant", "value": 5 }, "outer_radius": { "mode": "constant", "value": 0.35 }, "inner_radius": { "mode": "constant", "value": 0.15 }, "rotation_degrees": { "mode": "keyframes", "keyframes": [ { "time": 0, "value": 0, "interpolation": { "type": "linear" } }, { "time": 360000, "value": 36, "interpolation": { "type": "hold" } } ] } }, { "type": "trim", "start": { "mode": "constant", "value": 0 }, "end": { "mode": "keyframes", "keyframes": [ { "time": 0, "value": 0, "interpolation": { "type": "cubic_bezier", "x1": 0.65, "y1": 0, "x2": 0.35, "y2": 1 } }, { "time": 240000, "value": 1, "interpolation": { "type": "hold" } } ] } }, { "type": "stroke", "paint": { "mode": "constant", "value": { "type": "solid", "color": { "red": 1, "green": 0.75, "blue": 0.2, "alpha": 1 } } }, "width": { "mode": "constant", "value": 0.012 }, "join": "round", "cap": "round" } ] } ]}The shapes preset moves an ellipse along a keyframed centre:
{ "type": "text", "text": ..., "style": ... } draws text on a transparent picture, laid out and placed by its style as caption cues are. The TextStyle sets:
- Font:
font_family,font_size(a fraction of the canvas’s shorter side, 0.05 by default),font_weight(1 to 1000, matched as CSS matchesfont-weight),letter_spacing,line_height. - Placement:
positionandanchor(the point of the text placed atposition;(0.5, 1), its bottom centre, by default),max_width(the wrapping width, a fraction of the canvas width),align. - Look:
fill(a paint, white by default),strokes,shadows,background(a box behind each line). - Motion:
animators.
The text is a string, where \n starts a line, or a list of runs that animators can select by class or time.
Animators
Section titled “Animators”An animator changes characters without laying the text out again. Its selector gives each character a selection between 0 and 1, and its properties are applied in proportion: opacity, offset (in font sizes, +y down), scale, rotation_degrees, tracking, fill and stroke colors. There are three selectors:
range: a range over characters, words or lines, in percent or by index, with ashape(square,ramp_up,ramp_down,triangle,round,smooth), like After Effects’ range selector.timing: characters of timed runs, by whether their time isupcoming,activeorspoken(see karaoke captions).class: characters of runs that carry a class.
Here a range selector’s start moves from 0% to 100% over two seconds. Characters inside the range are fully selected, so they are transparent and lowered by half a font size, and each one rises into place as the range passes it:
{ "type": "text", "text": "Characters arrive one by one", "style": { "font_family": "Hanken Grotesk", "font_size": 0.09, "position": { "x": 0.5, "y": 0.5 }, "anchor": { "x": 0.5, "y": 0.5 }, "animators": [ { "selector": { "type": "range", "start": { "mode": "keyframes", "keyframes": [ { "time": 0, "value": 0, "interpolation": { "type": "linear" } }, { "time": 240000, "value": 100, "interpolation": { "type": "hold" } } ] } }, "properties": { "opacity": { "mode": "constant", "value": 0 }, "offset": { "mode": "constant", "value": { "x": 0, "y": 0.5 } } } } ] }}Animator keyframes are in the holder’s time: a text generator’s picture time, or the time since a caption cue started.
