A fast, minimal, realtime note-taking app.
Markdown you can see and edit live, notes that link to each other, and everything in sync across web, Windows and macOS.
- Three ways to write. Source (raw Markdown), Split (Markdown beside a live view, with a draggable divider) and Live (a formatted view you can type straight into).
- Type
/for anything. Headings, lists, checklists, quotes, callouts, code blocks, tables, dividers, highlights, dates, and links to other notes. - Link your notes.
/linksearches your notes and inserts either a compact link chip or a rich preview card. Click one to jump to that note. - Paste images. Paste or drop an image into a note; it is compressed and saved with the note. Click any image to enlarge it and download it again.
- Download as Markdown or PDF.
- Realtime sync. Firestore listeners keep every device up to date, with an offline cache, autosave and a live sync indicator.
- Keyboard first. Command palette, formatting shortcuts, and shortcuts you can change in Settings.
- Looks good everywhere. Light, dark or system theme, responsive down to phone width, no UI component library: every component is hand-built.
The note above is docs/sample-note.md. It uses a callout, a checklist, a link chip and a preview card to other notes, syntax-highlighted code and a table.
Type / to insert blocks |
Link to other notes |
|---|---|
![]() |
![]() |
| Live view, light theme | Command palette |
|---|---|
![]() |
![]() |
| Action | Shortcut |
|---|---|
| New note | Ctrl N (changeable) |
| Command palette | Ctrl K (changeable) |
| Focus search | Ctrl Shift F (changeable) |
| Bold / italic / code / link | Ctrl B / Ctrl I / Ctrl E / Ctrl L |
| Insert menu | / |
| Indent / outdent a list item | Tab / Shift Tab |
| Toggle Live view | Ctrl Shift P |
Open Settings (the gear in the sidebar, or the command palette) to change the app-level shortcuts.
**bold** *italic* ~~strike~~ `code` ==highlight==
# Heading - [ ] task > quote ---
> [!TIP] (also NOTE, IMPORTANT, WARNING, CAUTION)
[Title](enwrite://note/<id>) a link to another note
[Title](enwrite://note/<id> "card") a preview cardnpm install
npm start # http://localhost:4200Desktop (Electron):
npm run electron:local # production build, then launch
npm run electron:dev # with `npm start` running: launch against the dev server
npm run dist:win # Windows installer (.exe) in release/
npm run dist:mac # macOS disk image (.dmg), run on a MacAngular 22 (standalone components, signals) · Firebase 13 (Auth, Firestore) · Electron 45 · marked + DOMPurify for rendering · turndown for editing the live view · highlight.js for code.
The web config lives in src/environments/firebase.ts (project enwrite-web). In the Firebase console:
-
Authentication: enable Email/Password and Google, and add your hosting domain to the authorised domains.
-
Deploy the security rules so each user can only read their own notes:
npx firebase-tools deploy --only firestore:rules
Notes are stored at users/{email}/note/{id}. Small pasted images are kept inside the note document (compressed, up to a few hundred KB each). If you enable Firebase Storage (needs the Blaze plan), set imageStorageEnabled = true in src/environments/firebase.ts and deploy storage.rules to store images there instead.
npm run build:web # or: npx ng build
npx firebase-tools deploy --only hostingPushing to master also runs .github/workflows/deploy.yml. It needs a Firebase service-account key saved as the repository secret FIREBASE_SERVICE_ACCOUNT_ENWRITE_WEB.
Pushing a tag like v2.1.0 runs .github/workflows/release.yml, which builds the Windows installer and the macOS disk images on GitHub and attaches them to a release. The installers are not code-signed, so Windows SmartScreen and macOS Gatekeeper will warn on first launch.
Google sign-in has to run in a real browser. The desktop app serves its own build on a temporary localhost port, opens the sign-in page there, and the page posts the token back to the app over your own machine. Nothing leaves your computer except the normal Firebase sign-in.






