# Timeline

> The headless Timeline of @audio-ui/react: its parts, what each renders and owns, and their props.

```bash
npm install @audio-ui/react
```

```ts
import { adjacentPoint, clipEnd, copyRange, coverClips, duplicateClip, /* … */ } from "@audio-ui/react/timeline";
```

| Export | Kind | What it is |
| --- | --- | --- |
| `adjacentPoint` | function | The nearest of `points` strictly after `from` (`direction` 1) or strictly before it (`direction` -1), or null when there is none that way: what jumping to the next or the previous locator, or cue, needs. |
| `ClipLimits` | interface | What a clip edit keeps a clip within: the timeline's length, the shortest it may be, and its source's length. |
| `ClipValue` | interface | A clip: a stretch of a source (a recording, a pattern) placed on the timeline. |
| `clipEnd` | function | Where the clip ends on the timeline. |
| `copyRange` | function | What the stretch from `from` to `to` holds of `items`: the part of each clip inside it, moved so the stretch starts at 0. |
| `coverClips` | function | What a clip laid on a lane leaves of the clips already there: they are covered, not stacked. |
| `duplicateClip` | function | A copy of the clip placed right after it, or as late as the timeline allows when there is not room for it. |
| `FADE_SHAPES` | const | The fade shapes in the order a control steps through them. |
| `FadeShape` | type | How a fade rises or falls: evenly, quick then slow, slow then quick, or eased at both ends. |
| `fadeGain` | function | The gain a fade of `shape` has `progress` of the way through it, from 0 (silent) to 1 (full): the curve of a fade-in; a fade-out plays it backwards. |
| `insertTime` | function | Opens a stretch `length` long at `at`: everything from there moves later, and a clip across `at` is cut in two around the gap. |
| `moveClip` | function | Moves the clip to begin at `start`, keeping its length and its place in the source. |
| `nextFadeShape` | function | The shape after `shape`, going round, for a control that steps through them. |
| `removeTime` | function | Takes the stretch from `from` to `to` out of the timeline: what is in it goes, and everything after it moves back to close the gap. |
| `setClipFadeIn` | function | Sets the fade-in's length, which cannot run into the fade-out. |
| `setClipFadeOut` | function | Sets the fade-out's length, which cannot run into the fade-in. |
| `setClipFadeShape` | function | Gives the fade at `edge` the shape `shape`. |
| `splitClip` | function | Cuts the clip in two at `at`, a position on the timeline. |
| `trimClipEnd` | function | Trims the clip's end to `end`, as far as the timeline and the source allow. |
| `trimClipStart` | function | Trims the clip's start to `start`: what is cut off stays in the source, so the clip's content does not move on the timeline. |
| `Timeline.Clip` | function | A stretch of a source laid on a lane: a recording, a pattern. |
| `Timeline.ClipFade` | function | Draws a fade over the clip's content, as a DAW does: the ramp as a line from the clip's edge, as long as the fade, with what it attenuates shaded by `--clip-fade-shade` (the line's own color if it is not set). |
| `Timeline.ClipFadeHandle` | function | Sets how long one of the clip's fades lasts: by dragging, which is not on the grid, or from the keyboard through the native `<input type="range">` it holds, which carries the accessible name. |
| `Timeline.ClipHandle` | function | Trims one edge of the clip: by dragging, on the grid unless Cmd/Ctrl is held, or from the keyboard through the native `<input type="range">` it holds, which carries the accessible name. |
| `Timeline.ClipHeader` | function | The clip's title bar: dragging it moves the clip, on the grid unless Cmd/Ctrl is held, and over other lanes too. |
| `Timeline.Lane` | function | A strip along the timeline that its parts are placed on: a track, the ruler's strip, a row of markers. |
| `Timeline.Mark` | function | Something placed at `value` on a lane: a bar number on the ruler, a cue, a grid line. |
| `Timeline.Navigator` | function | The whole timeline as one bar, with the stretch the viewport shows drawn inside it as `Timeline.NavigatorWindow`: drag the window to scroll, drag one of its `Timeline.NavigatorHandle`s to zoom, double-click to show everything. |
| `Timeline.NavigatorHandle` | function | One edge of the window: dragging it zooms, holding the other edge in place. |
| `Timeline.NavigatorWindow` | function | The stretch of the timeline the viewport shows. |
| `Timeline.Playhead` | function | A marker at the playback position, on the lane it sits in. |
| `Timeline.Range` | function | A stretch of the timeline, such as a loop, a selection or a clip, laid on the lane it sits in from `value[0]` to `value[1]`. |
| `Timeline.RangeHandle` | function | Resizes one edge of the range: by dragging, on the grid unless Cmd/Ctrl is held, or from the keyboard through the native `<input type="range">` it holds, which carries the accessible name. |
| `Timeline.Root` | function | Groups the parts of a timeline and owns what they share: its length, its zoom, its grid and the playback position. |
| `Timeline.Ruler` | function | The lane that moves the position: a press jumps to the pointer and a drag scrubs, both on the grid unless Cmd/Ctrl is held; with Shift held the drag scrubs four times finer. |
| `Timeline.Track` | function | One track of the arrangement: a row holding a header beside a lane. |
| `Timeline.TrackHeader` | function | The strip beside a track's lane that names it and holds what sets it. |
| `Timeline.TrackResizeHandle` | function | Sets the track's height: by dragging, or from the keyboard through the native `<input type="range">` it holds, which carries the accessible name: the arrows move by a step (Down is taller), Page Up and Down by a large one, Home and End to the minimum and the maximum. |
| `Timeline.Viewport` | function | The scrolling window onto the timeline. |

## Anatomy

Import the primitive and assemble its parts.

```tsx
import { Timeline } from "@audio-ui/react";

<Timeline.Root>
  <Timeline.Viewport>
    <Timeline.Ruler>
      <Timeline.Mark value={0} />
      <Timeline.Playhead />
    </Timeline.Ruler>
    <Timeline.Track>
      <Timeline.TrackHeader>
        <Timeline.TrackResizeHandle />
      </Timeline.TrackHeader>
      <Timeline.Lane />
    </Timeline.Track>
    <Timeline.Lane>
      <Timeline.Range>
        <Timeline.RangeHandle edge="start" />
        <Timeline.RangeHandle edge="end" />
      </Timeline.Range>
      <Timeline.Clip>
        <Timeline.ClipHeader />
        <Timeline.ClipFade edge="in" />
        <Timeline.ClipFade edge="out" />
        <Timeline.ClipHandle edge="start" />
        <Timeline.ClipHandle edge="end" />
        <Timeline.ClipFadeHandle edge="in" />
        <Timeline.ClipFadeHandle edge="out" />
      </Timeline.Clip>
      <Timeline.Playhead />
    </Timeline.Lane>
  </Timeline.Viewport>
  <Timeline.Navigator>
    <Timeline.NavigatorWindow />
    <Timeline.NavigatorHandle edge="start" />
    <Timeline.NavigatorHandle edge="end" />
  </Timeline.Navigator>
</Timeline.Root>
```

## API reference

### Root

Groups the parts of a timeline and owns what they share: its length, its zoom, its grid and the playback position. Units are yours: seconds, beats, pulses or steps. `zoom` is how many px one unit takes; leave it unset and the timeline fits the width it is given. The position comes from `position`, or from a live `source` that the playhead follows straight in the DOM without re-rendering React. With a `snapStep`, every gesture lands on the grid unless Cmd/Ctrl is held, and `snapPoints` (the edges of other clips, the locators) pull a dragged clip or range onto them from a few px away. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `defaultPosition` | `number` | `0` | Uncontrolled starting position. |
| `defaultZoom` | `number` |  | Uncontrolled starting zoom, in px per unit. Unset, the timeline fits its width until zoomed. |
| `disabled` | `boolean` |  |  |
| `duration` | `number` | `1` | Length of the timeline, in your units. |
| `largeStep` | `number` |  | Step for Page Up/Page Down and Shift + arrow keys. Defaults to ten `step`s. |
| `maxZoom` | `number` | `Infinity` |  |
| `minZoom` | `number` | `0` |  |
| `onPositionChange` | `(value: number, eventDetails: PositionChangeEventDetails) => void` |  | Fires while the position is moved: press, drag, keyboard and input changes. |
| `onPositionCommitted` | `(value: number, eventDetails: PositionCommitEventDetails) => void` |  | Fires when a gesture that moved the position ends. |
| `onZoomChange` | `(zoom: number, eventDetails: ZoomChangeEventDetails) => void` |  | Fires when the zoom changes, already clamped. `eventDetails.cancel()` keeps the zoom where it was. |
| `position` | `number` |  | Playback position, from 0 to `duration`. |
| `snapOffset` | `number` | `0` | Where the grid's lines start, in your units. |
| `snapPoints` | `readonly number[]` |  | Places that pull a press, or a dragged clip or range, onto them from a few px away, ahead of the grid: the edges of other clips, the locators. Cmd/Ctrl lets go of them too. |
| `snapStep` | `number` | `0` | Distance between grid lines, in your units. 0 is no grid. |
| `source` | `Source` |  | A live position followed outside React; takes precedence over `position`. |
| `step` | `number` |  | Step for the arrow keys. Defaults to `snapStep`, or a hundredth of `duration`. |
| `zoom` | `number` |  | Zoom, in px per unit. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-fitted` | Whether no zoom is set, so the timeline fits the width it is given. |
| `data-scrubbing` | Whether a pointer is moving the position. |

### Navigator

The whole timeline as one bar, with the stretch the viewport shows drawn inside it as `Timeline.NavigatorWindow`: drag the window to scroll, drag one of its `Timeline.NavigatorHandle`s to zoom, double-click to show everything. Place it anywhere inside `Timeline.Root`, outside the viewport. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `getAriaValueText` | `DescribePosition` |  | Returns how a position is announced by the window and its handles. Defaults to the number. |
| `minWindowWidth` | `number` |  | The least width the window is drawn at, in px, so its handles keep room at any zoom. Dragged, the window follows the pointer, and the view follows the window. Leave it out and the window is as wide as the stretch it shows. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-fitted` | Whether no zoom is set, so the timeline fits the width it is given. |
| `data-scrubbing` | Whether a pointer is moving the position. |

The styled `TimelineNavigator` sets `minWindowWidth` to 48.

### NavigatorWindow

The stretch of the timeline the viewport shows. Dragging it scrolls; its native `<input type="range">` scrolls from the keyboard and carries its accessible name. Renders a `<div>` element.

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-fitted` | Whether no zoom is set, so the timeline fits the width it is given. |
| `data-scrubbing` | Whether a pointer is moving the position. |

### NavigatorHandle

One edge of the window: dragging it zooms, holding the other edge in place. Its native `<input type="range">` does the same from the keyboard and carries its accessible name. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `edge` | `"end" \| "start"` |  | The edge of the window this handle moves. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-fitted` | Whether no zoom is set, so the timeline fits the width it is given. |
| `data-scrubbing` | Whether a pointer is moving the position. |

### Viewport

The scrolling window onto the timeline. Cmd/Ctrl + wheel (and pinch on a trackpad) zooms around the pointer; a bare wheel scrolls as usual. Every zoom change keeps its anchor point in place, or the middle of the view when there is none. A clip moved or trimmed with the pointer held near its edges scrolls it. It reports its scroll offset and width for `Timeline.Navigator`. Renders a `<div>` element.

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-fitted` | Whether no zoom is set, so the timeline fits the width it is given. |
| `data-scrubbing` | Whether a pointer is moving the position. |

### Lane

A strip along the timeline that its parts are placed on: a track, the ruler's strip, a row of markers. Zoomed, it is as long as the timeline; fitted, it takes the width it is given and the timeline is spread across it. Its `--timeline-unit` CSS variable is the width of one unit. With `seekable`, a press on its bare area moves the position, as on the ruler, so the cursor can be put anywhere along a track; with `onSelectionChange` too, a drag from there selects a stretch of time instead of scrubbing. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `seekable` | `boolean` | `false` | Whether a press on the lane's bare area moves the position, and a drag scrubs it, on the grid unless Cmd/Ctrl is held. |
| `onSelectionChange` | `(range: readonly [number, number], eventDetails) => void` |  | With `seekable`, fires while a drag from the lane's bare area selects a stretch of time, as `[start, end]` in timeline units on the grid unless Cmd/Ctrl is held: from where the press put the position to the pointer. The drag then no longer scrubs. `eventDetails.cancel()` keeps the selection as it was. |
| `onSelectionCommitted` | `(range: readonly [number, number], eventDetails) => void` |  | Fires when a selection that changed ends. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-fitted` | Whether no zoom is set, so the timeline fits the width it is given. |
| `data-scrubbing` | Whether a pointer is moving the position. |

### Track

One track of the arrangement: a row holding a header beside a lane. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `height` | `number` |  | The height in px, or leave it out for the row to share what room there is. |
| `minHeight / maxHeight` | `number` | `32 / 480` | Bounds the height is clamped to. |
| `step / largeStep` | `number` | `8 / 32` | How far the arrows, and Page Up and Page Down, move the height. |
| `selected` | `boolean` | `false` | Whether the track is the one picked: only styling, `data-selected`. |
| `onHeightChange` | `(height \| undefined, eventDetails) => void` |  | A new height is asked for, by a drag or a key; a double-click on the handle gives the height up, which is `undefined`. `eventDetails.cancel()` refuses it. |
| `onHeightCommitted` | `(height \| undefined, eventDetails) => void` |  | A resize ended having changed the height. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-selected` | Present when the track is selected. |
| `data-resizing` | Whether a pointer is resizing the track. |

### TrackHeader

The strip beside a track's lane that names it and holds what sets it. It stays at the left edge while the lane scrolls under it, at the stacking level of the `--timeline-track-header-z` CSS variable (20): raise it while the header is hovered or focused if it shows something that reaches into the next row, such as a value readout. It carries the track's `data-selected` and `data-resizing`. Renders a `<div>` element.

### TrackResizeHandle

Sets the track's height: by dragging, or from the keyboard through the native `<input type="range">` it holds, which carries the accessible name. The arrows move by a step (Down is taller), Page Up and Page Down by a large one, Home and End to the minimum and the maximum. Place it along the track's lower edge. A double-click clears the height, so the track shares the room again. Renders a `<div>` element.

### Ruler

The lane that moves the position: a press jumps to the pointer and a drag scrubs, both on the grid unless Cmd/Ctrl is held; with Shift held the drag scrubs four times finer. With `onSelectionChange`, a drag that starts with Shift held selects a stretch instead, to loop. It holds the native `<input type="range">` that takes focus, handles the keyboard and carries the accessible name (`aria-label` / `aria-labelledby`). Place `Timeline.Mark`s in it for its labels. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `getAriaValueText` | `DescribePosition` |  | Returns how the position is announced, e.g. `"bar 3, beat 2"`. Defaults to the number. |
| `onSelectionChange` | `(range: readonly [number, number], eventDetails) => void` |  | Fires while a stretch is selected by dragging with Shift held, as `[start, end]` in timeline units on the grid unless Cmd/Ctrl is held: feed it to a `Timeline.Range` as a loop. A plain press and drag still move the position. `eventDetails.cancel()` keeps the selection as it was. |
| `onSelectionCommitted` | `(range: readonly [number, number], eventDetails) => void` |  | Fires when a selection that changed ends. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-fitted` | Whether no zoom is set, so the timeline fits the width it is given. |
| `data-scrubbing` | Whether a pointer is moving the position. |

### Mark

Something placed at `value` on a lane: a bar number on the ruler, a cue, a grid line. Its children are its label. With `onValueChange` or `onValueCommitted` it moves: a drag takes it along the lane, on the grid unless Cmd/Ctrl is held, landing on a `snapPoints` place within a few px, and Left and Right on something focused inside it move it by `step`. A press that stays one keeps its click; a drag does not click.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `number` |  | Where the mark sits, in the timeline's units. |
| `onValueChange` | `(value: number, eventDetails) => void` |  | Fires as the mark moves, on each step of a drag and each arrow key. With it or `onValueCommitted`, the mark can be moved. |
| `onValueCommitted` | `(value: number, eventDetails) => void` |  | Fires once a drag or an arrow key has moved it, with where it landed. |
| `step` | `number` |  | How far Left and Right move it. Defaults to the timeline's `step`. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-dragging` | Whether a pointer is moving the mark. |

### Range

A stretch of the timeline, such as a loop, a selection or a clip, laid on the lane it sits in from `value[0]` to `value[1]`. Dragging its body moves it, on the grid unless Cmd/Ctrl is held; add a `Timeline.RangeHandle` per edge to resize it. With `drawable`, dragging across empty lane draws a new range. Its own native `<input type="range">` moves it from the keyboard and carries its accessible name (`aria-label` / `aria-labelledby`): Left and Right by a step, Up and Down by its own length, and with Cmd/Ctrl, Left and Right shorten or lengthen it by a step while Up and Down double or halve it. A drag lands an edge on a `snapPoints` place within a few px. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `defaultValue` | `Value` |  | Uncontrolled starting range. Defaults to the whole timeline. |
| `disabled` | `boolean` |  |  |
| `drawable` | `boolean` | `false` | Whether dragging across empty lane draws a new range. |
| `getAriaValueText` | `DescribePosition` |  | Returns how a position is announced, for the range and its handles. Defaults to the number. |
| `minDrawnWidth` | `number` |  | The least room it is drawn with, in px, so its handles keep apart at any zoom. From twice that it is as wide as it is long; under that it stays wider, and a drag of its end follows what is drawn. Leave it out and it is always as wide as it is long. |
| `minLength` | `number` |  | The shortest the range can be, in the timeline's units. Defaults to the grid step. |
| `movable` | `boolean` | `true` | Whether dragging the body, or its keys, moves the range. |
| `onValueChange` | `(value: Value, eventDetails: ChangeEventDetails) => void` |  | Fires while the range is moved, resized or drawn. |
| `onValueCommitted` | `(value: Value, eventDetails: CommitEventDetails) => void` |  | Fires when a gesture that changed the range ends. |
| `value` | `Value` |  | The range, as `[start, end]` in the timeline's units. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-dragging` | Whether a pointer is moving, resizing or drawing the range. |

### RangeHandle

Resizes one edge of the range: by dragging, on the grid unless Cmd/Ctrl is held, or from the keyboard through the native `<input type="range">` it holds, which carries the accessible name. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `edge` | `"end" \| "start"` |  | The edge of the range this handle resizes. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-dragging` | Whether a pointer is moving, resizing or drawing the range. |

### Clip

A stretch of a source laid on a lane. Dragging its `Timeline.ClipHeader` moves it, on the grid unless Cmd/Ctrl is held, and over other lanes too, or to the nearest when the pointer is off them; held near an edge of the view, a move or a trim scrolls it, and a move scrolls down to the lanes below too; pressing its body selects it and puts the cursor there. Add a `Timeline.ClipHandle` per edge to trim it and a `Timeline.ClipFadeHandle` per fade. It sets `--clip-offset`, `--clip-source-length`, `--clip-fade-in` and `--clip-fade-out` for its content, and `--clip-fade-in-max` and `--clip-fade-out-max`, how long each fade can grow, to draw the limit of a fade being dragged (`data-fading`), and `--clip-unit`, the width of one unit for what is placed inside it. Its own native `<input type="range">` moves it from the keyboard and carries its accessible name (`aria-label` / `aria-labelledby`); Delete and Backspace on it call `onRemove`. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `Value` |  | The clip: `{ start, length, offset, fadeIn, fadeOut }`, all in the timeline's units. |
| `defaultValue` | `Value` |  | Uncontrolled starting clip. Defaults to the whole timeline. |
| `sourceLength` | `number` |  | How long the source is, in the timeline's units: trimming stops where it runs out. Defaults to no limit. |
| `selected` | `boolean` |  | Whether the clip is selected. |
| `defaultSelected` | `boolean` | `false` | Whether the clip starts selected, when `selected` is not set. |
| `additive` | `boolean` | `false` | Whether every press is reported, as one with Shift, Cmd or Ctrl held is: for building a selection where there are no modifier keys, such as a touch screen. |
| `onSelectedChange` | `(selected: boolean, eventDetails) => void` |  | Fires when a press on the clip selects it, and again on a press with Shift, Cmd or Ctrl held (or any, when `additive`), which `eventDetails.event` carries. |
| `onValueChange` | `(value: Value, eventDetails: ChangeEventDetails) => void` |  | Fires while the clip is moved, trimmed or faded. |
| `onValueCommitted` | `(value: Value, eventDetails: CommitEventDetails) => void` |  | Fires when a gesture that changed the clip ends, or one that dropped it on another lane. |
| `onRemove` | `(eventDetails) => void` |  | Fires when Delete or Backspace is pressed on the clip: removing it is up to you. |
| `minLength` | `number` |  | The shortest the clip can be trimmed to, in the timeline's units. Defaults to the grid step. |
| `movable` | `boolean` | `true` | Whether dragging the header, or the keys, moves the clip. |
| `getAriaValueText` | `DescribePosition` |  | Returns how a position is announced. Defaults to the number. |
| `disabled` | `boolean` |  |  |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-dragging` | Whether a pointer is moving, trimming or fading the clip. |
| `data-fading` | `"in"` or `"out"`: the fade a pointer is dragging. |
| `data-selected` | Present when the clip is selected. |

### ClipHeader

The clip's title bar: dragging it moves the clip, on the grid unless Cmd/Ctrl is held, and over other lanes too. The rest of the clip is its body, where a press puts the cursor. Place it along the clip's top and put the clip's name in it. Renders a `<div>` element.

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-dragging` | Whether a pointer is moving, trimming or fading the clip. |
| `data-selected` | Present when the clip is selected. |

### ClipHandle

Trims one edge of the clip: by dragging, on the grid unless Cmd/Ctrl is held, or from the keyboard through the native `<input type="range">` it holds, which carries the accessible name. Trimming the start moves where in the source the clip begins and leaves its content where it is; trimming the end stops where the source or the timeline does. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `edge` | `"end" \| "start"` |  | The edge of the clip this handle trims. |

### ClipFadeHandle

Sets how long one of the clip's fades lasts: by dragging, or from the keyboard through the native `<input type="range">` it holds, which carries the accessible name. Double-clicking it, or pressing Enter on its input, steps the fade through its shapes, and Delete or Backspace takes the fade away. It sits where its fade ends, at the clip's top edge. The two fades cannot overlap. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `edge` | `"in" \| "out"` |  | The fade of the clip this handle sets: the one at its start or at its end. Double-click it, or press Enter on its input, to step the fade through its shapes. |

### ClipFade

Draws a fade over the clip's content, as a DAW does: the ramp as a line from the clip's edge, as long as the fade, with what it attenuates lightly shaded. It is hidden while its fade is empty and ignores the pointer. Its color is the `color` it is given. Renders an `<svg>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `edge` | `"in" \| "out"` |  | The fade of the clip this draws. |

### Playhead

A marker at the playback position, on the lane it sits in. It follows the position straight in the DOM, through its own `--timeline-offset` CSS variable, so a playhead moving every frame never re-renders React. Renders a `<div>` element.

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-fitted` | Whether no zoom is set, so the timeline fits the width it is given. |
| `data-scrubbing` | Whether a pointer is moving the position. |

### Mark

Something placed at `value` on a lane: a bar number on the ruler, a cue, a grid line. Its children are its label. Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `number` |  | Where the mark sits, in the timeline's units. |

**Data attributes**

| Attribute | Description |
| --- | --- |
| `data-disabled` | Present when disabled. |
| `data-fitted` | Whether no zoom is set, so the timeline fits the width it is given. |
| `data-scrubbing` | Whether a pointer is moving the position. |

## Styled

The registry's styled Arrangement, its usage and interaction: [Arrangement](/docs/components/base/arrangement).
