Geometry-accurate per-line text layout becomes auto mode - #243
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mokuro's block font_size is the detected line-quad width (furigana included), median 1.2x the true character size, so block-level original rendering overflows. Per-line quads are accurate: place each line at its quad and fit the font size to quad_length / text_advance, capped by quad width. Falls back to the legacy path when lines_coords is missing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Quads are often wider than the glyph column (ruby, mask slack, empty margin) with the base glyphs near the middle; left-edge anchoring shoved wide-quad columns into their neighbors (Dr Stone 01 p27 本物から). Center each line on the quad's cross axis instead. The detector also emits ~19 duplicate blocks per 1000 pages: the same balloon as a properly segmented block plus a single whole-box synthetic line with a huge font_size (Dr Stone 01 p29). Dedupe at render time by identical joined text + box IoU > 0.5, keeping the better-segmented block; applies to all font modes and already-imported volumes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A quad much wider than the block's typical line size whose text only fits far smaller is multiple print columns captured as one OCR line — usually base text plus its furigana reading (Dr Stone 01 p32 空は私ならだいじょうぶ: 112px quad squeezed to 14.7px). Such lines now wrap inside their full quad bbox at (near) the block's median line size. Clean lines keep their own fitted size: print mixes sizes within a balloon (emphasis words like 大丈夫), so uniformity is not forced. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Print keeps one size per balloon; per-quad fitted sizes vary only via quad slack, and mixed sizes look sloppy (user feedback: Dr Stone p32 大丈夫 is 1:1 with the base line, its tall quad is just loose). All lines now render at the block's median clean-line size, tolerating 1.15x length / 1.2x cross quad slack. Escapes: deliberately-small lines (standalone furigana) keep their own size, and wrapped merged-column lines pull the whole block down with them so sizes stay uniform. wrapFitSize now searches column counts exactly instead of iterating to a suboptimal fixpoint. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The fixed 1.6x-reference quad-width wrap gate missed Dr Stone 01 p53 必要なことはう by 0.7px, leaving a merged line at a tiny 19px when two columns at 31.5px fit. Gate on what wrapFitSize actually achieves (>= 1.25x the single-line size) instead. And when >= 2 clean lines agree within 1.25x, their median fixes the block size — a wrapped line's lower fit no longer drags well-attested blocks down (it still does for 0-1 clean-line blocks, which is what makes p32 land on the true size). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…al size A block whose only line is one quad covering the whole balloon (Dr Stone 01 p87: 9 chars in 356x390) could never wrap: the reference size derives from that same line, so the shrink gate never fired, leaving a small single column in a huge box. When a block has no clean lines, suspect lines now wrap at their geometry-optimal size (~sqrt(main x cross / advance)) — p87 renders 3 columns at ~119px matching the print. Still gated on the 1.25x benefit so genuine one-liners in loose quads stay single. Hallucinated lines now wrap into dense contained columns instead of rendering sub-pixel. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Killing Bites 01 p42: 「百獣王」 with its katakana gloss split into two small ruby lines around it — a plain per-line median is ruby-dominated and dragged the 76px base text down to 31px. Lines now vote for the block reference size proportionally to their quad ink area (the base line holds 80% of the block's ink), so ruby fragments register as small outliers and keep their own sizes while the base renders at its true size. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reconstruction supersedes the old measure-and-shrink auto mode and is not a faithful raster either, so auto (the app default) is its honest home. Blocks without lines_coords fall back to the legacy hover-fit auto path; original mode reverts to raw font_size rendering. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Saki the Succubus 02 p129: the detector re-captures the same ink region as several overlapping lines — a column alone AND a bigger quad spanning it plus its neighbors (あれは inside あれはキスではないですよ), or nested hallucination blobs — which rendered stacked text. When one line bbox covers >= 70% of a smaller one: if the smaller's text is contained in the bigger's, hide the smaller (the bigger wraps the full region, no text lost); otherwise hide the enclosing blob and keep the precise small captures. Hidden lines don't vote on the block size and don't render. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hiding the enclosing blob of a hallucination cluster (Saki 02 p129) filtered out most of the OCR text — unreadable in a new way. The user requirement is that OCR text stays readable even when it is wrong: diverged overlapping captures now merge into a cluster whose union bbox is partitioned into reading-order bands weighted by text length; each line wraps inside its own band. All text renders, ordered, nothing stacks. Text-subsumed duplicates (あれは) still collapse losslessly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Killing Bites 01 p211: the detector assigned the middle column of one balloon to the neighboring block (its quad slots exactly between the victim block's columns). Per-line placement renders it at the correct print position, but the overlapping block's whole-box white background painted over it, hiding the text. In per-line mode the opaque backing now lives on each line span — it still masks the printed glyphs under the rendered text, and overlapping boxes can no longer blank out each other's lines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-line white strips only mask print they cover — on stylized, angled or misaligned text (Saki 02 p129) the original ink bleeds around every strip. Restore the whole-box white panel and fix the actual p211 problem, which was paint order: text boxes no longer create stacking contexts (z-index removed; tree order still stacks smaller boxes over bigger), and positioned line spans get z-index 1, lifting every block's text above every block's panel. Overlapping blocks mask robustly and can no longer blank out each other's lines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced Jul 5, 2026
Merged
Merged
adrian-tompkins
pushed a commit
to adrian-tompkins/mokuro-reader
that referenced
this pull request
Aug 2, 2026
fix: Prevent scrollbars in reader by hiding document overflow
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
mokuro's block-level
font_sizeis the mean detected line-quad width — for vertical Japanese that includes furigana and mask slack, overstating the true character size by 20% at the median and 2× at p95 (measured across 120 volumes / 160k blocks). Rendering it faithfully overflows balloons; the old auto mode's measure-and-shrink workaround discarded line breaks and per-line positions.The per-line quads (
lines_coords) mokuro already emits are accurate, and they're stored verbatim in IndexedDB — no re-import needed. This PR renders each OCR line at its own quad with a geometry-derived font size, and makes that the auto mode (app default).originalmode reverts to faithful raw rendering; blocks withoutlines_coordsfall back to the legacy hover-fit auto.Root-cause analysis with annotated evidence: https://claude.ai/code/artifact/611aa1cc-41ea-4186-ae7a-83542e5c4032
Layout algorithm (src/lib/reader/line-coords-layout.ts)
min(quad_cross, quad_length ÷ measured text advance)(canvas measurer, heuristic fallback)Verification
🤖 Generated with Claude Code