The extension began as brian-girko/image-reader — the original OCR Image Reader extension by Brian Girko, licensed under MPL 2.0 — and has been rewritten around this server since. It lived at
deckyfx/web-ocruntil 2026-09-23 (now archived); the history came along.
A browser extension (MV3) that lets you select any region on screen and extract text via OCR. Supports two engines: Tesseract.js (runs entirely in-browser, no server needed) or a self-hosted Bun server with ONNX OCR, translation, whole-page manga translation and a Studio for editing translated pages.
- Click the toolbar button, drag to select a region — text appears instantly
- Dual engine: Tesseract.js (offline, in-browser) or the self-hosted server (faster, and it translates)
- Japanese vertical text support via
jpn_verttraineddata (reads columns right-to-left) - Per-word dictionary panel (Jisho or local Jitendex) with romaji and JLPT tags
- Draggable, resizable result panel
- Translation the server decides: the built-in model, DeepL, or a self-hosted Sugoi — chosen once in the server's settings, so every device gets the same answer
- Page translation: detect text, OCR, translate, clean the lettering and typeset the translation, replacing the image in the open tab
- Studio (
/studio): edit detected regions, paint the text mask, re-clean areas, and move / resize / rotate / restyle the lettering with a live preview that matches the final image — with a display of what the machine is doing while it works on a page - Library (
/manage): series → volume (optional) → chapter → page, with cover art, tags, ZIP / CBZ import, drag-to-reorder, whole-chapter translation and export - Reader (
/read): browse by title, tag or status and read a chapter right to left or left to right, resuming where you left off - Editing a page never changes what readers see until it is published
- Accounts: reading is open to everyone; managing the library, the Studio and OCR need an account, with an authenticator app or a passkey on top of the password if you want one
- Manifest V3 — works on Chrome, Edge, and Firefox
server/ Self-hosted server: OCR, translation, page pipeline, Studio (Bun + Elysia + ONNX)
extension/ Browser extension (TypeScript + Bun)
desktop/ Desktop companion app (Avalonia / C#)
docs/ Studio, library and reader plan
tools/ sugoi/: a Sugoi translation server in a container, for the server to use
MangaReader.slnx .NET solution for the desktop app
- Bun v1.2+
- Chrome / Edge / Firefox (MV3)
cd extension
bun install
bun run build # production — bumps patch version, outputs to dist/
bun run build:dev # dev — skips version bump / archiveLoad the extension in Chrome: chrome://extensions → Load unpacked → select extension/dist/
No server needed. Language data is downloaded on first use from tessdata.projectnaptha.com.
Supported languages include Japanese (jpn), Japanese vertical (jpn_vert), English (eng), Chinese Simplified/Traditional, Korean, and more — selectable in the settings page.
Requires the Bun server running locally. On first run it downloads the ONNX models it needs (OCR, translation, text detection, inpainting, bubble detection) and the Jitendex dictionary.
cd server
bun install
bun run devDefault address: http://localhost:3579 — reader at /read, library management at /manage, Studio at /studio, your account at /user, server settings at /admin.
Put settings such as DEEPL_API_KEY in server/.env.
First run: open the server in a browser and it asks for one admin account at /setup; that page closes itself as soon as an account exists. Reading stays open to anyone. Everything else — the library, the Studio, OCR, translation, the dictionary — needs an account, and an admin decides from /admin whether other people may register themselves.
The server binds to 127.0.0.1 by default. Set HOST=0.0.0.0 to reach it from other devices. Plain http is fine for development, but it sends passwords and session cookies across the network in clear, so put TLS in front of any real deployment (and set TRUST_PROXY). Passkeys only work on localhost or over https.
data/secret.key appears on first start and encrypts the authenticator secrets. Back it up with the database: without it, enrolled authenticator apps stop working and have to be set up again.
Three engines, picked in Settings → Translation by an admin and remembered across restarts:
| needs | notes | |
|---|---|---|
| built-in | nothing | Opus-MT, downloaded on first run. Always available. |
| DeepL | DEEPL_API_KEY in server/.env |
Fastest to set up, best general prose. |
| Sugoi | SUGOI_URL — see tools/sugoi/ |
Self-hosted, tuned for Japanese fiction. Research use only, see its README. |
auto takes the best one configured. A page's blocks are translated in one request rather than one each, which
on a nine-bubble page cut translation from about four seconds to under one; a translator having a bad moment (a 429,
or a container still loading) is waited out and tried again, while an answer that makes no sense is not.
Whichever is chosen, the extension and the desktop app use it: they ask whether to translate, not how.
- In the server's UI, open
/user→ API keys and create one. It is shown once. - In extension settings, choose the Remote Server tab, enter the server URL and paste the key.
- Click Test Connection — it reports whether the server is up and whether the key was accepted, naming the account it belongs to. Then save.
For a plain-http address that isn't on this machine (a LAN server, say), the extension withholds the key, and Test Connection refuses, until you tick Send the key over plain http anyway: anyone on that network could read the key.
Without a key the server refuses OCR, translation and page jobs. The desktop app takes the same key in its settings, withholds it from a plain-http address that isn't this machine under the same tick-box, and follows no redirects — a server that answers 302 would otherwise carry the key to wherever it points.
To build an executable: bun run build. It writes server/dist/app and copies the shared libraries its native
parts need into server/dist/lib/, which the binary loads itself at startup — so ./dist/app runs as it is, with
lib/ kept beside it. It reads the .env of whatever directory you start it from, so bun run start from
server/ behaves like the dev server, models and database included.
Started with no .env and someone there to answer, it asks a few questions — port, whether the network may reach
it, which reader and translator, whether to translate whole pages — writes them, and carries on. Unattended it
skips the questions and takes the defaults, so it can be started by a service manager. --setup asks again,
--doctor reports what this machine can and cannot run (libraries, models, fonts, folders) and exits non-zero if
something would stop the server.
bun run build --archive also writes dist/manga-reader-<target>.tar.gz — the binary and its libraries, ready to hand
to CI or to a machine. --target= picks one of ubuntu64 (the default), linux-arm64, macos-arm64,
macos-x64 or windows64; the JavaScript cross-compiles, but the native libraries come from the machine doing the
building, so a build for another platform lands in its own folder and says what is missing.
The models are not inside the binary; they are downloaded on first run into DATA_DIR.
- ONNX OCR (Manga-OCR or Baberu) and Japanese→English translation: the built-in Opus-MT, DeepL, or a self-hosted Sugoi
- Jitendex dictionary lookups with Kuromoji tokenization (
/analyze) - Page pipeline: comic text detection, block OCR and translation, LaMa inpainting to clean lettering, bubble-aware typesetting
- Studio for correcting and re-lettering pages, with per-stage state, partial re-runs, publish history and rollback
- Library of series, volumes, chapters and pages: import, reorder, batch translate, export, and a reader that is served published pages only
- Accounts with roles (admin, contributor, reader), authenticator apps and passkeys as second factors, and API keys for the extension and the desktop app
- What each page costs the machine, in the log and live in the Studio: processor, memory and GPU per stage
- SQLite (Drizzle) with migrations embedded in the build
/healthreports readiness while models load
The Avalonia desktop companion runs in the system tray and provides a global hotkey (Super+Shift+O) to capture a screen region and analyze it without a browser.
cd desktop
dotnet runThe app sends captured regions to the running server at http://localhost:3579 (configurable in settings).
The extension version lives in extension/package.json and extension/static/manifest.json, and bun run build
bumps the patch number in both. A build that shouldn't touch it says so: --no-bump leaves the version alone (what
the checks use) and --version=1.2.3 sets it outright (what a tagged release uses, so the tag and the manifest
agree). They contradict each other, so passing both is refused rather than quietly favouring one.
This is free, and staying that way. If it saved you an afternoon and you'd like to put something in the hat:
- Trakteer — QRIS and the usual Indonesian e-wallets, one-off
- Patreon — if you'd rather make it monthly
Neither buys priority, a support contract, or a say in what gets built — it buys coffee, and the occasional model download. Bug reports and pages that translate badly are worth more than either.