This article covers the recent 2.4.0 release of the dotLottie players supporting state machines, allowing for powerful interactivity configurations.


This new release of the dotLottie (.lottie) players supports a new custom state machine definition, allowing you to easily define and integrate simple or complex interactive scenarios with dotLottie animations. You can now play specific parts of a single animation or bundle multiple animations inside a single dotLottie file and use them within your state machine. This enhances your Lottie and user experience. With this new update, you’ll no longer need to keep your animations and interactivity code separate – they’ll be bundled inside your .lottie file and easily usable on the web.

What's a state machine? How does it make Lottie interactive?

As XState defines:

A state machine is a finite set of states that can transition to each other deterministically due to events.

Ok…but how can we harness and use this to make Lottie animations interactive?

With Lottie animations, you have the power to customize their behavior in response to certain and specific web interactions such as scrolling, clicking, or hovering. Now, with the ability to bundle multiple animations into a single .lottie file, we can listen for interactions to happen and change to a different animation or change the animation’s playback settings.

Our states will be animations and playback settings, transitions the different events that can happen to a Lottie!

Our goals with this feature were:

  • Allow users to eliminate the need for writing interactivity code – the dotLottie players handle the parsing of your defined state machine schema and loading.
  • Allow users to define their own state machines in a simple and easy-to-understand manner. You can read the state machine and understand exactly what happens at every stage and why.

We’ve created something that tackles both of these problems.

  • A custom state machine schema you can define and bundle within your dotLottie files - all you need to do is load the file on the web – no additional steps required.
  • You can read the schema and easily follow what's going to happen and why when it's activated!

Enough talk – let's dive into what you can do!

What can I make with it?

We've got tons of exciting features and possibilities in store!

  • A pigeon that explodes on click? ✅
  • A night and day toggle? ✅
  • Growing a plant on hover? ✅
  • Scroll then shower the page in confetti? ✅

Endless possibilities! dotLottie gives you the fundamental building blocks of interactivity allowing you to create complex interactive scenarios easily! ✨

👀 Take a peek at the HTML and JS tabs – No interactivity code written! Everything is bundled inside the .lottie and the player takes care of the rest!

How do I make that?

Two ways of doing it.

1) dotlottie-js

dotlottie-js is our creation library used to create .lottie files via code. If that's more your thing you can find that tutorial here.

2) dotLottie playground

Our second option is to use the dotLottie playground available here. You can drag and drop your animations, create states and test them as you write and finally export your .lottie with everything neatly bundled together.

Before we get started

A quick explanation on what the different parts do is needed, if you’d rather skip this and get your hands dirty making your own state machine go ahead! You can also quickly read up on the technical documentation here before you get started.

The state machine schema we’ve come up with has two parts, the descriptor and the states:

descriptor: {
	id: '...',
	initial: '...',
},
states: {
	...
}

Descriptor

The descriptor contains the state machine’s unique id as well as the name of the initial state to load.

States

Here we define our state objects. A state defines which animation of the .lottie to use, its playback settings and how it should transition to another state if you want it to:

states: {
	state_name: {
		animationId: '...',
		playbackSettings: {
			autoplay: true,
			loop: true,
			direction: 1,
			segments: 'bird',
		},
		onClick: {
			state: '',
		},
		onMouseEnter: {
			state: '...'
		},
	},
}

The full list of playback settings is available here.

Also, the full list of transitions here.

Let’s go through the steps of integrating a state machine into a dotLottie file! In this example, we’re going to make a snail retreat into its shell when we hover over it.

Setup

First of all get the playground and drop a .json animation into the animations panel:

Animation panel
Add animation to panel

Adding a state machine

Next, to add a state machine simply click the plus button on the states panel and give it a name:

Adding a state machine

Editing a state machine

After you click on the state file it’ll open up in the editor with some default values.

Editing a state machine

The first value to change is under ‘initialState’, paste the ‘animationId’ given from the animations panel.

Then set autoplay and loop to false.

This is our initial state or the first state to load when we activate our state machine. With autoplay and loop false our animation will be paused. Adding the 'animationId' is important in the initial state to apply it to the correct animation, otherwise it will be applied to the current playing animation.

