Cette page a été traduite automatiquement et peut contenir des erreurs. Lire l'original en anglais

Native Shell

Écrivez une fois, natif partout

Votre app est au centre. Chaque arc autour d’elle est une plateforme.

N’écrivez que du TSX et livrez des clients natifs qui suivent le rythme de Rust. Une seule base de code tourne sur 8 plateformes, chacune avec l’interface et les interactions propres au système.

FPS
120
première image
~1 ms
plateformes
8

Un client écrit en TSX, juste à côté de Rust

Dans NSH, seul le code de votre app est en JS. Le graphe réactif, le moteur de rendu, la mise en page et chaque module sont en Rust. Les apps TSX et Rust partagent le même pipeline d’exécution natif.

120 FPS
22 sparklines en direct, un carnet d’ordres et un flux de transactions mis à jour ensemble, image p95 sous 4 ms
~0.1 ms
Démarrage du moteur (75–155 µs)
~1 ms
Première image d’une app compteur
~0.12 ms
Un tap, de l’événement au commit
< 1 KB
Le code applicatif d’un hello world
~1.1 MB
Le téléchargement d’une app TSX sur le web (runtime Wasm)
Petites apps mesurées : quelques MB au-dessus de la fenêtre système nue
TSXRustFenêtre système nue
Empreinte mémoire, macOS~20 MB~19 MB~17 MB
Mémoire privée modifiée (private dirty), Linux (GTK, GL)~48 MB~44 MB~38 MB
Au-dessus de la fenêtre système, macOS / Linux+3 / +9 MB+2 / +5 MB
Working set privé, Windows~15 MB~14 MB
Taille sur chaque plateforme : le hello world de nsh init
Exécutable TSXPaquet TSXExécutable RustPaquet Rust
macOS (Apple silicon)19.8 MB9.5 MB12.4 MB6.0 MB
Linux (x86_64)25.7 MB11.6 MB16.5 MB7.5 MB
Windows (x86_64)28.6 MB12.4 MB15.0 MB6.7 MB
Web—~1.1 MB à télécharger——

Builds de release. Mémoire au repos : empreinte macOS sur un Apple M3 (l’app compteur et le template Rust en 1200 × 800 ; la fenêtre système contient un seul label en 480 × 640) ; mémoire privée modifiée sous Linux sur une NVIDIA RTX 3060 Ti (les templates TSX et Rust de nsh init et une fenêtre GTK avec un seul label, le tout en 480 × 640) ; working set privé sous Windows. La mesure de chaque plateforme, avec RSS et USS, figure dans le rapport. Tailles : builds de release de nsh package, avec optimisation à l’édition de liens et symboles retirés ; l’exécutable TSX embarque le runtime QuickJS, le code de l’app fait moins de 1 KB ; le paquet est le .app compressé sur macOS, le .tar.gz sur Linux et le .zip sur Windows ; sur le web, ce que le navigateur télécharge, runtime et app compris. Le rapport de performances complet

TSX avec 0 dépendance

Une app, ce sont les fichiers ci-dessous. La ligne de commande nsh embarque son propre bundler et sa propre chaîne d’outils, et les modules que vous importez sont natifs.

$ nsh init my-app --template ts
$ nsh run my-app --target macos

my-app/
  App.tsx
  nsh.json
  tsconfig.json
  • Un seul exécutable nsh crée, lance, teste et empaquette
  • ~120 ms entre l’enregistrement d’un fichier et l’exécution de la nouvelle version
  • nsh check vérifie les types avec le tsc natif de TypeScript 7
TSXApp.tsx
import { mount, signal, Text, View } from "nsh";

function App() {
  const count = signal(0);
  return (
    <View class="items-center gap-4">
      <Text>Count: {count()}</Text>
      <View
        class="rounded-lg bg-blue-600 px-5 py-3"
        onPress={() => count.update((n) => n + 1)}
      >
        <Text class="text-white">Tap</Text>
      </View>
    </View>
  );
}
mount(App);

8 plateformes, chacune avec les contrôles propres au système

