https://github.com/mash/markdown-fast
A faster Markdown preview for VS Code. Drop-in replacement for the builtin — TTFP drops from ~4.6s to under 1s on large code-heavy docs.
https://github.com/mash/markdown-fast
autoresearch claude-code markdown markdown-preview performance vscode vscode-extension
Last synced: 5 days ago
JSON representation
A faster Markdown preview for VS Code. Drop-in replacement for the builtin — TTFP drops from ~4.6s to under 1s on large code-heavy docs.
- Host: GitHub
- URL: https://github.com/mash/markdown-fast
- Owner: mash
- License: other
- Created: 2026-05-02T19:13:55.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-03T17:34:18.000Z (about 2 months ago)
- Last Synced: 2026-05-14T03:06:11.364Z (about 1 month ago)
- Topics: autoresearch, claude-code, markdown, markdown-preview, performance, vscode, vscode-extension
- Language: TypeScript
- Homepage: https://marketplace.visualstudio.com/items?itemName=maaashjp.markdown-fast
- Size: 1.32 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Markdown Fast
A faster Markdown preview for VS Code.
## Why
I didn't have a problem with the builtin Markdown viewer until this morning, when I opened a large plan file and it took at least a whole second before anything showed up. In the AI era we're reading a lot more Markdown than before — especially long, code-heavy design documents written in plan mode — and those pauses add up.
Markdown Fast is a fork of the builtin that keeps the same UX — same `markdown-it` pipeline, same keybindings, same syntax highlighting, same scroll-sync — but cuts time-to-first-paint by deferring and slicing work that the builtin does eagerly. You see the top of the document immediately; the rest fills in just after, with off-screen syntax highlighting deferred until you scroll there.
It's a drop-in replacement. Disable the builtin `vscode.markdown-language-features` extension to make Markdown Fast the default previewer.

