Typesetter

approved

by CHEN Hua

Render publication-quality typography in prose without changing Markdown source, with syntax-aware protection for technical content. - This plugin has not been manually reviewed by Obsidian staff.

84 downloadsUpdated 7d agoMIT

Typesetter for Obsidian

Publication-quality typography for Markdown, without changing the source.

简体中文

MIT License Obsidian 1.7.2 or later TypeScript Latest release CI Release

Current release: v0.1.4

Requires Obsidian 1.7.2 or later.

Typesetter is a free, open-source, local-first Obsidian plugin for academic writing, scientific notes, and multilingual prose. It adds a non-destructive typesetting layer to Source Mode, Live Preview, Reading View, and print/PDF rendering. Every surface and typography rule is independently configurable.

The plugin does not modify the underlying Markdown source.

Source:
The result----although unexpected----was obtained in 2025-2026.

Rendered:
The result—although unexpected—was obtained in 2025–2026.

Contents

Features

AreaBehavior
Non-destructive renderingDisplays typeset characters while preserving the Markdown file, editor document, frontmatter, and clipboard text.
Four rendering controlsSource Mode, Live Preview, Reading View, and print/PDF output can be enabled separately.
Syntax-aware safetyCodeMirror 6 syntax information protects code, math, links, metadata, and Markdown structure.
Safe rendered DOMReading View processes visible prose text nodes without changing attributes or link targets.
Deterministic engineIndependent rules return ranges; conflicts use fixed priority and longest-match resolution.
Multilingual punctuationPreserves input-method Unicode by default, with opt-in CJK shaping and script-aware corrections.
Editing-friendly displayOriginal tokens appear at the cursor by default; editor copy keeps source tokens.
Offline and local-firstNo account, telemetry, advertising, remote service, or runtime download.

Platform support

Typesetter declares isDesktopOnly: false and uses Obsidian and CodeMirror web APIs, not Node.js, Electron, or direct file-system APIs. Source Mode, Live Preview, Reading View, settings, and commands are designed for desktop and mobile Obsidian.

Print/PDF rendering is a compatibility surface, not a PDF generator. It works when Obsidian or an export plugin captures the post-processed Reading View DOM and honors print CSS. Desktop Obsidian's native print/PDF path follows this model. A mobile or third-party exporter can also work, but an exporter that reparses Markdown, skips Obsidian post processors, or discards print CSS needs a dedicated adapter.

Platform or workflowStatus
Windows, macOS, LinuxSupported architecture; verify each relevant Obsidian release.
Android, iOS, iPadOSMobile-compatible architecture for editor and Reading View rendering.
Obsidian native print/PDFSupported through the independent print/PDF setting.
Third-party export pluginsCompatible when they use Obsidian's rendered DOM and print styles; verify per exporter.

Installation

Community plugins

Typesetter is not yet listed in Obsidian's Community plugins directory. After it is accepted, installation will be available from Settings → Community plugins.

Install a release manually

  1. Download main.js, manifest.json, and styles.css from the matching GitHub release.
  2. Create <vault>/.obsidian/plugins/typesetter/.
  3. Place all three files in that directory.
  4. Reload Obsidian.
  5. Open Settings → Community plugins and enable Typesetter.

The folder name must match the manifest ID: typesetter.

Build from source

git clone https://github.com/ichenh/obsidian-typesetter.git
cd obsidian-typesetter
npm ci
npm run build

Copy main.js, manifest.json, and styles.css to <vault>/.obsidian/plugins/typesetter/, then reload Obsidian.

Quick start

  1. Enable Typesetter.
  2. Leave Live Preview, Reading View, and Print and PDF output enabled.
  3. Keep Source Mode disabled for literal Markdown while editing.
  4. Type a shorthand such as --, ----, or ... in ordinary prose.
  5. Move the cursor into a transformed token to reveal its source.
  6. Disable any rule that conflicts with a vault's notation or house style.

Commands can toggle all rendering, Live Preview, or Reading View without changing note content.

Typography rules

Dashes and ranges

Source token or contextDisplayDefaultNotes
--en dash OnOrdinary prose only.
----em dash OnEvaluated before --; --- is not a shorthand.
2025-2027, pp. 15-23range with OnConservative detection; subtraction and scientific notation stay literal.

Markdown thematic breaks and frontmatter delimiters are structural syntax and are never treated as dash shorthands.

Dash shorthands also work in safe prose inside nested lists, including bold or italic list text:

- Drawing tangents:
    - The "long--line" principle----extend the tangent.

Dash replacements inherit the surrounding text font. Regional CJK punctuation fonts apply only when a punctuation rule explicitly selects them; the interface language alone does not change the font of dash shorthands. Glyph appearance still depends on the note's font and theme.

Arrows

Every mapping has its own switch. Single-line arrows are enabled by default. Operator-like double arrows are disabled because <= and => are common in code.

Source tokenDisplay characterDefault
->, <-, <->, , On
-->, <--, <-->, , On
=>, <=, <=>, , Off
==>, <==, <==>, , Off

These are prose display rules, never source replacements. Code and formulas stay protected even when a corresponding option is enabled.

Ellipses

Source tokenDisplay characterDefault
...On
......centered Chinese ellipsis ……On

