Tag

Alles zu UI auf einer Seite

Alle Inhalte mit dem Tag UI am Stück auf einer Seite.

7. Mai 2026

Devlog: Ctrl-P als ruhiger Einstieg in die Kommandosuche

Heute ging es um eine kleine, aber recht grundlegende Stelle im Editor: Kommandos sollen nicht nur irgendwo existieren, sondern im Arbeitsfluss auffindbar sein. Nicht als großes Einstellungsfenster, nicht als Dokumentationsersatz, sondern als ruhige Übersicht direkt im HUD.

Der Einstieg dafür ist Ctrl-P. Die Taste öffnet den HUD-Editor, und derselbe Text dient jetzt zusätzlich als Suchstring für eine Command-Palette in der Bildschirmmitte.

HUD-Command-Palette

Der konkrete Schritt: Beim Öffnen des HUD-Editors erscheint zusätzlich eine zentrierte Command-Palette. Während man in die Ctrl-P-Textbox tippt, wird die Tabelle gefiltert. Sichtbar sind Kommandoname, Tastenkürzel und eine kurze Beschreibung.

Das klingt zunächst unspektakulär. Genau das ist hier auch beabsichtigt. Es soll kein neues großes Bedienkonzept sein, sondern eine einfache Klärung: Welche Aktionen gibt es gerade, wie heißen sie, wie löse ich sie aus?

Warum das überhaupt nötig ist

Bei einem grafischen Editor wachsen Kommandos oft schleichend. Erst gibt es ein paar Tastenkürzel. Dann ein Kontextmenü. Dann Sonderfälle für Debug-Ansichten, Selektion, Textmodus, Viewports, Hilfsanzeigen. Irgendwann ist das System für den Entwickler noch logisch, für den späteren Benutzer aber nicht mehr unmittelbar sichtbar.

Ctrl-P ist dafür ein guter Ort. Es ist bereits ein temporärer HUD-Einstieg: aufrufen, etwas eingeben, wieder schließen. Die Command-Palette hängt sich an genau diese Bewegung an, statt eine zusätzliche Oberfläche zu erzwingen.

Die Palette ist ein Gegenmittel gegen verstreute Bedienlogik. Sie nimmt vorhandene Kommandos und macht sie als Liste sichtbar. Wichtig ist dabei nicht nur die Anzeige selbst, sondern die Richtung im Code: Kommandos sollen stärker als Daten beschrieben werden. Ein Kommando ist dann nicht nur ein Zweig in irgendeiner Eingabelogik, sondern ein kleiner beschreibbarer Eintrag mit Name, Auslöser und Zweck.

Das ist kein spektakulärer Umbau. Eher ein Aufräumen an einer Stelle, die später sonst teuer wird.

Was sichtbar geändert wurde

Die sichtbare Änderung ist die Tabelle in der Bildschirmmitte. Sie bleibt bewusst schlicht:

  • links der Kommandoname,
  • daneben bekannte Tastenkürzel,
  • rechts eine knappe Beschreibung.

Die Suche ist als Volltextsuche gedacht. Man muss also nicht wissen, ob etwas als Menübefehl, Tastenkürzel oder interne Aktion geführt wird. Ein Begriff reicht, und die Liste schrumpft auf die passenden Einträge.

Das Schließen folgt dem bestehenden Verhalten: Escape beendet den Modus, ebenso erneutes Ctrl-P. Damit bleiben HUD-Textbox und Command-Palette temporäre Werkzeuge und werden kein dauerhaftes Panel, das Platz beansprucht.

Was absichtlich nicht gezeigt wird

Der Screenshot zeigt nur das Ergebnis im UI. Die interessantere Arbeit liegt darunter, aber sie muss nicht öffentlich ausgebreitet werden. Es geht allgemein um weniger Verzweigung, weniger doppelte Beschreibungen und mehr kleine Datentypen, die das Verhalten beschreiben.

Das ist eine nüchterne Architekturarbeit. Keine große neue Engine-Funktion, kein Demo-Effekt. Eher eine Maßnahme gegen künftige Unordnung.

