1 Punkte von GN⁺ 3 일 전 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Ein neues Terminalprotokoll ist erschienen, um das bisherige Problem zu lösen, dass man zum Rendern benutzerdefinierter Icons in Terminal-Anwendungen gepatchte Fonts installieren musste, etwa Nerd Font
  • Das Glyph Protocol ermöglicht es Anwendungen, zur Laufzeit Vektorglyphen direkt im Terminal zu registrieren und abzufragen, ob das Rendering eines bestimmten Codepunkts möglich ist
  • Die Glyphendaten verwenden das glyf-Format von TrueType, sodass Terminals ihren bereits vorhandenen Rasterizer weiterverwenden können und keine neuen Abhängigkeiten nötig sind
  • Die registrierbaren Codepunkte sind auf die Unicode Private Use Area (PUA) beschränkt, um Phishing- und visuelle Spoofing-Angriffe grundsätzlich zu verhindern
  • Die erste Implementierung entsteht im Rio-Terminal; Beispielcode für wichtige TUI-Frameworks wie Bubble Tea, Ratatui und Ink ist bereits veröffentlicht

Das bisherige Problem: Abhängigkeit von gepatchten Fonts

  • Damit Terminal-Editoren, Prompts und TUIs Icons korrekt anzeigen, müssen Nutzer gepatchte Fonts wie Nerd Font oder Powerline selbst installieren
  • Ohne installierte Fonts erscheint anstelle der Icons Tofu (□), und gepatchte Fonts sind mit 6–12 MB pro Datei relativ groß
    • JetBrainsMono Nerd Font Regular etwa 7,8 MB, FiraCode Nerd Font Regular etwa 10,4 MB, das vollständige Symbolarchiv etwa 60 MB
  • Anwendungsentwickler haben keine Möglichkeit, gewünschte Glyphen selbst zu verteilen, und müssen darauf hoffen, dass Nutzer die richtigen Fonts, Versionen und Codepunkt-Zuordnungen haben

Kernfunktionen des Glyph Protocol

  • Unterstützung für zwei zentrale Operationen
    • Registrierung benutzerdefinierter Glyphen: Eine Anwendung wählt einen Unicode-PUA-Codepunkt und überträgt die Vektoroutline direkt an das Terminal, das sie zur Laufzeit registriert
    • Codepunkt-Abfrage: Es kann abgefragt werden, ob ein bestimmter Codepunkt durch den Systemfont, durch eine Registrierung in der aktuellen Sitzung, durch beides oder durch keines von beiden abgedeckt wird
  • Wenn der Nutzer bereits Nerd Font installiert hat, kann die Anwendung per Abfrage die Glyphenübertragung überspringen; ohne installierten Font kann sie die Outline direkt senden, damit Icons trotzdem korrekt angezeigt werden

Protokollstruktur

Übertragungsweg (Transport)

  • Verwendet wird APC (Application Program Command) statt OSC
  • APC wurde für anwendungsdefinierte Befehle entworfen; nicht implementierende Terminals können die Sequenz sicher ignorieren
  • OSC verwendet einen globalen Namespace mit einzelnen dezimalen Ganzzahlen als Befehlskennung und birgt dadurch Kollisionsrisiken; APC hat diese Probleme dank eigener Identifikationsstruktur nicht

Kennung (Identifier)

  • Allen Glyph-Protocol-Nachrichten wird der Codepunkt 25a1 (U+25A1, WHITE SQUARE) vorangestellt
    • Dieses Zeichen ist das Standardsymbol für Tofu, das das Terminal bei fehlender Glyphe anzeigt
  • Framing-Format: ESC _ 25a1 ; <verb> [ ; key=value ]* [ ; <payload> ] ESC \\
  • Vier Verben: s (support), q (query), r (register), c (clear)

