Markdown rendered
by the editor, not by a web view.

A preview is usually a browser in a panel: a web view, a stylesheet, and a rendering engine that has nothing to do with the editor around it. Here the plugin returns a description of the document and Linelark draws every pixel of it in the same SwiftUI the rest of the app is built from.

Studio 1.6.1 · macOS 14+6.8 MB download

Why a description rather than HTML.

Handing a plugin a web view would make previews easy and make three other things impossible: theme fidelity, a reading position that survives the switch, and the guarantee that a document cannot reach the network while being read.

01

The toolbar button appears only when something can render

The Preview toggle (⇧⌘V, or View ▸ Preview) is live for a document some installed plugin has claimed by extension or language, and disabled otherwise. It never offers a rendering nobody can produce.

02

Every block carries its source offset

Which is what keeps your place across the switch, in both directions: rendered from the paragraph you were editing, back to the line the block you were reading began at.

03

Preview belongs to the pane, not the file

So the same file can be source in one split and rendered in the other, which is the arrangement most people actually want while writing.

04

The theme is the app’s theme

Because the blocks are drawn by the same views the built-in panels use. There is no second stylesheet to keep in step with Light, Dark, and the five themes.

05

A preview cannot fetch anything

There is no document, no script engine and no stylesheet loader in the rendering path. A Markdown file that references a remote image cannot cause a request.

06

Rendering is capped, not unbounded

The parser runs interpreted in JavaScriptCore, so the example Markdown renderer caps itself at 256 KB rather than stall the editor on every keystroke of a very large document.

The blocks a preview can be built from.

A plugin picks from this vocabulary. A node type the app does not recognise is skipped rather than drawn wrong, which is why a plugin declares the API generation it was written against.

NodeDrawn as
HeadingA themed heading at one of the document’s levels.
ProseA paragraph with inline emphasis, strong, code and links.
Code blockMonospaced, in the editor’s own font, with its language label.
QuoteAn indented block with a rule down its edge.
ListOrdered or unordered, nested.
TableA native table with aligned columns.
RuleA horizontal divider.

Read from the Linelark Studio 1.6.1 source, not from its documentation. Where the two disagree, this is the one that ships.

What a preview is not.

It is a reading view drawn by the editor. Several things a browser-based preview would give you for free are genuinely absent.

  • Code inside a preview is not highlightedThe tokenizer paints an NSTextStorage and a preview block is an AttributedString. A fenced block is monospaced and legible; it is not coloured.
  • Nothing in a preview is editableSwitch back to the source to type. The find bar searches the text view behind the preview, so ⌘F while previewing marks hits nobody can see.
  • It re-renders whole, when the text settlesNot incrementally as you type. On a large document that is a visible pause rather than a live update, which is why the example plugin stops at 256 KB.
  • The scroll anchor is per block, not per lineReturning to the source lands on the line the block began at. A nested block a plugin cannot place carries no offset at all and is not scrolled to.
  • A preview comes from a pluginNothing renders Markdown until you install something that does. In Studio that is the catalog; in the App Store edition it is a bundle you install from a file.
  • No export, no print of the rendered viewPrint (⌘P) prints the source text. There is no PDF or HTML output from a preview.

Open it on
your own files.

Apple-notarized, macOS 14 and newer, Intel and Apple silicon.

Download Studio 1.6.1 6.8 MB · every version, with checksums