Mir ist dabei wichtig, dass solche Änderungen nicht zu breit werden. Ein kleiner Cluster ist besser als ein halber Umbau. Wenn Eingabe, Menüs, Editorzustand und Rendering gleichzeitig angefasst werden, ist nachher schwer zu sagen, welche Änderung welches Verhalten verursacht hat. Deshalb hier nur ein enger Schnitt: Command-Beschreibung, Filtermodell, HUD-Anzeige.

Warum das zur Richtung des Projekts passt

Das Projekt bewegt sich seit einiger Zeit weg von einzelnen Speziallösungen hin zu beschreibbaren Strukturen. Nicht alles muss sofort eine große DSL werden. Aber Formulare, HUD-Elemente, Kommandos und Zustände sollten so gebaut sein, dass man sie lesen kann, ohne erst zehn Callchains im Kopf zu simulieren.

Eine Command-Palette ist dafür ein guter Prüfstein. Wenn ein Kommando nur durch implizite Logik existiert, lässt es sich schlecht anzeigen. Wenn es als Datenbeschreibung existiert, kann man es filtern, sortieren, dokumentieren oder später anders darstellen.

Ctrl-P wird damit nicht zu einem magischen Sonderfall, sondern zu einem Einstiegspunkt in ein allgemeineres Modell: Text rein, passende Kommandos sichtbar machen, Aktion finden, Modus wieder verlassen.

Das ist der eigentliche Nutzen: Die Anzeige zwingt zu etwas mehr Ordnung.

Stand

Der aktuelle Stand ist bewusst pragmatisch. Die Palette ist da, die Suche funktioniert, und vorhandene Kommandos werden zusammengeführt. Noch ist das kein endgültiges Command-System für alle Eingabearten. Es ist eher ein Zwischenstand, der die Richtung vorgibt.

Der nächste sinnvolle Schritt wäre nicht, sofort mehr Oberfläche zu bauen. Besser wäre, weitere verstreute Kommandobeschreibungen nach und nach in dasselbe Modell zu ziehen. Langsam, testbar, ohne den Rest des Editors dabei unnötig aufzureißen.

Für heute reicht das: Ctrl-P, ein Suchfeld, eine Tabelle, weniger Rätselraten.

27. April 2026

Innerframe-Zooming, Nested Viewports und das Chessboard

Ein globaler Kamera-Zoom stößt bei fensterbasierten 3D-Interfaces schnell an Grenzen. Wenn ein Formular detaillierte Informationen enthält, ist ein gezieltes Vergrößern des Inhalts oft sinnvoller, als die Kameraposition im Raum zu verändern.

Daraus ergab sich die Notwendigkeit für lokales Innerframe-Zooming, verschachtelte Viewports (Nested Scrolling) sowie neue Test-Objekte wie das Chessboard.

Innerframe Zoom und Nested ViewportsAbb 1: Die Benutzeroberfläche mit individuell skalierten Innerframes. Jedes Fenster hält seinen eigenen Zoom-Faktor.

Innerframe-Zooming: Lokaler Maßstab

Jedes virtuelle Fenster besitzt nun einen eigenen zoomScale-Wert im Datenmodell. Mit Ctrl + Mausrad über einem Fenster wird isoliert dessen Inhalt skaliert. Alternativ lässt sich das fokussierte Fenster über die Tastatur mit Ctrl + Numpad+ und Ctrl + Numpad- vergrößern oder verkleinern.

Ein Blick unter die Haube: Die Skalierung erfolgt nicht durch nachträgliches Strecken einer gerenderten Textur. Der Zoom-Faktor wird direkt in den Kontext des Layout-Systems übergeben. Bei der Berechnung des UI-Gitters durch den Worker-Thread werden Parameter wie Margins, Paddings und Font-Metriken mit diesem Faktor multipliziert. Textelemente, die auf Signed Distance Fields (SDF) basieren, werden so mathematisch neu berechnet und bleiben scharf. Fällt der Inhalt aus dem sichtbaren Bereich, werden Scrollbars aktiviert.

Nested Viewports und Nested Scrolling

