# CometTrail (/docs/charts/comet-trail)

CometTrail answers "where is the value now, and where has it just been?" A bright head dot marks the current value;
behind it, a trail of recent points fades out with age, like a comet. In the interactive entry the head eases to each
new value and the old head decays into the trail, so a live stream draws a comet and a stall goes still. Opacity encodes
**age only** — the y position does the value — so the trail is recency context, never data you have to decode.

```tsx
<CometTrail data={[40, 45, 50, 55, 60, 65, 70, 72, 75, 78, 80, 84, 87]} title="Latency" width={90} />
```

## Install

```tsx
import { CometTrail } from "@microcharts/react/comet-trail";

<CometTrail data={rollingWindow} title="Latency" />
```

Setup (package + stylesheet): [Quickstart](/docs/quickstart#set-up-with-an-ai-agent) or paste [`/agent-setup.md`](/agent-setup.md) into your agent.


## Motion, and reduced motion

Motion happens **only on a data change** — there is no idle loop. When a new value arrives the head eases (~200 ms, the
library's canonical strong ease-out) from its old position to the new one and the previous head steps down into the
trail; a continuous stream produces the comet, a stalled stream simply goes still, which is itself the signal (staleness
reads as stillness). The dot jumps to the truth, eased — it never simulates phantom positions between updates. Under
`prefers-reduced-motion` the head repositions instantly (the static encoding is already complete), and the same is true
off-screen — one shared viewport check means the ease only runs while the chart is actually in view.

## When to use it

- **Good for** — a live price or metric with a little recency context, a realtime KPI that should show momentum, or
  per-stream "where is it now" in a table.
- **Avoid for** — the full history (`Sparkline`), an exact multi-point comparison (`Sparkline`, `DotPlot`), or discrete
  events (`HeartbeatBlip`).

## Sizing

`width` and `height` are viewBox units that also set the rendered pixel box — they default to `60 × 16`, sized to sit in
a table cell or beside a line of text. Omit them and drive the width from CSS to fill a column; the viewBox keeps the
aspect ratio. `trail` controls how many recent points the tail carries, which is a density decision rather than a size
one.

## Variants

```tsx
<CometTrail data={window} trail={6} />
<CometTrail data={window} label="none" />
```

## Edge cases

```tsx
<CometTrail data={[]} title="No stream yet" />
```

```tsx
<CometTrail data={[52]} title="First reading" />
```

```tsx
// trail=20 but only 4 points exist — every point shows, no padding
<CometTrail data={[40, 55, 48, 62]} trail={20} title="Short stream" />
```

Empty data draws just the frame, with "No data." as the summary. A single point has no trail to fade — just the head and
"Now 52." A `trail` larger than the data never backfills or pads: the trail simply shows every point there is.


## Why this default

`label="last"` is on because a live value without its number is a mood, not a measurement — the whole point is knowing
where it is now. Opacity encodes age and nothing else, so changing `trail` gives you more or less recency context
without ever changing the head read. The trail is capped at 20 points: past that it stops being a trail and becomes a
sparkline, which is the better tool for the full history.

## Accessibility

The accessible name is the now-value and the recent trend — **"Now 62, rising over the last 3 updates."** — or just the
value when there is a single point, as in the edge case above: **"Now 52."** Arrow keys step back through the trail ("3
updates ago: 78.") and return toward now; motion is gated on `prefers-reduced-motion`, and the trail opacity is age,
never a value you must read from fading.

The interactive entry follows the shared [interaction contract](/docs/accessibility#one-interaction-contract):
arrow keys rove between units on both axes, `Home` and `End` jump to the ends, and a click, tap, `Enter` or
`Space` selects a unit — pinning its readout so it survives blur, until you select it again or press `Escape`.
On touch, a tap pins and a drag scrubs.

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `data` (required) | `number[]` | The rolling window, oldest → newest (last = now). |
| `trail` | `number` | Points kept visible (default 12, cap 20). |
| `label` | `"last" \| "none"` | Numeral after the head (default last). |

Plus the shared grammar — `data`, `domain`, `color`, `title`, `summary`, `format` — and the layout props (`width`, `height`, `className`, `style`) that every chart accepts. Interactive entries also share `animate` and `live`, and — wherever a chart has more than one navigable unit — `onActive`, `onSelect`, `selectedIndex` and `defaultSelectedIndex`; and — wherever the chart shows a hover value — `readout`. See [the shared grammar](/docs/quickstart#the-shared-grammar).
