← All work
Case study

LinguaPop

A Japanese reading app that turns real novels and news into graded study material: tokenized, colour-coded, dictionary-backed and fully offline.

LinguaPop screenshot
Role
Everything: product, Flutter app, NLP pipeline
Stack
Flutter · Dart · Riverpod · MeCab · Hive
Ships as
Android app + web build
Data
On-device tokenizer + JMdict dictionary, no server
How it came together
  1. 01

    The problem

    Learners hit a wall between textbooks and real Japanese. Native material has no furigana, no glossary, and no sense of what's at your level. The readers I found either want you to paste text into a website, or stream everything through their server.

    I wanted the opposite. Import anything, an EPUB novel or today's NHK article, and read it like a proper learner's edition, entirely on your own device.

  2. 02

    The build

    The core is an on-device NLP pipeline. MeCab tokenizes raw Japanese into words, each token gets JLPT-graded and underlined in its level colour, and tapping any word opens a JMdict entry with readings, senses and frequency tags. A paired-translation mode lines the original up against an English version paragraph by paragraph.

    Around that sits a real reader: a library with progress, eleven typography-tuned themes, adjustable line height and column width, chapter navigation and text-to-speech. Everything persists locally. The app never phones home.

  3. 03

    What was hard

    Running MeCab, a native C++ tokenizer, inside a Flutter app across Android and desktop meant wrangling FFI, dictionary packaging and platform-specific builds.

    Token-level colour coding also had to survive text selection, font scaling and line spacing without wrecking the reading flow. The underline treatment you see now came after several failed attempts at background highlighting.

In screenshots

What this means for your project

End-to-end product work in a hard domain: native NLP integration over FFI, offline-first architecture, and the hundreds of small reading-comfort decisions that separate a real product from a demo.

FlutterDartRiverpodgo_routerHiveMeCab tokenizerTTS