bible-viewer
A Bible reader that puts two Korean translations side by side
PersonalSole designer, developer, and operator2026.01 — Present
ReactTypeScriptViteTailwindFirebase
Why I built it
I often compare two Korean Bible translations verse by verse, but every reader I tried made switching translations a tab change. Reading both at once meant opening two windows. I wanted a viewer that lines the two texts up against the same verse.
What I did
Everything — data pipeline, search indexing, the column layout, Firestore sync, deployment.
What I learned
Importing a 30MB scripture JSON through resolveJsonModule kills tsc with a heap OOM: the type checker
expands the entire literal into a type. Switching to ?url plus a runtime fetch fixed it.
I also spent a while deciding whether translations belonged in static JSON or Firestore. Scripture is immutable and large, so it stayed static; only per-user state (bookmarks, reading position) went to Firestore. That is where I learned that Firestore’s last-write-wins semantics will resurrect a deleted document from a stale write on another device unless deletions are modeled as tombstones.
The interesting part
I built column drag-and-reorder with raw Pointer Events, no dnd-kit. The layout is a row-based grid, so a
“column” is not one DOM node. I laid a single absolutely-positioned pillar card behind transparent cells
and wrote CSS custom properties (--drag-x) straight onto an ancestor, so a pointermove triggers zero
re-renders. The other columns yield with translateX(±pitch). It ends up feeling like rearranging icons
on an iPhone home screen.
What I’d do differently
To run integration tests without a browser I executed the Firestore logic in Node through Vite’s
ssrLoadModule. Honest as that is, it still does not cover IndexedDB persistence in a real browser.