DexterLagan/MarkUp

A minimal, fast Markdown editor with live visualizer for macOS and Windows.

0

stars

15

commits

JavaScript

primary language

Sep 3, 2026

updated

README

MarkUp

A minimal, fast Markdown editor with live visualizer for macOS, Windows, and Linux. Edit on the left, watch the rendered document on the right — local files, no cloud, no accounts, no bloat.

Built with Tauri 2, CodeMirror 6, and remarkable.

MarkUp in light modeMarkUp in dark mode

Why? Importing Markdown into Apple Notes is cumbersome, and many existing macOS editors (e.g. MacDown) are Intel-only and require Rosetta on Apple Silicon. MarkUp builds natively for Apple Silicon, with Windows x64 and Linux x64 built by GitHub Actions and published as tagged releases.

Features

  • Split view — source editor and rendered preview side by side, with a draggable divider
  • Full-window preview — one click hides the source editor for a distraction-free, window-filling view of the rendered document; the splitter and divider return exactly where you left them when toggled off
  • Live preview — the rendered document updates as you type (100 ms debounce)
  • Full GFM Markdown — tables, strikethrough, task lists, autolinks, and nested lists via remarkable
  • Code highlighting — fenced code blocks in the preview highlighted by highlight.js (~190 languages); the editor itself has Markdown syntax highlighting with a GitHub-style palette
  • File handling — open/save dialogs (.md, .markdown, .mdown, .txt), plus drag & drop a file onto the window to open it
  • Open from Finder — registered as the editor for .md, .markdown, and .mdown files: double-click a document to open it in MarkUp (works on launch and when MarkUp is already running)
  • Unsaved-changes guard — dirty indicator dot and confirmation before discarding edits
  • Light/dark themes — follows the system appearance on launch, with a manual toggle in the toolbar
  • Status bar — live word count, character count, and cursor position (Ln / Col)
  • Small and native-feeling — transparent title bar, native traffic lights, no web UI chrome

Specifications

Architecture

LayerTechnology
Desktop shellTauri 2 (Rust) — system WebView only, no bundled Chromium
FrontendVanilla JavaScript (ES modules), no framework, bundled by Vite 6
EditorCodeMirror 6 with @codemirror/lang-markdown
Markdown engineremarkable 2.x
Code highlightinghighlight.js 11.x
System integrationtauri-plugin-fs + tauri-plugin-dialog (v2)
CI / ReleaseGitHub Actions (release.yml) — builds macOS (aarch64), Windows (x64), and Linux (x64) and publishes a tagged release

Markdown engine configuration

OptionValueNotes
htmltrueRaw inline HTML passes through
gfmtrueGitHub Flavored Markdown: tables, strikethrough, task lists, autolinks
breaksfalseStandard CommonMark line-break rules
langPrefixhljs language-Feeds fenced code to highlight.js
highlighthighlight.js callbackSilently skips unknown languages

Editor (CodeMirror 6)

  • Markdown language mode with syntax highlighting (custom light/dark HighlightStyles)
  • Line numbers, active-line highlight, soft line wrapping
  • Autocompletion, bracket matching, undo/redo history, code folding

UI & window

ElementBehavior
Title bartitleBarStyle: Transparent — native traffic lights, toolbar acts as the drag region
Window1180 × 760 default, 760 × 480 minimum
PanesResizable via pointer-drag divider, clamped to 20–80 % editor width
ToolbarNew / Open… / Save / full-window preview / theme toggle buttons; shows current file name
Themeprefers-color-scheme on launch; button toggles light/dark live
Window titleMirrors the open file's name

Status bar

FieldDetail
Word countWhitespace-delimited token count of the document
Character countRaw UTF-16 length of the document
CursorLn <line>, Col <column> of the main selection head
Dirty dotBullet next to the file name while unsaved changes exist

