Le framework Kotlin
pour les apps desktop natives multiplateformes.

Du vrai multiplateforme — pas seulement macOS, Windows et Linux, mais la même base Kotlin que les apps Android, iOS et web. Un langage, tous les écrans, toutes les architectures.

Partout ailleurs, Kotlin règne sur toute la plateforme.
Le desktop aussi, maintenant.

Sur Android, Kotlin et Compose sont citoyens de première classe. Sur iOS, Kotlin/Native touche chaque API UIKit et Foundation, et Compose s'affiche comme une vraie app native. Sur le web, Kotlin/JS et Wasm peignent des UI Compose avec toute la surface des APIs du navigateur. Le desktop n'avait que la moitié de tout ça — tu pouvais dessiner une fenêtre, mais atteindre l'OS, ça voulait dire jongler avec des pointeurs, compiler des bibliothèques natives par plateforme, brancher des ponts JNI ou FFM, et apprendre une API native différente pour chaque OS — un mur que la plupart des développeurs Kotlin ne pouvaient pas franchir. Nucleus comble l'écart.

Android
APIs OSNatives, intégrées
UI nativeWidgets Material 3
EntréesTactile · gestes
OptimisationR8 · ProGuard · réduction AAB
Empaquetage.aab via Gradle
DistributionGoogle Play, en deux clics
iOS
APIs OSKotlin/Native ↔ UIKit
UI nativeInterop SwiftUI
EntréesTactile · Apple Pencil
OptimisationLLVM AOT · App Thinning
Empaquetage.ipa via Xcode
DistributionApp Store Connect
Web
APIs navigateurKotlin/JS · Wasm
UI nativeInterop HTML / DOM
EntréesSouris · tactile · pointeur
OptimisationTree-shaking · code splitting
EmpaquetageBundle Webpack
DistributionPush sur n'importe quel CDN
Desktop
APIs OSvia Nucleus30+ modules Kotlin · accès natif via Kotlin/Native
UI nativevia NucleusmacOS · Fluent · Yaru en Compose + overlay natif
Entréesvia NucleusSouris · clavier · multi-touch · stylet · gestes Wayland
Optimisationvia NucleusGraalVM closed-world · cache JIT + AOT · stripping des libs natives
Empaquetagevia Nucleus16 formats, signés + notarisés
Distributionvia NucleusMS Store · App Store · Snap · GitHub · mise à jour auto
Stack hybride
JS / TS / DartIPCRust / C++ / Swift
UI dans un langage, cœur natif dans un autre, bindings par OS — chaque frontière devient un pont IPC, une étape de sérialisation, et un changement de contexte mental.
Nucleus + Compose
Kotlin
Compose pour l'UI, Kotlin pour la logique, les appels OS et le packaging — un seul langage de bout en bout, pas d'IPC, un seul état d'esprit, un seul graphe d'appel.
Quatre looks natifs

Colle à chaque desktop, par design.

Une UI écrite une fois en Compose, rendue dans le style desktop voulu — macOS, Windows 11 Fluent, Ubuntu Yaru ou IntelliJ Jewel. Chaque toolkit embarque un DecoratedWindow assorti. macOS et Yaru sont faits par Nucleus ; Jewel est le toolkit officiel de JetBrains (le choix naturel pour les apps de type IDE cross-platform) ; Fluent vient de la communauté open-source.

Paramètres
Général
Apparence
Réseau
Mode sombre
macOS 26Nouveau · 2.0
Liquid Glass
macOS Tahoedecorated-window-macos26
Paramètres — Démo Nucleus
Apparence Système
Mode sombre
Suivre le système
Accent
FluentNouveau · 2.0
Mica · Acrylic
Windows 11decorated-window-fluent
Paramètres
Apparence
Style sombre
Couleur d'accent
YaruNouveau · 2.0
GTK · LibAdwaita
Ubuntu · GNOMEdecorated-window-yaru
ParamètresÉditeurPlugins
Apparence
Thème
Couleurs
Éditeur
Raccourcis
Thème
Darcula
Jewel
IntelliJ Platform
Outils multiplateformesdecorated-window-jewel
Deux runtimes, un seul binaire

Choisis ton compromis. Tu gagnes dans les deux cas.

Le même code Kotlin, deux runtimes : une image native GraalVM pour un démarrage à froid instantané et une empreinte minuscule, ou un JDK moderne avec cache AOT où le JIT de HotSpot s'approche du C++ et de Rust sur les chemins chauds. Même source. Même build.

Closed world

GraalVM Native Image

Démarrage à froid instantané. Empreinte minuscule.

L'app entière est compilée AOT en binaire autonome. Pas de démarrage JVM, pas de chargement de classes — le process est vivant en une demi-seconde. La plus petite empreinte mémoire du marché.

0.00s
Démarrage à froid
0MB
RAM au repos
0MB
Binaire
Débit CPUTrès bon · compilé AOT
C++
PGO GraalVM + optimisations IR Compose
Idéal pour
CLIs & petites appsCibles sandboxéesApp Store / MSIXDistribution avant tout
nucleus.graalvm-runtime
Open world

JDK 25 + cache AOT

Débit JIT au sommet. Plugins, agents, réflexion totale.

Le JIT C2 de HotSpot est le compilateur le plus mûr jamais construit. Le cache AOT de JDK 25 amorce les métadonnées de classes : le warm-up disparaît — et tout ce que le closed-world abandonne reste accessible : chargement dynamique, réflexion totale, agents JVM, moteurs de scripting, plugins et extensions à chaud.

