23. April 2026
Deklarative UI
Das Problem mit imperativem UI-Code
Jeder, der schon einmal komplexe Benutzeroberflächen in einer Custom-Engine von Grund auf neu gebaut hat, kennt die typischen Stolpersteine. Anfangs ist es einfach: Man zeichnet ein Rechteck, schreibt Text hinein und prüft, ob die Maus beim Klicken innerhalb der Koordinaten war.
Doch je mehr die Anwendung wächst, desto schneller vermischt sich die Render-Logik (Wo wird ein Pixel gezeichnet? Welche Farbe hat der Rand?) mit dem Anwendungszustand (Ist der Schalter an oder aus? Welcher Text steht im Feld?). Das führt oft zu hartkodierten Layout-Koordinaten – sogenannten "Magic Numbers" – und extrem starrem Code. Das Hinzufügen eines simplen neuen Eingabefeldes erfordert plötzlich Anpassungen in diversen, tief vergrabenen Dateien der Grafik-Pipeline.
Um das System langfristig wartbar und flexibel zu halten, haben wir uns heute für einen Paradigmenwechsel entschieden: Weg vom imperativen Pixel-Schubsen, hin zu einem strikteren, funktionalen Ansatz, inspiriert von Prinzipien, wie man sie aus modernen deklarativen Frameworks kennt.
Die Lösung: Eine abstrakte Formular-DSL
Anstatt UI-Elemente direkt auf den Bildschirm zu zwingen, definieren wir sie jetzt über eine schlanke, lesbare DSL. Ein Formular existiert im Speicher nur noch als abstraktes Datenmodell – konzipiert als Algebraischer Datentyp (ADT). Es beschreibt lediglich die Struktur (was dargestellt werden soll), enthält aber keinerlei Informationen über das Wie.
Im Code sieht diese abstrakte Definition nun so aus:
// Deklarative und zustandsfreie Definition der UI
const settingsForm = buildForm("settings_id",
Header("h1", "Mitarbeiter Profil"),
TextInput("input_1", "Name:", "Max Mustermann", "cmd_edit_name"),
LabeledValue("val_1", "Rolle:", "Entwickler"),
Toggle("tgl_1", "Aktiv:", true, "toggle_active"),
Spacer("sp_1", 0.1),
Button("btn_1", "Befördern, "cmd_1")
)
Dieser Baum an Informationen ist pure Struktur. Er ist komplett entkoppelt von der Grafik-API.

Immutable State & Redux-Pattern
Der eigentliche Gewinn dieser Architektur zeigt sich in der Interaktion. Wenn der Nutzer beispielsweise auf die Checkbox klickt, ändern wir nicht direkt den Zustand einer UI-Komponente, die gerade auf dem Bildschirm liegt. Wir mutieren keine globalen Variablen.
Stattdessen feuert das System lediglich ein generisches Event – einen "Intent" – mit der entsprechenden Action-ID (z.B. toggle_active). Dieser Intent wandert in einen zentralen Reducer. Dort nutzen wir "reine Funktionen" (Pure Functions), um aus dem alten Zustand eine neue, veränderte Kopie des Formulars zu erzeugen.
// Rein funktionale Zustandsänderung ohne Side-Effects
function toggleFieldValue(form: FormModel, targetId: String): FormModel {
let newFields = form.fields.map(field => {
if (field.id == targetId) {
// Erzeugt eine neue Kopie des Feldes mit invertiertem Status
return copyWith(field, isActive: !field.isActive)
}
return field
})
// Gibt ein komplett neues Formular-Modell zurück
return copyWith(form, fields: newFields)
}
Da diese Funktionen keinerlei Nebeneffekte (Side Effects) haben und den bestehenden Speicher nicht überschreiben, lassen sie sich isoliert und blitzschnell mit Unit-Tests validieren. Ein weiterer massiver Vorteil: Da wir für jede noch so kleine Änderung ein komplett neues Modell erzeugen, bekommen wir eine saubere Historie. Ein robustes Undo/Redo-System fällt dabei als architektonisches Nebenprodukt fast kostenlos ab.
Vom Datenmodell auf den Bildschirm
Wie kommt diese abstrakte Datenstruktur am Ende auf den Monitor?
Die Engine nimmt im nächsten Frame das aktualisierte Datenmodell und übersetzt es in einen abstrakten Syntaxbaum für das Layouting. Hier greift ein separat definiertes Theme, das globale Konstanten für Ränder, Abstände und Schriftgrößen enthält. Die Engine berechnet die Layout-Mathematik für Zeilen und Spalten und generiert im allerletzten Schritt eine flache Liste von puren Render-Kommandos (Quads, Text-Vertices, Linien).
Diese vorbereitete, "dumme" Liste wird dann optimiert und in einem Rutsch an die Grafikkarte übergeben.
Fazit
Der Umbau auf einen funktional-deklarativen Architektur-Stil erfordert anfangs etwas mehr Disziplin bei der Modellierung der Datenstrukturen. Die strikte Einbahnstraße des Datenflusses (Datenmodell ➔ Layout-Engine ➔ Render-Befehle) macht sich jedoch bezahlt: Neue UI-Komponenten lassen sich jetzt in Minuten sicher hinzufügen, der Code ist deutlich weniger fehleranfällig und die Rendering-Schicht muss nichts mehr über die Business-Logik der Anwendung wissen.
📰 Aktuelle Beiträge
Zurück zur Startseite mit den neuesten Projekten und Gedanken.
🖼️ Galerie
Screenshots und visuelle Einblicke in die aktuelle Entwicklung der Engine und UI.
🗄️ Artikel-Archiv
Ältere Beiträge und Notizen, die zur Dokumentation erhalten bleiben.