# Progress (/docs/concepts/progress)

> A transition is a function of one number. Play, pause and seek all move that number.

A transition has one input: progress, from `0` (state A) to `1` (state B).

```ts
change.progress(0);     // A
change.progress(0.5);   // halfway
change.progress(1);     // B
change.value;           // where it is now
```

`progress()` draws that frame immediately and stops any playback. You can seek
in any order. Ordinary reversible routes reuse the same frames backward; Unit's opt-in `directionalEase()` is a documented exception.

## Play [#play]

```ts
change.play();                     // 0 → 1
change.play({ duration: 1200 });   // slower
change.play({ from: 1, to: 0 });   // backward
change.play({ from: change.value }); // carry on from here
```

`play()` starts at `0` unless you say otherwise, and `pause()` stops on the
current frame.

`duration` is per **stage**. A route with one stop has two stages, so
`{ duration: 800 }` takes 1600 ms.

## Sequences count in states [#sequences-count-in-states]

For a [`sequence()`](/docs/api/sequence), progress runs from `0` to the number
of states minus one. `1.5` is halfway between the second and third state.
Whole numbers always land exactly on a state you wrote.

## States, legs and stages [#states-legs-and-stages]

For authored states `[A, B, C]`, the two legs are `A → B` and `B → C`.
A chart may insert intermediate states and rendered phases *inside* either leg;
these do not add new integer positions to a sequence.

| Sequence position | Location |
| --- | --- |
| `0` | Authored A |
| `0.5` | Halfway through the complete A → B leg |
| `1` | Authored B |
| `1.5` | Halfway through the complete B → C leg |
| `2` | Authored C |

A pair controller's route stages split its 0..1 progress range equally.
`inspect()` gives the actual compiled phase intervals inside that range. A
semantic action can span several phases; neither the number of actions nor
`states.length` is a phase count. If the two legs contain 2 and 3 serial route
stages, `play({ duration: 800 })` takes `(2 + 3) × 800 = 4000 ms` for the
whole sequence. The midpoint of a leg is not necessarily half of its semantic
operations.

`play()` returns its controller, so `await change.play()` does **not** wait for
completion. Await `transition()` or `sequence()` to prepare a controller, then
read `value` while playback runs. The [scroll template](/docs/guides/scroll-template)
drives progress externally and never assumes `play()` is a Promise.

## Resize and clean up [#resize-and-clean-up]

A transition follows its container's width on its own. Call `resize()` after a
theme change, or `resize({ height: 480 })` to change the height. Call
`destroy()` when the chart leaves the page.
