Generators
This content is for v0.4. Switch to the latest version for up-to-date documentation.
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 or a text never changes over time: a clip animates it with its transform, effects and masks. 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:
color(white by default),outline(a band around the glyphs, itswidtha fraction of the font size, at most 0.5),background(a box behind each line, itspaddinga fraction of the font size).
The text is a string, where \n starts a line.
Moving text
Section titled “Moving text”A text picture is still. To move it, animate the clip that shows it: its visual opacity, position, scale and rotation_degrees take keyframes like any clip’s, and effects and masks apply as they do to any picture. Here the clip fades the title in while it rises into place:
{ "id": "text-clip", "source_id": "headline", "timeline_range": { "start": 0, "end": 360000 }, "source_range": { "start": 0, "end": 360000 }, "visual": { "opacity": { "mode": "keyframes", "keyframes": [ { "time": 0, "value": 0, "interpolation": { "type": "linear" } }, { "time": 120000, "value": 1, "interpolation": { "type": "hold" } } ] }, "position": { "mode": "keyframes", "keyframes": [ { "time": 0, "value": { "x": 0.5, "y": 0.55 }, "interpolation": { "type": "cubic_bezier", "x1": 0.2, "y1": 0, "x2": 0, "y2": 1 } }, { "time": 120000, "value": { "x": 0.5, "y": 0.5 }, "interpolation": { "type": "hold" } } ] } }}The source is { "type": "text", "text": "A title from JSON alone" } with font_family, a font_size of 0.09, and position and anchor at the centre.
