# Architecture

Récit keeps a single chain, whatever the output:

```text
Markdown / MDX  ──parse──►  Story (a list of Scenes)  ──render──►  format
```

A **scene** is the common unit: a slide in a deck, a shot in a video, a section in a report, a panel
in a webtoon, a chapter in a book.

## From source to formats

<Mermaid
  chart={`
flowchart TB
  src["story.md / .mdx"] --> core
  cfg["recit.config.ts"] --> core
  core["<b>@recit/core</b><br/>scan, front matter, scenes, directives, AST<br/>defineConfig / mergeConfig, theme tokens<br/>rules: density, accessibility, diagnostics"]
  core --> story(["Story { meta, settings, scenes }"])
  story --> deck & sites & motion & report & more
  deck["<b>@recit/deck</b><br/>slides, presenter, HTML / PDF"]
  sites["<b>@recit/site-stories</b><br/>routes, embeds, Pagefind index"]
  motion["<b>@recit/motion</b><br/>film schema and timing<br/><b>@recit/motion-blocks</b> animated blocks<br/><b>@recit/motion-render</b> MP4 and stills"]
  report["<b>@recit/report</b> (planned)<br/>sections, PDF"]
  more["toon, book, roadmap,<br/>calendar, stories"]
  story --> mcp["<b>@recit/mcp</b><br/>build, validate and render from an agent"]
`}
/>

Around the chain, in every format:

- `@recit/components`: the same Callout, Grid, Code, Mermaid… everywhere
- `@recit/theme`: tokens and the CSS of each format
- `@recit/cli`: the `recit` command — every one of them is on the
  [CLI reference](/documentation/reference/cli), which this page does not copy

The same compiled HTML is displayed by `recit dev`, `recit build`, the HTML export, the PDF and the
sites: a deck looks the same everywhere.

## The Story model

The compiler produces a `Story`. Fields specific to a format live under a dedicated key: the core
knows no format.

```ts
type StoryFormat =
  | "deck"
  | "motion"
  | "docs"
  | "report"
  | "toon"
  | "book"
  | "roadmap"
  | "calendar"
  | "stories";

type Story = {
  version: 1;
  format: StoryFormat; // front matter `format:`, "deck" by default
  meta: { title: string; description?: string; author?: string; lang: string };
  settings: ResolvedConfig; // recit.config.ts + front matter, after mergeConfig
  design: { width: number; height: number; aspectRatio: string };
  themeCss: string;
  scenes: Scene[];
  diagnostics: Diagnostic[];
  summary: { totalDurationMs: number; formattedTotalDuration: string };
};

type Scene = {
  id: string; // explicit `id=`, otherwise s1, s2…
  index: number;
  source: { file: string; line: number; endLine: number }; // for diagnostics
  attrs: Record<string, string>; // separator attributes: layout, cols…
  html: string; // sanitized HTML (deck, docs)
  mdast?: Root; // kept for formats that reinterpret the scene (motion)
  steps: number;
  notesHtml?: string;
  durationMs?: number;
  density: DensityReport;
  accessibility: A11yReport;
};
```

- The **deck** uses `scene.html`, `steps` and `notesHtml`.
- The **motion** format will read `scene.mdast` and `scene.attrs` to build its shots.
- MDX components are compiled by the CLI or by Vite, one module per scene
  (`<file>.recit-scene-N.jsx`).

:::note

`compileDeck`, `CompiledDeck` and `CompiledSlide`, the former names, stay exported as deprecated
aliases of `compileStory`, `Story` and `Scene`. `compileDeck` still accepts `format` and `deckId`,
and its result keeps `slides` next to `scenes`.

:::

## Packages

The monorepo is split into groups: foundations (`packages/core`, `theme`, `components`),
`packages/formats/*`, `packages/integrations/*`, distribution (`packages/cli`), `packages/tools/*`,
one site per sub-domain in `sites/*`, and `examples/*`.

### Available

<AvailablePackages />

### Planned

<PlannedPackages />

The status of each format is on the [formats overview](/formats/overview).

## The site framework

`packages/site` (`@recit/site`) is the site framework: routing, prerendering, Pagefind search and
the MDX shell that every site of the project, including this documentation, is built on. It is never
published on its own.

Récit still reaches it **through its plugin API**, `@recit/site-stories`, because a plugin is easier
to test and to move than a patch. See [the integration](/documentation/integrations/site-stories).

### One configuration file

Each project has a single `recit.config.ts`, read by the sites, the CLI and the Vite plugin:

- the framework's config loader looks for `recit.config.*`;
- `defineConfig` (`recit/config`, `@recit/core/config`) validates the Récit sections with zod 4,
  takes them out of the framework's options and attaches them to the result;
- `@recit/site-stories` then adds `recitPlugin` to `plugins`. Its `transformConfig` hook lists the
  package's `vite.config.mjs` in `__pluginDirs`, which the framework merges into the site's Vite
  config: that is how `recitVitePlugin` is added without a `vite.config.ts`;
- `recit dev | build` load the same file and keep only its Récit sections.
