Open Source · MIT · Kommandozeile

breaklint prüft die Seite, die am Ende gedruckt wird.

Wer PDFs aus HTML erzeugt, sieht Fehler erst nach der Paginierung: eine Überschrift am Seitenfuß, eine Restzeile allein auf der Folgeseite, ein Block, der auf keine Seite passt. breaklint misst jede Seite nach dem Umbruch und nennt zu jedem Befund den gemessenen Wert neben der Schwelle, an der er scheiterte.

Quellcode auf GitHub Paket auf npm

Film · 0:39 · Instrumentalmusik, kein Sprechtext

Was im Film zu sehen ist
  1. 0:00 Im Browser: perfekt. Auf Seite 47: kaputt. · Überschrift allein am Seitenende · Seite 48: zwei Zeilen. Sonst nichts. · Tabelle passt auf keine Seite · Kunde: „Was ist auf Seite 47 los?“ · Fr 17:58 · ab in den Druck · Diagramm-Beschriftung abgeschnitten · Hat jemand das PDF geprüft? · Im Browser sah alles gut aus. · Seite: 1 → 212 / 212
  2. 0:06 212 Seiten. Alle von Hand prüfen? Bei jedem Build?
  3. 0:10 Ein Befehl. Jede Seite gemessen.
  4. 0:13 Open Source · MIT · breaklint · Layout-Prüfung für HTML zu PDF, gemessen nach dem Seitenumbruch.
  5. 0:17 Genau hier bricht es. · Echte Ausgabe
  6. 0:21 Seite 1: Überschrift allein unten. · Beispiel · Seite 1
  7. 0:25 Seite 4: 5 % gefüllt. · Beispiel · Seite 4
  8. 0:29 Jeder Befund mit Messwert. · Verwaiste Zeilen · Überschrift ganz unten · Zu hohe Blöcke · SVG-Text über dem Rand
  9. 0:33 Gefunden, bevor es der Kunde findet. · Kostenlos · Open Source · MIT · npx breaklint --demo

In einer Zeile ausprobieren

npx breaklint --demo

Der Befehl braucht keinen Browser und keine Konfiguration. Er endet mit Exit 1, weil das mitgelieferte Beispiel absichtlich Befunde enthält — eine Demo, die mit 0 endet, zeigt nie, wie ein Befund aussieht. Der Block unten zeigt einen vollständigen Befund der mitgelieferten Demo; nur die langen Zeilen sind für das Lesemaß umbrochen. Die Regelkette darin ist die echte; die Seite, die sie beurteilt, ist ein handgeschriebenes Fixture, damit jeder Regelpfad ohne Browser erreichbar ist — der Bericht schreibt selbst in sein source-Feld, welche Art Fixture er gelesen hat.

error svg/text-overflows-viewport  page 5
  measured   72 px; threshold 0 px (uncalibrated)
  detail     This text extends 72.00 px beyond the
             SVG viewport and is not drawn.
             Coordinates are normalised through
             getScreenCTM().
  remedy     Text rendered inside an SVG extends
             outside the SVG viewport bounds and is
             clipped. Enlarge the SVG 'viewBox' or
             its width/height, or adjust the <text>
             coordinates ('x', 'y', 'text-anchor').
             'overflow: visible' on the container
             also clears the finding, but it does not
             move the text: the viewport then no
             longer clips, the target becomes
             non-applicable and this rule stops
             measuring it. Use that only where the
             overflow is intended.
             untested: no trigger/remedied pair in
             this package shows this advice removing
             this finding
  source     unknown (node produced by the paginator)
  render     unknown (no evidence produced)

Warum es das gibt

Prosa-Linter sehen keine Seite. Satzsysteme sehen die Seite, kennen aber die deutsche typografische Konvention nicht. Für Dokumente, die aus HTML zu PDF entstehen, gab es beides nicht.

