# Understanding State Machines
Explains how state machines work in the dotLottie React Native Player. Covers the core model, workflow, controller methods, setting inputs, event callbacks, and interactive examples.

# Understanding State Machines

This page explains how state machines work in the React Native player — what they are, how they integrate with animation playback, and when to use them. It also documents the controller methods for loading, starting, and interacting with state machines.

> **Note:** State machine support is an actively developing feature. APIs and capabilities might change. If your state machine isn't working as expected please [create an issue on Github↗](https://github.com/nicholasgasior/dotlottie-react-native/issues).

## Core Workflow

1. **Define:** Create your state machine logic (states, transitions, events, context) within your `.lottie` file.
2. **Load Animation:** Set up the `DotLottie` component with your animation source.
3. **Load State Machine:** Specify the `stateMachineId` prop or load programmatically via the controller ref.
4. **Start State Machine:** The state machine starts automatically when using `stateMachineId`, or call `stateMachineStart()` after programmatic loading.
5. **Interact:** Send inputs and fire events from your application code using the controller ref.
6. **Listen (Optional):** Use event callback props to react to state changes, transitions, and input changes.
7. **Stop (Optional):** Stop the state machine using the controller when interactivity is no longer needed.

## Basic Setup

The simplest way to use a state machine is to set the `stateMachineId` prop and attach a `ref` to access the controller:

```tsx
import React, { useRef, useState } from "react";
import { View, Text } from "react-native";
import { DotLottie, type Dotlottie } from "@lottiefiles/dotlottie-react-native";

function StateMachineExample() {
  const controllerRef = useRef<Dotlottie>(null);
  const [currentState, setCurrentState] = useState("idle");

  return (
    <View style={{ alignItems: "center", justifyContent: "center", flex: 1 }}>
      <DotLottie
        ref={controllerRef}
        source={{ uri: "https://lottie.host/your-animation.lottie" }}
        style={{ width: 300, height: 300 }}
        stateMachineId="myStateMachine"
        onStateMachineStateEntered={(state) => {
          setCurrentState(state);
        }}
      />
      <Text>Current State: {currentState}</Text>
    </View>
  );
}
```

## Setting Inputs

State machines can use boolean, numeric, and string inputs to control transitions. Set inputs via the controller ref.

### Boolean Inputs

```tsx
controllerRef.current?.stateMachineSetBooleanInput("isActive", true);
controllerRef.current?.stateMachineSetBooleanInput("isActive", false);
```

### Numeric Inputs

```tsx
controllerRef.current?.stateMachineSetNumericInput("speed", 5.0);
```

### String Inputs

```tsx
controllerRef.current?.stateMachineSetStringInput("theme", "dark");
```

## Interactions and Events

Pointer and click interactions defined in the state machine's `interactions` array (e.g., `Click`, `PointerDown`, `PointerEnter`) are handled **automatically** by the React Native player based on user touches on the `DotLottie` component. You do not need to wire up gesture handlers for these.

Use `stateMachineFire` to trigger `Event`-type inputs explicitly from your application code — for example, responding to a button press or other app-level gesture outside the animation component:

### Firing Events

Events cause immediate transitions in the state machine:

```tsx
// Fire a named event
controllerRef.current?.stateMachineFire("onTap");
```

## Controller State Machine Methods

The following methods are available on the controller ref for state machine interaction:

| Method                                                     | Description                               |
| ---------------------------------------------------------- | ----------------------------------------- |
| `stateMachineLoad(stateMachineId: string)`                 | Loads a state machine by ID.              |
| `stateMachineStart()`                                      | Starts the loaded state machine.          |
| `stateMachineStop()`                                       | Stops the state machine.                  |
| `stateMachineFire(event: string)`                          | Fires a named event to the state machine. |
| `stateMachineSetBooleanInput(key: string, value: boolean)` | Sets a boolean input.                     |
| `stateMachineSetNumericInput(key: string, value: number)`  | Sets a numeric input.                     |
| `stateMachineSetStringInput(key: string, value: string)`   | Sets a string input.                      |

## State Machine Event Callbacks

Listen to state machine events using callback props on the `DotLottie` component:

```tsx
<DotLottie
  source={require("./animation.lottie")}
  style={{ width: 300, height: 300 }}
  stateMachineId="myStateMachine"
  // Lifecycle
  onStateMachineStart={() => {
    console.log("State machine started");
  }}
  onStateMachineStop={() => {
    console.log("State machine stopped");
  }}
  // State changes
  onStateMachineStateEntered={(state) => {
    console.log("Entered state:", state);
  }}
  onStateMachineStateExit={(state) => {
    console.log("Exited state:", state);
  }}
  onStateMachineTransition={(from, to) => {
    console.log(`Transition: ${from} → ${to}`);
  }}
  // Input changes
  onStateMachineBooleanInputChange={(name, oldVal, newVal) => {
    console.log(`${name}: ${oldVal} → ${newVal}`);
  }}
  onStateMachineNumericInputChange={(name, oldVal, newVal) => {
    console.log(`${name}: ${oldVal} → ${newVal}`);
  }}
  onStateMachineStringInputChange={(name, oldVal, newVal) => {
    console.log(`${name}: ${oldVal} → ${newVal}`);
  }}
  // Events and errors
  onStateMachineInputFired={(inputName) => {
    console.log("Input fired:", inputName);
  }}
  onStateMachineError={(error) => {
    console.log("Error:", error);
  }}
  onStateMachineCustomEvent={(event) => {
    console.log("Custom event:", event);
  }}
/>
```

