{
  "formatBench": [
    {
      "format": "MDX (compile per request)",
      "packageVersion": "@mdx-js/mdx@3.1.1",
      "payloadBytes": 664,
      "htmlBytes": 840,
      "avgRenderMs": 0.73,
      "p95RenderMs": 0.86,
      "rendererLoc": 3,
      "nodeTypesHandled": 0,
      "depsToRender": 1,
      "depsToAuthor": 0,
      "majorLinesIn24mo": 1,
      "releasesIn24mo": 2,
      "preV1": false
    },
    {
      "format": "MDX (precompiled)",
      "packageVersion": "@mdx-js/mdx@3.1.1",
      "payloadBytes": 664,
      "htmlBytes": 840,
      "avgRenderMs": 0.2,
      "p95RenderMs": 0.24,
      "rendererLoc": 2,
      "nodeTypesHandled": 0,
      "depsToRender": 1,
      "depsToAuthor": 0,
      "majorLinesIn24mo": 1,
      "releasesIn24mo": 2,
      "preV1": false
    },
    {
      "format": "Markdown (parse per request)",
      "packageVersion": "react-markdown@10.1.0",
      "payloadBytes": 664,
      "htmlBytes": 840,
      "avgRenderMs": 0.5,
      "p95RenderMs": 0.74,
      "rendererLoc": 1,
      "nodeTypesHandled": 0,
      "depsToRender": 1,
      "depsToAuthor": 0,
      "majorLinesIn24mo": 2,
      "releasesIn24mo": 6,
      "preV1": false
    },
    {
      "format": "Markdown (cached output)",
      "packageVersion": "react-markdown@10.1.0",
      "payloadBytes": 664,
      "htmlBytes": 840,
      "avgRenderMs": 0,
      "p95RenderMs": 0,
      "rendererLoc": 1,
      "nodeTypesHandled": 0,
      "depsToRender": 0,
      "depsToAuthor": 0,
      "majorLinesIn24mo": 2,
      "releasesIn24mo": 6,
      "preV1": false
    },
    {
      "format": "Portable Text",
      "packageVersion": "@portabletext/react@8.0.1",
      "payloadBytes": 2254,
      "htmlBytes": 797,
      "avgRenderMs": 0.19,
      "p95RenderMs": 0.35,
      "rendererLoc": 2,
      "nodeTypesHandled": 11,
      "depsToRender": 1,
      "depsToAuthor": 0,
      "majorLinesIn24mo": 6,
      "releasesIn24mo": 20,
      "preV1": false
    },
    {
      "format": "Lexical",
      "packageVersion": "lexical@0.49.0",
      "payloadBytes": 3765,
      "htmlBytes": 1642,
      "avgRenderMs": 0.35,
      "p95RenderMs": 0.52,
      "rendererLoc": 6,
      "nodeTypesHandled": 7,
      "depsToRender": 7,
      "depsToAuthor": 5,
      "majorLinesIn24mo": 1,
      "releasesIn24mo": 532,
      "preV1": true
    },
    {
      "format": "Slate",
      "packageVersion": "slate@0.126.2",
      "payloadBytes": 1282,
      "htmlBytes": 771,
      "avgRenderMs": 0.02,
      "p95RenderMs": 0.04,
      "rendererLoc": 1,
      "nodeTypesHandled": 8,
      "depsToRender": 1,
      "depsToAuthor": 1,
      "majorLinesIn24mo": 1,
      "releasesIn24mo": 69,
      "preV1": true
    }
  ],
  "scaling": [
    {
      "format": "MDX (compile per request)",
      "size": "short",
      "payloadBytes": 664,
      "htmlBytes": 840,
      "avgMs": 0.73
    },
    {
      "format": "MDX (precompiled)",
      "size": "short",
      "payloadBytes": 664,
      "htmlBytes": 840,
      "avgMs": 0.2,
      "compileOnlyMs": 0.81
    },
    {
      "format": "Markdown",
      "size": "short",
      "payloadBytes": 664,
      "htmlBytes": 840,
      "avgMs": 0.5
    },
    {
      "format": "Portable Text",
      "size": "short",
      "payloadBytes": 2254,
      "htmlBytes": 797,
      "avgMs": 0.19
    },
    {
      "format": "Slate",
      "size": "short",
      "payloadBytes": 1282,
      "htmlBytes": 771,
      "avgMs": 0.02
    },
    {
      "format": "Lexical",
      "size": "short",
      "payloadBytes": 3765,
      "htmlBytes": 1642,
      "avgMs": 0.35
    },
    {
      "format": "MDX (compile per request)",
      "size": "medium",
      "payloadBytes": 2659,
      "htmlBytes": 3363,
      "avgMs": 1.84
    },
    {
      "format": "MDX (precompiled)",
      "size": "medium",
      "payloadBytes": 2659,
      "htmlBytes": 3363,
      "avgMs": 0.39,
      "compileOnlyMs": 1.76
    },
    {
      "format": "Markdown",
      "size": "medium",
      "payloadBytes": 2659,
      "htmlBytes": 3363,
      "avgMs": 1.28
    },
    {
      "format": "Portable Text",
      "size": "medium",
      "payloadBytes": 9013,
      "htmlBytes": 3188,
      "avgMs": 0.24
    },
    {
      "format": "Slate",
      "size": "medium",
      "payloadBytes": 5125,
      "htmlBytes": 3084,
      "avgMs": 0.06
    },
    {
      "format": "Lexical",
      "size": "medium",
      "payloadBytes": 14793,
      "htmlBytes": 6568,
      "avgMs": 1.06
    },
    {
      "format": "MDX (compile per request)",
      "size": "long",
      "payloadBytes": 6662,
      "htmlBytes": 8422,
      "avgMs": 4.39
    },
    {
      "format": "MDX (precompiled)",
      "size": "long",
      "payloadBytes": 6662,
      "htmlBytes": 8422,
      "avgMs": 0.77,
      "compileOnlyMs": 4.25
    },
    {
      "format": "Markdown",
      "size": "long",
      "payloadBytes": 6662,
      "htmlBytes": 8422,
      "avgMs": 3.02
    },
    {
      "format": "Portable Text",
      "size": "long",
      "payloadBytes": 22575,
      "htmlBytes": 7983,
      "avgMs": 0.57
    },
    {
      "format": "Slate",
      "size": "long",
      "payloadBytes": 12824,
      "htmlBytes": 7723,
      "avgMs": 0.11
    },
    {
      "format": "Lexical",
      "size": "long",
      "payloadBytes": 36862,
      "htmlBytes": 16433,
      "avgMs": 2.52
    }
  ],
  "editorLandscape": [
    {
      "format": "Markdown",
      "editor": "react-md-editor",
      "editorPackage": "@uiw/react-md-editor",
      "finding": "Plain Markdown's most common editor isn't a structured rich-text editor at all — it's a text area with a live-rendered preview pane. No AST-aware editing UI is needed because the storage format is the editing format.",
      "sourceUrl": "https://www.npmjs.com/package/@uiw/react-md-editor",
      "sourceLabel": "npmjs.com — @uiw/react-md-editor"
    },
    {
      "format": "MDX",
      "editor": "MDXEditor",
      "editorPackage": "@mdxeditor/editor",
      "finding": "MDXEditor's editing engine is Lexical, not MDX — it converts bidirectionally between a Markdown AST and the Lexical AST, and only serializes to MDX text on save.",
      "sourceUrl": "https://mdxeditor.dev/editor/docs/overview",
      "sourceLabel": "mdxeditor.dev — Overview"
    },
    {
      "format": "Portable Text",
      "editor": "Portable Text Editor",
      "editorPackage": "@portabletext/editor",
      "finding": "Sanity extracted its own Studio editor into a standalone package purpose-built for Portable Text — the only format here with an editor designed around its storage format rather than adapted to it.",
      "sourceUrl": "https://www.sanity.io/docs/studio/portable-text-editor-configuration",
      "sourceLabel": "sanity.io — Portable Text Editor configuration"
    },
    {
      "format": "Lexical",
      "editor": "Payload CMS",
      "editorPackage": "@payloadcms/richtext-lexical",
      "finding": "Payload switched its default rich-text editor to Lexical and has deprecated its previous Slate-based editor, removing it entirely in v4.0 — a production CMS abandoning Slate for Lexical, not a lab comparison.",
      "sourceUrl": "https://payloadcms.com/docs/rich-text/overview",
      "sourceLabel": "payloadcms.com — Rich Text Editor overview"
    },
    {
      "format": "Slate",
      "editor": "Plate",
      "editorPackage": "@udecode/plate",
      "finding": "Plate — the most active Slate-based editor framework — is built directly on top of Slate's primitives, layering plugins and state management on top rather than replacing them.",
      "sourceUrl": "https://plate.udecode.io/docs",
      "sourceLabel": "plate.udecode.io — Introduction"
    }
  ],
  "customElementBench": [
    {
      "format": "Markdown",
      "wiringLoc": 0,
      "needsNodeClass": false,
      "notSupported": true,
      "note": "No mechanism exists in the spec to embed a React component. Getting one in means inventing custom syntax and writing a remark/rehype plugin to parse it — at that point you have reinvented part of MDX."
    },
    {
      "format": "MDX",
      "wiringLoc": 1,
      "needsNodeClass": false,
      "note": "One entry in the `components` map passed to `run()`. Content authors the JSX tag directly — no data-shape decision to make."
    },
    {
      "format": "Portable Text",
      "wiringLoc": 2,
      "needsNodeClass": false,
      "note": "One `types` map entry plus the tagged block in the stored array — same pattern as any other custom type."
    },
    {
      "format": "Slate",
      "wiringLoc": 2,
      "needsNodeClass": false,
      "note": "One `elementTransforms` entry in `@slate-serializers/html`'s config, returning a `domhandler` `Element` — that's a second direct import, not a transitive one, since the transform has no other way to hand back a DOM node — plus a plain void node in the stored value. No class or registration to read it back."
    },
    {
      "format": "Lexical",
      "wiringLoc": 43,
      "needsNodeClass": true,
      "note": "A registered Node subclass is mandatory — plain objects are rejected by the editor. ~40 lines for the minimum class, plus registration, creation, and a render case. DecoratorNode defaults to inline; block placement needs an explicit isInline() override."
    }
  ]
}