Um skalierte Inhalte an den Fensterkanten korrekt abzuschneiden, wurde ein System für Nested Viewports (verschachtelte Ansichtsbereiche) implementiert. Wenn ein UI-Element aus einem scrollbaren Formular besteht, das wiederum ein scrollbares Text-Editor-Feld enthält, muss das Clipping über mehrere Ebenen hinweg korrekt berechnet werden.

Verschachteltes vertikales ScrollingAbb 2: Nested Scrolling in Aktion: Ein scrollbarer Editor-Bereich innerhalb eines scrollbaren Hauptformulars.

Durch das angepasste Event-Routing entsteht so ein funktionierendes Nested Scrolling: Die Scroll-Eingabe wird dem Viewport zugeordnet, über dem sich der Mauszeiger befindet. Scrollt der Nutzer über dem Editor-Feld, bewegt sich nur dessen Text. Scrollt der Nutzer im Rest des Formulars, bewegt sich die gesamte Maske.

Ein Blick unter die Haube: Die Umsetzung basiert auf einer Stack-Architektur und geometrischen Schnittmengen. Jedes scrollbare Element legt seine Begrenzungen auf einen Stapel. Liegt ein Child-Element in einem Parent-Element, berechnet das System die Schnittmenge beider Rechtecke (intersect). Nur Render-Befehle, die innerhalb dieser kombinierten Grenzen liegen, werden an den Fragment-Shader der Grafikkarte weitergegeben.

Neue Visualisierung: Das Chessboard

Zur Visualisierung von Datenrastern und Flächen wurde ein Schachbrett-Objekt (wokChessboard) implementiert. Dieses dient gleichzeitig als technischer Testfall für zwei Aspekte:

  1. GPU-Batching: Das Schachbrett berechnet sein Muster zustandsfrei in einem separaten Datensatz für die Worker-Threads. Die Performance bleibt dadurch auch bei mehreren parallel angezeigten Instanzen konstant.
  2. Proportionssperre (Uniform Resize): Ein Raster muss beim Skalieren quadratisch bleiben und darf sich bei Maus-Interaktionen nicht verzerren.

Ein Blick unter die Haube: Für diese Einschränkung wurde die Interaktions-Logik um eine Status-Variable (resizeUniform). Zieht der Nutzer den Maus-Cursor am Fensterrahmen, entstehen Deltas für die X- und Y-Achse. Ist das Flag aktiv, wird der größere der beiden Werte auf Breite und Höhe gleichermaßen angewendet, bevor die Transformations-Matrix aktualisiert wird. Das Grafik-Objekt selbst bleibt dabei von Logik bezüglich des Seitenverhältnisses befreit, da diese in der zentralen Interaktions-Schicht verbleibt.

Dies bildet die technische Grundlage für die Darstellung und Interaktion mit weiteren proportional gebundenen Datenansichten.

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.

Mitarbeiter Profil

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.

19. April 2026

Neue Objekt-Boundaries und verbessertes Snapping

Im Spatial Workspace unserer UI-Engine geht es stetig voran. Nachdem wir in den letzten Tagen die Performance bei tausenden Objekten gesichert haben, lag der Fokus heute auf einem entscheidenden Detail der räumlichen Interaktion: Wie exakt beanspruchen Objekte ihren Platz im Raum und wie verhalten sie sich, wenn sie aufeinandertreffen?

Visualisierung der neuen Objekt-BoundariesAbb 1: Die neuen Boundaries schließen das eigentliche Frame und die dazugehörige Caption in eine gemeinsame Bounding-Box ein.

Das Problem mit den Beschriftungen

Bisher lag der Fokus der Kollisions- und Layout-Logik primär auf dem eigentlichen Fenster (dem Frame). Das führte in der Praxis allerdings zu visuellen und logischen Unsauberkeiten: Sobald ein Objekt eine Beschriftung (die Objcaption) besaß, die über das visuelle Haupt-Frame hinausragte, wurde dieser Platz vom System nicht vollständig respektiert. Beim Andocken von Fenstern konnte es passieren, dass Frames die Texte benachbarter Objekte überlagerten.

Erweiterte Objekt-Boundaries