Support (s): Prüfen, ob das Terminal das Protokoll unterstützt

  • Dient dazu festzustellen, welche Payload-Formate und Protokollversionen das Terminal unterstützt
  • Es ist auch die standardisierte Methode, die Existenz des Glyph Protocol selbst zu erkennen
  • fmt in der Antwort ist ein Bitfeld, bei dem jedes Bit ein Payload-Format repräsentiert
    • 1 = glyf: einfache TrueType-Glyphen, in v1 verpflichtend
    • 2 = colrv0: mehrschichtige flache Farbglyphen (OpenType COLR v0), hinzugefügt in v1.2
    • 4 = colrv1: vollständiger Paint-Graph mit Verläufen und Transformationen (OpenType COLR v1), hinzugefügt in v1.2
  • Wenn eine Antwort kommt, wird die Protokollunterstützung bestätigt; bei Timeout wird keine Unterstützung angenommen; fmt=0 bedeutet, dass das Protokoll implementiert ist, aber kein Format unterstützt wird

Query (q): Abfragen, ob ein Codepunkt renderbar ist

  • Es wird abgefragt, ob ein bestimmter Codepunkt renderbar ist; die Antwort enthält den Wert status
    • 0 (free): es wird nichts gerendert, Tofu wird angezeigt
    • 1 (system): durch den Systemfont abgedeckt
    • 2 (glossary): durch Registrierung in der aktuellen Sitzung abgedeckt
    • 3 (both): durch beides abgedeckt; die Registrierung überschreibt beim Rendern den Systemfont
  • Wenn das TUI-Framework das benötigte Icon bereits im System findet, kann es die Registrierung überspringen; andernfalls kann es einen benutzerdefinierten Codepunkt registrieren und so elegant auf einen Fallback ausweichen

Register (r): Eine Glyphe registrieren

  • Die Anwendung wählt einen PUA-Codepunkt und registriert ihn, indem sie eine base64-kodierte glyf-Outline überträgt
  • Wichtige Parameter
    • cp: Ziel-Codepunkt (hex), muss in einem der 3 Unicode-PUA-Bereiche liegen (U+E000U+F8FF, U+F0000U+FFFFD, U+100000U+10FFFD); außerhalb wird mit reason=out_of_namespace abgelehnt
    • fmt: Payload-Format; in v1 ist nur glyf definiert und als Standardwert meist weglassbar
    • upm: units per em, definiert den Koordinatenraum der Outline; Standardwert 1000
  • Ein zweites r für denselben cp überschreibt die vorherige Registrierung
  • Bei Fehlern wie Nicht-PUA-Codepunkten, ungültiger Payload oder Composite-Glyphen kommt eine Antwort im Format status=<nonzero>; reason=<code>

Warum das glyf-Format gewählt wurde

Warum Vektorformate

  • Glyphen sind keine Fotos und haben deshalb keine feste Auflösung: Dasselbe Icon muss sowohl in dichten TUIs mit 12 px als auch auf 24-px-HiDPI-Displays korrekt gerendert werden
  • Rasterglyphen sind an eine bestimmte Auflösung gebunden und wirken auf HiDPI unscharf oder sind in kleinen Zellen schwer lesbar

Warum konkret glyf

  • Jedes Terminal, das Text rendert, hat bereits einen glyf-Rasterizer eingebunden, etwa aus FreeType, swash, ttf-parser, fontdue oder allsorts
  • Durch die Einführung des Glyph Protocol entstehen auf Terminalseite überhaupt keine neuen Abhängigkeiten
  • Würde SVG verwendet, müsste man resvg einbinden oder einen neuen XML- plus Path-Parser schreiben
  • Auch die Datenmenge auf der Leitung ist klein: Ein typisches Icon benötigt 150–400 Byte glyf-Daten und ist damit selbst inklusive base64-Overhead 2–3-mal kleiner als ein vergleichbares SVG
    • Bei 50 registrierten Icons ergibt sich etwa 13 KB statt 35 KB, was bei tmux-Pipes oder mobilen SSH-Verbindungen spürbar sein kann

Kurz erklärt: glyf

  • Ein glyf-Record speichert eine Glyphe als Menge geschlossener Konturen (contours)
  • Jeder Punkt besitzt 1 Bit Metadaten und ist entweder on-curve oder off-curve
    • Zwei aufeinanderfolgende on-curve-Punkte → gerade Linie
    • Ein off-curve-Punkt zwischen on-curve-Punkten → quadratische Bézier-Kurve
    • Zwei aufeinanderfolgende off-curve-Punkte → impliziter on-curve-Punkt in der Mitte als Komprimierungstrick
  • Koordinaten sind ganzzahlige Gitterpositionen innerhalb des EM-Quadrats; bei upm=1000 bedeutet (500, 900) halbe Breite und 90 % Höhe
  • Ein geschlossenes Dreieck benötigt etwa 30 Byte, ein Icon mit 30 Punkten etwa 200 Byte

