# Editor engine benchmark

This benchmark builds ten isolated production cases:

- a hand-written React editor reference;
- a direct React read-only renderer;
- Lexical with React rich text, history, and change plugins;
- the widget-first engine with static rich-text widgets and one lazy Lexical
  editor;
- the same widget document rendered without editor state;
- Puck's standard editor and separate `Render` path;
- BlockNote's standard text-block editor;
- a Craft.js page-editor tree;
- the GrapesJS canvas and component model.

The page-builder cases use the same mixed rich-text, callout, metric, and
gallery content. BlockNote and Lexical use native paragraph documents because
they are text editors rather than general page builders. Plain React is a
reference implementation, not a product competitor.

The benchmark app lives in `apps/benchmark`. Each case gets its own Vite
production build so dependencies from one engine cannot leak into another
engine's initial bundle.

## Run

Preview the benchmark report website:

```bash
pnpm --filter editor-benchmark dev
```

Install the pinned browser once:

```bash
pnpm --filter editor-benchmark exec playwright install chromium
```

Run the full 600-sample matrix:

```bash
pnpm benchmark
```

Run a smaller harness check:

```bash
pnpm --filter editor-benchmark build
pnpm --filter editor-benchmark benchmark --quick
```

Useful overrides:

```bash
pnpm --filter editor-benchmark benchmark \
  --sizes=100,1000 \
  --repetitions=3 \
  --cpu=1,4
```

The full matrix uses the mixed CMS shape. Run the text-only shapes separately
when investigating rich-text section composition:

```bash
pnpm --filter editor-benchmark benchmark \
  --cases=widgets \
  --widget-shape=split \
  --sizes=50,200 \
  --repetitions=5 \
  --cpu=1,4
```

Run the large-document appendix separately so it cannot dominate the normal
CMS result:

```bash
pnpm --filter editor-benchmark benchmark \
  --sizes=1000,2000 \
  --repetitions=2 \
  --cpu=1
```

Every run creates `raw.json`, `summary.json`, and `report.md` under
`benchmarks/results/<timestamp>`. `latest.txt` identifies the authoritative
run.

## Dimensions

The suite records production payload bytes with gzip and Brotli, cold and warm
startup, 1x and 4x CPU, heap after forced garbage collection, DOM size, lazy
editor activation, 20-character typing, a 2,000-character paste, canonical JSON
serialization, Markdown export where supported, full document replacement,
undo/redo, scroll frame intervals, and browser long tasks.
Editor runs also record a selection sweep, a shared insert, move, duplicate,
and delete sequence, and the persistence payload bytes emitted after input.

The cases are not feature-identical. Puck and GrapesJS include substantial
editor UI. Craft.js and Headless Widgets are lower-level systems. BlockNote is
text-first. The report keeps those differences beside the numbers. GrapesJS
renders its canvas inside an iframe, so the recorded host-page DOM count does
not include the canvas document and is not directly comparable with the other
DOM counts.
