# OrbitStatus (/docs/charts/orbit-status)

OrbitStatus encodes two numbers in one glyph. The orbit radius is latency, so a wider orbit is a slower service, and the
orbit's dash density is the call rate, so denser dashes mean more calls. In the interactive entry the satellite orbits
at a speed that mirrors the rate. Both channels are low-precision ambient reads; for exact numbers use a `Sparkline` for
latency and a `Delta` or `MiniBar` for rate.

Each channel reads against a stated reference. The radius spans 0–1000 ms, or 0–2× `threshold` when you set one, which
lands the alert edge on the halfway orbit. Dash density steps by decade: under 1 call/s, then 1, 10, 100, and 1000 or
more. Pass `domain` and `rateDomain` when you know the range you care about, because a service that answers in 40–90 ms
reads better on its own frame than on the second-wide default.

```tsx
<OrbitStatus latency={240} rate={12} latencyDomain={[0, 500]} rateDomain={[0, 20]} title="Payments API" size={40} />
```

## Install

```tsx
import { OrbitStatus } from "@microcharts/react/orbit-status";

<OrbitStatus
  latency={240}
  rate={12}
  latencyDomain={[0, 500]}
  rateDomain={[0, 20]}
  title="Payments API"
/>
```

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

## Try it

```tsx
import { OrbitStatus } from "@microcharts/react/orbit-status/interactive";

<OrbitStatus
  latency={240}
  rate={12}
  latencyDomain={[0, 500]}
  rateDomain={[0, 20]}
/>
```

## Motion, and reduced motion

The satellite's angular speed is quantized to the same five steps as the static dash density, so the motion and the
still frame decode identically. Rate lives in the dashes as well as the spin, which is what lets a paused satellite
still carry both variables. This is the deliberate idle-loop exception, allowed because the loop rate is the datum. It
pauses off-screen and, under `prefers-reduced-motion`, does not spin at all: the dash density already carries the rate.
Read the satellite's speed, not its angular position; the position encodes nothing.

## When to use it

Use it for a live dependency health dot in a service table, for latency and rate together in one small mark, or for an
infra status read. For exact latency or a trend over time use `Sparkline`; for exact rate use `Delta` or `MiniBar`.

## Sizing

One `size` prop, in viewBox units, sets the orbit box — it defaults to `20`. There is no separate `width`/`height`: the
glyph is square, and the rendered box widens only by the gutter a `label` reserves. `fontSize` follows `size` unless you
set it.

## Variants

```tsx
<OrbitStatus latency={340} rate={8} threshold={300} latencyDomain={[0, 500]} rateDomain={[0, 20]} />
<OrbitStatus latency={100} rate={0} latencyDomain={[0, 500]} rateDomain={[0, 20]} />
```

```tsx
<OrbitStatus
  latency={1240}
  rate={12}
  latencyDomain={[0, 2000]}
  rateDomain={[0, 20]}
  label="latency"
  locale="de-DE"
/>
```

## Edge cases

```tsx
<OrbitStatus latency={NaN} rate={5} title="Unreachable" />
```

```tsx
<OrbitStatus latency={90} rate={0} latencyDomain={[0, 500]} rateDomain={[0, 20]} />
```

An unknown latency or rate renders gray, drops the satellite, and stops the spin, so an unreachable dependency never
looks healthy. A rate of `0` draws a solid, dash-free orbit. At `threshold` the satellite doubles in size. The rate is
quantized to five ordinal steps in both renderings (five dash counts and five angular periods), and radius and speed
read from the same domains in the static and interactive frames.

## Four homes

**In a sentence**

```tsx
<p>
  Payments API health{" "}
  <span className="mc-inline">
    <OrbitStatus latency={240} rate={12} latencyDomain={[0, 500]} rateDomain={[0, 20]} size={16} summary={false} />
  </span>{" "}
  — 240 ms latency, 12 req/s, orbit stable.
</p>
```

**In a table cell**

```tsx
<td>
  <OrbitStatus latency={240} rate={12} latencyDomain={[0, 500]} rateDomain={[0, 20]} size={18} summary={false} />
</td>
```

**In a KPI card**

```tsx
<div className="kpi">
  <span className="figure">240ms</span>
  <span className="unit">· 12 rps</span>
  <OrbitStatus latency={240} rate={12} latencyDomain={[0, 500]} rateDomain={[0, 20]} />
</div>
```

**In a tab header**

```tsx
<button className="tab">
  payments <OrbitStatus latency={240} rate={12} latencyDomain={[0, 500]} rateDomain={[0, 20]} />
</button>
```

## Accessibility

The accessible name is both variables with units — **"240ms latency at 12 calls/s."** — plus "— above threshold" when
the latency crosses `threshold`, or **"Latency unknown."** when a value is missing. The satellite's size and the summary
carry the threshold state, never color alone. Motion is gated on `prefers-reduced-motion`, and the live region announces
threshold crossings only.

This chart is a single unit, so there is nothing to rove between: a click, tap, `Enter` or `Space` selects it
and fires `onSelect`, and no selection stays pinned. That is the scalar half of the shared
[interaction contract](/docs/accessibility#one-interaction-contract).
Hover or focus also reveals the reading itself in a floating chip, for the sizes and label modes where the mark
does not print it; `readout={false}` drops the chip and keeps everything else.

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `latency` (required) | `number` | Orbit radius, on the latency reference below. |
| `rate` (required) | `number` | Dash density / satellite speed. |
| `domain` | `[number, number]` | Latency extent (default [0, 2·threshold], else [0, 1000] ms). |
| `latencyDomain` | `[number, number]` | The same extent under its older name. |
| `rateDomain` | `[number, number]` | Rate extent (default: one dash step per decade). |
| `threshold` | `number` | Latency threshold: at/above it the satellite doubles + the summary flags it. |
| `size` | `number` | Orbit box edge in viewBox units (default 20). |
| `fontSize` | `number` | Type size of the gutter label, in viewBox units. Defaults from `size`. |

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).