## Install
**From the Marketplace (recommended):** [maaashjp.markdown-fast](https://marketplace.visualstudio.com/items?itemName=maaashjp.markdown-fast)
```bash
code --install-extension maaashjp.markdown-fast
```
Or search for "Markdown Fast" in the Extensions sidebar (`⇧⌘X`).
**From VSIX:**
```bash
cd ext/markdown-fast
npm install
npm run package # compiles + produces markdown-fast-*.vsix
code --install-extension markdown-fast-*.vsix
```
**From source (development):**
```bash
(cd ext/markdown-fast && npm install)
npm run build
# then launch a dev VS Code with --extensionDevelopmentPath=./ext/markdown-fast
```
**Usage:** open a `.md` file and press `⇧⌘V` (preview) or `⌘K V` (preview to side).
### Disable the builtin Markdown preview
Markdown Fast and the builtin both register the same commands and view types, so to make Markdown Fast the active previewer you should disable the builtin.
1. Open the **Extensions** sidebar (`⇧⌘X`).
2. In the search box, type `@builtin markdown language features`.
3. Click the entry **"Markdown Language Features"** (publisher: `vscode`) and choose **Disable** (or **Disable (Workspace)** if you only want it disabled in this project). Only this one — leave **"Markdown Language Basics"**, **"Markdown Math"**, and any other `@builtin markdown ...` extensions enabled.
After disabling, reload the window (`⌘R` / `Cmd+Shift+P` → "Developer: Reload Window") so VS Code picks up the change.
On first activation Markdown Fast will also prompt to set itself as the default editor for `*.md` (writing `workbench.editorAssociations` to your user settings). Without this, opening a `.md` still goes to the plain text editor; with it, opening goes straight to the rendered preview.

## How is it fast
Three optimizations, all benchmarked to actually move TTFP, run together:
- **Lazy highlight** — `highlight.js` is deferred from the host to the webview, and only visible code blocks get highlighted on first paint. The rest highlight as you scroll.
- **Viewport-first rendering** — the visible viewport is rendered and painted before anything below the fold; the rest of the document is rendered after first paint.
- **Token-boundary slicing** — the document is parsed once, then split at top-level markdown-it token boundaries: only the viewport's tokens are rendered synchronously; the rest is rendered lazily after first paint. Splitting on tokens (not source lines) means a slice never bisects a fenced code block, list, table, or blockquote.
Net effect: TTFP on a large plan file drops from roughly 4.6s to under 1s in the bench harness. Correctness and final DOM match the builtin once everything has finished rendering.
---
## Benchmarks & autoresearch
This repo is also an experiment: applying Karpathy's [autoresearch](https://github.com/karpathy/autoresearch) idea — let an agent run a tight measure → propose → keep-or-revert loop against a hard metric — to user-interfacing software instead of model training. The hard metric here is **TTFP (Time To First Paint)** of the preview pane, measured in two flavors:
- **Offline TTFP-host** — `parse + render(+ highlight)` in Node, measured by `benchmark/bench-engine.ts`. Fast feedback for host-side changes.
- **E2E TTFP** — wall-clock time between the harness pressing `Enter` in Quick Open and the first heading rendering inside the preview webview, captured via Playwright + Chrome DevTools Protocol.
```bash
npm run bench:e2e # baseline (builtin VS Code preview)
npm run build
BENCH_FORK=1 BENCH_LAZY_HL=1 BENCH_VIEWPORT_FIRST=1 BENCH_TOKEN_SLICE=1 npm run bench:e2e
```
Each run writes one JSON to `benchmark/results/e2e-${variant}.json`, including per-iteration TTFP samples and `[BENCH]`-prefixed phase markers (parse/render on the host, firstMorph/firstAnimFrame in the webview) so regressions can be attributed to a phase rather than a vague "slower."
The harness opens files via Quick Open (`Cmd+P` → type filename → `Enter`). Both variants are configured so the rendered preview is the default editor for `*.md` — the fork via its `customEditor` contribution, the baseline via a `workbench.editorAssociations` setting written into the test user-data dir — so a single `Enter` opens straight into a preview. Same gesture, same code path, apples-to-apples.
### Autoresearch
The `autoresearch` skill (`.claude/skills/autoresearch/SKILL.md`) runs the loop autonomously: pick an idea, edit the fork, build, bench, log to `results.tsv`, and either commit-and-keep or revert based on the numbers. The decision rule is simple: **keep** if median TTFP improves ≥3% and p95 doesn't regress >5%; otherwise **discard**.

The chart above is a representative run: each grey dot is a discarded experiment, each green dot is a kept improvement, and the green staircase is the running best.
The optimizations themselves were written by the autoresearch loop. I worked with Claude Code to set up the benchmark harness, the fork scaffolding, and the skill, contributed the "viewport-first rendering" idea, and let the loop iterate on the rest.
## Layout
```
benchmark/
gen-corpus.ts deterministic synthetic .md generator (4 profiles × 4 sizes)
bench-engine.ts offline (Node) markdown-it + highlight.js phase timings
e2e/run-ttfp.ts E2E harness; baseline or fork via BENCH_FORK=1
e2e-summarize.ts joins offline + e2e numbers into a markdown report
results/ *.json + *.md (gitignored — re-run to reproduce)
ext/markdown-fast/ the extension; this is what we're optimizing
tmp/vscode-markdown/ upstream microsoft/vscode shallow clone (reference; not edited)
tmp/corpus/ generated test corpus (gitignored)
```
## Conventions
- Synthetic corpus is deterministic (LCG-seeded); regenerate with `npm run gen:corpus`.
- Results JSON is gitignored — re-run benchmarks to reproduce.
## License & credits
MIT — see [LICENSE](LICENSE). Forked from [microsoft/vscode/extensions/markdown-language-features](https://github.com/microsoft/vscode/tree/main/extensions/markdown-language-features), © Microsoft Corporation, also MIT.