Three months ago I just wanted a Bible app that didn’t feel like a social network. No streaks, no notifications, no accounts, no clutter. Just a calm place to read and dig into the text when I felt like it.
That side project turned into Focused Word. It’s an open-source installable PWA that runs completely offline.
https://focusedword.com
Full disclosure up front: this whole thing was vibe-coded. I used AI heavily for almost everything — architecture, features, the parsers, the scrapers, the two backend services, debugging, all of it. I stayed in the loop and iterated a lot, but very little of the code was written the old-fashioned way.
What I aimed for
- Completely offline (Strong’s, cross-refs, word classes, everything)
- No accounts or tracking
- Installable on phone and desktop
- No build step — just native ES modules
- Chapter changes that feel instant
How it’s put together
I skipped frameworks and bundlers on purpose. Everything is plain modern JS.
The main glue is a simple Bridge (mediator + service registry). Modules register themselves on startup and talk to each other through direct calls or events. Kept things decoupled without dragging in a big state library.
Storage is split in two:
- Scripture, Strong’s, morphology, cross-references, etc. live in SQLite WASM (sql.js) on top of OPFS / Cache API
- User stuff (notes, highlights, bookmarks, reading progress) sits in IndexedDB
That split worked out well. The big reference data stays out of IndexedDB and queries stay fast.
For rendering I don’t store pre-made HTML. Chapters come back as token streams. A renderer builds a DocumentFragment in one pass (bionic reading, red letter, poetry layout, footnotes, the works) and drops it in. The extra study layers (word coloring, Clear Reading, Strong’s underlines) load in right after so the text shows up on the first frame.
The part that took longer than expected
A big chunk of the work wasn’t even the client. I ended up writing a bunch of parsers and scrapers to build the actual SQLite databases — Bible text, lexicon data, morphology, cross-references, word classes, summaries, all of it. Cleaning and normalizing that data properly took a lot more time than I thought it would.
I also built two smaller supporting projects:
- A sync server that handles the private multi-device sync. You just get a 3-word passphrase generated from a Bible wordlist. No accounts, no email, no passwords.
- A repo server that serves extra translation packages and study databases so people can download them on demand (with SHA-256 checks).
PWA side
Pretty standard service worker + manifest. Critical assets (fonts, the WASM binary, BSB data, lexicon) are cached hard so it actually works offline.
Stuff that surprised me
- You can get surprisingly far in 2026 with zero build tooling if you just stick to native ES modules
- OPFS + SQLite WASM is solid for this kind of reference data
- Making the first paint of a chapter feel instant meant I had to carefully cancel background study work when the user navigates away quickly
- The data pipelines and the two little servers ended up being a bigger part of the project than the frontend
- Vibe-coding a project this size actually worked better than I expected, as long as I kept directing it hard
It’s all MIT. Happy to answer questions about the architecture, the SQLite setup, the sync approach, or the general experience of building something like this mostly with AI.
What have other people run into with offline-first PWAs or SQLite WASM in production?