Der Anlass war ein Fall, den die Prüfung am Quelltext nicht gefunden hat: eine Grafik bestand die XML-Validitätsprüfung und eine Geometrieprüfung — und kam mit kollidierenden Beschriftungen aus dem Renderer. Ob eine Seite trägt, entscheidet sich nach der Paginierung, im Renderer, mit den Schriften, die tatsächlich verfügbar waren.

Was geprüft wird

Fünfzehn Regeln, zwölf davon per Default aktiv. Im Default können zwei Fehlerregeln einen Build scheitern lassen; die zehn weiteren aktiven Regeln sind Hinweise, bis man mit --fail-on warn ausdrücklich mehr verlangt. Die beiden neuen Figurenregeln sind Warnungen (warn), standardmäßig aus und unkalibriert. layout/half-empty-page bleibt experimentell, bewegt nie einen Exit-Code und läuft seit 0.6.0 nicht mehr im Default-Profil. Diese drei Regeln lassen sich mit --profile strict oder ausdrücklich aktivieren.

Umbruch

Zu hohe unteilbare Blöcke, Restzeilen am Seitenanfang und Seitenende, Überschriften am Seitenfuß, Fortsetzungsseiten und Trennungen über den Umbruch. Halbleere Seiten nur auf ausdrückliche Anforderung.

SVG

Text, der über den Viewport hinausläuft. Clip-/Masken-Beschneidung und Pixelkollision sind noch keine ausgelieferten Regeln: der Produktionspfad besitzt dafür keinen sicheren Ink-Pass.

Typografie

Bindestrich statt Gedankenstrich, gerade Anführungszeichen im Satz, zu kurze Ausgangszeilen, aufgerissene Wortabstände.

Artefakt

file:-Verweise und Pfade der Buildmaschine, die im ausgelieferten Dokument stehen geblieben sind.

Figur, Caption und lokaler Verweis

figure/caption-separated misst den Seitenabstand zwischen dem Bildkörper einer HTML-figure und ihrer sichtbaren figcaption. Unterstützt werden ein einzelnes img oder ein Einzel-SVG und genau eine zugehörige Caption. Geteilte oder wiederholte Bildkörper, mehrere Captions und fehlende Geometrie werden nicht gemessen. Ein Befund beweist weder die Umbruchursache noch, dass Figur und Caption auf eine gemeinsame Seite passen.

figure/dangling-reference prüft lokale href-Anker in Links, deren Text „Figure“, „Fig.“, „Abbildung“ oder „Abb.“ mit einer nachfolgenden Zahl enthält. Die Regel meldet fehlende Ziel-IDs und benennt den umgebenden Quellblock, nicht die genaue Position des Inline-Links. Externe Links, Freitext-Nummerierung und die Sichtbarkeit eines vorhandenen Ziels werden nicht validiert. Das ist kein vollständiges Figurenmodell.

Befunde weiterbearbeiten

Die Berichte für Menschen zeigen bis zu drei nächste Prüfschritte. Grenzen eines Teillaufs stehen vor den Befunden; danach folgen Hinweise zur Prüfung der vorhandenen Ergebnisse. Gezählt werden auch nicht gemessene Fälle: gezählte Ablehnungsgründe bleiben sichtbar, selbst wenn die Mindestabdeckung erfüllt ist. Im HTML-Bericht dient die Übersicht nach Regel der Navigation; die einzelnen Befunde bleiben erhalten.

JSON bleibt die kanonische Ausgabe. Console, HTML und Markdown leiten ihre Hinweise daraus ab und erfinden keine Ursache oder Leserwirkung. Markdown nennt die tatsächliche Befundmeldung und den Reparaturhinweis samt Teststatus. Ein ungetesteter Hinweis ist kein Nachweis, dass die Änderung funktioniert. Der Baseline-Vergleich bleibt an verifizierte, kompatible Messungen gebunden.

Was noch nicht kalibriert ist

