Web app overview
For what the editor does from a user's point of view, see the user guide overview.
The web app (apps/web) is the lesson editor, the lesson hub and everything around them. It is a single-page app with server rendering for public pages, and most of its logic lives in the shared @spelling-creator/core package (packages/core) so the MCP server and the Worker can use the same code.
Stack
- React 19 + Vite 8, with the React Compiler, React Router 7 and
vite-plugin-pwafor the installable, offline app. - shadcn/ui on Radix, with Tailwind CSS 4 for the UI (see Design system).
- tiptap 3 for lesson text blocks and for comments and bios (see Formatting, footnotes & sources and Rich text).
- isomorphic-git on LightningFS for version history: every lesson is a real git repository in the browser, one file per content block, committed automatically as you pause.
- Yjs for the live collaboration document, synced through a Cloudflare Durable Object room with one WebSocket per participant.
- i18next / react-i18next for every user-facing string (see Internationalization). Only English ships today.
docxto build Word documents, andmammothplushtml2pdf.jsto turn that same document into a PDF, all in@spelling-creator/coreand loaded on demand (see Export pipeline).- transformers.js (
@huggingface/transformers) for the models that run in the page: lesson summaries, lesson translation, reading imported text with a model (document import) and the natural read-aloud voice in interactive mode. - Supabase (
@supabase/supabase-js) for passwordless magic-link sign-in (see Hub & accounts). - The companion Worker in
apps/apihandles the hub, AI features, the Pixabay proxy and collaboration rooms. SetVITE_API_URLto point the app at it (see Getting started).
How the main features are built
| Feature | How it works | Page |
|---|---|---|
| Saving and the lesson list | Each lesson is kept in IndexedDB, with images as binary blobs so a large draft isn't capped by localStorage's ~5 MB quota. The editor holds a whole library of lessons, each with its own document and git repository. | Lessons on this device |
| Preview and lesson page | Both render the lesson model straight to React with LessonView, in the app's light or dark theme. No Word document is built to show a lesson. | Export pipeline |
| Word, PDF and Google Docs | One shared document builder makes the .docx; the PDF is that file converted to HTML with mammoth and rendered with html2pdf.js; Save to Google Docs uploads the same file to Drive with a Google OAuth2 token. | Export pipeline |
| Question blocks | The eight types, their colors, labels and Word styles are defined once in packages/core/src/questions.js. | Export pipeline |
| VAKT activities | A block type of its own, defined in packages/core/src/vakt.js. | VAKT activities |
| Text formatting | Text blocks are stored as tiptap JSON once formatted, with footnotes and a lesson-level source list. | Formatting, footnotes & sources |
| Pictures | Pixabay goes through the Worker; Wikimedia Commons and Wikidata are called from the browser. Credits are stored apart from captions. | Images |
| Long lessons | Sticky section headers, per-section question numbers, collapsible sections, the section outline and scroll anchoring. | Navigating large lessons |
| Import from text | A rule-based parser, with an optional on-device model for sections the rules can't read. | Document import |
| Comments and bios | Sanitized HTML, enforced by the Worker's allow-list sanitizer and again at render time. | Rich text |
| Live collaboration | A server-side room (a Cloudflare Durable Object), live cursors and an in-session chat. Invited people only start editing once the host adds them. | Live collaboration |
| Version history and forks | Forking clones a lesson's repository, and a fork can pull the original's changes in, merged block by block. | Version history |
The rest of this section covers project structure, pages & routing, server rendering, mobile layout and the other features one page each.