graphite.md logo
graphite.md
A richer Markdown preview for VS Code
Install GitHub Issues
v0.3.0

graphite.md

A Markdown preview for people who read a lot of Markdown: collapsible sections, a git-graph style outline, checklists, math, and diagrams — in a dark, distraction-free theme.

Features

Collapsible sections

Every heading in your document collapses and expands independently. Long specs and READMEs stop being one giant scroll.

A git-graph outline

The right-hand "On this page" pane shows your document's structure as a connected graph — not a flat list — split into three views:

Only one view is open at a time. Click any node to soft-scroll to that part of the document; the outline highlights where you are as you scroll.

It also folds away when you want the width back — the chevron in the preview's top-right corner, graphite.md: Toggle Outline from the Command Palette, or Ctrl+G O. With the pane gone the reading column takes the whole width and your text re-wraps to match, and which panels you folded is remembered per preview.

Front matter, as a table

A YAML block at the top of a document — a title, a date, tags — arrives as key/value rows rather than as a stray heading in the outline, the same treatment VS Code's own preview gives it. Front matter that won't parse is reported as an error block instead of half a table.

Checklists

Write - [ ] and - [x] as usual. In the preview they render as real, clickable checkboxes — checking one off edits your markdown file directly, so your task list and your document never drift apart.

Math

Inline ($...$) and block ($$...$$) math, rendered with KaTeX.

Diagrams

Fenced ```mermaid code blocks render as live diagrams.

Images

![alt](diagram.png) renders, resolved against the document it is written in — so a file in a subfolder finds the pictures beside it, and one that reaches up a level works whenever you have that folder open. Images from the network are a separate matter, and off by default; see Settings below.

Callouts

Blockquotes (>) get a distinct treatment so notes and asides stand out from body text.

Rich inline syntax

Superscript (^2^), subscript (~2~), underline (++text++), highlighting (==text==), strikethrough (~~text~~), and footnotes ([^1]) all render natively.

Raw HTML renders

<mark>, <kbd>, <details>, a hand-written <table>, an <img> pointing at a file beside the document — markup you write arrives as markup, the same way VS Code's own Markdown preview treats it, rather than as visible angle brackets. What does not run is script: <script>, an onclick= attribute and an <iframe> are all refused by the preview's Content-Security-Policy, and a <form> can't post anywhere. The boundary is the policy, not the renderer.

Links that go where you meant them to

A relative link opens the file it points at, resolved against the document you're previewing — the same way VS Code's own Markdown preview resolves it. Absolute URLs open in your browser. And a bare filename stays a filename: README.md in a sentence is not turned into a link to http://README.md, which matters because plenty of country domains (.md, .sh, .rs, .pl, .so, .cc) are also file extensions.

Syntax highlighting

Fenced code blocks are highlighted with highlight.js, tinted to match the graphite theme.

Tunable reading width

Set it once in settings.json — the preview picks the new width up immediately, no reload:

{
  "graphiteMd.contentWidth": 60
}

Usage

  1. Open a .md file.
  2. Run graphite.md: Open Preview to the Side from the Command Palette, or press Ctrl+G S. Ctrl+G P opens the preview in the current editor group instead, and Ctrl+G O folds the outline pane away.
  3. The preview updates live as you type.

If the preview ever misbehaves, the graphite.md output channel is where to look — run graphite.md: Show Output from the Command Palette, or pick it from the dropdown in the Output panel. It records which version you're on, every preview opened and closed, every render with how long it took and what it found, and every image the preview declined to load with the reason it declined.

Settings

SettingTypeDefaultDescription
graphiteMd.contentWidthnumber (40–100)60Width of the reading column, as a percentage of the available preview pane width.
graphiteMd.remoteImagesbooleanfalseLoad images from the network. Off by default — images stored beside the document always work, and turning this on lets any document you preview make requests to servers its author picked.
graphiteMd.typographerbooleantrueTurn what you typed into its typographic forms: straight quotes become curly, -- becomes an en dash, ... becomes an ellipsis. Code is never touched. VS Code's own preview has the same option (markdown.preview.typographer) with it off — so this is the one setting where the two previews disagree by default.
graphiteMd.animationbooleantrueAnimate the outline as it folds and unfolds. Turn it off for an instant fold, which is worth doing if you read in a narrow window: the reading column keeps its share of the width while the pane moves, so an animated fold re-wraps the text under you for its length. Either way the fold follows the system's "reduce motion" setting.

Requirements

VS Code 1.134.0 or later. No other setup — everything the preview needs (KaTeX, Mermaid) ships bundled with the extension.

Known limitations

Contributing

Build instructions and an overview of how the extension is put together are in DEVELOPMENT.md. Bug reports and pull requests are welcome on GitHub.

License

MIT

Documentation

A closer look at how to use each part of the preview.

Opening the preview

With a Markdown file open, run one of these from the Command Palette (Ctrl+Shift+P / Cmd+Shift+P):

The preview re-renders automatically as you edit — no manual refresh.

These are a chord of graphite.md's own because Ctrl+K V belongs to VS Code's built-in Markdown preview, so the same keystroke used to mean different things in different windows depending on which extension answered it.

Collapsing sections

Click any heading (or its chevron, hanging in the left margin) to collapse everything under it. Click again to reopen. This only affects what's shown in the reading pane — it doesn't touch your source file.

The "On this page" outline

Three collapsible groups on the right, at most one open at a time:

Clicking any node soft-scrolls the reading pane to that spot, opens any collapsed parent sections needed to reveal it (siblings stay untouched), and briefly pulses the node so you can confirm where you landed.

The pane folds away. The chevron in the preview's top-right corner hides it and brings it back, and graphite.md: Toggle Outline (Ctrl+G O) does the same from the keyboard. With the pane gone the reading column takes the whole width, so the measure grows and your text re-wraps to match; the fold is remembered per preview panel, which is why editing — and the re-render that follows — doesn't spring it open again. If an animated fold re-wrapping the text under you is worse than the width is worth, turn off graphiteMd.animation.

Front matter is read here too: a YAML block at the top of a document arrives as a table rather than as a stray heading above your first section, and one that won't parse is reported as an error block instead of half a table.

Setup Install Requirements Node Version Configure Usage
Depth nests by curving right; siblings hang off a shared vertical run. The path to the section you're reading is drawn in the accent colour as you scroll.

Checklists

Write these like any GitHub-flavored checklist:

- [ ] Not done yet
- [x] Done

They render as clickable boxes:

Clicking a box edits the underlying [ ] / [x] in your markdown file directly — the preview never holds state your file doesn't also have.

Math

Inline math sits in a line of text: $w = c + 2p + 2b$. Block math stands alone:

$$
\text{width} = \text{content} + 2\times\text{padding} + 2\times\text{border}
$$

Diagrams

Fence a Mermaid diagram like any code block, just with mermaid as the language:

```mermaid
graph TD
  A[Start] --> B{Decision}
  B -->|Yes| C[Do this]
  B -->|No| D[Do that]
