Command Palette

Search for a command to run...

State Machine Examples

Practical code examples for using state machines with the dotLottie Web Player — hover effects, click counters, tweened transitions, and custom events.

State Machine Examples

These examples show common patterns for building interactive animations with state machines in the dotLottie Web Player. Each example includes the state machine definition and the corresponding JavaScript setup code.

For the full API reference, see Understanding State Machines.

State machine definitions are stored as JSON in the s/ directory of your .lottie file. The examples below show both the definition (what you author in your .lottie) and the runtime code (what you write in JavaScript).

Hover Effect

A two-state animation that plays an idle loop by default and switches to a hover loop when the pointer enters the canvas.

State machine definition:

{
  "initial": "Idle",
  "inputs": [
    { "type": "Event", "name": "OnEnter" },
    { "type": "Event", "name": "OnExit" }
  ],
  "interactions": [
    {
      "type": "PointerEnter",
      "actions": [{ "type": "Fire", "inputName": "OnEnter" }]
    },
    {
      "type": "PointerExit",
      "actions": [{ "type": "Fire", "inputName": "OnExit" }]
    }
  ],
  "states": [
    {
      "name": "Idle",
      "type": "PlaybackState",
      "animation": "idle",
      "loop": true,
      "autoplay": true,
      "transitions": [
        {
          "type": "Transition",
          "toState": "Hover",
          "guards": [{ "type": "Event", "inputName": "OnEnter" }]
        }
      ]
    },
    {
      "name": "Hover",
      "type": "PlaybackState",
      "animation": "hover",
      "loop": true,
      "autoplay": true,
      "transitions": [
        {
          "type": "Transition",
          "toState": "Idle",
          "guards": [{ "type": "Event", "inputName": "OnExit" }]
        }
      ]
    }
  ]
}

JavaScript setup:

Pointer interactions defined in the state machine are handled automatically once it starts. No manual event wiring is needed.

import { DotLottie } from '@lottiefiles/dotlottie-web';

const dotLottie = new DotLottie({
  canvas: document.querySelector('#canvas'),
  src: 'button.lottie',
  autoplay: false,
});

dotLottie.addEventListener('load', () => {
  dotLottie.stateMachineLoad('hoverFSM');
  dotLottie.stateMachineStart();
});

dotLottie.addEventListener('loadError', (err) => {
  console.error('Failed to load animation:', err);
});

Click Counter with a Guard

A numeric input tracks a click count. A guard prevents the transition to a "complete" state until the count reaches 3.

State machine definition:

{
  "initial": "Counting",
  "inputs": [
    { "type": "Numeric", "name": "clicks", "value": 0 },
    { "type": "Event", "name": "OnClick" }
  ],
  "interactions": [
    {
      "type": "Click",
      "actions": [
        { "type": "Increment", "inputName": "clicks", "value": 1 },
        { "type": "Fire", "inputName": "OnClick" }
      ]
    }
  ],
  "states": [
    {
      "name": "Counting",
      "type": "PlaybackState",
      "animation": "counting",
      "loop": true,
      "autoplay": true,
      "transitions": [
        {
          "type": "Transition",
          "toState": "Complete",
          "guards": [
            { "type": "Event", "inputName": "OnClick" },
            { "type": "Numeric", "inputName": "clicks", "conditionType": "GreaterThanOrEqual", "compareTo": 3 }
          ]
        }
      ]
    },
    {
      "name": "Complete",
      "type": "PlaybackState",
      "animation": "complete",
      "loop": false,
      "autoplay": true,
      "final": true,
      "transitions": []
    }
  ]
}

JavaScript setup:

Read the clicks input value at any point to reflect it in your UI:

import { DotLottie } from '@lottiefiles/dotlottie-web';

const dotLottie = new DotLottie({
  canvas: document.querySelector('#canvas'),
  src: 'counter.lottie',
  autoplay: false,
});

dotLottie.addEventListener('load', () => {
  dotLottie.stateMachineLoad('counterFSM');
  dotLottie.stateMachineStart();
});

dotLottie.addEventListener('stateMachineNumericInputValueChange', (event) => {
  if (event.inputName === 'clicks') {
    document.querySelector('#count-label').textContent = `Clicks: ${event.newValue}`;
  }
});

