Table of contents
Animations Example

This example can be found in the Examples folder of the Gorilla Engine SDK.
It introduces:
- Which types of animations exist in Gorilla Engine
- When to use which type
- How add animations to your plugin UI
Summary
Gorilla Engine supports two types of animations: filmstrips and Lottie. Both types have their unique use cases and also partially overlap in the ways they can be used. This example shows how to use Lottie animations in-depth and only gives a brief overview of filmstrips.
Filmstrips
A filmstrip is a flipbook style animation. It can be added to knobs, sliders and meters. To use it, you have to provide a flipbook style image in png format. Gorilla Engine will then, depending on the value of the knob, slider or meter, automatically choose the correct page from the flipbook. The flipbook is just a metaphor and in fact the individual pages or frames of the animation must be arranged in a sprite map like image. All frames of the animation must be arranged on top of each other in a single image. Gorilla Engine then automatically selects the correct area of the image to display. A typical number of individual frames per animation is 128.
Example
The first eight frames of a filmstrip can be seen below. To see the whole file have a look at [email protected] in assets folder of the Piano Pad example of the Gorilla Engine SDK.

Using a filmstrip
To apply a filmstrip to a knob for example you just have to provide the path to the png file and the number of frames in that file. This is how you can add a filmstrip from a yaml file:
- knob:
x: 0
y: 0
width: 80
height: 80
value&: instrument.volume # The knob is bound to the volume parameter. The value of this parameter therefore determines which frame of filmstrip is visible
filmstrip:
path: images/[email protected] # The path to the filmstrip png file relative to the plugins asset directory
count: 128 # The number of individual frames in the filmstrip
Lottie
Lottie animations are different from filmstrips in that they do not rely on images but small snippets of JSON that describe vector shapes and colors and how they change throughout the animation. The main advantage of this approach is that the animations can be interactive if they need to. You can for example add a hover effect to an animated knob which is not possible with a filmstrip. Lottie animations can be created with industry standard tools like Adobe Affer Effects and can be applied to knobs, sliders, triggers, meters and toggles. They can also be used as standalone components for when you just need a loading indicator or something similar.
Standalone animations
To create an animation that is not attached to another control you can just instantiate it, passing the desired properties, and then append it to the viewport.
const loadingAnimation = new GorillaEngine.UI.LottieAnimation({
x: 0,
y: 0,
width: 80,
height: 80,
// Path to the animation file; absolute or realtive to the plugins asset directory
filePath: 'myLoadingIndicator.json',
// Whether playback starts automatically after creation
autoplay: false,
// Whether playback loops or stops after reaching the last frame
loop: true
});
// Finally append the animation to viewport
GorillaEngine.UI.getControlById('root').appendChild(animation);
Playback of the animation is then controlled from JavaScript by a set of functions available on each animation instance. Say you want to loop your animation until some long running task completes:
// Start playback
loadingAnimation.play();
// Imaginary wait for some long running task to complete
await new Promise(resolve => setTimeout(_ => resolve(), 5000));
// Stop playback (pause and reset to frame 0)
loadingAnimation.stop()
// Or pause playback at the current frame
loadingAnimation.pause()
You can also manually select the frame to display. Say you are downloading something and want to display the progress:
// Imaginary download start where 'size' is the total number of bytes to load and 'download' is
// something that emits a 'progress' event every now and then to indicate how many bytes have been
// downloaded already.
const { size, download } = await startDownload('https://example.com/my-large-file');
// Handle the progress event by setting the animations current frame based on a linear transformation
download.on('progress', progress => loadingAnimation.setFrameFromLinearTransform(progress, 0, size));
We used the setFrameFromLinearTransform shorthand to determine which of the animations frame corresponds to the given progress. The following calls to setFrame and setFrameFromLinearTransform are equivalent.
const min = -15;
const max = 33;
const value = 17;
animation.setFrame((value - min) * (amination.totalFrames / (max - min)));
animation.setFrameFromLinearTransform(value, min, max);
If your calculations are more involved than a linear transform, the following properties and setFrame will give you full control.
// Display the total number of frames in the loaded animation
animation.totalFrames
// Display the duration of the animation
animation.duration
// Display the currently selected frame of the animation
animation.currentFrame
Shorthands
To add an animation to a control, like for a example a knob, you just instantiate the animation and then pass it to the controls animation property. Doing so you can omit properties like x, y, width and height on the animation.
// Create the animation
const knobAnimation = new GorillaEngine.UI.LottieAnimation({
filePath: 'knobAnimation.json'
}):
// Pass the animation to a knobs animation property
const knob = new GorillaEngine.UI.Knob({
x: 0,
y: 0,
width: 100,
height: 100,
min: 0,
max: 1,
value: 0.5,
stepSize: 0.005,
animation: knobAnimation
});
The animation is now connected to the knob and whenever the knobs value changes, the animation follows. For knobs, sliders and meters Gorilla Engine calculates the frame to display using setFrameFromLinearTransform with the controls value, min and max. For triggers the whole animation plays once, when the trigger is clicked. For toggles the animation plays once when the toggle is checked and once backwards when unchecked. If you just want to connect the value of the control to animation but donβt want the animation to inherit the bounds of the control you can set autoConfigure: false on the animation. In that case you have to manually set x, y, width and height.
Interactivity
Lottie animations can be interactive. That is within limits of course. Each animation object exposes a setProperties function that can be used to modify properties of the animation. Say you have an animated trigger an you want that trigger to change itβs color whenever it is hovered by the mouse pointer.
// Create the animation
const triggerAnimation = new GorillaEngine.UI.LottieAnimation({
filePath: 'triggerAnimation.json'
}):
// Pass the animation to a triggers animation property
const trigger = new GorillaEngine.UI.Trigger({
x: 0,
y: 0,
width: 100,
height: 100,
animation: triggerAnimation
});
// Register a 'mouseEnter' event handler with the trigger
// that sets the fill color of all layers in the animation
// to white when the mouse enters the trigger control
trigger.on('mouseEnter', () => {
triggerAnimation.setProperties('**', {
fillColor: [1, 1, 1]
});
});
// Register a 'mouseExit' event handler with the trigger
// that sets the fill color of all layers in the animation
// to red when the mouse exits the trigger control
trigger.on('mouseExit', () => {
triggerAnimation.setProperties('**', {
fillColor: [1, 0, 0]
});
});
The setProperties function takes two arguments. The first one is a selector that determines which elements of the animation are affected by the function call. The selector can either be a glob expression like ** which selects all elements, a wildcard expression like Some Layer.* which selects all shapes in Some Layer, or it can be a path to a specific element of the animation like Some Layer.Some Shape.Fill 1.
Which paths are valid depends on the animation and which names were given to the layers and shapes of the animation during the design process i.e. in Adobe After Effects. You can also inspect the animation in various editors like the Lottie Editor.
The second argument to the setProperties function call is an Object whichβs properties determine the effect of the function call. Here is an example of all the possible properties that can be modified in an animation:
animation.setProperties('**', {
fillColor: [1, 0, 0], // Fill bright red
fillOpacity: 50, // Change fills to 50% opacity
strokeColor: [0, 1, 0], // Color strokes bright green
strokeOpacity: 50, // Change strokes to 50% opacity
strokeWidth: 3.5, // Change stroke width to 3.5px
transformAnchor: [100, 100], // Move the anchor to x = 100, y = 100
transformPosition: [200, 200], // Move to x = 200, y = 200
transformScale: [50, 50], // Scale to 50% size in x and y axis
transformRotation: 180, // Rotate by 180Β°
transformOpacity: 50, // Change opacity to 50%
})
Creating from yaml
Lottie animations can of course also be created from yaml. Although interactivity can only be controlled from JavaScript this can still be handy, especially when using the shorthand for knobs etc.
window:
id: 'window'
width: 1200
height: 800
children:
# Create a standalone animation
- lottie_animation:
x: 0
y: 0
width: 200
height: 200
file_path: loading indicator.json
autoplay: true
loop: true
# Create an animation along with another control
- knob:
x: 200
y: 0
width: 200
height: 200
value&: instrument.reverb
animation: reverb animation.json
# The animation property can be bound to a model
- levelmeter:
x: 400
y: 0
width: 200
height: 200
value&: instrument.volume
animation&: animationController.volumeAnimation
# Interactivity is still supported from JavaScript.
# You could for example do this:
#
# const animation = GorillaEngine.UI.getControlById('volumeAnimation')
#
# animation can now be controlled as if it was created by
# new GorillaEngine.UI.LottieAnimation()
- knob:
x: 600
y: 0
width: 200
height: 200
value&: instrument.volume
animation:
file_path: volume animation.json
id: volumeAnimation
Supported Adobe After Effects features
Not all of the features available in Adobe After Effects work with our Lottie implementation. This list gives an overview of supported and unsupported features.
| Shapes | Supported |
|---|---|
| Shape | π |
| Ellipse | π |
| Rectangle | π |
| Rounded Rectangle | π |
| Polystar | π |
| Group | π |
| Trim Path (individually) | π |
| Trim Path (simultaneously) | π |
| Renderable | Supported |
| Fill | π |
| Stroke | π |
| Radial Gradient | π |
| Linear Gradient | π |
| Gradient Stroke | π |
| Transforms | Supported |
| Position | π |
| Position (separated X/Y) | π |
| Scale | π |
| Skew | βοΈ |
| Rotation | π |
| Anchor Point | π |
| Opacity | π |
| Parenting | π |
| Auto Orient | π |
| Interpolation | Supported |
| Linear Interpolation | π |
| Bezier Interpolation | π |
| Hold Interpolation | π |
| Spatial Bezier Interpolation | π |
| Rove Across Time | π |
| Masks | Supported |
| Mask Path | π |
| Mask Opacity | π |
| Add | π |
| Subtract | π |
| Intersect | π |
| Lighten | βοΈ |
| Darken | βοΈ |
| Difference | βοΈ |
| Expansion | βοΈ |
| Feather | βοΈ |
| Mattes | Supported |
| Alpha Matte | π |
| Alpha Inverted Matte | π |
| Luma Matte | π |
| Luma Inverted Matte | π |
| Merge Paths | Supported |
| Merge | βοΈ |
| Add | βοΈ |
| Subtract | βοΈ |
| Intersect | βοΈ |
| Exclude Intersection | βοΈ |
| Layer Effects | Supported |
| Fill | βοΈ |
| Stroke | βοΈ |
| Tint | βοΈ |
| Tritone | βοΈ |
| Levels Individual Controls | βοΈ |
| Text | Supported |
| Glyphs | βοΈ |
| Fonts | βοΈ |
| Transform | βοΈ |
| Fill | βοΈ |
| Stroke | βοΈ |
| Tracking | βοΈ |
| Anchor point grouping | βοΈ |
| Text Path | βοΈ |
| Per-character 3D | βοΈ |
| Range selector (Units) | βοΈ |
| Range selector (Based on) | βοΈ |
| Range selector (Amount) | βοΈ |
| Range selector (Shape) | βοΈ |
| Range selector (Ease High) | βοΈ |
| Range selector (Ease Low) | βοΈ |
| Range selector (Randomize order) | βοΈ |
| expression selector | βοΈ |
| Other | Supported |
| Expressions | βοΈ |
| Images | βοΈ |
| Precomps | π |
| Time Stretch | π |
| Time remap | π |
| Markers | π |
Known issues
- Rounded rectangles imported from Figma into Adobe After Effects sometimes donβt have rounded corners. Paths work fine though.
- Linked animations wonβt work.
Comparison
While use cases of filmstrips and Lottie animations partially overlap each of the implementations has itβs niche.
| Test | Filmstrips | Lottie |
|---|---|---|
| Use cases | skeuomorph, non-vector visuals | 2d shapes |
| Interactivity | no | yes |
| File size | Β larger | Β smaller |
| Popularity | lower | Β higher |
| Standalone | Β no | yes |
| Controls | knobs, sliders, meters | knobs, sliders, meters, toggles, triggers |
| CPU utilization | lower | Β higher |