CHEN Hua78 downloadsRender publication-quality typography in prose without changing Markdown source, with syntax-aware protection for technical content.
Publication-quality typography for Markdown, without changing the source.
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.
| Area | Behavior |
|---|---|
| Non-destructive rendering | Displays typeset characters while preserving the Markdown file, editor document, frontmatter, and clipboard text. |
| Four rendering controls | Source Mode, Live Preview, Reading View, and print/PDF output can be enabled separately. |
| Syntax-aware safety | CodeMirror 6 syntax information protects code, math, links, metadata, and Markdown structure. |
| Safe rendered DOM | Reading View processes visible prose text nodes without changing attributes or link targets. |
| Deterministic engine | Independent rules return ranges; conflicts use fixed priority and longest-match resolution. |
| Multilingual punctuation | Preserves input-method Unicode by default, with opt-in CJK shaping and script-aware corrections. |
| Editing-friendly display | Original tokens appear at the cursor by default; editor copy keeps source tokens. |
| Offline and local-first | No account, telemetry, advertising, remote service, or runtime download. |
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 workflow | Status |
|---|---|
| Windows, macOS, Linux | Supported architecture; verify each relevant Obsidian release. |
| Android, iOS, iPadOS | Mobile-compatible architecture for editor and Reading View rendering. |
| Obsidian native print/PDF | Supported through the independent print/PDF setting. |
| Third-party export plugins | Compatible when they use Obsidian's rendered DOM and print styles; verify per exporter. |
Typesetter is not yet listed in Obsidian's Community plugins directory. After it is accepted, installation will be available from Settings → Community plugins.
main.js, manifest.json, and styles.css from the matching
GitHub release.<vault>/.obsidian/plugins/typesetter/.The folder name must match the manifest ID: typesetter.
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.
--, ----, or ... in ordinary prose.Commands can toggle all rendering, Live Preview, or Reading View without changing note content.
| Source token or context | Display | Default | Notes |
|---|---|---|---|
-- |
en dash – |
On | Ordinary prose only. |
---- |
em dash — |
On | Evaluated before --; --- is not a shorthand. |
2025-2027, pp. 15-23 |
range with – |
On | Conservative 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.
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 token | Display character | Default |
|---|---|---|
->, <-, <-> |
→, ←, ↔ |
On |
-->, <--, <--> |
⟶, ⟵, ⟷ |
On |
=>, <=, <=> |
⇒, ⇐, ⇔ |
Off |
==>, <==, <==> |
⟹, ⟸, ⟺ |
Off |
These are prose display rules, never source replacements. Code and formulas stay protected even when a corresponding option is enabled.
| Source token | Display character | Default |
|---|---|---|
... |
… |
On |
...... |
centered Chinese ellipsis …… |
On |
The engine uses explicit tokens and does not guess an ellipsis convention from the document's dominant language.
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.
Typesetter always excludes:
script, and style;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.
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.
| Section | Controls | Defaults |
|---|---|---|
| Rendering | Global rendering, Source Mode, Live Preview, Reading View, print/PDF output, reveal at cursor | Global on; Source Mode off; others on |
| Dashes | En dash shorthand, em dash shorthand, numerical ranges | On |
| Symbols | Six single-line arrows and six operator-like double arrows | Single-line on; double-line off |
| Punctuation | Two ellipses, CJK glyph and quote shaping, four CJK systems, six corrections | Ellipses and CJK systems on; shaping and corrections off |
| Safety | Read-only summary of protected contexts | Always enforced |
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.
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.
package.json, package-lock.json, manifest.json, versions.json,
both READMEs, and CHANGELOG.md.npm run check.0.1.0.main.js,
manifest.json, and styles.css.See .github/workflows/release.yml.
Typesetter is an independent community project under the MIT License. It has no paid edition, licensing service, telemetry, advertising, or commercial gate.