Files
keluna/docs/keluna-concept.md
2026-09-16 11:03:07 +02:00

20 KiB
Raw Permalink Blame History

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.

┌──────────────────────────────────────────────┐
│              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:

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:

Vaadin Flow

Java Server
    │
    │ HTTP / WebSocket
    ▼
Browser

Keluna reduziert dieses Modell auf:

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:

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.

keluna-core
keluna-ui
keluna-runtime
keluna-web
keluna-platform
keluna-components

keluna-core

Enthält grundlegende Framework-Abstraktionen.

Beispielsweise:

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:

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:

{
  "op": "set",
  "node": 17,
  "property": "textContent",
  "value": "Open"
}

Oder:

{
  "op": "append",
  "parent": 3,
  "node": 17
}

Ein Klick könnte in Gegenrichtung übertragen werden:

{
  "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.

keluna-platform
    │
    ├── linux
    │     ├── GTK
    │     └── WebKitGTK
    │
    ├── macos
    │     ├── Cocoa
    │     └── WKWebView
    │
    └── windows
          ├── Win32
          └── WebView2

Die gemeinsame API könnte beispielsweise Funktionen bereitstellen wie:

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.

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:

Window #1
└── VerticalLayout #2
    ├── TextField #3
    ├── Button #4
    └── Label #5

Jede Komponente besitzt eine interne ID.

Ändert Kotlin beispielsweise:

Label #5
"Ready"
    ↓
"Loading..."

muss lediglich folgende Änderung an die WebView übertragen werden:

SET #5 textContent "Loading..."

Es wird nicht die gesamte Benutzeroberfläche neu aufgebaut.


Event-Modell

Events laufen in Gegenrichtung.

Beispielsweise:

WebView
Button #4 clicked
        │
        ▼
IPC
        │
        ▼
Keluna Runtime
        │
        ▼
Kotlin callback

In der Anwendung könnte das beispielsweise so aussehen:

button("Open") {
    openProject()
}

Keluna registriert intern lediglich:

#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:

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:

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:

Kotlin/Native executable
+
Keluna runtime
+
HTML/CSS/JS resources

Die Browser-Engine wird nicht mitgeliefert.

Auf den Plattformen wird stattdessen verwendet:

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:

Window
Column
Text
Button

Dieser erzeugt DOM-Strukturen.

Phase 3 – Events

Browser-Events werden an Kotlin übertragen:

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

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:

keluna-core
keluna-components
keluna-platform

Gradle-Integration

Langfristig sollte eine Keluna-Anwendung über ein Gradle-Plugin konfiguriert werden können.

Konzeptionell:

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:

Keluna Components
+
Kotlin State
+
Kotlin Event Handler

Der Entwickler benötigt keine Webkenntnisse.

Low-Level

Für Spezialkomponenten:

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:

                    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:

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.