A PDF reader that you actually want to use.
Optimized for textbooks and long-form content.
Write in the margins, collate and review your notes, track your progress, and navigate your documents seamlessly.
Scriptorium runs in your browser at kevin-taha.github.io/Scriptorium and installs as an app. There's no account and no server: your books and notes stay on your devices, or in a folder you choose (how data is stored).
Click beside a passage to write a note level with it, or select text and press N to quote it. Highlight in one of five colours and attach a note to any highlight. Notes never overlap, take bold and italics, and save as you type.
Shift+R lays out every annotated page with its thumbnail, notes and highlights. Filter by colour or text, edit in place, and export to Markdown. Large reviews load pages as you scroll; the review filter still searches every note. Select Show all pages to make every note available to the browser's Find command or an assistive technology at once.
Press G and type a page number, a chapter, a bookmark, words from your notes or anything in the text. Printed page numbers work, roman numerals included.
Hover a link like "see Figure 2.1" to preview it without leaving your page. When you do jump, a Return to p. N pill takes you back, and keeps offering the next place back through a chain of jumps; its menu skips straight to any earlier one.
F hides everything but the page, and R adds a reading ruler. Light, sepia and dark themes, with optional page inversion for reading at night.
Covers, progress, and your place saved as you read. Link a folder of PDFs, on your computer or in OneDrive, Google Drive or Dropbox, and every computer that links it shares the same books, notes and progress.
- Book map: a strip along the right edge marking chapters, notes and bookmarks; hover to preview.
- Chapter progress: a hairline under the toolbar that fills as you read.
- Bookmarks: click the ribbon on a page or press B.
- Long books: pages render as you reach them, so 1,000-page textbooks stay quick.
- Backups: export everything to one file and restore it anywhere.
- Offline: once installed, your library opens without a connection.
Press ? in the app for the full list.
The ones you'll use most
| Shortcut | Action |
|---|---|
| G | Go to a page, chapter, bookmark or note, or run an action (#N for a PDF page number) |
| Ctrl+F or / | Find in the book; F3 / Shift+F3 step through matches |
| N | New margin note on the current page, quoting any selected text |
| H | Highlight the selected text in the colour used last |
| B | Bookmark the current page |
| Shift+R | Open or close the notes review |
| F | Focus mode (Esc also leaves) |
| R | Reading ruler |
| [ | Show or hide the sidebar |
| Alt+← / Alt+→ | Back / forward through jumps |
| + / - / 0 | Zoom in / zoom out / fit width |
| Ctrl+B / Ctrl+I | Bold / italic while writing a note |
| Esc | Leave focus mode, dismiss the return pill or close a menu |
The live site at kevin-taha.github.io/Scriptorium is
published from main on every merge. To run it yourself, Scriptorium uses Bun, a
single install that provides the runtime, package manager and script runner:
# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"
# macOS / Linux
curl -fsSL https://bun.sh/install | bashThen, from the repository:
bun install
bun run devOpen the printed local address and drop a PDF onto the library. To install it as an app, use your browser's install button in the address bar, or Install app in the library when it appears.
| Command | Description |
|---|---|
bun run dev |
Start the development server |
bun run build |
Type-check and build for production into dist/ |
bun run preview |
Serve the production build locally |
bun run check |
Type-check, lint, check formatting, unit test and build |
bun run lint / bun run format |
Lint / format the code (Biome) |
bun run test |
Run unit tests (Vitest) |
bun run e2e |
Run end-to-end tests (Playwright) against the production build |
bun run fixture |
Generate the synthetic textbook used by the end-to-end tests |
The first end-to-end run needs a browser: bunx playwright install chromium.
Scriptorium is a single-page React application built with Vite and TypeScript. PDFs are rendered with pdf.js by a custom virtualized viewer that lays each page out beside its margin column.
src/
app/ App shell, hash router, settings and theming
components/ Shared UI primitives (toasts)
features/
library/ Library screen and PDF import
reader/ Reader shell, viewer engine, zoom, link peek
navigation/ Jump history, return pill, bookmarks, outline, page labels, chapter progress, shortcuts
palette/ Go to: pages, chapters, bookmarks, notes and actions in one box
bookmap/ The book map along the reader's right edge
focus/ Focus mode and the reading ruler
notes/ Margin notes (bold/italic editing), collated review, Markdown export
search/ Full-text index and in-page highlights
settings/ Library & storage: linked folder, backups, persistent storage
sync/ Folder sync engine
lib/
pdf/ pdf.js loading, destinations and outline, thumbnails
storage/ IndexedDB schema and repository
sync/ Backup format, merging and device identity
styles/ Design tokens and base styles
docs/ Roadmap, data and sync model, design spec, README images
e2e/ Playwright end-to-end tests
scripts/ Development scripts (test fixture generator)
All persistence goes through src/lib/storage/repository.ts, which keeps the door open for a
filesystem-backed store in a future desktop build. State lives in small
Zustand stores per feature.
The production build ships a strict Content-Security-Policy (contentSecurityPolicy in
vite.config.ts): scripts, styles, fonts and workers come only from the app's own origin, and
runtime styles go through constructed stylesheets rather than <style> elements.
See docs/ROADMAP.md for what's next, docs/DATA.md for how
data is stored and synced, and docs/DESIGN.md for the design system.





