Skip to content

Commit

Permalink
Add time remap specs (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
fmalita committed Jul 16, 2024
1 parent 409b7ed commit e37fb3e
Show file tree
Hide file tree
Showing 3 changed files with 1,209 additions and 0 deletions.
114 changes: 114 additions & 0 deletions docs/specs/layers.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ In this example there's a layer with a rectangle and a star being masked by an e

{schema_object:layers/precomposition-layer}

<h4 id="precomposition-time-stretch">Time Stretch</h4>

The `st` property specifies a start time offset, while `sr` defines a time stretch factor,
to be applied when evaluating animated properties pertaining to the layer:

Expand All @@ -107,3 +109,115 @@ decrease it ("stretching" the layer timeline).
</script>
</lottie-playground>

<h4 id="precomposition-time-remap">Time Remap</h4>

The `tm` property specifies a time remap function as an animatable property, allowing full control
over the precomp timeline (subset, speedup/slowdown, reverse, frame-freeze, or any other arbitrary
transformation).

It maps the current layer time (in the frame index $[ip \ldots op]$ domain) to a precomp time
expressed in seconds, and evaluates all animatable precomp properties based on the new time value:

$$tm \colon \left[ip \ldots op\right] \mapsto seconds$$
$$t\prime = tm(t) \cdot FPS$$

Note: the global frame rate factor $FPS$ ([Animation](composition.md#Animation) `fr` property) is
required to convert back into the frame index domain.

When both time stretch (`sr`) and time remap (`tm`) are specified, time stretch is applied first.


<lottie-playground example="time_remap.json">
<title>Example</title>
<form>
<select title="Time Remap">
<option value="0">Linear</option>
<option value="1">Reverse</option>
<option value="2">Subset</option>
<option value="3">Discrete</option>
<option value="4">Easing 1</option>
<option value="5">Easing 2</option>
<option value="6">Easing-Reverse</option>
</select>
</form>
<json>lottie.layers[1].tm</json>
<script>
const time_maps = [
{ 'a': 1, k: [
{ 't': 0, 's': [ 0], 'o': { 'x': [0], 'y': [0]}, 'i': { 'x': [1], 'y': [1] }},
{ 't': 600, 's': [10] }
]},
{ 'a': 1, k: [
{ 't': 0, 's': [10], 'o': { 'x': [0], 'y': [0]}, 'i': { 'x': [1], 'y': [1] }},
{ 't': 600, 's': [ 0] }
]},
{ 'a': 1, k: [
{ 't': 0, 's': [3], 'o': { 'x': [0], 'y': [0]}, 'i': { 'x': [1], 'y': [1] }},
{ 't': 600, 's': [7] }
]},
{ 'a': 1, k: [
{ 't': 0, 's': [ 0.0], 'o': { 'x': [0], 'y': [0]}, 'i': { 'x': [1], 'y': [1] }, 'h': 1 },
{ 't': 150, 's': [ 2.5], 'o': { 'x': [0], 'y': [0]}, 'i': { 'x': [1], 'y': [1] }, 'h': 1 },
{ 't': 300, 's': [ 5.0], 'o': { 'x': [0], 'y': [0]}, 'i': { 'x': [1], 'y': [1] }, 'h': 1 },
{ 't': 450, 's': [ 7.5], 'o': { 'x': [0], 'y': [0]}, 'i': { 'x': [1], 'y': [1] }, 'h': 1 },
{ 't': 600, 's': [10.0] }
]},
{ 'a': 1, k: [
{ 't': 0, 's': [ 0], 'o': { 'x': [0], 'y': [0.5]}, 'i': { 'x': [0.5], 'y': [1] }},
{ 't': 600, 's': [10] }
]},
{ 'a': 1, k: [
{ 't': 0, 's': [ 0], 'o': { 'x': [0], 'y': [0.5]}, 'i': { 'x': [1], 'y': [0.5] }},
{ 't': 600, 's': [10] }
]},
{ 'a': 1, k: [
{ 't': 0, 's': [ 0], 'o': { 'x': [0.2], 'y': [0]}, 'i': { 'x': [0.8], 'y': [1] }},
{ 't': 300, 's': [ 7], 'o': { 'x': [0.2], 'y': [0]}, 'i': { 'x': [0.8], 'y': [1] }},
{ 't': 600, 's': [ 0] }
]},
];
const time_paths = [
{
'v': [[-250, 50], [250, -50]],
'o': [[ 0, 0], [ 0, 0]],
'i': [[ 0, 0], [ 0, 0]],
'c': false
}, {
'v': [[250, 50], [-250, -50]],
'o': [[ 0, 0], [ 0, 0]],
'i': [[ 0, 0], [ 0, 0]],
'c': false
}, {
'v': [[250, 20], [-250, -20]],
'o': [[ 0, 0], [ 0, 0]],
'i': [[ 0, 0], [ 0, 0]],
'c': false
}, {
'v': [[-250, 50], [-125, 50], [-125, 25], [0, 25], [0, 0], [125, 0], [125, -25], [250, -25]],
'o': [[ 0, 0], [ 0, 0], [ 0, 0], [0, 0], [0, 0], [ 0, 0], [ 0, 0], [ 0, 0]],
'i': [[ 0, 0], [ 0, 0], [ 0, 0], [0, 0], [0, 0], [ 0, 0], [ 0, 0], [ 0, 0]],
'c': false
}, {
'v': [[-250, 50], [ 250, -50]],
'o': [[ 0, -50], [ 0, 0]],
'i': [[ 0, 0], [-250, 0]],
'c': false
}, {
'v': [[-250, 50], [250, -50]],
'o': [[ 0, -50], [ 0, 0]],
'i': [[ 0, 0], [ 0, 50]],
'c': false
}, {
'v': [[-250, 50], [ 0, -20], [ 250, 50]],
'o': [[ 100, 0], [ 100, 0], [ 0, 0]],
'i': [[ 0, 0], [-100, 0], [-100, 0]],
'c': false
},
];
const sample_index = data["Time Remap"];
const precomp_layer = lottie.layers[1];
precomp_layer.tm = time_maps[sample_index];
const time_shape = lottie.layers[0].shapes[1].it[0];
time_shape.ks.k = time_paths[sample_index];
</script>
</lottie-playground>
Loading

0 comments on commit e37fb3e

Please sign in to comment.