# transition() (/docs/api/transition)

> Create one seekable transition between two states of the same chart type.

```ts
import { transition } from 'visdelta/transition';

function transition(
  from: Visualization,
  to: Visualization,
  options: TransitionOptions,
): Promise<VisualizationTransition>;
```

`transition()` resolves and loads both states' data, computes their
[`delta()`](/docs/api/core#delta), loads the chart's renderer and mounts a
seekable route into `options.target`. If setup fails, the target's previous
contents are restored.

```ts
const change = await transition(from, to, {
  target: '#chart',
  data: { sales: rows },
  height: 420,
  chartStyle: paperChartStyle,
});
```

`from` and `to` can be builder states or plain specs; plain specs need a
[registered chart module](/docs/concepts/chart-states#plain-specs).

## TransitionOptions [#transitionoptions]

### TransitionOptions

| Prop          | Type                      | Description                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data?`       | `Record<string, unknown>` | Named sources for visualizations that use .data("name").                                                                                                                                                                                                                                                                                                                                                                        |
| `width?`      | `union`                   | Outer width of the canvas (the SVG), margins included, as in Observable Plot. A number is a fixed width in pixels: a container narrower than that overflows instead of the chart shrinking. `"auto"` makes the canvas exactly the container's content width and re-fits when it changes; the figure's own border gives way on that axis. Omitted: the container's width, inside the figure's own border.                        |
| `height?`     | `union`                   | Outer height of the canvas (the SVG), margins included. A number is a fixed height in pixels and overrides the chart's default. `"auto"` makes the canvas exactly the container's content height and re-fits when it changes; the figure's border gives way. The container needs a height of its own (a fixed height, a flex or grid track), otherwise the chart keeps its default height. Omitted: the chart's default height. |
| `target`      | `Target`                  | Where the chart renders. Required: the library never guesses a host element.                                                                                                                                                                                                                                                                                                                                                    |
| `chartStyle?` | `object`                  | Structural chart presentation; CSS can target its generated style class.                                                                                                                                                                                                                                                                                                                                                        |

### Canvas size [#canvas-size]

`width` and `height` are the outer size of the canvas (the SVG), margins included,
as in Observable Plot. Each takes a number of CSS pixels or `"auto"`.

| Option   | Omitted                                                                   | A number                                                          | `"auto"`                                                                                                  |
| -------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `width`  | The container's width, inside the figure's own border, re-fit on change.  | Exactly this wide. A narrower container overflows; nothing is clipped. | Exactly the container's content width, re-fit when it changes.                                            |
| `height` | The chart's own height (an authored `height`, else 500).                  | Exactly this tall; overrides the chart's own height.              | Exactly the container's content height, re-fit when it changes. The container needs a height of its own.  |

```ts
// Fixed: always 640 × 360, whatever the container is.
await transition(from, to, { target: '#chart', width: 640, height: 360 });

// Fit: follow the container, e.g. a resizable or floating panel with a height.
await transition(from, to, { target: '#panel', width: 'auto', height: 'auto' });
```

A chart is wrapped in a figure that a theme may give a border. A number is always
the canvas itself, so that chrome sits outside it. A top
legend also sits outside the canvas, above it, and never counts toward `width` or
`height`. For `"auto"` the figure's border on that axis gives way and the legend
takes its room from the container, so the canvas fills exactly what
is left and nothing overflows the container. The legend is a second
`<svg class="vd-legend-svg">` that exists only while there is a legend, after the
canvas in the document, so `querySelector('svg')` is still the canvas. A
transition opens or closes the legend space with playback progress. In Fit
mode the canvas uses the remaining height.
A style with `legendPosition: 'right'` keeps its legend inside the canvas.

`height: 'auto'` reads the room the container gives the chart. A container with
no height of its own (its height comes from its content) gives none, so the
chart keeps its own height instead of growing in a loop. Give the container a
fixed height, or make it a flex or grid track. An explicit `height` also
releases the view's default `min-height`, so it is the canvas height rather
than a floor under it.

`target` is a CSS selector or an element. The transition owns its contents until
`destroy()`.

## VisualizationTransition [#visualizationtransition]

The returned controller.

### VisualizationTransition

| Prop              | Type       | Description                                                                                                                                                                                                    |
| ----------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `from`            | `object`   | Defensive copy of the resolved start state.                                                                                                                                                                    |
| `to`              | `object`   | Defensive copy of the resolved end state.                                                                                                                                                                      |
| `delta`           | `object`   | Semantic difference between the resolved endpoints, as returned by delta().                                                                                                                                    |
| `view`            | `object`   | The mounted chart-view element.                                                                                                                                                                                |
| `value`           | `number`   | Current progress from 0 to 1.                                                                                                                                                                                  |
| `progress`        | `function` | Synchronously display a frame. Direction is inferred from the previous value.                                                                                                                                  |
| `play`            | `function` | Plays from 0 to 1 by default. Returns this controller for chaining.                                                                                                                                            |
| `pause`           | `function` | Stop owned playback at the current frame.                                                                                                                                                                      |
| `resize`          | `function` | Recompile at the container's current size/theme, retaining progress and data. `width` and `height` change the requested canvas size as in `TransitionOptions`; a dimension left out keeps its current request. |
| `stageCount`      | `function` | Serial route stages planned for this pair (at least 1). Stages split progress equally and `play({ duration })` gives each one `duration` ms, so a full play lasts `stageCount() × duration`.                   |
| `stageChanges`    | `function` | Semantic changes for each actual route stage, in authored playback order.                                                                                                                                      |
| `stageOperations` | `function` | Exact planner operation per route stage; undefined for direct or chart-refined stages.                                                                                                                         |
| `inspect`         | `function` | Read compiled SVG property tracks without pausing or seeking playback.                                                                                                                                         |
| `destroy`         | `function` | Stop playback and remove the mounted transition. The controller cannot be used afterwards.                                                                                                                     |

| Method                     | Returns     | Notes                                                                     |
| -------------------------- | ----------- | ------------------------------------------------------------------------- |
| `progress(value)`          | controller  | Pauses playback and draws one frame. Finite values clamp to `[0, 1]`.      |
| `play(options?)`           | controller  | Animates from `from` to `to`; see `PlayOptions`.                           |
| `pause()`                  | controller  | Stops playback at the current frame.                                      |
| `resize(options?)`         | controller  | Recompiles at the container's size and current theme, keeping progress. `{ width, height }` change the requested canvas size; a dimension left out keeps its request. |
| `stageCount()`             | `number`    | Serial route stages VisDelta planned for the pair (at least 1). They split progress equally, and `play({ duration })` gives each stage `duration` ms, so a full play lasts `stageCount() × duration`. |
| `destroy()`                | `void`      | Stops playback, disconnects observers and removes the chart.              |

Pair controllers observe their container's width and resize automatically.

## PlayOptions [#playoptions]

### PlayOptions

| Prop        | Type     | Description                                               |
| ----------- | -------- | --------------------------------------------------------- |
| `duration?` | `number` | Milliseconds for one serial route stage. Defaults to 800. |
| `from?`     | `number` | Start progress, clamped to [0, 1]. Defaults to 0.         |
| `to?`       | `number` | End progress, clamped to [0, 1]. Defaults to 1.           |

```ts
change.play();                       // 0 → 1
change.play({ from: 1, to: 0 });     // reverse
change.play({ from: change.value });  // resume
```

## Errors [#errors]

| Message                                              | Cause                                    |
| ---------------------------------------------------- | ---------------------------------------- |
| `transition() requires two states of the same chart type.` | Endpoints from different chart families |
| `VisDelta needs a target: …`                         | `options.target` is missing              |
| `VisDelta target not found: …`                       | The selector matched no element          |
| `transition(): missing dataset "…"`                  | A named source is not in `options.data`  |
| `progress must be a finite number.`                  | `progress()` received `NaN` or `Infinity` |
| `duration must be a finite non-negative number.`     | Invalid `play({ duration })`             |
| `This transition has been destroyed.`                | The controller was used after `destroy()` |

See [Troubleshooting](/docs/guides/troubleshooting) for fixes.

## Inspect compiled motion [#inspect-compiled-motion]

`await change.inspect()` returns the compiled SVG phases and their recorded
property tracks, without pausing playback or changing its position. Each phase
has normalized `start`, `end`, and `properties`; each property identifies its
DOM `node`, `name`, `kind`, scheduled interval within the phase, and `from` / `to`
values at the **phase boundaries**. These are not necessarily the endpoints of
a delayed or chained property interval.

`await sequence.inspect()` reads the active leg. Refresh after resize or theme
changes. Borrowed nodes must not be mutated; reconstruction, resize and destroy
invalidate them. Custom tweens are explicitly opaque. Immediate DOM writes
and insertions/removals are outside this
recorded SVG report. The playground's **Inspect stages** control displays these
tracks alongside the timeline, including the coverage limits.

When height is `"auto"` (Fit), a constrained container hides the legend to
preserve the main canvas. The canvas budget is half the available width, capped
at 200 pixels. The legend returns when space allows; fixed pixel heights retain it.

`change.stageChanges()` reports the semantic changes between each actual pair of
planned intermediate states, in authored playback order. The playground uses
these to label the stage strip directly. It does not split the full pair's delta
into guessed phases.

`transition.stageOperations()` returns the exact planner operation for each route stage, in authored playback order. Each entry carries the slot path, action, and previous/next declaration values. Direct and chart-refined stages return `undefined`; semantic categories remain available through `stageChanges()`. These operations do not prove visible motion or alter stage timing.

Each inspected property includes `ancestry`, an array of `{ tag, classes }` from
its SVG root to the animated element. It is captured with the phase DOM restored,
before seeking can detach entering or exiting nodes. This snapshot remains readable
after inspection restores the visible frame. Repeated elements can share an ancestry;
`selector` retains the phase-specific positional path. An empty ancestry means no
complete SVG path was available.