NSH construit chaque UI à partir de ce que sa plateforme offre déjà. La saisie de texte, la sélection, les méthodes de saisie et l’accessibilité viennent du système, et ce qu’une nouvelle version de l’OS leur apporte parvient à l’app avec elle.

PlateformeVuesTexteSaisie de textePrérequis
macOSAppKitCoreTextNSTextViewmacOS 14+
LinuxGTK 4PangoGtkTextViewGTK 4.14+
WindowsWin32, Direct2DDirectWriteL’éditeur de NSH, IMM32Windows 10 1809+
WebHTML, CSSCelui du navigateur<input>, <textarea>Navigateurs modernes
iOSUIKitCoreTextUITextViewiOS 15+
AndroidVues AndroidStaticLayoutEditTextAPI 28+
TUIratatuiLa police du terminalTouches Readline, méthodes de saisiemacOS, Windows, Linux
GPUIGPUILe système de texte de GPUIL’éditeur de NSHIntégré aux apps GPUI Kit

Les cartes, les web views, la vidéo et toute vue native enregistrée par l’hôte sont une sous-vue de plus dans la même hiérarchie : elles se positionnent, se découpent, défilent et reçoivent les touchers comme le reste de l’app. Le backend de chaque plateforme

Une app, dans la forme propre à chaque appareil

Le même code compilé s’exécute ici deux fois, et seul l’appareil change. Avec un pointeur, c’est une fenêtre avec ses conversations sur le côté ; sur un téléphone, les boutons et le champ de saisie flottent en Liquid Glass, avec le fil qui défile en dessous ; dans un terminal, tout tient sur la grille de caractères. L’app n’est écrite qu’une seule fois.

BureauEn direct : saisissez un message
TéléphoneEn direct : saisissez un message
TerminalDécouvrir TUI
+ New chat           │ What makes an NSH app native?
Today                │ A signal holds the count; only the Text that reads it updates   │
What makes an NSH…   │ when you press.                                                 ┃
Plot a week of NSH   │ import { mount, signal, Text, View } from "nsh";                ┃
Signed packages,…    │                                                                 ┃
A sheet with two…    │ const count = signal(0);                                        ┃
Taffy grid vs flex   │ mount(() => (                                                   ┃
                     │   <View onPress={() => count.set(count() + 1)}>                 ┃
                     │     <Text>{count()}</Text>                                      ┃
                     │   </View>                                                       ┃
                     │ ));                                                             ┃
                     │                                   What makes an NSH app native? ┃
                     │ Every element is the platform's own view: UIKit on iOS, Android ┃
                     │ views, AppKit on macOS and GTK 4 on Linux. Your TSX describes   ┃
                     │ them; layout, text and the reactive graph run in Rust.          ┃
                     │                                 And the glass around this chat? ┃
                     │ It's Liquid Glass, one glassEffect style. iOS 26 and macOS 26   ┃
                     │ draw the system's material; elsewhere it blurs what scrolls     ┃
                     │ beneath.                                                        ┃
                     │ • The buttons and the composer float over the thread            ┃
                     │ • Messages pass under them as you scroll                        ┃
                     │ • The same code at every idiom                                  ┃
                     │ ╭───────────────────────────────────────────────────────────────╮
                     │ │ › Ask anything                                                │
                     │ ╰───────────────────────────────────────────────────────────────╯

Le bureau et le téléphone tournent en direct dans votre navigateur, sur le runtime web de Native Shell. Le terminal est la vraie sortie de nsh run --target tui.

Le même moteur en Rust, quand vous le souhaitez

Rust est un langage de premier rang pour des apps entières : l’UI, la logique et les composants compilent en code natif, prêt pour une logique métier exigeante. Les deux utilisent les mêmes éléments et signaux, et les écrans TSX importent vos composants Rust.

Développer avec Rust

Rustsrc/lib.rs
use nsh_core::element::prelude::*;

#[component]
pub fn App() -> impl IntoElement {
    let count = signal(0);
    view()
        .items_center()
        .gap_4()
        .child(text(move || format!("Count: {}", count.get())))
        .child(
            view()
                .rounded_lg().bg(rgb(0x2563eb)).px_5().py_3()
                .on_press(move || count.update(|n| *n += 1))
                .child(text("Tap").text_color(white())),
        )
}