Das vom Protokoll definierte glyf-Subset

  • Nur einfache Glyphen sind erlaubt: keine Composite-Glyphen, keine Verweise auf andere Glyphen, kein fontweiter Kontext
  • Es wird die im OpenType-Standard definierte normale Flag-Kodierung verwendet
  • Keine Hinting-Befehle: Hinting setzt fontweite Kontrollwertsätze voraus und passt hier nicht
  • Der Koordinatenraum wird durch upm definiert, Standardwert ist 1000 und kann pro Registrierung überschrieben werden

Farbe, Skalierung und Erstellung

  • glyf-Outlines enthalten keine Farbinformationen und werden in der aktuellen Vordergrundfarbe gerendert — genau wie bei vererbten Nerd-Font-Fällen
  • Farbglyphen werden über separate Payload-Formate fmt=colrv0 und fmt=colrv1 unterstützt
  • Der Wert upm definiert den Glyphen-Koordinatenraum, den das Terminal beim Rendern auf die Zelle abbildet — dadurch ist bei Schriftgrößenänderungen keine Neuregistrierung nötig
  • Die meisten Entwickler werden glyf-Bytes nicht von Hand schreiben, sondern sie zur Build-Zeit aus SVG konvertieren: nutzbar sind etwa die ttx-/pens-Schnittstellen von fonttools; ein svg2glyf-Helper soll zusammen mit der Rio-Referenzimplementierung erscheinen

Lebensdauer und Kapazität

  • Jede Terminalsitzung besitzt ein Glossary mit maximal 1024 gleichzeitig registrierten Einträgen, adressiert über Codepunkte in den drei PUA-Bereichen
  • Registrierungen bleiben für die Dauer der Sitzung gültig
  • Bei der Registrierung der 1025. Glyphe wird die älteste Registrierung in FIFO-Reihenfolge verdrängt — ein Fehler wie „glossary full“ existiert also nicht
  • Anwendungen, die lautloses Verdrängen nicht tolerieren können, sollten vor der Ausgabe den betreffenden Codepunkt abfragen

Praxisbeispiel: Ein Icon in einer freien PUA registrieren

  • Gezeigt wird eine vollständige Pipeline, die eine stilisierte Outline bei U+100000 (dem ersten Codepunkt von Supplementary PUA-B) registriert
  • fontTools wird als SVG→glyf-Konverter verwendet
  • Nach dem Zeichnen der Outline mit TTGlyphPen wird sie base64-kodiert, per APC-Sequenz übertragen und danach der betreffende Codepunkt ausgegeben
  • Die glyf-Payload eines typischen 20-Punkte-Icons ist etwa 150 Byte groß, mit APC-Wrapper und base64 etwa 250 Byte
  • Für Entwickler mit vorhandenen SVG-Assets ist ein svg2glyf-Helper geplant — damit wäre die Registrierung in zwei Zeilen erledigt

Option für Massenregistrierung: reply=

  • Standardmäßig sendet das Terminal für jedes r eine ACK-Antwort. Wenn beim Start-Hook 100 Glyphen registriert werden, führt das jedoch zu 100 gepufferten ACKs im PTY, die als Müll in der Shell erscheinen können
  • Es gibt drei Steuerungsstufen
    • reply=1 (Standard): Antwort bei Erfolg und Fehler, für interaktive Einzelregistrierungen
    • reply=2: Antwort nur bei Fehlern, Erfolg bleibt stumm; geeignet, wenn bei Massenregistrierungen nur Fehler erkannt werden sollen
    • reply=0: überhaupt keine Antwort, fire-and-forget; sinnvoll bei Start-Hooks, wenn niemand die Antwort liest
  • Unbekannte Werte fallen automatisch auf reply=1 zurück, wodurch bei künftigen Erweiterungen Abwärtskompatibilität erhalten bleibt