Alle fünfzehn ausgelieferten Regeln sind weiterhin als uncalibrated gekennzeichnet. Die zwei Ink-Definitionen bleiben als ausdrücklich nicht ausgelieferte M3-Forschung erhalten. Für eine spätere Kalibrierung liegen Läufe im echten Renderer und ein auf Rechte und Datenschutz geprüfter Prozesspilot mit drei realen Dokumenten vor: mit getrennten Daten für Entwicklung, Schwellenabstimmung und Schlussprüfung sowie verblindeten Prüfpaketen und Kontrollen gegen unzulässige Evidenz.

Das ist noch keine empirische Kalibrierung. Dafür fehlen ein ausreichend großer Korpus echter Dokumente, zwei voneinander unabhängige blinde menschliche Bewertungen, die dokumentierte Klärung von Uneinigkeiten, eine extern bestätigte und unverändert eingefrorene Testmenge sowie genau eine vorab festgelegte Schlussauswertung. Bis dahin bleibt bei jeder Regel calibrated: false.

Tests und Renderer-Nachweise prüfen die dokumentierten Messpfade und bekannte Gegenbeispiele. Eine verpflichtende Prüfung an realen Dokumenten bindet eine unveränderte, auf Rechte und Datenschutz geprüfte Project-Gutenberg-HTML-Datei eines Dritten und zusätzlich einen eigenen Fall zur Paketierung, verlangt exakte Zahlen für Seiten und gemessene Regeln und weist Abweichungen der Infrastruktur zurück; das belegt Robustheit, nicht Kalibrierung. Wie häufig heuristische Grenzen bei realen Dokumenten richtig liegen, bleibt unbekannt.

Was es nicht tut

Keine PDF-Normkonformität

Dafür gibt es veraPDF und pdfcpu.

Kein visueller Bildvergleich

Für Pixel- oder Bilddifferenzen gibt es Visual-Diff-Werkzeuge. Der konservative Dokument-Reparaturvergleich von breaklint verlangt dagegen ein vollständig verifiziertes, kompatibles Ziel.

Keine Stil- und Sprachprüfung

Dafür gibt es vale und typopo.

PDF ist kein Eingabeformat

PDF wird erzeugt und gerastert, um Belege zu produzieren — nie gelesen, um es zu prüfen.

Voraussetzungen

Aktueller Release: 0.9.0; 0.8.0 ist der unmittelbare Vorgänger. Fünfzehn Regeln sind registriert, zwölf standardmäßig aktiv. Alle Regeln sind weiterhin unkalibriert. Ein Bildfehler wird nur dann als image-content-unavailable nicht-fatal benannt, wenn positive width- und height-Attribute exakt der gemessenen Browserbox entsprechen; Ersatztext und CSS-Abweichungen genügen nicht.

Seit 0.8.0 gilt für jedes Dokument standardmäßig ein Zeitbudget von 600000 ms (zehn Minuten). In breaklint.config.json setzt documentTimeoutMs den Wert; --document-timeout-ms <n> überschreibt ihn für einen Lauf. Erlaubt sind ganzzahlige Werte von 30000 bis 1800000 ms. Ungültige Werte enden mit Exit 2. Wird das Budget erreicht, endet der Lauf mit Exit 3 und nennt den wirksamen Wert. Das Budget begrenzt die Dauer; es beschleunigt die Paginierung nicht und senkt den Speicherbedarf großer Dokumente nicht.

0.8.0 weist zwei bekannte Quellen stillen Inhaltsverlusts vor der Messung zurück: einen body mit berechnetem column-count oder column-width (auch column-count: 1) und eine nichtleere Überschrift mit display: contents. Beide Fälle enden mit Exit 3 statt einem sauberen Ergebnis. Wiederholter SVG-Text im normalen Seiteninhalt wird pro Vorkommen zugeordnet. Inline-SVG-Text in laufenden Randkästen bleibt eine Ausnahme: Wiederholen sich die Kopien auf mehreren Seiten mit derselben Target-ID, endet die Prüfung mit checker-crashed (Exit 3). Eine allgemeine Vollständigkeitsprüfung des PDFs ist damit nicht belegt.