Seules les vues modifiées sont touchées

Chaque élément est une vue que la plateforme conserve. Un changement n’exécute que les expressions qui lisent le signal modifié, en un seul lot par image. Le thread principal n’attend jamais le JS et les animations natives s’exécutent sans lui : le défilement et les animations tiennent 120 FPS, et l’app reste quasi inactive au repos.

Comment elle reste rapide

Les deux textes qui lisent les signaux changent et l’historique gagne une ligne ; aucune autre vue n’est touchée.

$ nsh test examples/counter/App.tsx --trace
perf commit: 56 ops, 50 mount items, 21 nodes
press(+1)
perf commit: 10 ops, 7 mount items, 24 nodes

Après la publication, votre app peut encore recevoir de nouvelles UI

Votre équipe peut l’écrire, ou un modèle peut la générer pour chaque requête. Elle arrive sur l’appareil sous forme de module signé, s’exécute dans un sandbox défini par l’hôte et s’affiche nativement.

  1. Écrire

    Votre équipe ou un modèle écrit un module TSX.

    App.tsx
  2. Vérifier

    Vérifiez les types, puis exécutez ses tests en headless.

    nsh check nsh test
  3. Signer

    Un .nshpkg signé Ed25519, dont la clé de release est certifiée par une racine hors ligne.

    nsh publish
  4. Frontière de confiance

    Exécuter

    L’appareil vérifie la signature, le certificat et les révocations. Chaque vue reçoit une VM avec des limites de mémoire, de temps d’appel et de nœuds, et uniquement les capacités que l’hôte accorde.

    NshAppView NshView AppView

Trois façons de livrer, un seul moteur

Apps autonomes

Écrivez-la en Rust, en TSX ou les deux, et empaquetez une app installable pour iOS, Android, macOS, Windows ou Linux, ou un site web statique.

$ nsh init my-app --template rust
$ nsh run my-app --target macos
$ nsh package my-app --target windows
# --template ts for TSX
# ios · android · macos · windows · linux · gpui · web
Premiers pas

UI dynamique et plugins

Intégrez une vue sur n’importe quel écran et chargez-y des modules TSX signés à l’exécution, aux côtés des composants natifs de l’hôte.

let app = NshAppView()
try app.grantCapabilities(grants)
let info = try await app
  .loadPackage(at: file, trust: trust)
// verified, sandboxed, running
// NshView on Android, AppView elsewhere
Intégration, plateforme par plateforme

UI générée par IA

Un modèle écrit un module par requête, et l’app répond avec une interface. Votre serveur le vérifie et le signe.

import { mount, signal, View } from "nsh";

function Answer() {
  const range = signal("1W");
  return <View class="gap-3 p-4">…</View>;
}
mount(Answer);
Signature et sandboxing

Le comportement vient de NSH, l’apparence de vous

nsh/base contient des composants de base sans style qui gèrent l’état, le focus, le clavier et l’accessibilité, et l’app stylise chaque partie. Une seule ligne de commande nsh fait le reste.

Composants de base sans style

Navigation, boîtes de dialogue, menus, popovers, onglets, selects, tableaux de données, un éditeur de code et un noyau de texte enrichi. Stylisez chaque partie avec des classes Tailwind ou des styles typés.

nsh/base

Une seule chaîne d’outils, pour les humains et les agents

Un seul exécutable nsh crée, compile, vérifie les types, recharge à chaud, teste, empaquette et signe. Les déclarations sont générées à partir des sources Rust et la documentation est servie sous forme de llms.txt, de sorte qu’un agent exécute toute la boucle avec les mêmes commandes.

nsh run, nsh test, nsh package

Vérifié sur chaque cible

Les mêmes tests s’exécutent en headless, ainsi que dans de vraies fenêtres, un simulateur iOS, un appareil Android ou un navigateur, avec la saisie propre à la plateforme.

nsh test --target ios

Vues et interactions natives,
votre design visuel

Installez nsh et lancez votre première app TSX en une minute.