# Keluna **Kotlin Embedded Local UI for Native Applications** Keluna ist die Idee für ein leichtgewichtiges Framework zur Entwicklung nativer Desktop-Anwendungen für Linux, macOS und Windows mit **Kotlin/Native**. Das Ziel ist eine Entwicklererfahrung ähnlich moderner Kotlin-UI-Frameworks, ohne dafür eine JVM, eine eigene Rendering-Engine oder einen mitgelieferten Browser zu benötigen. Keluna kombiniert dafür drei grundlegende Konzepte: - **Kotlin/Native** für Anwendungscode und Betriebssystemintegration - ein **Vaadin-Flow-artiges Komponentenmodell** für die Beschreibung und Verwaltung der UI - die vorhandene **System-WebView** des jeweiligen Betriebssystems als Rendering-Engine Dadurch sollen kleine, schnell startende Desktop-Anwendungen entstehen, deren Anwendungscode nahezu vollständig in Kotlin geschrieben werden kann. --- ## Motivation Für plattformübergreifende Desktop-Anwendungen existieren heute mehrere etablierte Ansätze. ### Electron Electron bietet eine sehr komfortable Web-Entwicklungsumgebung, liefert jedoch Chromium und Node.js mit jeder Anwendung aus. Selbst kleine Anwendungen erreichen dadurch schnell Größen von deutlich über 100 MB und benötigen vergleichsweise viel Arbeitsspeicher. ### Compose Multiplatform Compose Multiplatform ermöglicht eine hervorragende Kotlin-Entwicklung, basiert auf dem Desktop jedoch auf der JVM und einer eigenen Rendering-Infrastruktur. Dadurch entstehen ebenfalls relativ große Distributionen und zusätzliche Startkosten durch JVM und UI-Runtime. ### Tauri Tauri vermeidet den eingebetteten Browser und verwendet stattdessen die WebView des Betriebssystems. Dadurch können Anwendungen sehr klein bleiben. Die typische Architektur besteht jedoch aus zwei Welten: - TypeScript oder JavaScript für das Frontend - Rust für den nativen Teil ### Qt Qt ermöglicht kleine und schnelle Desktop-Anwendungen, verwendet traditionell jedoch C++. Rust-Bindings verbessern diese Situation, dennoch bleibt Qt ein großes, eigenständiges UI-Ökosystem. --- ## Grundidee Keluna soll einen anderen Weg gehen: > Die Anwendung ist eine Kotlin/Native-Anwendung. > Die System-WebView ist lediglich ihre Rendering-Engine. Die Anwendung selbst lebt vollständig im nativen Kotlin-Prozess. ```text ┌──────────────────────────────────────────────┐ │ Kotlin/Native App │ │ │ │ Domain Model │ │ Application State │ │ Services │ │ UI Component Tree │ │ Event Handler │ │ OS Integration │ └─────────────────────┬────────────────────────┘ │ UI Synchronisation │ kleines IPC-Protokoll │ ┌─────────────────────▼────────────────────────┐ │ JavaScript Runtime │ │ │ │ DOM Updates │ │ Event Forwarding │ │ Browser Interaction │ └─────────────────────┬────────────────────────┘ │ DOM │ ┌─────────────────────▼────────────────────────┐ │ System WebView │ │ │ │ Windows WebView2 │ │ macOS WKWebView │ │ Linux WebKitGTK │ └──────────────────────────────────────────────┘ ``` Keluna bringt damit **keine eigene Browser-Engine** mit. Ebenso benötigt Keluna: - keine JVM - kein Chromium-Bundle - kein Node.js - keine eigene GPU-Rendering-Engine --- ## Inspirationsquellen Keluna kombiniert Ideen aus mehreren existierenden Frameworks, ohne eines davon direkt nachzubauen. ### Kotlin und Compose Von Kotlin und Compose übernimmt Keluna vor allem die gewünschte Entwicklerergonomie: - typsichere APIs - Kotlin DSLs - Properties und State - deklarative UI-Beschreibung - gute Integration mit Coroutines - Gradle als Build-System Ein Keluna-Programm könnte beispielsweise konzeptionell so aussehen: ```kotlin window("Keluna Demo") { verticalLayout { textField("Repository") button("Open") { openRepository() } } } ``` Die genaue API ist dabei noch offen. Wichtig ist das Prinzip: **Der Anwendungsentwickler soll möglichst ausschließlich Kotlin sehen.** ### Vaadin Flow Von Vaadin Flow übernimmt Keluna die Idee eines **serverseitigen Komponentenbaums**. Bei Vaadin existieren Komponenten als Java-Objekte auf dem Server. Änderungen an diesen Objekten werden mit dem DOM im Browser synchronisiert. Keluna verwendet ein ähnliches Modell, jedoch ohne Netzwerk. Bei einer Desktop-Anwendung befinden sich beide Seiten lokal: ```text Vaadin Flow Java Server │ │ HTTP / WebSocket ▼ Browser ``` Keluna reduziert dieses Modell auf: ```text Kotlin/Native │ │ lokale WebView Bridge ▼ System WebView ``` Dadurch entfallen große Teile der Komplexität von Vaadin: - HTTP - WebSocket - Sessions - Reconnect - Authentication zwischen Client und Server - Netzwerk-Retry - Cluster-Synchronisation Übrig bleibt im Wesentlichen: ```text Component Tree │ ▼ DOM Patch │ ▼ WebView WebView │ ▼ Event │ ▼ Kotlin Handler ``` ### Tauri Von Tauri übernimmt Keluna vor allem das Prinzip: > Nutze die Browser-Engine, die das Betriebssystem ohnehin bereitstellt. Keluna verwendet deshalb unterschiedliche WebView-Implementierungen: | Plattform | WebView | |---|---| | Windows | WebView2 | | macOS | WKWebView | | Linux | WebKitGTK | Die WebView ist dabei kein eigenständiger Anwendungsteil. Sie ist lediglich der Renderer für: - HTML - CSS - Text - Layout - Form Controls - SVG - Animationen --- ## Architektur Keluna könnte zunächst aus sechs grundlegenden Bereichen bestehen. ```text keluna-core keluna-ui keluna-runtime keluna-web keluna-platform keluna-components ``` ### `keluna-core` Enthält grundlegende Framework-Abstraktionen. Beispielsweise: ```text Component Element Property State Event StateTree ``` Dieses Modul sollte weitgehend unabhängig von den konkreten Plattformen sein. ### `keluna-ui` Enthält die Kotlin-API zur Beschreibung der Benutzeroberfläche. Beispielsweise: ```text Window Layout Button TextField Checkbox Select Table Dialog Tabs Menu ``` Darauf baut die Kotlin-DSL auf. ### `keluna-runtime` Verwaltet den Komponentenbaum und den Anwendungszustand. Aufgaben sind unter anderem: - Component Lifecycle - State Management - Event Dispatching - Erkennung von Änderungen - Erzeugung von DOM-Patches - Synchronisation mit der WebView ### `keluna-web` Enthält die kleine JavaScript-Runtime innerhalb der WebView. Diese Runtime sollte bewusst minimal bleiben. Ihre Aufgaben: - DOM-Elemente erzeugen - DOM-Properties ändern - Elemente entfernen - Events registrieren - relevante Browser-Events an Kotlin weiterleiten Beispielsweise könnte Kotlin intern folgende Instruktion erzeugen: ```json { "op": "set", "node": 17, "property": "textContent", "value": "Open" } ``` Oder: ```json { "op": "append", "parent": 3, "node": 17 } ``` Ein Klick könnte in Gegenrichtung übertragen werden: ```json { "node": 17, "event": "click" } ``` Das Protokoll sollte später vermutlich kompakter sein als JSON. Für einen ersten Prototyp wäre JSON jedoch ideal. --- ## Plattform-Layer Keluna benötigt für jedes Betriebssystem einen sehr kleinen nativen Adapter. ```text keluna-platform │ ├── linux │ ├── GTK │ └── WebKitGTK │ ├── macos │ ├── Cocoa │ └── WKWebView │ └── windows ├── Win32 └── WebView2 ``` Die gemeinsame API könnte beispielsweise Funktionen bereitstellen wie: ```text createWindow() loadResource() evaluateJavaScript() receiveMessage() showFileDialog() setClipboard() showNotification() ``` Die Anwendung selbst soll diese Plattformunterschiede normalerweise nicht sehen. --- ## Native Desktop-Funktionen Keluna soll nicht nur eine Web-Anwendung in einem Fenster darstellen. Der Kotlin-Prozess besitzt direkten Zugriff auf das Betriebssystem. Dadurch können Anwendungen beispielsweise folgende Funktionen nutzen: - Dateisystemzugriff - native File Dialogs - Clipboard - Drag & Drop - Notifications - System Tray - Menüleiste - Prozesse starten - lokale Sockets - Git - Credential Stores - Betriebssysteminformationen Diese Funktionen können als Kotlin-APIs bereitgestellt werden. ```text Keluna Application │ ├── UI │ ├── Files ├── Process ├── Clipboard ├── Notifications ├── Dialogs └── Platform APIs ``` --- ## Verantwortlichkeit zwischen Kotlin und WebView Nicht jede UI-Interaktion sollte den Kotlin-Prozess erreichen. Lokale Browserfunktionen sollten möglichst lokal bleiben. ### WebView Die WebView übernimmt beispielsweise: - Hover - CSS - Animationen - Scrolling - Text Selection - Focus-Darstellung - Cursor - einfache visuelle Interaktionen ### Kotlin Kotlin übernimmt: - Application State - Navigation - Business Logic - Commands - persistente UI-Zustände - Dateisystem - Prozesse - Netzwerk - Git - Betriebssystemintegration Dadurch bleibt die IPC-Schicht klein. --- ## State und Synchronisation Der zentrale Bestandteil von Keluna wäre ein State Tree ähnlich dem Komponentenmodell von Vaadin Flow. Beispiel: ```text Window #1 └── VerticalLayout #2 ├── TextField #3 ├── Button #4 └── Label #5 ``` Jede Komponente besitzt eine interne ID. Ändert Kotlin beispielsweise: ```text Label #5 "Ready" ↓ "Loading..." ``` muss lediglich folgende Änderung an die WebView übertragen werden: ```text SET #5 textContent "Loading..." ``` Es wird nicht die gesamte Benutzeroberfläche neu aufgebaut. --- ## Event-Modell Events laufen in Gegenrichtung. Beispielsweise: ```text WebView Button #4 clicked │ ▼ IPC │ ▼ Keluna Runtime │ ▼ Kotlin callback ``` In der Anwendung könnte das beispielsweise so aussehen: ```kotlin button("Open") { openProject() } ``` Keluna registriert intern lediglich: ```text #4 → click → callback ``` --- ## HTML und CSS HTML und CSS sind Implementierungsdetails der Rendering-Schicht. Der Entwickler muss sie nicht zwingend direkt verwenden. Für fortgeschrittene Anwendungen sollte Keluna sie jedoch nicht verstecken. Denkbar wären deshalb mehrere Ebenen: ```text High Level Keluna Components ↓ Keluna Element API ↓ HTML / CSS ↓ System WebView ``` Dadurch könnten Entwickler bei Bedarf eigene Web Components oder CSS einbinden. --- ## Custom Components Neben Standardkomponenten sollte Keluna eigene Komponenten erlauben. Beispielsweise: ```text Graph CodeEditor Tree MarkdownViewer Terminal Diagram ``` Solche Komponenten könnten aus: - Kotlin - HTML - CSS - etwas JavaScript bestehen. Für Spezialfälle könnte auch eine bestehende JavaScript-Komponente eingebettet werden. Keluna soll JavaScript also nicht verbieten. Es soll lediglich **für normale Anwendungsentwicklung nicht notwendig sein**. --- ## Packaging Ein wichtiges Ziel von Keluna ist eine kleine Distribution. Eine Anwendung besteht im Wesentlichen aus: ```text Kotlin/Native executable + Keluna runtime + HTML/CSS/JS resources ``` Die Browser-Engine wird nicht mitgeliefert. Auf den Plattformen wird stattdessen verwendet: ```text Windows → WebView2 macOS → WKWebView Linux → WebKitGTK ``` Unter Linux würden GTK und WebKitGTK typischerweise Paketabhängigkeiten darstellen. Ein Debian-Paket könnte beispielsweise von diesen Systembibliotheken abhängen, anstatt sie selbst mitzubringen. Dadurch sollte eine einfache Keluna-Anwendung potenziell im Bereich von **wenigen Megabyte bis niedrigen zweistelligen Megabyte** bleiben können. Die tatsächliche Größe müsste durch einen Prototyp überprüft werden. --- ## Startzeit Keluna benötigt: - keine JVM-Initialisierung - keinen Node-Prozess - keinen Start eines eingebetteten Chromium - keine eigene Grafik-Runtime Der native Prozess startet lediglich die vorhandene WebView und lädt lokale Ressourcen. Damit sollte die Startzeit eher in der Größenordnung kleiner nativer Anwendungen bzw. Tauri-Anwendungen liegen als bei Compose Desktop oder Electron. Auch dies müsste frühzeitig durch einen Proof of Concept gemessen werden. --- ## Ziele Keluna soll: - Desktop-Anwendungen vollständig oder nahezu vollständig in Kotlin ermöglichen - Kotlin/Native verwenden - Linux, macOS und Windows unterstützen - kleine Distributionen erzeugen - schnell starten - die vorhandene System-WebView verwenden - keine eigene Rendering-Engine benötigen - keinen Webserver starten - keine JVM voraussetzen - keine JavaScript-Anwendungsarchitektur erzwingen - sich natürlich in Gradle und Kotlin Multiplatform integrieren --- ## Nicht-Ziele Keluna soll zunächst ausdrücklich **kein**: - Browser-Webframework - Mobile-Framework - eigener Browser - eigener HTML-Renderer - eigener GPU-Renderer - Electron-Ersatz mit eingebettetem Chromium - vollständiges Vaadin-Flow-Reimplementation sein. Ebenso sollte Keluna nicht versuchen, von Anfang an hunderte UI-Komponenten bereitzustellen. --- ## Ein mögliches MVP Ein erster Proof of Concept benötigt überraschend wenig. ### Phase 1 – WebView Für eine Plattform, beispielsweise Linux: - Kotlin/Native Executable - GTK-Fenster - WebKitGTK-WebView - lokale `index.html` laden - JavaScript aus Kotlin aufrufen - Nachricht von JavaScript an Kotlin senden Damit wäre die technische Grundlage bewiesen. ### Phase 2 – Element Tree Ein einfacher Kotlin-Elementbaum: ```text Window Column Text Button ``` Dieser erzeugt DOM-Strukturen. ### Phase 3 – Events Browser-Events werden an Kotlin übertragen: ```text click change input keydown ``` ### Phase 4 – State Synchronisation Änderungen im Kotlin-Component-Tree erzeugen nur noch inkrementelle DOM-Patches. ### Phase 5 – weitere Plattformen Implementierung von: - WKWebView für macOS - WebView2 für Windows ### Phase 6 – Desktop APIs Erste native Funktionen: - File Picker - Clipboard - Notifications - Prozessstart --- ## Mögliche Modulstruktur ```text keluna/ ├── keluna-core ├── keluna-ui ├── keluna-runtime ├── keluna-components ├── keluna-web-runtime ├── keluna-platform-linux ├── keluna-platform-macos ├── keluna-platform-windows └── keluna-gradle-plugin ``` Eine Anwendung könnte anschließend beispielsweise nur benötigen: ```text keluna-core keluna-components keluna-platform ``` --- ## Gradle-Integration Langfristig sollte eine Keluna-Anwendung über ein Gradle-Plugin konfiguriert werden können. Konzeptionell: ```kotlin plugins { kotlin("multiplatform") id("dev.keluna.application") } keluna { applicationName = "My Application" mainClass = "MainKt" } ``` Das Plugin könnte anschließend: - Kotlin/Native Targets konfigurieren - Web-Ressourcen bündeln - native Abhängigkeiten konfigurieren - Installer erzeugen - Signing vorbereiten - Plattformpakete bauen --- ## Entwicklungsmodell Keluna könnte zwei Ebenen anbieten. ### High-Level Für normale Anwendungen: ```text Keluna Components + Kotlin State + Kotlin Event Handler ``` Der Entwickler benötigt keine Webkenntnisse. ### Low-Level Für Spezialkomponenten: ```text DOM CSS JavaScript Web Components ``` Dadurch bleibt das Framework offen. Eine komplexe Komponente wie ein Code-Editor könnte beispielsweise intern Monaco oder CodeMirror verwenden, während die restliche Anwendung vollständig in Kotlin bleibt. --- ## Designprinzipien ### Kotlin first Die öffentliche API wird für Kotlin entworfen und nicht aus einer anderen Sprache übernommen. ### Native application first Keluna ist kein Webframework, das zufällig Desktop-Fenster erzeugt. Es ist ein Desktop-Framework, das Web-Technologie zum Rendern verwendet. ### System WebView instead of bundled browser Der größte Baustein vieler Desktop-Webframeworks wird bewusst nicht ausgeliefert. ### Thin client Die JavaScript-Runtime sollte möglichst klein und weitgehend zustandslos bleiben. ### Escape hatches HTML, CSS und JavaScript bleiben erreichbar, wenn eine Anwendung sie benötigt. ### Incremental adoption Eine Anwendung sollte mit wenigen Standardkomponenten beginnen können und später komplexere eigene Komponenten hinzufügen können. ### Measure early Binary-Größe, RAM-Verbrauch und Startzeit sind zentrale Eigenschaften des Projekts und sollten von Anfang an automatisiert gemessen werden. --- ## Risiken ### Unterschiedliche WebView-Engines Windows verwendet Chromium über WebView2. macOS und Linux verwenden WebKit. Dadurch können Unterschiede bei: - CSS - JavaScript - Web APIs - Rendering auftreten. Keluna sollte deshalb bewusst nur auf gut unterstützte Webstandards setzen. ### Linux-Abhängigkeiten Linux besitzt keine so klar definierte System-WebView wie macOS. WebKitGTK und GTK müssen auf dem Zielsystem vorhanden sein. Distribution und Packaging müssen deshalb früh untersucht werden. ### Kotlin/Native Interop Die Plattformadapter benötigen Interop mit: - Win32 und COM - Cocoa/Objective-C - GTK und WebKitGTK Dieser Bereich dürfte einer der technisch anspruchsvollsten Teile des Frameworks sein. Er bleibt jedoch innerhalb des Frameworks verborgen und betrifft nicht den normalen Anwendungsentwickler. ### UI-State-Komplexität Ein nativer Komponentenbaum klingt zunächst einfach. Komplexität entsteht jedoch bei: - Textfeldern während der Eingabe - Selection - Focus - Cursorpositionen - Drag & Drop - großen Tabellen - virtuellen Listen Keluna sollte deshalb nicht versuchen, jeden Browserzustand permanent nach Kotlin zu spiegeln. --- ## Langfristige Perspektive Keluna könnte langfristig drei Ebenen bilden: ```text Keluna │ ┌───────────┴───────────┐ │ │ Kotlin Components Custom Components │ │ └───────────┬───────────┘ │ Component Tree │ Keluna Runtime │ WebView │ Native Platform ``` Damit entsteht ein ungewöhnliches Desktop-Modell: > **Native application logic with web-based rendering, without turning the application itself into a web application.** --- ## Zusammenfassung Keluna kombiniert drei bewährte Ideen: ### Kotlin/Native für: - Anwendungscode - Domain-Logik - State - Betriebssystemzugriffe ### Vaadin-Flow-artiges Komponentenmodell für: - Component Tree - Properties - Events - inkrementelle UI-Synchronisation ### Tauri-artige System-WebView-Nutzung für: - kleines Packaging - schnelles Startup - HTML/CSS-Rendering ohne eingebettetes Chromium Das Ziel ist eine Desktop-Anwendung, die sich für den Entwickler wie eine normale Kotlin-Anwendung anfühlt: ```text Kotlin ↓ Keluna ↓ System WebView ↓ Native Desktop ``` Der Browser ist dabei kein Teil der Anwendungsarchitektur. Er ist lediglich der Renderer. **Keluna – Kotlin Embedded Local UI for Native Applications.**