Bei sichtbarem Strich um SVG-Text kann breaklint in eng begrenzten Fällen nachweisen, dass eine konservativ berechnete Hülle vollständig innerhalb des SVG-Viewports liegt. Dafür müssen auch Strichbreite und -form sowie die Transformationen prüfbar sein. Berührt die Hülle den Viewport-Rand, bleibt das Ziel ungemessen. Da die Regel svg/text-overflows-viewport vollständige Abdeckung verlangt, endet der Lauf mit Exit 4. Der Nachweis bestimmt weder die exakte sichtbare Kontur noch meldet er einen nur teilweise außerhalb liegenden Strich als Fehler. Masken und Filter bleiben ungemessen.

0.9.0 schreibt Snapshot 6 mit dem begrenzten Figurenindex. Report 5, Agenten-Kontext 2 und Configuration 1 bleiben unverändert. Gespeicherte Snapshots der Version 5 bleiben lesbar; bei aktivierten Figurenregeln fehlt darin der Index und die Messung wird mit env/figure-index-unavailable abgelehnt.

layout/unbreakable-block-too-tall, eine der zwei Regeln, die per Default einen Build scheitern lassen, summiert seit 0.7.0 die Höhe eines Blocks über seine Fragmente, sobald der Paginator ihn in drei oder mehr Stücke geteilt hat; ein zu hoher Block, der in genau zwei Stücke bricht, bleibt weiterhin ungemeldet. Einen geteilten Block, dessen Fragmente sich nicht über ihre Quelle zusammenführen lassen, misst die Regel nicht am ersten Fragment, sondern lehnt ihn ab und rechnet das gegen die Abdeckung; ein solcher Lauf kann mit Exit 4 enden. Inhalte in den Seitenrändern, etwa Kopf- und Fußzeilen aus position: running(...), zählen nicht als Textfluss und werden von keiner Regel beurteilt. Ob eine Seitengrenze erzwungen war, liest breaklint aus der Umbruchentscheidung des Paginators, auch in Bereichen mit benannten Seiten. Ein Bericht, der in eine Pipe geschrieben wird, kommt vollständig an; bis 0.6.0 konnte er an einem Vielfachen des Pipe-Puffers abgeschnitten werden, unter Linux meist bei 64 KiB. Lässt er sich nicht vollständig schreiben, endet der Lauf mit Exit 3.

Für erzeugte Dokumente benennt breaklint eine editierbare Originalstelle nur, wenn ein hostgesteuerter Producer die Originalbytes erfasst und die Herkunft nachweist. Aus demselben kanonischen JSON entstehen die offline nutzbare Ansicht für Menschen und ein begrenzter Kontext für KI-Systeme. Ein Reparaturvergleich erklärt einen Befund nur bei verifiziertem, identischem Ziel sowie kompatibler Revision, Regeln, Konfiguration, Renderumgebung, Fonts und Ressourcen für behoben; unbekannte Herkunft und Teilabdeckung bleiben ausdrücklich sichtbar.

Die seit 0.7.0 verfügbare GitHub Action lässt sich mit uses: godarg/breaklint@v0.9.0 einbinden. Sie installiert das veröffentlichte npm-Release, prüft die angegebenen HTML-Pfade in einem Lauf, schreibt aus dem einen kanonischen JSON-Bericht zusätzlich SARIF, JUnit und eine Markdown-Zusammenfassung und lässt den Schritt mit dem Exit-Code von breaklint enden; Exit 2, 3 und 4 lassen ihn immer scheitern. Einen Workflow zum Übernehmen enthält docs/ci-recipe.md. Getestet ist die Action auf ubuntu-latest, macOS-Runner sind ungetestet. Sie braucht bash 4 oder neuer; mit dem /bin/bash 3.2 von macOS bricht sie mit Exit 3 ab.