```

Images

Write an image the usual way and it renders — resolved against the document it is written in, not against the folder you happen to have open:

![Shard map](diagrams/shard-map.png)

A file in a subfolder therefore finds the pictures beside it, and ../images/logo.png works whenever the folder above the document is open. An image outside the open folder, or one named by an absolute path, is left alone and shows an empty box — the same line VS Code's built-in preview draws.

Images from the network are the one thing that stays off until you ask for it. With graphiteMd.remoteImages at its default, an https://… image doesn't load: a preview is a local reading surface, and loading one tells a server its author picked that you opened the file. Turning the setting on allows them, and the Output channel records every image the preview declined and why.

Callouts

A normal blockquote:

> Percentages resolve against the parent's content box.

renders as:

Percentages resolve against the parent's content box.

Rich inline syntax

Beyond the usual emphasis, these all render natively:

WriteGet
^2^superscript
~2~subscript
++text++underlined text
==text==highlighted text
~~text~~strikethrough
[^1]a footnote reference

Footnotes collect at the bottom of the preview as a numbered list. Clicking a reference jumps to its note, and the ↩︎ beside the note brings you back to where you were reading.

Water is H~2~O, and E = mc^2^.

Here's a claim that needs a source.[^1]

[^1]: And here's the source.

Raw HTML

Markup you write arrives as markup — the same way VS Code's own preview treats it — so <mark>, <kbd>, <details>, <dl>, <figure> and a hand-written table all render:

<details>
  <summary>Measured on the 2026-09-30 run</summary>
  p99 dropped from 480 ms to 310 ms after the shard split.
</details>

What does not run is script. <script>, an onclick= attribute, an <iframe> and a posting <form> are refused by the preview's Content-Security-Policy, so a document cannot execute in the pane or reach a server through it. The boundary is the policy rather than the renderer — which is how VS Code's own preview draws it too.

Code blocks

Fenced code is highlighted with highlight.js, using the language you name after the backticks:

```ts
const answer: number = 42;
```

An unknown or missing language falls back to plain monospace rather than failing.

Settings

Four settings, all under graphiteMd:

SettingDefaultWhat it does
contentWidth60The reading column's share of the available pane (40–100). Changing it widens an already-open preview immediately — there's no in-panel control.
remoteImagesfalseWhether images from the network may load. See Images above.
typographertrueWhether straight quotes become curly, -- an en dash and ... an ellipsis. Code is never touched. VS Code's own preview has the same option with it off, so a document can read slightly differently in the two.
animationtrueWhether the outline animates as it folds. Off makes it instant, which suits reading in a narrow window; the system's "reduce motion" setting always makes it instant.

All four, with their defaults:

{
  "graphiteMd.contentWidth": 60,
  "graphiteMd.remoteImages": false,
  "graphiteMd.typographer": true,
  "graphiteMd.animation": true
}

Keyboard shortcuts

ActionKey
Open the preview in this groupCtrl+G P
Open the preview to the sideCtrl+G S
Fold the outline away and backCtrl+G O

These work on every platform — Ctrl, not Cmd, on macOS — because they are graphite.md's own chord rather than a VS Code default. Every binding is rebindable in Keyboard Shortcuts, where the commands are listed under graphiteMd.*.