Clear (c): Registrierung aufheben

  • Verwendbar beim Beenden eines Editors, beim Wechsel eines TUI-Themes oder beim Debuggen, um den Terminal-Standardzustand wiederherzustellen
  • Einzelnen Slot löschen: mit Parameter cp einen bestimmten Codepunkt angeben
  • Ganzes Glossary löschen: cp weglassen
  • Das Löschen eines leeren Slots ist kein Fehler, sondern ein No-op mit Antwort status=0
  • cp muss im PUA-Bereich liegen, andernfalls wird reason=out_of_namespace zurückgegeben

Funktionen, die bewusst nicht in v1 enthalten sind

  • Keine Registrierung von Nicht-PUA-Codepunkten: Beschränkung auf die drei Unicode-PUA-Bereiche
  • Keine Ligaturen: Registrierungen gelten nur für einzelne Codepunkte; Sequenzersetzungen sind nicht Teil von v1, Programmierligaturen wie -> werden bereits von OpenType-Fonts behandelt
  • Keine Persistenz über Sitzungen hinweg: Bei jedem Lauf müssen Glyphen neu übertragen werden, damit das Terminal nicht zu einem Font-Cache wird
  • Kein anwendungsübergreifendes Sharing: Jede Terminalsitzung besitzt ihr eigenes Glossary; es gibt weder IPC noch Daemon
  • Keine Farbglyphen in glyf-Payloads von v1: Rendering erfolgt in der Vordergrundfarbe, Farben sind in v1.2 über colrv0 und colrv1 getrennt
  • Diese Funktionen können später ergänzt werden, wurden aber bewusst ausgeschlossen, weil sie sich nach einer Einführung nur schwer wieder entfernen lassen

Sicherheitsbegründung für die PUA-Beschränkung

  • Die PUA-Beschränkung ist keine Frage der API-Ästhetik, sondern eine Sicherheitseigenschaft, die das Protokoll auch bei standardmäßiger Aktivierung sicher macht
  • Würde man die Registrierung beliebiger Codepunkte erlauben, könnte man etwa für U+0061 (a) eine Glyphe in Form von o registrieren, sodass bad.com wie bod.com aussieht
    • Im Zellpuffer stünde weiterhin bad.com, sodass Copy-and-Paste technisch korrekt bleibt, doch das, was Nutzer lesen, wäre falsch
    • Damit entstünde für alle Terminalprogramme ein Phishing-Primitive, dessen Wirkung auch auf später in derselben Sitzung gestartete Programme anhält
  • Durch die Beschränkung auf PUA wird dieser Angriffstyp mechanisch unmöglich: Nutzer tippen keine PUA-Codepunkte, und Dateinamen, URLs, Befehle, Variablennamen oder Logs enthalten keine PUA-Codepunkte
  • Damit wird das von Nerd Font etablierte Vertrauensmodell auf Protokollebene erzwungen: benutzerdefinierte Glyphen existieren nur in reservierten Bereichen und niemals über echtem Text
  • Weitere Sicherheitseigenschaften
    • Der Zellpuffer ist autoritativ: Auswahl, Kopieren, Suche, Hyperlink-Erkennung, Shell-Historie usw. müssen die von der Anwendung ausgegebenen Codepunkte zurückgeben; die Falle „sehen und kopieren sind verschieden“ kann nicht erzeugt werden
    • Sitzungsisolation: Zwei Tabs können U+E0A0 unabhängig voneinander mit unterschiedlichen Branch-Icons belegen; eine Registrierung in einem Tab beeinflusst das Rendering im anderen nicht

Vergleich mit bestehenden Ansätzen