dotLottie.addEventListener('stateMachineStateEntered', (event) => {
  if (event.state === 'Complete') {
    console.log('Animation complete!');
  }
});

Tweened Transition

Use a tweened transition to animate smoothly between two states over a fixed duration instead of cutting immediately.

State machine definition:

The duration (in seconds) and easing (cubic Bézier control points) are set on the transition:

{
  "initial": "Idle",
  "inputs": [
    { "type": "Event", "name": "OnEnter" },
    { "type": "Event", "name": "OnExit" }
  ],
  "interactions": [
    {
      "type": "PointerEnter",
      "actions": [{ "type": "Fire", "inputName": "OnEnter" }]
    },
    {
      "type": "PointerExit",
      "actions": [{ "type": "Fire", "inputName": "OnExit" }]
    }
  ],
  "states": [
    {
      "name": "Idle",
      "type": "PlaybackState",
      "animation": "idle",
      "loop": true,
      "autoplay": true,
      "transitions": [
        {
          "type": "Transition",
          "toState": "Active",
          "duration": 0.4,
          "easing": [0.4, 0.0, 0.2, 1.0],
          "guards": [{ "type": "Event", "inputName": "OnEnter" }]
        }
      ]
    },
    {
      "name": "Active",
      "type": "PlaybackState",
      "animation": "active",
      "loop": true,
      "autoplay": true,
      "transitions": [
        {
          "type": "Transition",
          "toState": "Idle",
          "duration": 0.3,
          "easing": [0.4, 0.0, 0.2, 1.0],
          "guards": [{ "type": "Event", "inputName": "OnExit" }]
        }
      ]
    }
  ]
}

During a tweened transition, new state changes are blocked until the animation completes. Entry actions run after the tween finishes.


Custom Events from JavaScript

Fire named events from your own UI code to drive state machine transitions — for example, reacting to a form submission or an API response.

State machine definition:

{
  "initial": "Idle",
  "inputs": [
    { "type": "Event", "name": "submit" },
    { "type": "Event", "name": "reset" }
  ],
  "states": [
    {
      "name": "Idle",
      "type": "PlaybackState",
      "animation": "idle",
      "loop": true,
      "autoplay": true,
      "transitions": [
        {
          "type": "Transition",
          "toState": "Loading",
          "guards": [{ "type": "Event", "inputName": "submit" }]
        }
      ]
    },
    {
      "name": "Loading",
      "type": "PlaybackState",
      "animation": "loading",
      "loop": true,
      "autoplay": true,
      "transitions": [
        {
          "type": "Transition",
          "toState": "Idle",
          "guards": [{ "type": "Event", "inputName": "reset" }]
        }
      ]
    }
  ]
}

JavaScript setup:

Call stateMachineFireEvent with the event name defined in your inputs array:

import { DotLottie } from '@lottiefiles/dotlottie-web';

const dotLottie = new DotLottie({
  canvas: document.querySelector('#canvas'),
  src: 'form.lottie',
  autoplay: false,
});

dotLottie.addEventListener('load', () => {
  dotLottie.stateMachineLoad('formFSM');
  dotLottie.stateMachineStart();
});

document.querySelector('#submit-btn').addEventListener('click', async () => {
  dotLottie.stateMachineFireEvent('submit');

  try {
    await submitForm();
  } finally {
    dotLottie.stateMachineFireEvent('reset');
  }
});

Listening to State Machine Events

Use addEventListener to observe state transitions and input changes at runtime:

// Log every state transition
dotLottie.addEventListener('stateMachineTransition', (event) => {
  console.log(`Transition: ${event.fromState} → ${event.toState}`);
});

// React when a specific state is entered
dotLottie.addEventListener('stateMachineStateEntered', (event) => {
  if (event.state === 'Complete') {
    document.querySelector('#cta').style.display = 'block';
  }
});

// Watch a string input change
dotLottie.addEventListener('stateMachineStringInputValueChange', (event) => {
  console.log(`${event.inputName}: "${event.oldValue}" → "${event.newValue}"`);
});

// Catch errors
dotLottie.addEventListener('stateMachineError', (event) => {
  console.error('State machine error:', event.error);
});

Last updated: April 10, 2026 at 9:12 AMEdit this page