The engine uses explicit tokens and does not guess an ellipsis convention from the document's dominant language.

CJK and Latin punctuation

Input-method Unicode is authoritative by default. Typesetter preserves Simplified Chinese, Traditional Chinese, Japanese, and Korean punctuation, including fullwidth and halfwidth forms such as , , , 「」, , and .

Regional punctuation shaping and shared curly-quote shaping are separate opt-in features. Glyph display preserves the input characters; optional punctuation corrections and shorthand conversions have separate controls. Bold and italic formatting do not interrupt a continuous quotation, while code, math, images, and paragraph boundaries remain separate. Full stop, comma, colon, semicolon, question mark, and exclamation mark corrections are independent advanced rules and default to off. This avoids overriding the author's input method or editorial house style.

For untagged Chinese text, Default Chinese punctuation region selects Simplified Chinese, Traditional Chinese (Taiwan), or Traditional Chinese (Hong Kong / Macau). This selects fonts only; it never converts quotation characters or edits notes. Japanese kana and Korean Hangul remain independent of this preference.

Explicit inherited BCP 47 language metadata takes precedence in rendered HTML. Hong Kong and Macau tags remain distinct and use the Hong Kong font stack rather than the Taiwan stack. The regional font must be installed for its exact glyphs to be available. Japanese kana and Korean Hangul can identify local script, but Han characters alone cannot distinguish mainland Chinese, Taiwan, Hong Kong, Macau, or Japanese conventions.

Protected contexts

Typesetter always excludes:

  • YAML frontmatter and Properties;
  • inline, fenced, and indented code, including TikZ;
  • inline and display LaTeX, MathJax output, and technical math containers;
  • HTML source, SVG, script, and style;
  • URLs, Markdown link destinations, wikilink targets, and embed targets;
  • tags, block IDs, and Markdown structural syntax; and
  • plugin-generated technical DOM where safe prose cannot be established.

Visible prose in headings, lists, blockquotes, tables, callouts, footnotes, and link labels may still be typeset. A missed conversion is preferable to a conversion inside technical or structural content.

Settings

The interface follows Obsidian's language and includes English, Simplified Chinese, Traditional Chinese, Japanese, and Korean. Hong Kong and Macau locale codes use the Traditional Chinese interface; unsupported locales fall back to English.

Setting names describe the typographic result. Source and display characters are shown separately in descriptions to avoid ambiguous “token to token” labels.

SectionControlsDefaults
RenderingGlobal rendering, Source Mode, Live Preview, Reading View, print/PDF output, reveal at cursorGlobal on; Source Mode off; others on
DashesEn dash shorthand, em dash shorthand, numerical rangesOn
SymbolsSix single-line arrows and six operator-like double arrowsSingle-line on; double-line off
PunctuationTwo ellipses, CJK glyph and quote shaping, four CJK systems, six correctionsEllipses and CJK systems on; shaping and corrections off
SafetyRead-only summary of protected contextsAlways enforced

How it works

Obsidian syntax tree or rendered DOM
        ↓
approved ordinary-prose spans
        ↓
pure typography engine
        ↓
CodeMirror decorations or paired rendered-DOM tokens

The typography engine has no Markdown, DOM, or Obsidian knowledge. Adapters approve safe text first; the engine collects candidates, resolves overlaps deterministically, and returns display replacements.

Source Mode and Live Preview use CodeMirror 6 decorations over visible ranges. Reading View uses an Obsidian Markdown post processor and changes visible text nodes only. Print CSS selects the typeset half of paired DOM tokens. No path writes a note or dispatches a source-replacement edit.

See ARCHITECTURE.md for implementation and trust boundaries.

Development

Requirements: Node.js 24, npm 11, and Obsidian 1.7.2 or later for runtime testing.

npm ci                 # reproducible dependency installation
npm run dev            # watch build
npm run build          # strict TypeScript and production bundle
npm run lint           # ESLint
npm test               # Vitest
npm run check:release  # manifest and release metadata
npm run check          # complete local and CI gate

Use fixtures/typography-test.md for manual acceptance and confirm its hash is unchanged. Do not commit generated main.js, local vault data, node_modules, coverage output, or temporary release notes.

Release process

  1. Synchronize package.json, package-lock.json, manifest.json, versions.json, both READMEs, and CHANGELOG.md.
  2. Run npm run check.
  3. Create a bare semantic-version tag matching the manifest, such as 0.1.0.
  4. Push the commit and tag.
  5. GitHub Actions rebuilds tagged source and publishes exactly main.js, manifest.json, and styles.css.

See .github/workflows/release.yml.

Known limitations

  • Mobile-compatible architecture does not replace hands-on testing for each Obsidian mobile release.
  • Han-only text cannot identify a regional Chinese or Japanese publishing convention.
  • Different input methods may write identical curly-quote code points; explicit language metadata is the reliable override.
  • Exporters that skip Obsidian's post-processed DOM or print CSS need an adapter.
  • Host-controlled syntax-node names and export timing require manual Obsidian testing in addition to automated tests.

Project policies

Typesetter is an independent community project under the MIT License. It has no paid edition, licensing service, telemetry, advertising, or commercial gate.

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.