CLI Logo

2. Oktober 2026 von Theo Döllmann

Zugverbindungen teilen (powered by Typst)

Mit Freund:innen zu klären, welche Zugverbindung man für den Urlaub oder ein anderes Ziel nimmt, kann durchaus nervig sein. Am besten setzt man sich dafür zusammen, denn das Teilen verschiedener Zugverbindungen in Messenger-Gruppen wird schnell unübersichtlich. Schuld daran ist der DB Navigator: Er teilt Zugverbindungen als Textnachricht, mit allen erdenklichen Details, aber wenig Struktur.

Abbildung 1: Beim Teilen von Zugverbindungen hat man die Wahl: übergroßes Smartphone oder durchdachtes Design

Abbildung 1 zeigt, wie eine solche Zugverbindung auf dem Smartphone aussieht, und wie Bahn-Vorhersage es seit Mitte Juli 2026 besser macht.

Wer mit dem DB-Navigator Zugverbindungen abspricht, macht vermutlich einen Screenshot der Verbindungen oder der Verbindungsübersicht, denn nur das gibt eine tatsächliche Übersicht. Dabei geht aber die Möglichkeit verloren, sich die Verbindung selbst zu speichern und Echtzeitdaten abzufragen. Alternativ kann man den nervigen Text löschen und nur den Link verschicken, aber dann fehlt dem Link im Messenger jeglicher Kontext. Alles suboptimal. Deshalb musste ich eine eigene Lösung bauen.

Vorüberlegung: Ohne Datenbank

Am liebsten hätte ich das Feature ohne Datenbank implementiert. Dafür müsste der geteilte Link die gesamte Verbindung enthalten. Leider sind Zugverbindungen dafür typischerweise zu groß: Eine einfache Zugverbindung mit 2 Umstiegen von Tübingen nach Köln ist ca. 16 kB groß. Das ergibt einen gut 20.000 Zeichen langen Link (base64). Besser als der Text vom DB-Navigator ist das nicht.

Auch mit Brotli-Komprimierung landet man noch bei über 3.000 Zeichen. Mit weiteren Verbesserungen wie Protobuf und vortrainierten Wörterbüchern für die Komprimierung ließen sich vermutlich noch einige Zeichen einsparen. Der DB-Navigator braucht für die Textbeschreibung der Verbindung in Abbildung 1 aber lediglich 315 Zeichen. Darunter komme ich auch mit der besten Komprimierung nicht, weil ich Zusatzinformationen wie die Zwischenhalte und natürlich die Anschlusssicherheit behalten möchte.

Vorschaubilder

Um die Übersicht zu verbessern, möchte ich automatisch Vorschaubilder der Reisen teilen. Damit das Bild nicht manuell geteilt werden muss (und das Teilen somit auch am Computer gut funktioniert), wird es auf einem Server dynamisch generiert und über das Open-Graph-Protokoll automatisch nachgeladen, sobald der Link zur Verbindung in einem Messenger oder auf Social Media geteilt wird.

Open-Graph-Protokoll

Wird auf Social Media oder in einem Messenger ein Link geteilt, lädt meistens eine Vorschau der verlinkten Seite. Dafür ist Open Graph da. Dazu fügt man im Head der Webseite lediglich ein paar Metadaten ein, wie in Listing 1 zu sehen ist.

<head>
    ...
    <meta property="og:type" content="website" />
    <meta property="og:image:width" content="1200" />
    <meta property="og:image:height" content="630" />
    <meta property="og:locale" content="de" />
    <meta property="og:image" content=".../share.png" />
    <meta property="og:title" content="..." />
    <meta property="og:description" content="..." />
    <meta property="og:site_name" content="Bahn-Vorhersage" />
    ...
</head>
Listing 1: Einfaches Beispiel für Open Graph Metadaten

Typischerweise sind die Vorschaubilder pro Seite statisch. Für dynamische Vorschaubilder schlägt einem das Internet ungefähr Folgendes vor:

  • Ein Node.js-Server
  • Satori erstellt ein SVG-Bild aus HTML und CSS
  • Resvg rendert das SVG in ein PNG-Bild (Open Graph unterstützt kein SVG)

Ich entwickle persönlich lieber in Python als in JavaScript und finde es auch ein Stück weit absurd, eine Web-Technologie über diverse Umwege in ein Bild zu rendern. Stattdessen habe ich mich für eine etwas experimentelle Lösung entschieden: Typst

Dynamische Vorschaubilder mit Typst

Typst ist ein modernes Textsatzsystem. Mich persönlich hat es größtenteils von LaTeX abgebracht, weil es einfacher und deutlich schneller ist. Unter anderem kann Typst auch direkt PNG-Bilder erstellen. Dadurch reicht ein einfacher Python-Server, der die Zugverbindung entgegennimmt, Typst aufruft und das PNG-Bild zurückgibt.

Abbildung 2: Bahn-Vorhersage-Vorschau für eine Zugfahrt von Tübingen nach Köln