Die öffentliche checkPage-API prüft getrennt davon eine bereits vorbereitete Playwright-Page: Sie übernimmt weder Navigation noch Anmeldung oder Netzpolitik. Im eigenen Betrieb prüft sie in der Testsuite eines internen Dashboards 45 Zustände. Der Kommandozeilenpfad nimmt weiterhin ausschließlich .html/.htm an; eigenständige SVG-, PDF- und Markdown-Dateien enden mit Usage Exit 2. Node 22.13 oder neuer, auf macOS oder Linux. Ein Lauf über echte Dokumente braucht zusätzlich einen Chromium-basierten Browser und pagedjs@0.4.3; pdfjs-dist rastert das erzeugte PDF, um Belege an Befunde zu binden. Windows wird nicht unterstützt — die Prozessbehandlung ruht auf POSIX-Prozessgruppen. Der Messpfad ist unter Linux belegt; Prozessbeendigung und Profilbereinigung sind empirisch nur auf macOS gemessen.

npm i -D breaklint
npm i -D puppeteer-core@^25.8.0 pagedjs@0.4.3 pdfjs-dist@6.2.108

breaklint führt fremdes HTML samt Skripten aus. Der Offline-Modus fängt Seitenanfragen ab, ist aber keine Egress-Kontrolle: WebSocket-, WebTransport- und WebRTC-Verbindungen eines Dokuments sowie Browser-Verkehr über DNS over HTTPS und den Component Updater erfasst er nicht. Seit 0.8.0 verweigert breaklint den Renderer-Start, wenn PUPPETEER_DANGEROUS_NO_SANDBOX oder PUPPETEER_TEST_EXPERIMENTAL_CHROME_FEATURES gesetzt ist; CHROME_EXTRA_FLAGS wird aus der Chrome-Umgebung entfernt. Weitere Wrapper-Variablen sind nicht allgemein geprüft. Fremde Dokumente gehören in einen Container oder Netz-Namespace ohne Egress.

Noch offen: Dokumente mit Paged.js-Fußnoten enden vor der Regelprüfung mit Exit 3. Einzelne Regeln lehnen die Messung mehrspaltiger Blöcke ab. Ein zu hoher unteilbarer Block, der in genau zwei Fragmente zerfällt, bleibt ungemeldet.

breaklint verwendet zur Prüfzeit kein Sprachmodell. Es führt keine Inferenz aus und enthält keinen API-Client.

Offener Community-Test · freiwillig · unbezahlt

Wo widersprechen sich Messung und menschlicher Blick?

Genau diese Fälle suchen wir. Jeder kann ein öffentliches oder eigens dafür gebautes HTML-Dokument testen — ohne Bewerbung, Auswahl oder Vorkenntnisse. Der kurze Leitfaden führt in etwa zehn Minuten vom Installieren bis zum strukturierten Bericht.

Bitte nur Inhalte verwenden, die veröffentlicht werden dürfen. GitHub-Name, Bericht und Reproduktion sind öffentlich; vertrauliche Dokumente, personenbezogene Daten und Sicherheitsbefunde gehören nicht in das Formular. Die Auswertung nimmt strukturierte Angaben automatisch an, führt eingereichte Inhalte aber niemals aus.

Das Programm ist zusätzliche Qualitätssicherung. Öffentliche Tests sind keine Blindstudie und ersetzen nicht die noch ausstehende empirische Kalibrierung der Regeln.

Herkunft

breaklint entsteht bei Dargel Solutions und ist unter der MIT-Lizenz frei verwendbar, auch kommerziell. Teile des Repositories wurden mit Hilfe von Sprachmodellen geschrieben. Regeln, Schwellen, Quellen und dokumentierte Grenzen stehen im öffentlichen Repository. Regeln mit Bezug zum deutschen Regelwerk der Rechtschreibung wurden gegen dessen veröffentlichten Text geprüft.

Für Erstellung, Pflege und Prüfung dieser Seite wird generative KI eingesetzt. Dargel Solutions verantwortet die Veröffentlichung.

breaklint ist im Verzeichnis PeerPush eingetragen.