Open source · MIT · command line

breaklint checks the page that will actually be printed.

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.

Source on GitHub Package on npm

Try it in one line

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

Why this exists

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.

What is checked

Fifteen rules. Two of them can fail a build by default; twelve 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.

Pagination

Widows and orphans, headings at the foot of a page, half-empty pages, orphaned continuation pages, and hyphenation across a break.

SVG

Text that runs past the viewport, is removed by a clip path or mask, or shares device pixels with a shape.

Typography

A hyphen where a dash belongs, typewriter quotes in typeset prose, short last lines, and word gaps torn open by justification.

Artefacts

file: URIs and build-machine paths left behind in the delivered document.

What is not calibrated — and why that is written on the tin

None of the fifteen thresholds is calibrated against a corpus of real documents with human-checked truth. That is why uncalibrated appears in the type, in every single finding and on every rule page. The fixtures show that each rule does what it says — not that what it says is the right thing to say about a real document.

That is the difference between a verified implementation and a validated one, and only the first is claimed. A layout checker whose green state means nothing is more dangerous than no checker at all, so the repository keeps its own page on what has been measured and what has not.

What it does not do

No PDF standard conformity

Use veraPDF or pdfcpu for that.

No comparison against a previous build

Use a visual diff tool. breaklint judges the first build, where there is nothing to compare to.

No prose or style checking

Use vale or typopo for that.

PDF is not an input format

PDF is produced and rasterised here to make evidence, never read as input.

Requirements

Node 20 or newer, on macOS or Linux. A run over real documents additionally needs a Chromium-based browser and [email protected]; pdfjs-dist rasterises the produced PDF to bind evidence to findings. Windows is not supported — process termination here rests on POSIX process groups — and Linux has not yet been measured empirically: the process and profile-cleanup path has real evidence on macOS only.

npm i -D breaklint
npm i -D puppeteer-core [email protected] [email protected]

breaklint uses no language model at check time. It performs no inference and contains no API client.

Where it comes from

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.