0.0s
Démarrage à froid
0MB
RAM au repos
0MB
Binaire
Débit CPU≈ C++ / Rust sur les chemins chauds
C++
HotSpot C2 · escape analysis · vectorisation
Idéal pour
Hôtes de plugins / extensionsOutils de type IDEApps long-runningRuntimes scripting / DSL
nucleus.aot-runtime
Le paradoxe Nucleus

APIs natives.
Plus simple que le natif.

Win32 ITaskbarList3. NSUserNotifications. freedesktop D-Bus. IOKit. ScreenCaptureKit. Chaque API desktop est son propre petit calvaire — langage différent, modèle de threading différent, conventions différentes. Nucleus enveloppe chacune dans une fonction Kotlin qui paraît évidente. Résultat : une abstraction multiplateforme plus simple que l'originale, sur chaque plateforme.

API native · macOS · SwiftUI
1// SwiftUI app (2025) — still goes through UserNotifications + UNNotificationCenter
2import SwiftUI
3import UserNotifications
4
5@main
6struct MyApp: App {
7 @UIApplicationDelegateAdaptor(NotifDelegate.self) var delegate
8 var body: some Scene { WindowGroup { ContentView() } }
9}
10
11func postBuildNotif() async {
12 let center = UNUserNotificationCenter.current()
13
14 // 1. Authorization
15 let ok = try? await center.requestAuthorization(options: [.alert, .sound])
16 guard ok == true else { return }
17
18 // 2. Declare the actions and register the category up-front
19 let reveal = UNNotificationAction(identifier: "REVEAL",
20 title: "Reveal in Finder", options: [.foreground])
21 let copy = UNNotificationAction(identifier: "COPY",
22 title: "Copy path", options: [])
23 let share = UNNotificationAction(identifier: "SHARE",
24 title: "Share…", options: [.foreground])
25
26 let cat = UNNotificationCategory(identifier: "BUILD_DONE",
27 actions: [reveal, copy, share], intentIdentifiers: [],
28 options: .customDismissAction)
29 center.setNotificationCategories([cat])
30
31 // 3. Build content
32 let content = UNMutableNotificationContent()
33 content.title = "Build complete"
34 content.body = "Installer ready. What now?"
35 content.categoryIdentifier = "BUILD_DONE"
36 content.sound = .default
37
38 let req = UNNotificationRequest(identifier: UUID().uuidString,
39 content: content, trigger: nil)
40 try? await center.add(req)
41}
42
43// 4. Delegate to receive callbacks (must be retained, AppDelegate is easiest)
44class NotifDelegate: NSObject, UIApplicationDelegate,
45 UNUserNotificationCenterDelegate {
46 func application(_ a: UIApplication, didFinishLaunchingWithOptions o:
47 [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
48 UNUserNotificationCenter.current().delegate = self
49 return true
50 }
51
52 func userNotificationCenter(_ c: UNUserNotificationCenter,
53 didReceive r: UNNotificationResponse,
54 withCompletionHandler done: @escaping () -> Void) {
55 switch r.actionIdentifier {
56 case "REVEAL": revealInFinder(file)
57 case "COPY": copyPath(file)
58 case "SHARE": shareSheet(file)
59 case UNNotificationDismissActionIdentifier:
60 telemetry.log("notif_dismissed")
61 default: break
62 }
63 done()
64 }
65}
66// + Info.plist NSUserNotificationsUsageDescription
67// + handle authorization revoked mid-app-lifecycle
~74 linesModèle de threading : à la charge du développeur
Une seule API Kotlin · toutes plateformes
1import dev.nucleusframework.notification.notify
2import dev.nucleusframework.notification.NotificationAction
3
4notify(
5 title = "Build complete",
6 body = "Installer ready. What now?",
7 icon = Icon.AppIcon,
8 actions = listOf(
9 NotificationAction("reveal", "Reveal in Finder") {
10 Desktop.open(file.parent)
11 },
12 NotificationAction("copy", "Copy path") {
13 Clipboard.put(file.absolutePath)
14 },
15 NotificationAction("share", "Share…") { shareSheet(file) },
16 ),
17 onDismiss = { telemetry.log("notif_dismissed") },
18)
18 lignesCompatible coroutines · type-safe · zéro callback perdu
Du tag à la release

Pousse un tag. Récupère des installeurs signés.

Nucleus livre des GitHub Actions réutilisables qui compilent, signent, notarisent, empaquettent et publient pour chaque desktop — sans YAML copié-collé. Six actions composites, un workflow de référence, un seul push de tag.

Déclenchement
git push tag v1.0.0
Build matriciel
6 runners en parallèle
Ubuntu · amd64Ubuntu · arm64Windows · amd64Windows · arm64macOS · arm64macOS · x64
Signer · bundler · notariser
lipo universal · MSIX · staple
GitHub Release
installeurs + YAML auto-update
Six actions composites
setup-nucleus

JBR 25 ou Liberica NIK, cache Gradle, Node, outils de packaging Linux — une étape, tout runner.

setup-macos-signing

Trousseau temporaire, .p12 importé depuis les secrets, identités exposées aux étapes suivantes.

build-macos-universal

Fusion lipo arm64 + x64, re-sign inside-out, notarisation via notarytool, staple — un DMG en sortie.

build-windows-appxbundle

Fusion amd64 + arm64 .appx en .msixbundle, signature SignTool — prêt pour le Microsoft Store.

generate-update-yml

SHA-512 de chaque installeur, génère latest-mac.yml / latest.yml / latest-linux.yml pour l'auto-updater.

publish-release

gh release create avec les bons assets, marque -alpha / -beta / -rc en pre-release automatiquement.