> ## Documentation Index
> Fetch the complete documentation index at: https://docs.graphy.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How a chart is built

Every chart in the Graphy SDK is a **spec** — a plain, immutable object you build by folding parts together.

## The builder pipeline

You start a spec with `createSpec` and fold parts onto it with `pipe`. Each part is a small tagged object produced by a builder (`geom.*`, `scale.*`, `coord.*`, `config`, …):

```tsx theme={null}
import { createSpec, pipe, geom, scale } from '@graphysdk/react';

const spec = pipe(
  createSpec({ x: 'month', y: 'revenue' }),
  geom.line(),
  scale.x(),
  scale.y()
);
```

`pipe(spec, ...parts)` returns a **new** spec with each part folded in, left to right — it never mutates. Each kind folds in its own way:

| Kind | How it folds |
| - | - |
| `geom.*`, `scale.*`, `transform.*`, `highlight` | Appended to a list |
| `mapping` | Shallow-merges over the current mapping |
| `config` | Deep-merges over the current config |
| `coord` | Overwrites — one coord per spec, the last one wins |
| `styles` | Becomes the new stylesheet, with the previous one nested into its `extends` |

Two of those are worth reading twice. `coord` **overwrites**, so piping `coord.polar({ innerRadius: 0.5 })` after `coord.polar({ theta: 'y' })` leaves you with the inner radius and no `theta` — pass both params in one call. And a piped `styles(...)` sits **above** everything piped before it, so a later stylesheet wins where the two declare the same property.

Because a spec is a plain object, you can build it up conditionally, share fragments across charts, and [store or serialize it](/sdk-next/concepts/serializable-spec).

```tsx theme={null}
import { createSpec, pipe, geom, scale, stat } from '@graphysdk/react';

declare const showAverage: boolean;

// Build in stages — each call returns a new spec.
let spec = createSpec({ x: 'month', y: 'revenue' });
spec = pipe(spec, geom.line(), scale.x(), scale.y());
if (showAverage) {
  spec = pipe(spec, geom.rule({ stat: stat.mean() }));
}
```

## The parts of a spec

A spec brings together these parts. Each has its own page:

| Part | What it decides | Builder |
| - | - | - |
| [Mapping](/sdk-next/concepts/mappings) | Which data columns feed which aesthetics | `mapping`, `createSpec` |
| [Geoms](/sdk-next/concepts/geoms) | The shapes drawn — line, bar, point, area, rule | `geom.*` |
| [Scales](/sdk-next/concepts/scales) | How data values become positions, colors and sizes | `scale.*` |
| [Coordinate systems](/sdk-next/concepts/coordinate-systems) | The plane observations are drawn in | `coord.*` |
| [Statistics](/sdk-next/advanced/statistics) | Per-layer summaries (count, sum, mean, smoothing) | `stat.*` |
| [Transforms](/sdk-next/advanced/transforms) | Reshaping the data before it's drawn | `transform.*` |
| [Styles](/sdk-next/config/styling) | How the marks and chart furniture are painted | `styles`, `style.*` |
| [Highlights](/sdk-next/emphasis/highlights) | Which observations are called out | `highlight` |
| [Annotations](/sdk-next/emphasis/annotations) | Text, arrows and brackets drawn over the plot | `annotation.*` |

Plus [configuration](/sdk-next/config/index) (`config`) for chart chrome — titles, axes, legend, layout.

## Compile, then render

A spec is a *description*; it isn't yet pixels. Turning it into a chart happens in two stages, one per package:

```mermaid theme={null}
flowchart LR
  S[Spec] --> C[viz-engine: compile]
  D[Data] --> C
  C --> R[Scene]
  R --> P[react-renderer: paint]
  P --> SVG[SVG chart]
```

1. **Compile (`@graphysdk/viz-engine`).** The engine takes your spec plus your data and produces a `Scene`: scales are resolved to concrete domains, statistics are run, every observation is placed in a normalized `[0,1]` position space, the stylesheet is validated and its `token()` references are inlined, and guides (axes, legend) are worked out. This stage is pure data-in, data-out — no DOM. It is also what makes a styled spec serializable: paint comes out the far side as plain values.
2. **Render (`@graphysdk/react-renderer`).** The renderer takes the `Scene` and paints it: it lays out pixel rectangles, formats numbers and dates for the locale, picks the light or dark half of every color pair, and wires up hover and animation.

In a React app you don't call the compiler yourself — `<GraphProvider>` does it for you and recompiles when the spec or data change. The `colorScheme` is resolved as the chart is read rather than at compile time, so switching it costs nothing:

```tsx theme={null}
import { GraphProvider, GraphRenderer } from '@graphysdk/react';

<GraphProvider spec={spec} data={data} colorScheme="light">
  <GraphRenderer />
</GraphProvider>;
```

## Why the split matters

The split between the two packages shapes how you use the SDK:

* **Data lives outside the spec.** A spec references columns by name; the actual rows are passed to `<GraphProvider>` separately. One spec can draw many datasets.
* **The compiler never formats.** It emits raw values and *descriptors*; the renderer turns them into locale-aware text. That's why formatting options live on the renderer side.
* **Scales are resolved once, at compile time.** This is why you declare scales explicitly in the spec — the engine can't paint a position it was never told how to compute.

Authoring concerns — mapping, geoms, scales, stats, and the [stylesheet](/sdk-next/config/styling) that paints the marks — live in the engine; presentation concerns — layout, formatting, interactivity, and chrome theme — live in the renderer. Both are imported from `@graphysdk/react`.

## Next

* [Scales](/sdk-next/concepts/scales) — the one part you must always declare
* [Serializable spec](/sdk-next/concepts/serializable-spec) — a spec is plain JSON you can persist and reload


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.