Um das zu lösen, haben wir die Berechnung der Bounding-Boxen umgeschrieben. Die neuen Objekt-Boundaries umschließen nun konsequent das gesamte Element: Sie fassen das Haupt-Frame und die Objcaption zu einer gemeinsamen, logischen Einheit zusammen. Die Engine "weiß" nun exakt, wie viel Raum ein Objekt mitsamt seiner Metadaten und Titel wirklich benötigt.

Die neue Grundlage für das Snapping-System

Diese architektonische Anpassung ist weit mehr als nur ein optischer Fix. Die neuen Boundaries bilden ab sofort die exakte mathematische Grundlage für die Snappings zwischen den Frames.

Wenn Nutzer nun Virtual Windows im 3D-Raum verschieben und diese aneinander andocken, greift das Constraint-System auf die erweiterten Bounding-Boxen zurück. Das Andocken passiert exakt an den Außenkanten dieser neuen Geometrie – was zu einer völlig neuen, flüssigen Gruppendynamik führt.

Rasten beispielsweise die drei Masken-Frames aneinander ein, bilden sie fortan einen kohärenten Verbund. Zieht man nun an einem dieser Frames, gleiten die anderen beiden durch die magnetische Bindung nahtlos und synchron mit durch den Raum. Das angrenzende Texteditor-Frame hingegen ist von diesem System bewusst ausgenommen; es bleibt stets ein autarkes, frei platzierbares Element, das sich nicht in diesen Bewegungsfluss einklinkt.

Das Ergebnis ist ein extrem sauberes Layout-Verhalten ohne überlappende Texte. Das visuelle Element der Caption ist endgültig zu einem vollwertigen, berechenbaren Teil der räumlichen Geometrie geworden.

9. April 2026

3D Spatial UI und Text-Editor

Heute möchte ich euch einen Blick auf den aktuellen Stand des Interfaces werfen lassen. Wir haben nun eine funktionierende, räumliche Benutzeroberfläche (Spatial UI), die komplett in unserem Stack gerendert wird.

Hier ist ein aktueller Screenshot aus der Engine:

Vorschau der 3D Spatial UI mit schwebenden Text-Panels und KoordinatensystemAbb 1: Unsere räumliche Benutzeroberfläche mit aktiven Text-Modulen, Selektions-Pfeilen und globalem Koordinatensystem.

Was gibt es Neues zu sehen?

Wie man auf dem Screenshot gut erkennen kann, verschmelzen 2D-UI-Konzepte immer mehr mit der 3D-Welt. Die wichtigsten Neuerungen auf einen Blick:

  1. Virtual Windows: Wir haben mehrere schwebende Panels im Raum platziert ("Mitarbeiter Profil", "Projekt Übersicht", "Aufgabenliste"). Diese Panels sind keine statischen Texturen, sondern echte 3D-Objekte, die im Raum frei bewegt und skaliert werden können.
  2. Der integrierte Texteditor: Das gelb umrandete Panel rechts ("Textobjekt Test") zeigt unseren neuen Texteditor in Aktion. Wie im Textfeld beschrieben:
    • Mit F2 startet man den Edit-Mode direkt im 3D-Raum.
    • Strg+W schaltet den Wordwrap um.
    • Strg+P öffnet zusätzlich unser HUD-Eingabefeld.
  3. Selektion & Snapping: Die gelben und grünen Pfeile, die vom Zentrum ausgehen, visualisieren unser neues Navigations- und Snapping-System. Objekte "wissen", wo sie sich relativ zueinander befinden. Ein Constraint-System sorgt dafür, dass Fenster logisch aneinander andocken können, ohne sich unschön zu überlappen.
  4. Das globale Koordinatensystem: Die X-, Y- und Z-Achsen helfen bei der Orientierung, während die Kamera (mit Maus und Numpad steuerbar) stufenlos heranzoomen oder um die Panels kreisen kann.

Wie geht es weiter?

Das Fundament steht! Das Rendering über den Render-Pass funktioniert performant. Wie bereits im Editor-Testfenster auf dem Screenshot angeteasert, lauten die nächsten Ziele:

  • Verfeinerung der Mauslogik (besseres Drag & Drop Verhalten).
  • "Echte" Inner-Frame-Inputs für die Virtual Windows (z.B. Buttons klicken oder Text markieren).
  • Erweiterung der Undo/Redo-Historie für komplexe Layout-Änderungen.

