# Plotter — Animated Data Visualization for React

> A self-drawing chart — line, area, or bar — that performs its data on scroll-in: axes and gridlines fade in first like ruled paper, lines trace left to right behind a bright pen tip with the gradient fill sweeping beneath, bars spring from the baseline and settle. Dataset changes morph the marks, and a tooltipTour mode walks an active tooltip across the points once after the draw.

- Page: https://crucibleui.com/components/data/plotter
- Category: [data](https://crucibleui.com/components/data)
- Tier: pro (one-time purchase, see https://crucibleui.com/pricing)
- Engine: motion
- npm dependencies: motion

## Install

```bash
npx shadcn@latest add @crucible/plotter
```

Pro install requires adding the token-bearing `@crucible` registry to components.json (issued at https://crucibleui.com/account after purchase).

Import from `@/components/crucible/plotter`.

## Props (`PlotterProps`)

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `labels` | `string[]` | — | X-axis category labels — one per data point. |
| `series` | `PlotterSeries[]` | — | The series to plot. Multi-series draws one at a time with overlapping tails. |
| `type?` | `PlotterType` | `"line"` | Chart form. |
| `drawDuration?` | `number` | `1.8` | Seconds a single series takes to draw. |
| `drawEasing?` | `PlotterEasing` | `"ease-in-out"` | Easing for the pen stroke (named or a custom 0–1 function). |
| `stagger?` | `number` | `1.1` | Seconds between series starts — smaller overlaps the tails more. |
| `trigger?` | `PlotterTrigger` | `"view"` | What starts the draw: scroll into view, mount, or the `play` prop. |
| `inViewThreshold?` | `number` | `0.35` | IntersectionObserver threshold for `trigger="view"`. |
| `play?` | `boolean` | `false` | Starts the draw when `trigger="manual"`. |
| `morph?` | `boolean` | `true` | Morph existing marks to new values on data change (vs. snapping). |
| `morphSpring?` | `{ stiffness?: number; damping?: number }` | `{ stiffness: 120, damping: 20 }` | Spring driving the morph. |
| `gridLead?` | `number` | `0.6` | Seconds the axes + gridlines fade in before any ink lands. |
| `tooltipTour?` | `boolean` | `false` | Walk an active tooltip across the data once after the draw. |
| `tourDwell?` | `number` | `0.6` | Seconds the tour dwells on each stop (tour visits at most 12 stops). |
| `colors?` | `string[]` | — | Fallback palette for series without an explicit `color`. |
| `format?` | `(value: number) => string` | `compact en-US` | Number formatting for axis ticks and tooltip values. |
| `yTicks?` | `number` | `4` | Approximate horizontal gridline count. |
| `paused?` | `boolean` | `false` | Freezes all animation in place. |

Also accepts: `Omit<React.HTMLAttributes<HTMLDivElement>, "children">`.

## Usage example

```tsx
import { Plotter, seededWalk } from "@/components/crucible/plotter";

const LABELS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

const SERIES = [
  { name: "Series A", values: seededWalk(7, LABELS.length, { min: 24, max: 92 }), color: "#3987e5" },
  { name: "Series B", values: seededWalk(23, LABELS.length, { min: 10, max: 64 }), color: "#199e70" },
];

export default function PlotterDemo() {
  return (
    <div className="relative isolate flex h-full min-h-[360px] w-full items-center justify-center overflow-hidden rounded-xl bg-neutral-950">
      <div className="relative z-10 w-full max-w-xl px-6 py-8">
        <Plotter labels={LABELS} series={SERIES} type="area" tooltipTour />
        <p className="mt-4 text-center text-[11px] font-medium uppercase tracking-[0.2em] text-neutral-500">
          Scroll into view — the grid lands, each series draws, then the tooltip tours the data
        </p>
      </div>
    </div>
  );
}
```

## Accessibility & performance

Honors `prefers-reduced-motion` with a designed static frame or fade (never a blank box) and passes `className` through.