## Complete Interactive Example

Here's a complete example of an interactive button with multiple states:

```tsx
import React, { useRef, useState } from "react";
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
import { DotLottie, type Dotlottie } from "@lottiefiles/dotlottie-react-native";

function InteractiveButton() {
  const controllerRef = useRef<Dotlottie>(null);
  const [currentState, setCurrentState] = useState("idle");
  const [isEnabled, setIsEnabled] = useState(true);

  const handlePressIn = () => {
    if (isEnabled) {
      controllerRef.current?.stateMachineFire("pressDown");
    }
  };

  const handlePressOut = () => {
    if (isEnabled) {
      controllerRef.current?.stateMachineFire("pressUp");
    }
  };

  const toggleEnabled = () => {
    const newValue = !isEnabled;
    setIsEnabled(newValue);
    controllerRef.current?.stateMachineSetBooleanInput("isEnabled", newValue);
  };

  const handleReset = () => {
    controllerRef.current?.stateMachineFire("reset");
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity onPressIn={handlePressIn} onPressOut={handlePressOut} activeOpacity={1}>
        <DotLottie
          ref={controllerRef}
          source={require("./button-animation.lottie")}
          style={{ width: 200, height: 200 }}
          stateMachineId="buttonStateMachine"
          onStateMachineStateEntered={(state) => {
            setCurrentState(state);
          }}
        />
      </TouchableOpacity>

      <Text style={styles.stateText}>State: {currentState}</Text>

      <View style={styles.controls}>
        <TouchableOpacity style={styles.button} onPress={toggleEnabled}>
          <Text>{isEnabled ? "Disable" : "Enable"}</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.button} onPress={handleReset}>
          <Text>Reset</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, alignItems: "center", justifyContent: "center" },
  stateText: { fontSize: 18, marginVertical: 20 },
  controls: { flexDirection: "row", gap: 10 },
  button: { paddingHorizontal: 20, paddingVertical: 10, backgroundColor: "#e0e0e0", borderRadius: 8 },
});
```

## Loading State Machines Programmatically

You can load state machines programmatically instead of using the `stateMachineId` prop:

```tsx
// Load by ID after animation is ready
controllerRef.current?.stateMachineLoad("myStateMachine");
controllerRef.current?.stateMachineStart();

// Stop when done
controllerRef.current?.stateMachineStop();
```

**Important:** Ensure the animation is loaded before calling `stateMachineLoad`. You can use the `onLoad` callback to confirm the animation is ready.

## Understanding State Machine Components (Defined in `.lottie`)

Understanding the structure defined within the `.lottie` file helps in using the player API effectively:

- **Descriptor:** Contains the state machine's unique `id` (used in `stateMachineLoad` or the `stateMachineId` prop) and the index of the `initial` state.
- **States:** Defines possible animation states. The main type `PlaybackState` controls animation aspects like `marker`, `segment`, `loop`, `autoplay`, `speed`, and `mode`.
- **Transitions:** Rules for moving between states (`from_state`, `to_state`) based on a trigger event.
- **Events:** Triggers for transitions, fired via the `stateMachineFire` method or by setting inputs.
- **Guards (Optional):** Conditions within transitions that check context variables to allow or prevent the transition.
- **Context Variables (Optional):** Stored data (`Numeric`, `String`, `Boolean`) used by guards.

## Debugging and Troubleshooting

1. **State Machine Not Loading/Starting:**
   - **Check ID:** Verify the `stateMachineId` matches the ID in the `.lottie` manifest.
   - **Animation Loaded?** Ensure the animation loaded before programmatic loading. Use the `onLoad` callback to confirm.
2. **Events Not Triggering Transitions:**
   - **Check Event Name:** Ensure you're firing the correct event name that matches the state machine definition.
   - **Verify Guards:** Check guard conditions defined in the `.lottie` file.
   - **State Machine Started?** Confirm the state machine is running.
3. **Animation Playback Issues in States:**
   - **Check Marker/Segment:** Ensure `marker` names or `segment` frame numbers defined in states exist in the animation.
4. **Debugging Tip:** Use `onStateMachineStateEntered`, `onStateMachineStateExit`, and `onStateMachineTransition` callbacks to log state changes.

## Related Topics

- [React Native Examples](/en/runtimes/distributions/react-native/v0.x/examples)
- [React Native API Reference](/en/runtimes/distributions/react-native/v0.x/api-reference)
