How the Pipeline Works
What happens to a page: detection, OCR, translation, cleaning and typesetting, and the models behind each step.
1. Overview
XianScan has two parts that run together: a Rust engine that runs the image models (through ONNX Runtime), and a Node.js web server that runs the studio, translation and typesetting. For each page:
[Raw page]
│
├─ (optional) Re-slice webtoon strips at panel gaps engine: src/ml/reslice.rs
▼
1. Detect speech bubbles and text areas (RF-DETR) engine: src/ml/detect/
2. Read the text (OCR) and put regions in reading order engine: src/ml/ocr/, src/pipeline/
│
├──────────────────────────────┐
▼ ▼
3. Translate with the LLM 4. Remove the original text web: server/translate/
(glossary + dialogue (LaMa inpainting) engine: src/ml/inpaint/
context) │
└──────────────┬───────────────┘
▼
5. Typeset the translation into the cleaned page web: server/typeset/
▼
[Translated page]
Translation and cleaning run at the same time, and typesetting starts when both are done. Re-slicing happens only before a full-chapter translation (when Auto-Reslice Before Batch Translation is on) or when you start it by hand.
2. Detection and Text Regions
- Koharu RF-DETR Seg 2XL (
src/ml/detect/rfdetr.rs), a 768 px transformer detector, finds speech bubbles, captions, sound effects and panels as rectangles. - The OCR's own text-line detector (DBNet post-processing in
src/ml/detect/dbnet.rs) finds the individual text lines inside them. src/pipeline/region_builder/merges nearby lines into dialogue blocks, pads them so every glyph is covered, and removes duplicates.- Clean-up rules keep dark bubbles contained, preserve the angle of tilted sound effects, drop bubble tails, repeated dashes and stray dots, and keep Latin words inside CJK text.
- Overlapping-tile detection for very tall strips (
src/ml/detect/tiling.rs) exists but is off by default while its accuracy is reviewed.
3. OCR and Reading Order
- RapidOCR (
src/ml/ocr/engine.rs) reads 10 source languages: Chinese (Simplified and Traditional), Japanese, Korean, English, Spanish, French, Russian, Indonesian and Thai. Detection and most recognition use PP-OCRv6 models; Korean and Cyrillic use PaddleOCR mobile models, and Thai a PP-OCRv5 model. - Reading order (
src/ml/detect/grouping.rs): regions are grouped into horizontal bands from top to bottom. Within a band, Japanese reads right to left; Chinese and Korean read left to right. Vertical text inside one region is read in columns from right to left.
4. Translation
The web server (web/src/lib/server/translate/) sends the page's text to your chosen LLM together with:
- matching glossary terms (found with an Aho-Corasick matcher that tolerates small OCR errors),
- the book's directives,
- recent dialogue from previous pages (see Dialogue Context).
Failed or cut-off answers are retried with a larger output budget.
The model also returns a styles map that marks accent text (named techniques, attacks, spells and title cards). The labels are cached with the translation, stored per text region, and topped up by glossary terms of the category technique.
5. Cleaning (Inpainting)
- LaMa (
src/ml/inpaint/lama.rs, a manga-tuned model) paints over the original text and rebuilds the artwork, screentones and gradients behind it. - White bubble clean-up: after LaMa, confirmed white speech bubbles are wiped clean inside (removing leftover dust and smudges) while their outline is kept. On by default.
- Inpainting Strategy (Settings -> Inpainting & Cleaning, planned in
src/ml/inpaint/plan.rs): - Patch Crop (default): cleans small patches around each text area at full resolution. Fastest and sharpest for most pages.
- Balanced (512 px Tiles): cleans the page in square tiles scaled to 512 px, instead of squashing the whole page into one 512x512 pass. Better on some tall strips, but much slower on them.
- Full Dynamic: cleans the whole page at native resolution up to about 2048x2048 pixels (4096 px per side); larger pages are processed in overlapping bands so memory stays bounded.
- The detector, OCR and cleaning models each have their own lock, so cleaning a page is not blocked while a long re-slice runs.
6. Typesetting
The web server draws the translation with Skia (@napi-rs/canvas, code in web/src/lib/server/typeset/):
- Font size: tries sizes from large to small until the wrapped text fits the region. (A binary search is not used, because wrapping does not shrink evenly.)
- Line breaks: balanced line lengths, with hyphenation for English. Hindi and other complex scripts break only between whole characters, Thai at dictionary word boundaries.
- Arabic: drawn right to left with Arabic punctuation (
؟ ، ؛), whole words kept together. - Fonts: each line uses a font that really covers its script (see Typography & Fonts). If none does, a warning appears, because the text would show as boxes.
- Outline and tilt: an outline in contrast to the background, and text rotated to match tilted bubbles (2 to 45 degrees).
- Accented letters: a Latin letter the font has no glyph for (
É,Ñ,ßin CC Wild Words) is drawn plain (E,N,ss) in the same font, so a word never switches fonts halfway. A font that has the letter keeps it. Saved translations are not changed. - Accent text: drawn in the accent font for its script when that font has every letter; missing symbols come from the dialogue font, and the text is centred on its measured ink. Otherwise it uses the dialogue font with one outline step heavier.