pad.software
Kontakt

Blog · Werkstatt

Leere Blasen, echter Text

Ein Cartoon-Strip in der Strichzeichnungs-Welt dieser Site. Die Sprechblasen entstehen leer, der Text steht in einer Datendatei und sitzt per CSS im Bild.

4 Min. LesezeitAuf LinkedIn teilen

  • css
  • astro
  • ki-bilder
  • a11y

Die Motive dieser Site sind Strichzeichnungen: der Nighthog und sein Blechroboter, blaue Linien auf Schwarz, immer zu zweit, immer mit derselben Arbeitsteilung. Der Roboter arbeitet die Menge ab, der Hog urteilt. Ob diese Welt auch einen Cartoon-Strip trägt, war offen. Sie hat keinen Grauwert, keine Farbfläche, nichts, worin eine Sprechblase Halt findet. Hier ist die Antwort.

Strichzeichnung: Der Blechroboter mauert zügig an einer geraden Ziegelmauer, neben ihm Mörtelkübel und Kelle. Rechts steht der Nighthog mit einer Wasserwaage in der Hand und sieht ihm skeptisch zu.

Roboter:Zwölf Meter. In einer Stunde!

Panel 1 von 2
Strichzeichnung: Dieselbe Baustelle von weiter hinten. Die Mauer beschreibt eine Spirale, der Roboter steht mitten darin und breitet begeistert die Arme aus. Links davor der Nighthog mit der Wasserwaage, ungerührt.

Nighthog:Beeindruckend. Und jetzt komm da raus.

Panel 2 von 2
Strip: Zwölf Meter

Warum die Blasen leer bleiben

Kein Bildgenerator setzt zuverlässig Schrift. Umlaute verkrüppeln, Wörter verrutschen, aus „Zwölf” wird „Zwoolf”. Also werden die Blasen leer generiert, und zwar ausdrücklich: „One large EMPTY speech bubble, completely empty inside.” Der Text kommt danach.

Der naheliegende Weg wäre, ihn nach der Generierung ins PNG zu montieren, ein Dutzend Zeilen Pillow genügen dafür. Auf einer Site, die über Typografie und Flächen lebt, wäre eingebrannter Text aber die schlechtere Hälfte von allem: unscharf beim Zoomen, nicht markierbar, nicht durchsuchbar, für Screenreader unsichtbar, und jede Korrektur eines Tippfehlers heißt neu rendern. Der Text liegt deshalb in einer Datendatei und sitzt per CSS in der Blase. Was du oben liest, kannst du mit der Maus markieren.

Zwei Dateien, kein Bildtext

src/data/strips.ts ist die einzige Quelle. Eine Blase ist ein Text plus ihr Sitz im Panel:

export interface Blase {
  text: string;
  sprecher: Sprecher;   // trägt die Screenreader-Zuordnung
  x: number;            // Mitte der Blase, % der Panelbreite
  y: number;            // Mitte der Blase, % der Panelhöhe
  breite: number;       // Textspalte, % der Panelbreite
}

src/components/Strip.astro legt den Text darüber. Kein Island, kein JavaScript, und die Schriftgröße hängt an der Panelbreite statt am Viewport:

.strip-blase {
  position: absolute;
  transform: translate(-50%, -50%);
  font-family: var(--font-mono);
  /* Skaliert mit dem Panel, nicht mit dem Viewport. */
  font-size: clamp(0.6875rem, 3.2cqw, 1.05rem);
}

Dass in der Blase Monospace steht, war zuerst Verlegenheit und dann Absicht. Eine Comic-Schrift wäre in dieser Site ein Fremdkörper. JetBrains Mono liest sich in einer technischen Zeichnung wie die Beschriftung, die dort sowieso hingehört.

Der sprecher ist kein Zierfeld. Er wird zu einem sr-only-Präfix vor dem Blasentext, deshalb liest ein Screenreader den Strip als Dialog vor: erst die Szenenbeschreibung aus dem alt, dann „Roboter: Zwölf Meter. In einer Stunde!“. Ein Strip mit eingebranntem Text ist an dieser Stelle einfach still.

Prozent statt Pixel

Die Koordinaten stehen in Prozent der Panelkante, nicht in Pixeln. Der Grund ist unspektakulär und hat sich sofort bezahlt: Die Rohbilder kommen mit 2048 Pixeln aus der Generierung, im Repo liegen sie mit 1024. Pixelkoordinaten hätten diesen Schritt nicht überlebt.

Was die Maschine nicht wollte

Der erste Versuch hatte drei Panels, weil Comics drei Panels haben. Das ging nicht auf. Ab Panel zwei gibt man das erste Panel als zusätzliche Referenz mit, damit der Ort derselbe bleibt, und das funktioniert erschreckend gut: Mörtelkübel, Kelle und die losen Ziegel standen in allen Panels an derselben Stelle. Nur klebt das Modell dann eben auch an der Komposition. „Closer medium shot” hat es ignoriert, und Panel eins und zwei waren fast dasselbe Bild. Ein stummer Mittel-Beat, den man nicht von seinem Vorgänger unterscheiden kann, erzählt nichts. Zwei Panels, Aufbau und Pointe, waren die Lösung.

Der zweite Widerstand waren die Maßlinien. Das Referenzbild ist der Hero der Startseite, und dort gehören dünne Maßpfeile zum Motiv. Sie im Prompt zu verbieten, reichte nicht, auch nicht in Großbuchstaben mit fünf Synonymen. Was ging: das fertige Bild noch einmal schicken und nur löschen lassen, mit der Auflage, alles andere unangetastet zu lassen. Ein Durchgang, danach war das Panel sauber.

Die Linien messen

Strichbilder dieser Site laufen über mix-blend-mode: lighten auf schwarzem Grund. Schwarz ist für lighten neutral, damit ist der Bildgrund exakt die Seitenfarbe. Was dabei auffällt, sobald zwei Bilder nebeneinander liegen: Die Renders schwanken in der Linienhelligkeit. Die beiden Panels kamen mit Luminanz-p99 182 und 177 aus der Generierung, und schon diese kleine Differenz sieht man im Streifen. scripts/strip-panels.mjs misst deshalb jedes Panel und zieht es per sharp.linear auf denselben Zielwert:

public/images/strip/zwoelf-meter-1.webp: p99 182 → gain 1.10
public/images/strip/zwoelf-meter-2.webp: p99 177 → gain 1.13

Ziel ist hier 200, nicht die 150 der Hintergrund-Motive. Ein Strip ist Inhalt bei voller Deckkraft und kein abgedimmter Hintergrund.

Ein Detail noch, gefunden beim Sichttest: Unter 40 rem stapeln die Panels, statt zu schrumpfen. Schrumpfende Panels drücken den Blasentext irgendwann aus der Blase, weil die Schrift eine Untergrenze hat und die Blase nicht. Der Strip wird auf dem Telefon also länger, nicht kleiner.

Lieber direkt fragen?

Antwort innerhalb eines Werktages.