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.
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.
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.
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.
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é.
nucleus.graalvm-runtimeDé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.
nucleus.aot-runtimeWin32 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.
1// SwiftUI app (2025) — still goes through UserNotifications + UNNotificationCenter2import SwiftUI3import UserNotifications45@main6struct MyApp: App {7 @UIApplicationDelegateAdaptor(NotifDelegate.self) var delegate8 var body: some Scene { WindowGroup { ContentView() } }9}1011func postBuildNotif() async {12 let center = UNUserNotificationCenter.current()1314 // 1. Authorization15 let ok = try? await center.requestAuthorization(options: [.alert, .sound])16 guard ok == true else { return }1718 // 2. Declare the actions and register the category up-front19 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])2526 let cat = UNNotificationCategory(identifier: "BUILD_DONE",27 actions: [reveal, copy, share], intentIdentifiers: [],28 options: .customDismissAction)29 center.setNotificationCategories([cat])3031 // 3. Build content32 let content = UNMutableNotificationContent()33 content.title = "Build complete"34 content.body = "Installer ready. What now?"35 content.categoryIdentifier = "BUILD_DONE"36 content.sound = .default3738 let req = UNNotificationRequest(identifier: UUID().uuidString,39 content: content, trigger: nil)40 try? await center.add(req)41}4243// 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 = self49 return true50 }5152 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: break62 }63 done()64 }65}66// + Info.plist NSUserNotificationsUsageDescription67// + handle authorization revoked mid-app-lifecycle1import dev.nucleusframework.notification.notify2import dev.nucleusframework.notification.NotificationAction34notify(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)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.
git push tag v1.0.0setup-nucleusJBR 25 ou Liberica NIK, cache Gradle, Node, outils de packaging Linux — une étape, tout runner.
setup-macos-signingTrousseau temporaire, .p12 importé depuis les secrets, identités exposées aux étapes suivantes.
build-macos-universalFusion lipo arm64 + x64, re-sign inside-out, notarisation via notarytool, staple — un DMG en sortie.
build-windows-appxbundleFusion amd64 + arm64 .appx en .msixbundle, signature SignTool — prêt pour le Microsoft Store.
generate-update-ymlSHA-512 de chaque installeur, génère latest-mac.yml / latest.yml / latest-linux.yml pour l'auto-updater.
publish-releasegh release create avec les bons assets, marque -alpha / -beta / -rc en pre-release automatiquement.