A desktop writing room for long-form fiction — offline, crash-safe, and warm to look at.
Electron · React · TypeScript · TipTap. Windows, browser, and Android tablet.
Platform status · Documentation · Download
Writing a book and just want the app? Read the setup guide in English or Русский. No development tools required.
✳✳✳
Scriptorium Writer is a local-first desktop app for writing long books. It looks like a warm parchment page in a leather frame, saves constantly and safely, keeps a full version history of every chapter, and checks spelling in Russian and English at the same time — all completely offline. Your stories live in a plain, syncable folder on your own computer, one file per chapter, not locked inside a database. Priorities, in order: (1) reliability of your data, (2) comfort of writing, (3) warm "book" aesthetics.
Most of this app exists to make sure you never lose a word. Manual Save and every kind of autosave share one write path, and that path is always atomic — so a crash, a full disk, or closing the laptop mid-save can never corrupt what you already wrote.
- JSON canon + Markdown shadow. Each chapter is stored as lossless ProseMirror
JSON (the only file the app reads back) plus a best-effort
.mdcopy any tool can read. The.mdwrite can fail without ever endangering the canon. - Atomic writes only. Temp file →
fsync→rename. Never written in place. - Version snapshots on every successful save, pruned to a configurable cap — roll any chapter back to an older draft from inside the app.
- Never blanks corrupt data. A missing or unparseable canon triggers a one-click recovery from the newest snapshot; the bad file is never overwritten silently.
- Quit guard. Closing the app waits for a final flush (or a 5-second safety timeout) so a stuck window can never lose your last keystrokes — or wedge shut.
| Capability | What it does |
|---|---|
| Book-themed editor | Parchment TipTap page: marks, alignment, undo/redo, first-line-indent toggle, ✳✳✳ dividers, focus mode. |
| Autosave & quit guard | 2 s debounce + 2 min interval + lifecycle flush, all on manual Save's write path; never exits with unsaved work. |
| Version history | A timestamped snapshot per save; preview an older draft read-only, or restore it (snapshotting the current state first). |
| Footnotes | Inline footnotes with [N] markers auto-numbered by document order — hover to read, select to edit; lossless round-trip. |
| Offline spellcheck (RU + EN) | Simultaneous RU + EN Chromium spellcheck from bundled dictionaries, with suggestions and add-to-dictionary — no network. |
| Navigation & views | Sidebar router: Editor, Chapters (drag-to-reorder), Story info, Notes, Search, Statistics, Library, Settings. |
| Cleanup wand | Text-cleanup rules (spacing, punctuation, -→—, quotes→«…») applied as one undoable transaction behind a preview. |
| Find & Replace | Non-modal bar with live highlighting, case-sensitive and whole-word toggles, and a single-transaction Replace-all. |
| Full-text search | Read-only sweep of every chapter and every notes section for a phrase, with hit counts, snippets, and jump-to-match. |
| Import / Export | Import a .md/.docx as one chapter or split by headings; export any chapter or the whole story to .docx/.md. |
| Library backup | One click zips the whole library folder (stories, snapshots, notes, .trash/) to a chosen path — atomic, read-only. |
| Auto-update | Packaged builds check GitHub Releases in the background and offer a restart routed through the quit-guard flush. |
| UI language (RU / EN) | Switch the whole interface between Russian and English live from Settings — never touches your story text. |
Per-feature detail: docs/features.md.
| Platform | Status | How it ships |
|---|---|---|
| Windows 10/11 | Released — 1.6.0 | Installer, auto-update |
| Browser / PWA | Released — 1.6.0 | Open the app, installable |
| Android tablet | Beta — 1.6.0 | Sideloaded APK, updated by hand |
Detail: docs/web-pwa.md and docs/android.md.
✳✳✳
Download the Windows installer from the Releases page.
Windows will show a "Windows protected your PC" warning because the installer has no paid code-signing certificate yet — click "More info", then "Run anyway".
No-code walkthroughs: English · Russian.
✳✳✳
- Node.js ≥ 22.12 (LTS) — the Electron 43 / electron-builder 26 toolchain
require()s ESM-only dependencies, so on older Nodenpm run build:winfails withERR_REQUIRE_ESM. Windows:winget install OpenJS.NodeJS.LTS, then open a new terminal. - npm 10+ (bundled with Node; Node 24 ships npm 11).
- Building the Android app additionally needs Android Studio, JDK 21 and SDK Platform 36 — see docs/android.md.
npm install
npm run dev # opens the book-themed editor on a seeded demo chapternpm 11 note: npm 11 blocks package install scripts by default, so
npm installmay not download the Electron binary. Ifnpm run devfails withError: Electron uninstall, fetch it once withnode node_modules/electron/install.js(or allow it vianpm approve-scripts electron), then re-runnpm run dev.
| Script | What it does |
|---|---|
npm run dev |
Launch the app in development with HMR and DevTools. |
npm run dev:web |
Launch the browser build on a LAN-reachable dev server. |
npm run build |
Typecheck, then build main / preload / renderer into out/. |
npm run build:web |
Typecheck, then build the browser bundle into dist-web/. |
npm run build:win |
Full build + package a Windows NSIS installer into release/. |
npm run start |
Preview the production build (electron-vite preview). |
npm run typecheck |
Type-check the node (main/preload/shared) and web (renderer) projects. |
npm run lint |
ESLint over src (.ts/.tsx). |
npm run test |
Run the Vitest unit suite once (data layer, Node env). |
npm run test:watch |
Run Vitest in watch mode. |
npm run test:browser |
Run the browser-only suite in real Chromium via Vitest browser mode. |
npm run format |
Prettier-format src. |
npm run sync:android |
Build the web bundle, then npx cap sync android. |
npm run build:web:dev |
Build the browser bundle in development mode (keeps the DEV harness). |
npm run sync:android:dev |
build:web:dev + npx cap sync android — the on-device debug loop. |
npm run open:android |
npx cap open android. Does not build or sync first. |
npm run run:android |
Build the web bundle, then npx cap run android (syncs and deploys). |
- main (
src/main/) — window lifecycle, IPC handlers, spellcheck, docx/zip, and the Electron wiring that handsFileServicea Node filesystem port. - data (
src/data/) — the platform-neutral data layer: atomic writes, snapshots, scan/restore, Markdown backup. All disk work goes through an injectedFsPort. - platform (
src/platform/{node,web,capacitor}/) — oneFsPortimplementation each, overnode:fs, OPFS, and@capacitor/filesystem. All three pass one shared contract. - preload (
src/preload/) — a typedcontextBridgewindow.apisurface; thin wrappers overipcRenderer.invoke. - renderer (
src/renderer/) — React UI. Never importsfs,path, or any Node built-in. Enforced bycontextIsolation: true/nodeIntegration: false. - shared (
src/shared/) — domain types (the IPC contract), schema-version constants, errors, and the word-count and footnote-markdown helpers, imported by all three processes.
Detail: docs/architecture.md.
Scriptorium-Writer/ ← library root (libraryPath)
stories/
<story-id>/
story.json ← StoryMeta + chapterOrder + schemaVersion
chapters/
01-slug.json ← Chapter canon (ProseMirror JSON) — SOURCE OF TRUTH
01-slug.md ← Human-readable Markdown backup (lossy, write-only)
versions/
<chapterId>/
2026-07-09T10-15-00-123Z.json ← per-chapter snapshots (pruned to a cap)
notes/
notes.json
.trash/ ← soft-deleted stories/chapters land here
NN-slug filenames are for human legibility only; the app always resolves chapters by the
stable id stored inside each file, so files may be renamed safely. Because they exist
to be read by a human they follow the chapter title — renaming a chapter renames its .json
and .md on the next save, and reordering renumbers the NN- prefixes. Per-platform roots
are in docs/architecture.md.
✳✳✳
- docs/writers-guide.en.md — install and use the app, no code.
- docs/writers-guide.ru.md — the same guide in Russian.
- docs/architecture.md — processes, the filesystem port, data locations, repository layout.
- docs/android.md — the tablet build: storage, permissions, signing, verification status.
- docs/web-pwa.md — the browser build, OPFS, offline and update behaviour, backups.
- docs/features.md — per-feature notes on how each capability works.
- docs/CHANGELOG.md — released versions, newest first.
All rights reserved. The source is published for reference; no licence to use, copy, or distribute is granted.
✳✳✳
Issues & questions → github.com/julia-shtal/scriptorium-writer/issues