Kitty Image Protocol (KIP) + Unicode-Placeholders

  • Mit den Unicode-Placeholders von KIP ließe sich das Glyph Protocol näherungsweise nachbilden, doch die Integration ist kompliziert, und Placeholders werden derzeit nur von Kitty, Ghostty und Rio unterstützt
  • KIP ist ein Bildprotokoll, aber Glyphen sind keine Bilder
    • Kosten pro Verwendung: Wenn eine Glyphe 200-mal auf dem Bildschirm wiederverwendet wird, etwa für Tabellenrahmen oder Bullet-Marker, müssen auch 200 Bildreferenzen platziert werden, inklusive Layout- und Compositing-Kosten. Beim Glyph Protocol wird nach der Registrierung eines Codepunkts mit Font-Geschwindigkeit gerendert
    • Keine native Auflösung: glyf-Outlines haben keine Pixelgröße und passen sich bei Schriftgrößenänderungen automatisch an. KIP überträgt Bitmaps fester Größe, die bei Größenänderung unscharf werden oder neu hochgeladen werden müssen; außerdem gibt es keine Möglichkeit, Änderungen der Schriftgröße zu erkennen
    • Vererbung der Vordergrundfarbe: Monochrome glyf-Outlines werden in der aktuellen Vordergrundfarbe der Zelle gerendert und passen sich dadurch automatisch an Themes an. Bilder haben eigene Pixel und nehmen nicht an Textfärbung teil

DEC DECDLD / DRCS

  • Dynamically Redefinable Character Sets, eingeführt mit dem VT220 im Jahr 1983, ähneln dem Glyph Protocol formal
  • Sie haben jedoch zwei zentrale Probleme
    • Bitmap-basierter Ansatz: Es wird ein Pixelraster hochgeladen, das auf die aktuelle Zellgröße des Terminals zugeschnitten ist. Bei Änderungen der Schriftgröße, bei HiDPI oder beim Wechsel auf 4K-Monitore werden Blockpixel vergrößert oder verkleinert. Das passt zur festen 10×20-CRT-Welt, aber nicht zu den variablen Zellgrößen moderner Terminals
    • Keine Namespace-Beschränkung: DECDLD kann Zeichensätze überschreiben, die auf den GL-Bereich gemappt werden können, also den Bereich mit Zeichen wie a, b oder c. Damit könnte ein nicht vertrauenswürdiges Programm das Rendering von a neu definieren — der wichtigste Grund, warum moderne Terminals DECDLD ungern aktivieren

Implementierungsstatus im Rio-Terminal

  • Das Glyph Protocol ist bereits im Main-Branch des Rio-Terminals nutzbar und soll im Mai offiziell landen — die erste Implementierung
  • Die vollständige Spezifikation wird zusammen mit dem Release veröffentlicht und enthält Beispielcode für Glyphenregistrierung und Terminalabfragen
  • Laufende Beispiele finden sich im Repository raphamorim/glyph-protocol-examples, darunter Sample-Integrationen für Bubble Tea, Ratatui und Ink
  • Das Protokoll kann sich noch ändern; mit mehr Anwendungen und Terminals könnten sich Nachrichtenformate, Query-Antworten und Edge Cases weiterentwickeln — deshalb sollte man es derzeit als bewegliches Ziel behandeln und Implementierungsversionen fest pinnen
  • Es besteht die Hoffnung auf Übernahme durch weitere Terminal-Emulatoren; der Nutzen für das gesamte Ökosystem ist groß, und der Implementierungsumfang wurde bewusst klein gehalten

Offene Fragen an die Community

  • Soll eine Benachrichtigung über Schriftgrößenänderungen Teil des Protokolls sein? Das Glyph Protocol selbst umgeht dieses Problem, weil Outlines auflösungsunabhängig sind. TUIs, die Bilder und Glyphen kombinieren, haben jedoch außer Polling keine Möglichkeit, Änderungen an Zellmetriken zu erkennen — diskutiert wird daher, ob ein resize- oder metrics-changed-Signal in den Umfang des Protokolls gehört oder nicht
  • Gibt es einen verantwortbaren Weg, Nicht-PUA-Registrierungen zu erlauben? Die PUA-only-Regel garantiert Standardsicherheit, blockiert aber Anwendungsfälle wie CJK-Eingabemethoden, die fehlende Han-Zeichen als Glyphen übertragen, oder sprachspezifische Tools, die Glyphen überschreiben möchten. Gesucht werden Meinungen dazu, ob sich solche Fälle mit explizitem Opt-in auf Nutzerebene, signierten Fähigkeiten oder Trusted-Source-Flags öffnen lassen, ohne Phishing wieder zu ermöglichen

Noch keine Kommentare.

Noch keine Kommentare.