Bleibt dran, wir nähern uns mit großen Schritten einem voll funktionsfähigen Spatial-Workspace!

8. April 2026

Architektur einer UI-Engine: Interaktion und Zustand

Bei interaktiver Software liegt die eigentliche Arbeit nicht bei Farben, Abständen oder Widget-Namen. Die harten Probleme beginnen dort, wo ein System gleichzeitig Geometrie zeichnen, Eingaben auswerten, Zustände halten und Änderungen wieder zurücknehmen muss. Genau dort trennt sich eine bloße Oberfläche von einem echten Werkzeug.

In meinem aktuellen Engine-Projekt arbeite ich genau in diesem Bereich. Der Kern liegt nicht in einem Satz fertiger Controls, sondern in den technischen Schichten darunter: Objektmodell, Eingabeverarbeitung, zielgenaues Anvisieren (Picking) und Nebenläufigkeit.

Präzises Picking statt reiner Optik

Sichtbare Geometrie und auswertbare Geometrie sind zwei verschiedene Probleme. Ein Element kann optisch korrekt sein und trotzdem für den Nutzer schlecht treffbar. Deshalb nutzt das Projekt eine strikt vom visuellen Rendering getrennte Logik. Die Bedienung hängt daran, dass Dinge pixelgenau und zuverlässig adressierbar bleiben, unbeeinflusst von komplexen visuellen Effekten, Transparenzen oder Überdeckungen.

Zentrale Shader-Architektur & Pipeline

Die grafische Darstellung wird über eine zentrale Architektur gesteuert. Aus einer zentralen Beschreibung werden die passenden Artefakte generiert. Primitive, Tiefentests und Layouts werden pro Pfad explizit gesetzt. Das ist zwingend, denn transparente Überlagerungen, Texte und 3D-Körper haben völlig unterschiedliche Anforderungen an die Grafikkarte.

Nebenläufigkeit ohne Ruckeln

Die wichtigste Regel für flüssige Werkzeuge: Hintergrundarbeit darf den UI-Takt niemals blockieren. Sobald Berechnungen neben den Eingaben laufen, muss der Haupt-Thread frei bleiben. Die Architektur nutzt getrennte Worker-Prozesse, damit die Oberfläche mit konstanten Framerates reagiert, völlig unabhängig davon, wie viel Last das System im Hintergrund verarbeitet.

Der Wert dieses Projekts liegt nicht in einer Sammlung von Einzel-Features, sondern im architektonischen Fundament. Wer diese Probleme in eine gemeinsame, stabile Struktur zwingt, baut ein belastbares Werkzeug.

7. April 2026

Eine Arbeitsumgebung

Verwendet wird Arch-Linux. Entscheidend daran ist vor allem der klare Unterbau und die Nähe zu den üblichen Werkzeugen. Es handelt sich nicht um ein überfrachtetes System, sondern um eines, bei dem die technische Grundlage überschaubar bleibt.

Für die Programmierung kommt eine kompilierte und statisch typisierte Sprache zum Einsatz. Interessant ist dabei die Verbindung aus technischer Strenge und vergleichsweise knapper Syntax. Damit lässt sich strukturiert arbeiten, ohne den Quelltext unnötig aufzublähen.

Als Editor dient Visual Studio Code. Seine Aufgabe ist hier schlicht die Bearbeitung des Quelltexts: Dateien öffnen, ändern, im Projekt navigieren und den Überblick behalten. Der Editor ist damit Werkzeug und nicht selbst das Thema.

Für die verwendete Sprache ist in VSCode die entsprechende Erweiterung installiert, welche die Sprachunterstützung direkt im Editor bereitstellt.

Insgesamt ergibt sich eine Arbeitsumgebung aus klar getrennten Bausteinen: Arch-Linux als Basis und VSCode als Editor. Die Kombination ist technisch unspektakulär, aber für praktische Entwicklungsarbeit gut brauchbar.