Product case study
eBook Pro: turning reading into knowledge
A reader for people who study what they read. The case study covers why it is a local-first Flutter app, the three hardest engineering problems, and what the product still does not do.
Web live · Android in preparation
- Role
- Product, design and engineering
- Stack
- Flutter, Dart, Drift, Firebase, Google ML Kit
- Version
- 1.5.1 (build 9)
- Links
- ebookpro.hycyon.com · ebookpro.web.app
The problem
People who study a book use three tools: a reader, a notebook and a flashcard app. Every highlight has to be copied from the first to the second and again to the third, and scanned or non-English books make each step worse.
eBook Pro starts from one question: how do you shorten the distance between reading a sentence and understanding it?
Product philosophy
The product moves in one direction: read, understand, research, annotate, connect, learn, create. Three decisions follow from that.
- Your own files. The reader opens your PDF, EPUB and text files rather than selling a library.
- Local first. Books, progress and notes live in a local SQL database on the device. The network adds features; it is not required to read.
- AI is optional and bounded. It explains a selection. It does not replace reading.
UX decisions
- A page turn with physical shading, written as GLSL fragment shaders, so reading a long book feels like handling a page. This is the reason for Flutter over native.
- Peek-and-pop word lookup and translation, so a lookup does not take the reader out of the page.
- A progress overlay that shows pages left in the chapter and time remaining, and shows a dash until it has enough reading-speed samples rather than a misleading zero.
- Three reading palettes with literary typography and a generous line height.
- Zoom and page turning that never fight each other: paging is disabled while a zoom or selection gesture is active.
Engineering
One Flutter codebase for web and Android. Native Swift and Kotlin would have meant building every feature twice, and Flutter exposes the shader pipeline the page turn depends on.
Drift (type-safe SQL) is the local database. The architecture notes record that Isar was considered and rejected because the project had stalled, a decision made after researching it rather than assuming it.
Firebase supplies authentication, Firestore, Cloud Functions and Cloud Storage. Google ML Kit provides on-device OCR and translation, so scans never leave the device.
Architecture
Three layers: core (data, parsing, geometry, OCR, services), domain (logic that spans features, such as spaced-repetition scheduling and streaks) and presentation (screens and reader widgets). Repositories are the only code that touches both the database and the domain models, so the rest of the app sees plain objects and streams.
The hard problems
Everything on a page must agree on where things are
Native PDF text, OCR words, search matches, selections and the magnifier all draw over the page. If each computed its own coordinates they would drift apart, especially on rotated pages and two-page spreads.
They all go through one chain: document space, then a normalised upright page space, then the composed frame, then the viewport, then the zoom matrix. The two-page spread layout is defined once and used both for drawing and hit-testing, so painted pages and their text layers cannot disagree. PDF rotation behaviour was verified against real rotated PDFs and unit tested.
OCR on a phone without hurting the phone
Scanned pages have no text. The text layer checks memory, then a disk cache, then native text, and only then queues OCR. The queue runs one job at a time, newest page first, and drops pages the reader has already left. Parallel OCR was rejected because ML Kit is already multi-threaded and parallel jobs would only compete for memory.
Results are cached by a fingerprint of the file (size, modified time and the first and last 64 KiB), written atomically and validated on read.
EPUB files as they exist in the wild
The EPUB pipeline reads EPUB 2 and 3 leniently: case and percent-insensitive archive lookups, tolerant fallbacks for malformed XHTML, fixed-layout detection, embedded fonts and image pages. Reading positions are stored as EPUB CFIs so a position survives re-layout.
A deliberate trade-off: the publisher's CSS is not applied to reflowable text. The app's own typography is used, which keeps reading consistent but means some publisher styling is lost.
Cost and trust of AI features
AI answers are cached by a hash of the prompt so the first request pays and later ones do not. An early version limited daily use with a client-side counter. The architecture notes say plainly that a modified client could skip it, and name server-side enforcement as the real fix.
The cloud storage quota added in 1.5.1 is enforced on the server: an upload needs a reservation made inside a transaction, and storage rules accept only that path at exactly that size before the reservation expires. Clients cannot write reservations.
The solution
Today the product reads PDF, EPUB and text files; recognises text in scans in Latin and Devanagari scripts on the device; translates on the device; turns highlights into notes and spaced-repetition flashcards; offers AI explanations of a selection; and has a notes and writing workspace, accounts, and a Free and Premium plan.
Current state and limits
- Web app: live. Android: in preparation. iOS has not been built in the development environment.
- OCR recognises Latin and Devanagari only. Hindi OCR was verified on an emulator with a generated page, not on a corpus of real scans.
- Publisher CSS, MathML typesetting, audio and video, and tappable in-text links in EPUBs are not supported.
- No download, rating or review figures are shown here because none have been verified.