Pagination
Widows and orphans, headings at the foot of a page, half-empty pages, orphaned continuation pages, and hyphenation across a break.
When you generate PDFs from HTML, the mistakes only appear after pagination: a heading stranded at the foot of a page, one line of a paragraph carried alone onto the next, a block that fits on no page at all. breaklint measures every page after the break and reports, for each finding, the measured value next to the threshold it failed.
npx breaklint --demo
That command needs no browser and no configuration. It ends with exit 1, because the bundled fixture contains findings on purpose — a demo that ends 0 never shows you what a finding looks like. The block below is unedited output of that command. The rule chain running in it is the real one; the page it judges is a hand-written snapshot, built so that every rule path is reachable without a browser — and the report states which kind of fixture it read in its own source field.
error layout/unbreakable-block-too-tall page 2
measured 848 px; threshold 606 px (uncalibrated)
detail This block asks not to be broken and is
848.00 px tall; the page content box is
606.00 px. It cannot fit on any page.
source examples/demo.html:31
Prose linters never see a page. Typesetting systems see the page but do not know German typographic convention. For documents generated from HTML to PDF, neither exists.
The reason for measuring the rendered page rather than the source is a case that source-level checking did not catch: a chart passed an XML validity check and a geometry check, and still came out of the renderer with colliding labels. Whether a page works is decided after pagination — in the renderer, with the fonts that were actually available.
Thirteen rules. Two of them can fail a build by default; ten more are advisory until you ask for more with --fail-on warn; and one — layout/half-empty-page — is experimental and never moves an exit code at all, not even then. That split is not caution, it is the burden of proof: only two rules compare directly measured quantities against a structural boundary.
Widows and orphans, headings at the foot of a page, half-empty pages, orphaned continuation pages, and hyphenation across a break.
Text that runs past the viewport. Clip/mask removal and device-pixel collision are not released rules yet: production has no safe ink pass for them.
A hyphen where a dash belongs, typewriter quotes in typeset prose, short last lines, and word gaps torn open by justification.
file: URIs and build-machine paths left behind in the delivered document.
All thirteen released rules are still labelled uncalibrated. The two ink definitions remain explicitly unreleased M3 research. The technical foundation for later calibration is now in place: runs in the real renderer, a rights- and privacy-reviewed process pilot with three real documents, separate data for development, threshold tuning and the held-back final test, plus blind review packets and controls that reject invalid evidence.
That is not empirical calibration yet. It still requires a sufficiently large corpus of real documents, two independent blind human judgements, a documented resolution when they disagree, an externally verified final test set that has remained unchanged, and one final evaluation defined in advance. Until then, every rule remains calibrated: false.
The tests and renderer evidence show that breaklint performs the measurements of the thirteen released rules and catches known counterexamples. A mandatory real-document gate binds an unchanged third-party Project Gutenberg HTML file plus a first-party packaging case, requires exact page and measured-rule counts, and rejects infrastructure drift; that proves robustness, not calibration. How often heuristic boundaries are correct across real documents remains unknown.
Use veraPDF or pdfcpu for that.
Use a visual diff tool. breaklint judges the first build, where there is nothing to compare to.
Use vale or typopo for that.
PDF is produced and rasterised here to make evidence, never read as input.
Current release: 0.3.1. It ships thirteen public rules instead of fifteen definitions. The external-document gate measures 9 of 13 rules across nine pages of the unchanged, rights-reviewed Project Gutenberg HTML and exits 0; that is robustness evidence, not calibration. A second, first-party Dargel document measures 11 of 13 rules across six pages and separately tests missing-image packaging. Both runs expose the independent geometry oracle at 8 of 8 required browser-layout checks; a truncated or empty sample is fatal. A failed image becomes the non-fatal image-content-unavailable diagnostic only when positive authored width and height attributes exactly equal the measured browser box; replacement text and CSS drift are insufficient. Input is .html/.htm only; standalone SVG, PDF and Markdown files end with usage Exit 2. Node 22.13 or newer, on macOS or Linux. A run over real documents additionally needs a Chromium-based browser and pagedjs@0.4.3; pdfjs-dist rasterises the produced PDF to bind evidence to findings. Windows is not supported — process termination here rests on POSIX process groups. The measurement chain is exercised on Linux; process termination and profile cleanup have empirical evidence on macOS only.
npm i -D breaklint
npm i -D puppeteer-core pagedjs@0.4.3 pdfjs-dist@6.2.108
breaklint uses no language model at check time. It performs no inference and contains no API client.
Those are exactly the cases we are looking for. Anyone can test public or purpose-built HTML — no application, selection or prior experience required. The short guide takes about ten minutes from installation to a structured report.
Use only material you have the right to publish. Your GitHub identity, report and reproduction are public; confidential documents, personal data and security findings do not belong in the form. Structured intake is automated, but submitted content is never executed.
This is additional product QA. Public testing is not a blind study and does not replace the empirical calibration that the rules still need.
breaklint is built at Dargel Solutions and is free to use under the MIT licence, including commercially. Parts of the repository were written with the help of large language models; the rule set, the thresholds and their sources were chosen by a person. Every rule that cites the German orthography ruleset was checked against the published text of that ruleset, not against a model's summary of it.
Generative AI is used to create and maintain this page. Factual and visual publication approval remains with a person.