File I/O

  • Open dialog filters: md, markdown, mdown, txt (+ all files)
  • Save dialog: defaults to untitled.md, md filter
  • Drag & drop: opens dropped files in place (path-based on macOS/Windows; text fallback in the webview)
  • Guards: dirty state blocks New/Open via confirm dialog and blocks window unload
  • Associations: bundle.fileAssociations declares .md / .markdown / .mdown with role Editor (→ CFBundleDocumentTypes on macOS, file-type registrations on Windows, MIME in the .desktop entry on Linux). The path is forwarded to the frontend per platform — RunEvent::Opened on macOS, the launch argument on Windows/Linux — and queued in Rust (so cold-launch opens aren't lost) before being loaded on startup and live. tauri-plugin-single-instance keeps MarkUp to one instance, forwarding the file from a re-launch (Windows/Linux) to the running instance
  • Setting as default (macOS): right-click any .mdGet InfoOpen withMarkUpChange All… — or double-click once and confirm the picker

Keyboard shortcuts

ActionmacOSWindows
New document⌘NCtrl+N
Open file⌘OCtrl+O
Save file⌘SCtrl+S
Full-window preview⌘ECtrl+E

Platform support

PlatformRequirementNotes
macOS10.15+Native Apple Silicon build; x86_64 build also possible via --target x86_64-apple-darwin
Windows10 / 11 x64Requires WebView2 runtime (preinstalled on Win 11); NSIS + MSI installers
Linuxx64 (glibc)Requires WebKitGTK 4.1 + GTK3 runtime; .deb, .rpm (Arch: webkit2gtk)

Release profile (Rust)

opt-level = "s" (small binaries), lto = true, codegen-units = 1, panic = "abort", strip = true.

Security model

  • Access is declared up front through the Tauri v2 capability system in src-tauri/capabilities/default.json — no runtime permission prompts.
  • Granted: core:default, dialog:default, and fs text/binary read + write with full-disk scope. The native file dialogs are the user-facing gate; the app has no network commands.
  • CSP is null while in development; tighten before shipping a public build.

Repository structure

MarkUp/
├── .github/
│   └── workflows/
│       └── release.yml            # CI: macOS aarch64 + Windows x64 + Linux x64 → tagged release
├── docs/
│   └── screenshots/               # README screenshots (light & dark mode)
├── icon-source.png                # Master 1024×1024 app icon
├── scripts/
│   └── gen-icon.mjs               # Generates all platform icons from the master
├── index.html                     # App shell: toolbar, panes, status bar
├── src/
│   ├── main.js                    # Editor setup, remarkable rendering, file I/O, UI wiring
│   └── styles.css                 # Light/dark themes, layout
├── src-tauri/
│   ├── src/
│   │   └── main.rs                # Tauri builder + fs/dialog plugins
│   ├── capabilities/
│   │   └── default.json           # ACL: core, dialog, fs scope
│   ├── gen/                       # ACL schemas generated at build time
│   ├── icons/                     # Platform icons (.icns, .ico, .png)
│   ├── build.rs
│   ├── Cargo.toml
│   └── tauri.conf.json            # Window, bundling, build config
├── vite.config.js
├── package.json
└── LICENSE                        # MIT

Development

Prerequisites

  • Node.js 18+ and npm
  • Rust (stable, via rustup)
  • Platform prerequisites per Tauri:
    • macOS: Xcode command line tools (xcode-select --install)
    • Windows: Microsoft C++ Build Tools and the WebView2 runtime
    • Linux: WebKitGTK 4.1 dev packages (e.g. libwebkit2gtk-4.1-dev, librsvg2-dev, libayatana-appindicator3-dev)

Run in development

git clone https://github.com/DexterLagan/MarkUp.git
cd MarkUp
npm install
npm run tauri dev

Build release binaries

macOS (local, Apple Silicon by default):

npm run tauri build
# -> src-tauri/target/release/bundle/dmg/MarkUp_<ver>_aarch64.dmg
# -> src-tauri/target/release/bundle/macos/MarkUp.app

Windows x64 / Linux x64 (local):

# On the target OS (WebKitGTK deps required on Linux)
npm ci
npm run tauri build
# -> src-tauri/target/release/bundle/{nsis,msi,deb,rpm}/

Cutting a release

Releases are fully automated by the release.yml workflow (triggered on v* tags, or manually from the Actions tab):

  1. Bump the version in package.json, src-tauri/tauri.conf.json, and src-tauri/Cargo.toml.
  2. Commit and push a tag: git tag vX.Y.Z && git push origin vX.Y.Z.
  3. The workflow builds all three platforms in parallel (macOS aarch64 on macos-latest, Windows x64 on windows-latest, Linux x64 on ubuntu-latest) and publishes a GitHub Release with the DMG, NSIS + MSI, and deb + rpm installers.

Current release: v1.0.1 — DMG (Apple Silicon), NSIS + MSI (Windows x64), deb + rpm (Linux x64).

Roadmap ideas

  • Autosave and multiple open tabs
  • Export to HTML/PDF
  • Code signing for macOS (Developer ID) and Windows (EV/Code Sign cert) to silence Gatekeeper/SmartScreen

License

MarkUp is licensed under the MIT License — see LICENSE.

Copyright (c) 2026 Dexter Santucci

Contributors

DexterLagan

15 commits

DexterLagan/MarkUp

A minimal, fast Markdown editor with live visualizer for macOS and Windows.

0

stars

15

commits

JavaScript

primary language

Sep 3, 2026

updated

README

MarkUp

A minimal, fast Markdown editor with live visualizer for macOS, Windows, and Linux. Edit on the left, watch the rendered document on the right — local files, no cloud, no accounts, no bloat.

Built with Tauri 2, CodeMirror 6, and remarkable.

MarkUp in light modeMarkUp in dark mode

Why? Importing Markdown into Apple Notes is cumbersome, and many existing macOS editors (e.g. MacDown) are Intel-only and require Rosetta on Apple Silicon. MarkUp builds natively for Apple Silicon, with Windows x64 and Linux x64 built by GitHub Actions and published as tagged releases.

Features

  • Split view — source editor and rendered preview side by side, with a draggable divider
  • Full-window preview — one click hides the source editor for a distraction-free, window-filling view of the rendered document; the splitter and divider return exactly where you left them when toggled off
  • Live preview — the rendered document updates as you type (100 ms debounce)
  • Full GFM Markdown — tables, strikethrough, task lists, autolinks, and nested lists via remarkable
  • Code highlighting — fenced code blocks in the preview highlighted by highlight.js (~190 languages); the editor itself has Markdown syntax highlighting with a GitHub-style palette
  • File handling — open/save dialogs (.md, .markdown, .mdown, .txt), plus drag & drop a file onto the window to open it
  • Open from Finder — registered as the editor for .md, .markdown, and .mdown files: double-click a document to open it in MarkUp (works on launch and when MarkUp is already running)
  • Unsaved-changes guard — dirty indicator dot and confirmation before discarding edits
  • Light/dark themes — follows the system appearance on launch, with a manual toggle in the toolbar
  • Status bar — live word count, character count, and cursor position (Ln / Col)
  • Small and native-feeling — transparent title bar, native traffic lights, no web UI chrome

Specifications

Architecture

LayerTechnology
Desktop shellTauri 2 (Rust) — system WebView only, no bundled Chromium
FrontendVanilla JavaScript (ES modules), no framework, bundled by Vite 6
EditorCodeMirror 6 with @codemirror/lang-markdown
Markdown engineremarkable 2.x
Code highlightinghighlight.js 11.x
System integrationtauri-plugin-fs + tauri-plugin-dialog (v2)
CI / ReleaseGitHub Actions (release.yml) — builds macOS (aarch64), Windows (x64), and Linux (x64) and publishes a tagged release

Markdown engine configuration

OptionValueNotes
htmltrueRaw inline HTML passes through
gfmtrueGitHub Flavored Markdown: tables, strikethrough, task lists, autolinks
breaksfalseStandard CommonMark line-break rules
langPrefixhljs language-Feeds fenced code to highlight.js
highlighthighlight.js callbackSilently skips unknown languages

Editor (CodeMirror 6)

  • Markdown language mode with syntax highlighting (custom light/dark HighlightStyles)
  • Line numbers, active-line highlight, soft line wrapping
  • Autocompletion, bracket matching, undo/redo history, code folding

UI & window

ElementBehavior
Title bartitleBarStyle: Transparent — native traffic lights, toolbar acts as the drag region
Window1180 × 760 default, 760 × 480 minimum
PanesResizable via pointer-drag divider, clamped to 20–80 % editor width
ToolbarNew / Open… / Save / full-window preview / theme toggle buttons; shows current file name
Themeprefers-color-scheme on launch; button toggles light/dark live
Window titleMirrors the open file's name

Status bar

FieldDetail
Word countWhitespace-delimited token count of the document
Character countRaw UTF-16 length of the document
CursorLn <line>, Col <column> of the main selection head
Dirty dotBullet next to the file name while unsaved changes exist

File I/O

  • Open dialog filters: md, markdown, mdown, txt (+ all files)
  • Save dialog: defaults to untitled.md, md filter
  • Drag & drop: opens dropped files in place (path-based on macOS/Windows; text fallback in the webview)
  • Guards: dirty state blocks New/Open via confirm dialog and blocks window unload
  • Associations: bundle.fileAssociations declares .md / .markdown / .mdown with role Editor (→ CFBundleDocumentTypes on macOS, file-type registrations on Windows, MIME in the .desktop entry on Linux). The path is forwarded to the frontend per platform — RunEvent::Opened on macOS, the launch argument on Windows/Linux — and queued in Rust (so cold-launch opens aren't lost) before being loaded on startup and live. tauri-plugin-single-instance keeps MarkUp to one instance, forwarding the file from a re-launch (Windows/Linux) to the running instance
  • Setting as default (macOS): right-click any .mdGet InfoOpen withMarkUpChange All… — or double-click once and confirm the picker

Keyboard shortcuts

ActionmacOSWindows
New document⌘NCtrl+N
Open file⌘OCtrl+O
Save file⌘SCtrl+S
Full-window preview⌘ECtrl+E

Platform support

PlatformRequirementNotes
macOS10.15+Native Apple Silicon build; x86_64 build also possible via --target x86_64-apple-darwin
Windows10 / 11 x64Requires WebView2 runtime (preinstalled on Win 11); NSIS + MSI installers
Linuxx64 (glibc)Requires WebKitGTK 4.1 + GTK3 runtime; .deb, .rpm (Arch: webkit2gtk)

Release profile (Rust)

opt-level = "s" (small binaries), lto = true, codegen-units = 1, panic = "abort", strip = true.

Security model

  • Access is declared up front through the Tauri v2 capability system in src-tauri/capabilities/default.json — no runtime permission prompts.
  • Granted: core:default, dialog:default, and fs text/binary read + write with full-disk scope. The native file dialogs are the user-facing gate; the app has no network commands.
  • CSP is null while in development; tighten before shipping a public build.

Repository structure

MarkUp/
├── .github/
│   └── workflows/
│       └── release.yml            # CI: macOS aarch64 + Windows x64 + Linux x64 → tagged release
├── docs/
│   └── screenshots/               # README screenshots (light & dark mode)
├── icon-source.png                # Master 1024×1024 app icon
├── scripts/
│   └── gen-icon.mjs               # Generates all platform icons from the master
├── index.html                     # App shell: toolbar, panes, status bar
├── src/
│   ├── main.js                    # Editor setup, remarkable rendering, file I/O, UI wiring
│   └── styles.css                 # Light/dark themes, layout
├── src-tauri/
│   ├── src/
│   │   └── main.rs                # Tauri builder + fs/dialog plugins
│   ├── capabilities/
│   │   └── default.json           # ACL: core, dialog, fs scope
│   ├── gen/                       # ACL schemas generated at build time
│   ├── icons/                     # Platform icons (.icns, .ico, .png)
│   ├── build.rs
│   ├── Cargo.toml
│   └── tauri.conf.json            # Window, bundling, build config
├── vite.config.js
├── package.json
└── LICENSE                        # MIT

Development

Prerequisites

  • Node.js 18+ and npm
  • Rust (stable, via rustup)
  • Platform prerequisites per Tauri:
    • macOS: Xcode command line tools (xcode-select --install)
    • Windows: Microsoft C++ Build Tools and the WebView2 runtime
    • Linux: WebKitGTK 4.1 dev packages (e.g. libwebkit2gtk-4.1-dev, librsvg2-dev, libayatana-appindicator3-dev)

Run in development

git clone https://github.com/DexterLagan/MarkUp.git
cd MarkUp
npm install
npm run tauri dev

Build release binaries

macOS (local, Apple Silicon by default):

npm run tauri build
# -> src-tauri/target/release/bundle/dmg/MarkUp_<ver>_aarch64.dmg
# -> src-tauri/target/release/bundle/macos/MarkUp.app

Windows x64 / Linux x64 (local):

# On the target OS (WebKitGTK deps required on Linux)
npm ci
npm run tauri build
# -> src-tauri/target/release/bundle/{nsis,msi,deb,rpm}/

Cutting a release

Releases are fully automated by the release.yml workflow (triggered on v* tags, or manually from the Actions tab):

  1. Bump the version in package.json, src-tauri/tauri.conf.json, and src-tauri/Cargo.toml.
  2. Commit and push a tag: git tag vX.Y.Z && git push origin vX.Y.Z.
  3. The workflow builds all three platforms in parallel (macOS aarch64 on macos-latest, Windows x64 on windows-latest, Linux x64 on ubuntu-latest) and publishes a GitHub Release with the DMG, NSIS + MSI, and deb + rpm installers.

Current release: v1.0.1 — DMG (Apple Silicon), NSIS + MSI (Windows x64), deb + rpm (Linux x64).

Roadmap ideas

  • Autosave and multiple open tabs
  • Export to HTML/PDF
  • Code signing for macOS (Developer ID) and Windows (EV/Code Sign cert) to silence Gatekeeper/SmartScreen

License

MarkUp is licensed under the MIT License — see LICENSE.

Copyright (c) 2026 Dexter Santucci

Contributors

DexterLagan

15 commits

Languages

JavaScript

58.9%

CSS

21.0%

Rust

10.8%

HTML

9.3%