Adding a transition

Lets add the ‘onMouseEnter’ transition so that our snail will start playing when the mouse goes over it:

{
	"descriptor": {
		"id": "retreat",
		"initial": "initialState"
	},
	"states": {
		"initialState": {
			"animationId": "bf721c0c-fd20-41d9-b7c3-18e016153407",
			"playbackSettings": {
				"autoplay": false,
				"loop": false
			},
			"onMouseEnter": {
				"state": "playForwardState"
			}
		},
		"playForwardState": {

		}
	}
}

Making the animation play

We’re going to fill out our ‘playForwardState’ with playback settings and a ‘onMouseLeave’ transition to play in reverse when the cursor leaves the animation container:

"playForwardState": {
			"playbackSettings": {
				"autoplay": true,
				"loop": false,
				"segments": [0, 39]
			},
			"onMouseLeave": {
				"state": "playReverseState"
			}
}

With this configuration our snail will start playing forward to frame 39 when this state is entered and listen for 'onMouseLeave' to transition to the next state.

Playing in reverse

When the mouse leaves we want to play in reverse and when it's complete, go to the initial state:

"playReverseState": {
			"playbackSettings": {
				"autoplay": true,
				"loop": false,
				"direction": -1
			},
			"onComplete": {
				"state": "initialState"
			}
}

With this configuration, we’ll play the animation in reverse and when the frame hits 0 (onComplete) it’ll transition to the initial state which will wait for the cursor to enter again and start the cycle.

The full state machine looks like this:

{
	"descriptor": {
		"id": "retreat",
		"initial": "initialState"
	},
	"states": {
		"initialState": {
			"animationId": "bf721c0c-fd20-41d9-b7c3-18e016153407",
			"playbackSettings": {
				"autoplay": false,
				"loop": false
			},
			"onMouseEnter": {
				"state": "playForwardState"
			}
		},
	"playForwardState": {
			"playbackSettings": {
				"autoplay": true,
				"loop": false,
				"segments": [0, 39]
			},
			"onMouseLeave": {
				"state": "playReverseState"
			}
		}
	},
	"playReverseState": {
			"playbackSettings": {
				"autoplay": true,
				"loop": false,
				"direction": -1,
			},
			"onComplete": {
				"state": "initialState"
			}
	}
}

Export and download

You can now download your .lottie. It will contain any additional animations and states you added.

Export and download as a dotLottie

How do I play that?

Loading a state machine is super simple. Just add the ‘activeStateId’ prop:

<dotlottie-player activeStateId="exploding_pigeon" src="..." id="player"></dotlottie-player>

Or if you prefer to load the state machine at a later date you can do so using the enterInteractiveMode method:

player.enterInteractiveMode(’exploding_pigeon’);

and exit it when you want to stop using it:

player.exitInteractiveMode();

✨ Bonus features in this release ✨

Sync to scroll and play on show

Syncing to scroll and playing on show is now available with methods!

To sync your animation to page scroll simply call:

player.playOnScroll()

You can also pass how pass segments and a position threshold to the method so that it syncs only when the animation is in a specific portion of the viewport:

player.playOnScroll({
	   segments: [100, 200],
		 threshold: [0.5, 1]
})

Here with a threshold of [0.5, 1] the animation will only start syncing when it's halfway down the page.

To stop syncing the animation to the page, use:

player.stopPlayOnScroll();

To play your animation when it becomes visible use the playOnShow method:

player.playOnShow()

This method optionally takes a threshold that is passed on to the intersection observer.

player.playOnShow({
	threshold: [0.25]
})

To stop playing on show use:

player.playOnShow()

We hope you enjoy using these new features and be sure to check out all the available playback settings and transitions to get the most out of your .lotties!

Lottie light and bundle size improvements

The player now accepts the ‘light’ prop which would load a lighter version of lottie-web which doesn’t support expressions.

Alongside this we’ve also changed how the Lottie library and the chosen renderer were loaded and have managed to reduce the bundle size of the dotLottie player from 105kb gzipped to 29.1kb  - a 72% size reduction!