Um eine Verbindung zu teilen, kann man als Nutzer:in den „Teilen“-Button verwenden, der einen Link in die Zwischenablage legt. Wird dieser Link über einen Messenger oder auf Social Media geteilt, lädt automatisch das von Typst generierte Vorschaubild mit. Sobald der Link geöffnet wird, zeigt Bahn-Vorhersage die Verbindung wie gewohnt an.

Die Funktion des Webservers lässt sich in drei Teile gliedern:

  1. Einen Link erstellen, um die Verbindung zu teilen
  2. Open-Graph-Metadaten und Vorschaubild für Messenger und Co. zurückgeben
  3. Die Zugverbindung beim Öffnen des Links anzeigen

Im Folgenden gehe ich auf die Architektur der einzelnen Komponenten ein.

Verbindung teilen

Abbildung 3: Architektur des Teilen-Links

Eine Verbindung wird an den Server geschickt, der sie mit dem Modul DiskCache speichert. Zurück kommt eine ID für die Verbindung, die einfach ein Hash der Verbindung ist.

Vorschaubild anzeigen

Abbildung 4: Architektur der Vorschaubilder

Die dynamischen Vorschaubilder sind der eigentliche Hauptteil der Teilen-Funktion. Ruft ein Open-Graph-Crawler den geteilten Link auf, bekommt er die OG-Metadaten zurück, darunter auch den Link zum Vorschaubild. Sobald der Crawler das Vorschaubild lädt, zieht der Python-Webserver die wichtigen Details aus der gespeicherten Verbindung und gibt sie an Typst weiter. Typst erstellt daraus wiederum das Vorschaubild. Sollte dabei etwas schiefgehen, generiert Typst stattdessen ein Bild, das auf den Fehler hinweist.

Link öffnen

Abbildung 5: Architektur beim Öffnen des Links

Wenn der geteilte Link geöffnet wird, soll die gesamte Verbindung angezeigt werden. Dafür kommt nun doch ein Teil der oben beschriebenen Komprimierung zum Einsatz. Der geteilte Link enthält nämlich nicht nur die Open-Graph-Metadaten, sondern auch einen Soft Redirect auf die eigentliche Seite. Dieser Redirect enthält die gesamte Verbindung (gzip-Komprimiert in base64), sodass Bahn-Vorhersage sie direkt anzeigen kann, ohne eine weitere Anfrage an den Server zu stellen.

Hat man die Bahn-Vorhersage-App installiert, läuft es etwas anders ab, da der Link sofort in der App öffnet. In diesem Fall wird die Verbindung mithilfe der ID vom Server geladen und dann angezeigt.

Typst-Herausforderungen

Was einfach klingt, ist durch das experimentelle Typst-Setup leider nicht ganz so einfach. Im Vergleich zu CSS fehlten mir für dieses Projekt in Typst zwei Dinge: eine Pixel-Einheit und eine minmax-Funktion.

Pixel sind praktisch, wenn das Vorschaubild genau 1200×630 Pixel groß sein soll, wie es für Open Graph empfohlen wird. Als Lösung habe ich die Umrechnung 1px = 0.75pt verwendet, die Seite in Typst als 900pt breit definiert und mit 96ppi gerendert. Das ist problemlos machbar, aber etwas nervig.

minmax hätte ich gerne verwendet, um die einzelnen Abschnitte der Reise je nach Reisezeit kürzer oder länger darzustellen. Das soll einen schnellen Überblick ermöglichen. Dabei gibt es allerdings eine Mindestgröße, damit die Zugbezeichnung und die Bahnhofsnamen noch neben den Abschnitt passen. Genau das kann CSS minmax lösen. In Typst musste ich dafür selbst eine Funktion schreiben, die jedem Abschnitt eine definierte Mindestgröße zuweist und den restlichen Platz proportional zur Reisezeit verteilt.

Der exakte Typst-Code ist nicht interessant genug, um ihn hier zu erläutern. Wer Lust hat, kann ihn aber im Typst-Projekt einsehen, kopieren und damit herumspielen. Ich verwende Python, um eine Zusammenfassung der Verbindung zu erstellen, die dann als JSON an Typst weitergegeben wird. Typst muss also nicht die gesamte Verbindung verstehen und parsen können, das übernimmt weiterhin Python.

Im übrigen habe ich auch diesen Blogartikel testweise in Typst geschrieben und zu HTML exportiert. Bis darauf, dass ich am Ende noch ein paar Style-Classes manuell in das Typst-HTML einfügen musste, funktioniert auch das erstaunlich gut.

Gefördert von:

Logo des Bundesministeriums für Bildung und Forschung

Zeitraum: Sep. 23 - Feb. 24

Logo des Prototypefunds
Logo des Schülerforschungszentrums Südwürttemberg
© 2026 Bahn-Vorhersage ist ein unabhängiger Service. Dieser steht in keiner Verbindung mit der Deutschen Bahn und ihren Tochter-Unternehmen.