A lightweight, clean desktop app for opening, reading, editing, and exporting Markdown files.
Built with Electron, React, TypeScript, and electron-vite.
Current version: v0.1.4
Download: Windows · macOS (DMG) · Linux (AppImage) · Linux (DEB)
Moji (文字) literally means "letter", "character", or "writing" in Japanese. Short and easy to remember, it evokes characters and writing. The name fits its purpose: opening, editing, previewing, and exporting Markdown smoothly—without distractions.
- Open Markdown files: supports
.mdand.markdownthrough file dialog, drag and drop, CLI/file association entry points, and single-instance forwarding. - Multi-document workspace: horizontal tabs, dirty markers, close buttons, duplicate-file detection, and unsaved-change confirmation with clear action icons.
- Tab management: close other tabs, tabs to the right, saved tabs, or all tabs from the document tab menu.
- Preview mode: sanitized Markdown rendering with heading anchors, outline navigation, tables, task lists, footnotes, definition lists, subscript/superscript, highlight/insert marks, emoji shortcodes, LaTeX math via KaTeX (
$…$and$$…$$), linkify, typographer, syntax-highlighted code, and copy buttons for code blocks. - Graphics and Mermaid diagrams: every valid fenced
mermaidblock supported by bundled Mermaid renders as a responsive diagram, including flowcharts, sequence, Gantt, class, ER, state, and journey diagrams. Click any rendered SVG or Markdown image to inspect it in a modal with zoom, drag navigation, a minimap, and individual PNG export; malformed Mermaid blocks remain readable code blocks. - Outline navigation: collapsible heading tree available in Preview and Editor modes. Preview uses scroll-spy; clicking any heading scrolls preview or moves editor cursor to its Markdown source.
- Search and replace: top-bar search highlights matches in preview/editor, shows occurrence count, jumps to the next match, and replaces one match or all matches in the active document.
- Editor mode: CodeMirror 6 Markdown editor with line numbers, history, wrapping, localized untitled document names, Markdown formatting shortcuts, and save/save as flows.
- Export mode: export the active document as HTML, PDF, or PNG. PDF supports A4, Letter, Legal, portrait, and landscape; long code lines wrap in PDF and PNG exports.
- Diagram exports: rendered Mermaid diagrams are embedded as self-contained SVG in HTML, PDF, and PNG exports.
- Settings view: centered in-workspace panel for language, preview typography, and a localized shortcut reference.
- About view: in-workspace panel showing app name, version (from
package.json), author, repository link, and the story behind the name. - Markdown guide: bundled localized reference documents (
samples/markdown-guide.<locale>.md) opened from the status bar. - Recent files: Welcome screen shows recently opened Markdown files and lets you reopen or remove entries.
- Remembered app state: window size/position, recent files, last used folder, language, preview typography, and Markdown preview theme are persisted in user settings.
- Automatic updates: installed Windows NSIS and Linux AppImage builds check GitHub Releases, show download progress, and restart only after protecting unsaved documents.
- Markdown themes: dark/light toggle for rendered Markdown. App chrome remains dark; exports always use the light theme.
- Internationalization: English, Portuguese (Brazil), Spanish, Japanese, Chinese, and Russian. Initial language follows the OS when possible and user choice is persisted.
- Security: sandboxed renderer, context isolation,
nodeIntegration: false, DOMPurify sanitization, and external links opened in the OS browser. - Keyboard shortcuts: common file, search, replace, tab, preview, export, fullscreen, and font-size actions; Settings lists every available shortcut.
Windows and Linux install from the downloads above with no extra steps.
macOS refuses to open Moji the first time, saying it is damaged or that Apple cannot check it for malicious software. The app is fine. Signing an app requires a paid Apple Developer account, which Moji does not have yet, so macOS treats it as coming from an unidentified developer.
- Drag Moji from the DMG into your Applications folder.
- Double-click it. macOS blocks it. Dismiss the dialog.
- Open System Settings > Privacy & Security, scroll to the Security section, and click Open Anyway next to the message about Moji.
- Confirm. macOS remembers the choice, so this is a one-time step per version.
Control-clicking the app and choosing Open no longer works on macOS 15 (Sequoia) and later: Apple removed that override. System Settings is the only route through the interface.
If you prefer the terminal, clearing the quarantine flag skips the prompts entirely:
xattr -dr com.apple.quarantine /Applications/Moji.appThe missing signature is also why automatic updates stay off on macOS: upgrade by downloading a new DMG. Both limitations disappear once the app is signed and notarized.
- Node.js
^20.19.0 || >=22.12.0(required by Vite 7 and electron-vite 5; packaging also needsrequire()of ES modules, unflagged since Node 22.12) - npm
npm install
npm run dev
npm run typecheck
npm test
npm run buildUseful scripts:
npm run dev: launch Electron with hot reload.npm run typecheck: run TypeScript checks without emitting files.npm test: run the Vitest suite once (npm run test:watchfor watch mode).npm run build: build main, preload, and renderer intoout/.npm run preview: run the built app preview.
npm run dist
npm run dist:win
npm run dist:linux
npm run dist:macArtifacts are written to release/.
Current packaging targets:
- Windows: NSIS installer, x64, with automatic updates.
- Linux: AppImage with automatic updates, plus deb for manual installation.
- macOS: universal (Apple Silicon + Intel) DMG and ZIP, without automatic updates.
File associations for .md and .markdown are declared in electron-builder.yml.
macOS releases are not code-signed or notarized, because that requires a paid Apple Developer account. Consequences:
- Gatekeeper blocks the app when the DMG is downloaded from the web. Users open it through System Settings > Privacy & Security > Open Anyway, or by clearing the quarantine flag with
xattr -dr com.apple.quarantine /Applications/Moji.app. Control-clicking the app and choosing Open stopped working in macOS 15 (Sequoia), where Apple removed that override. The user-facing steps live under Installation. - Automatic updates stay disabled on macOS. Squirrel.Mac refuses to replace an unsigned bundle, so
updater.tsreportsunsupportedthere and users update by downloading a new DMG.
To sign locally, install an Apple Developer ID certificate in the keychain and drop the CSC_IDENTITY_AUTO_DISCOVERY=false override; build/entitlements.mac.plist and hardenedRuntime are already configured for notarization.
- Update
versioninpackage.jsonandpackage-lock.json. - Commit changes, then create and push matching tag such as
v0.2.0. .github/workflows/release.ymlvalidates tag, then builds Windows, Linux, and macOS in that order, uploading each platform's artifacts to a draft release. No binary is attached by hand.- Workflow makes GitHub Release public once Windows and Linux have succeeded: NSIS, AppImage, DEB, and the
latest.yml/latest-linux.ymlupdate metadata.
A Windows or Linux failure leaves the release as a draft. A macOS failure does not: the publish step waits for the macOS job to finish, so the release is never made public while the DMG is still uploading, but it does not require it to have succeeded. macOS is unsigned and secondary, and a broken DMG should not hold back a good Windows and Linux release. The macOS job still fails visibly in the workflow.
electron-updater runs only in packaged Windows NSIS builds and Linux AppImages. Development and deb builds do not self-update. AppImage must live in a user-writable directory to be replaced successfully. Windows production releases should use an Authenticode certificate through electron-builder signing environment variables; never store certificate credentials in repository.
electron/
main.ts Window lifecycle, persisted bounds, file opening, single-instance flow, close guard, macOS application menu, IPC registration
preload.ts Safe renderer API exposed through contextBridge
shared.ts Shared IPC names, settings, export types, languages, recent-file limits, supported extensions
updater.ts GitHub release checks, update download state, and NSIS/AppImage installation
settings.ts User settings persistence, window bounds, recent files, preview theme, and last dialog directory
export.ts HTML/PDF/PNG export implementation with remembered output directory
png.ts Streaming PNG encoder used to keep tall-document exports within memory
src/
App.tsx Renderer state, document actions, close guard wiring, mode switching
components/ Top bar, tabs, sidebar, outline tree, preview, Mermaid viewer, editor, export/settings/about dialogs, confirm dialog, welcome view
lib/ Markdown rendering, Mermaid rendering, outline extraction, preview scroll-spy, export HTML, hooks
locales/ en, pt-BR, es, ja, zh, ru translation files
styles/ Theme tokens, app shell CSS, Markdown preview CSS
samples/ Bundled Markdown documents (full Markdown guide)
.ai-framework/RULES.md: project rules for AI-assisted changes..ai-framework/DESIGN.md: visual system, tokens, layout, and component rules.openspec/specs/: current behavior specs.
MIT © Alex Ishida







