Vom Kopf zum Blatt
Neun bis dreißig Köpfe auf einer Fläche, jeder an seinem Platz, jeder in derselben Größe – und einer davon jederzeit groß in der Mitte. Das ist weniger Verwaltung, als es klingt: das Blatt ist ein Raster, ein Maßstab, eine Reihenfolge und eine Zahl.
Das Raster
Die Spaltenzahl springt an vier festen Schwellen – 560, 900, 1300, 1800 Pixel. Keine Formel, sondern eine Tabelle: eine Formel träfe irgendwann eine Breite, bei der sie zwei Spalten oder elf vorschlägt, und beides ist kein Blatt. Die Reihen ergeben sich danach aus einer einzigen Bedingung – die Zellen sollen ungefähr quadratisch bleiben.
Im Zweifel lieber eine Spalte mehr als große Köpfe mit Luft drumherum. Ein Kopf, der im Breitbild allein in einer flachen Kachel steht, sieht verloren aus; sechs kleine Köpfe in einer Reihe sehen nach Blatt aus.
Der Seed einer Zelle ist blattSeed + r · spalten + c.
Benachbarte Zellen haben also benachbarte Seeds – genau der Fall, für
den der Generator im Kapitel Zufall acht Züge
wegwirft. Ohne das Aufwärmen stünden hier Reihen von Verwandten.
Raumbedarf gegen platzIn
Der Stil sagt, was ein Kopf braucht (raum(dna)), die
Zelle sagt, was sie hergibt (platzIn). Beide rechnen in
Kopfeinheiten, damit sie überhaupt vergleichbar sind.
Nach unten wird nicht gemessen: dort steht der Name, und keine Frisur reicht so weit. Nach oben und zur Seite schon – der Afro ist rund und deutlich breiter als der Schädel, der Knoten eines Dutts sitzt obendrauf, und eine Hutkrempe ragt über jeden Kopf hinaus.
Verlangt eine Frisur mehr, als ihre Zelle hergibt, wird nicht dieser eine Kopf kleiner, sondern das ganze Blatt. Neun Köpfe in neun Maßstäben sehen aus wie ein Fehler; ein etwas kleineres Blatt sieht nach Absicht aus.
Meistens kommt 1 heraus. Die Zelle ist so bemessen, dass
die üblichen Frisuren hineinpassen; der Faktor greift erst bei den
größten Afro-Kugeln – und dann für alle.
Die Zeichenreihenfolge ist Teil der Korrektheit
Ein Kopf wird nicht zusammengesetzt, sondern gestapelt. Es gibt keine Verdeckungsrechnung, keinen Tiefenpuffer und keine Masken zwischen den Zügen – jeder Zug darf übermalen, was unter ihm liegt. Die Ordnung ist deshalb kein Ablauf, sondern eine Aussage darüber, was wovor liegt. (Die eine Ausnahme bleibt in einem Zug: der Wangenbogen beschneidet das Auge, zu dem er gehört, siehe Merkmale.)
Sie stand lange nirgends. Sie war die Reihenfolge von siebzehn
Aufrufen in zeichneGesicht, und wer einen davon zwei
Zeilen höher schob, verschob eine Verdeckung – ohne dass ihm etwas
sagte, dass er gerade einen Vertrag angefasst hatte. Heute nennt jeder
Zug seine Ebene, und die Ebenen stehen als Liste:
Die Züge werden gesammelt, stabil nach Ebene sortiert und dann gezeichnet. Stabil heißt: innerhalb einer Ebene gilt weiter, wer zuerst gesammelt wurde – sonst läge die Kontur unter ihrer eigenen Fläche und wäre weg.
| Ebene | Warum dort |
|---|---|
hals | Ganz hinten. Der Kopf sitzt darauf und deckt den Ansatz. |
hinter-dem-kopf | Zöpfe, die Afro-Kugel, die hintere Hutkrempe. Sie werden vor der Kopffläche gezeichnet und von ihr zur Hälfte verdeckt – das ist der ganze Trick. |
ohren | Das abgewandte Ohr sitzt seitlich am Schädel, also unter seiner Fläche. |
kopf | Der Deckel über allem Hinteren – und die Kontur darüber, sonst frisst der Rand der Fläche die Linie an. |
zugewandtes-ohr | Das zugewandte Ohr liegt vor der Wange: dreht der Kopf, wandert sein Anker hinter die Silhouette, und die Kopffläche biss ihm die Wurzel ab. Welches Ohr hier landet, sagt seine Normale – nicht die Seite im Bild. |
haut | Backen, Augenringe, Schraffur, Stirnfalten: Farbe und blasse Nebenlinien auf der Haut, unter allen Zügen. |
bart | Unter der Nase, auch in der Ordnung. Was die Nase überlappt, verdeckt sie. |
fernes-auge | Das Auge auf der abgewandten Seite. Welches das ist, sagt seine Tiefe – nicht das Vorzeichen der Drehung. |
nase | Sie hat Volumen und stellt sich frei – also verdeckt sie das Auge hinter sich. |
nahes-auge | Vor der Nase gezeichnet radierte sie auch dieses weg. |
mund | Über dem Bart, unter dem Rest. |
frisur | Haar und Kopfbedeckung: die Schale liegt auf dem Schädel, nicht darunter. |
aufgesetzt | Ohrring, Pflaster – am Kopf, aber nicht Teil von ihm. |
davor | Vor dem Gesicht und deshalb über allem – auch über der Mütze, die auf dem Schädel sitzt und nicht davor. |
Symptom: Bei gedrehtem Kopf fehlt dem vorderen Auge ein Stück, als wäre es angeschnitten. Ursache: Die Nase ist keine Linie, sondern eine Form mit Fläche. Vor beiden Augen gezeichnet deckt sie nicht nur das ferne, sondern auch das nahe zu. Lösung: Drei Ebenen verschränken sich: fernes Auge, Nase, nahes Auge. Welches der beiden das ferne ist, entscheidet die Tiefe der Augen-Felder, nicht das Vorzeichen der Drehung – und eine Probe hält es fest: über vierhundert Seeds muss das zuletzt gezeichnete Auge das mit dem größeren z sein.
Die Großansicht ist eine Zahl
Kein zweites Element, kein Modal, kein zweites Canvas.
fokus.t läuft zwischen 0 (der Kopf sitzt in seiner Zelle)
und 1 (er steht in der Mitte), und der Ort wird daraus gerechnet.
Weil ohnehin jedes Bild neu gezeichnet wird – die Köpfe folgen dem
Zeiger –, ist das der einfachere Weg und nebenbei der weichere:
t nähert sich seinem Ziel jedes Bild um einen festen
Anteil des Restwegs. Das ist in beide Richtungen „schnell los, weich
an" und lässt sich mitten in der Bewegung umkehren, ohne dass etwas
springt.
Der Schleier über dem Raster ist papierfarben, nicht grau. Das Blatt tritt zurück, statt dass ein Vorhang davorfällt – und am Ende deckt er ganz, damit hinter dem großen Kopf kein Raster durchschimmert.
Die Namen sind kein Teil des Bildes
Sie liegen als <span> über dem Canvas, an genau der
Stelle, an der das Canvas sie sonst gemalt hätte – den Ort rechnet die
App ohnehin aus, für den Zoom.
Symptom: Ein Name lässt sich nicht markieren, nicht
kopieren, nicht suchen, und eine Vorlesesoftware findet auf dem
Blatt nichts als ein leeres Rechteck.
Ursache: Gemalter Text ist ein Bild.
Lösung: Text bleibt Text. Das Canvas trägt ein
aria-label, die Namen stehen darüber im DOM.
Der Gewinn ist nicht nur das Kopieren. Der Name in der Großansicht bekommt damit eine eigene Bewegung: er kommt einen Hauch von unten nach, wenn der Kopf schon steht, und geht schneller, als er kam. Ein Name, der so lange bräuchte wie der Kopf, würde mit ihm um die Aufmerksamkeit streiten.
Zwei Namen, nicht einer: wunsch ist, was dort stehen
soll, gezeigt, was gerade dort steht. Die App fragt jedes
Bild neu an – sechzig Mal in der Sekunde denselben Wunsch. Ohne diese
Trennung liefe in jedem Bild ein neues Ausblenden an, und das
Einblenden käme nie dran; der Name bliebe für immer halb da.
Prüfen ohne Bildschirm
Der Entwicklungsbau legt vier Griffe an window.presse:
wuerfle(seed) stellt ein bestimmtes Blatt,
schaue(x, y, s) rechnet die Federn ohne Bildschleife
weiter, zellen() sagt, wo welcher Kopf sitzt und was er
trägt, und abzug(name) schickt das Blatt in voller
Auflösung per POST /__abzug an den Server, der es unter
abzuege/ ablegt.
Symptom: Eine automatisierte Prüfung sieht Köpfe,
die stur geradeaus schauen – ob sie dem Zeiger folgen, lässt sich
nur behaupten.
Ursache: Ohne sichtbare Seite hält der Browser
requestAnimationFrame an. Es gibt niemanden, der das
nächste Bild malt.
Lösung: schaue() rechnet die Federn in
Schritten von 1/60 Sekunde selbst weiter und zeichnet einmal. Für
den Abzug werden die Namen einmalig ins Canvas gemalt – das nächste
Bild wischt sie wieder weg.
Der ganze Zweig existiert nur unter import.meta.env.DEV;
im Bündel ist er entfernt. Ein Griff, der im Auslieferungsstand
mitläuft, ist keine Prüfhilfe mehr, sondern eine Schnittstelle.