Diese Seite wurde maschinell übersetzt und kann Fehler enthalten. Das englische Original lesen

Native Shell

Einmal bauen, überall nativ

Deine App sitzt in der Mitte. Jeder Bogen darum ist eine Plattform.

Schreibe nur TSX und liefere native Clients aus, die mit Rust Schritt halten. Eine Codebasis läuft auf 8 Plattformen, jede mit der systemeigenen UI und Interaktion.

FPS
120
erster Frame
~1 ms
Plattformen
8

Ein in TSX geschriebener Client, direkt neben Rust

In NSH ist nur der Code deiner App JS. Der reaktive Graph, der Renderer, das Layout und jedes Modul sind Rust. TSX- und Rust-Apps teilen sich dieselbe native Ausführungspipeline.

120 FPS
22 Live-Sparklines, ein Orderbuch und ein Tape werden gemeinsam aktualisiert, Frame p95 unter 4 ms
~0.1 ms
Engine-Start (75–155 µs)
~1 ms
Erster Frame einer Counter-App
~0.12 ms
Ein Tap, vom Event bis zum Commit
< 1 KB
App-Code eines Hello World
~1.1 MB
Download einer TSX-App im Web (Wasm-Runtime)
Gemessene kleine Apps: wenige MB über dem nackten Systemfenster
TSXRustNacktes Systemfenster
Speicherbedarf, macOS~20 MB~19 MB~17 MB
Private Dirty Memory, Linux (GTK, GL)~48 MB~44 MB~38 MB
Über dem Systemfenster, macOS / Linux+3 / +9 MB+2 / +5 MB
Private Working Set, Windows~15 MB~14 MB
Größe je Plattform: Hello World von nsh init
TSX-ExecutableTSX-PaketRust-ExecutableRust-Paket
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 Download——

Release-Builds. Speicher im Ruhezustand: macOS-Footprint auf einem Apple M3 (die Counter-App und das Rust-Template bei 1200 × 800; das Systemfenster enthält ein Label bei 480 × 640); Linux Private Dirty Memory auf einer NVIDIA RTX 3060 Ti (die TSX- und Rust-Templates von nsh init und ein GTK-Fenster mit einem Label, alle bei 480 × 640); Windows Private Working Set. Die Messgröße jeder Plattform, mit RSS und USS, steht im Bericht. Größen: Release-Builds von nsh package, mit Link-Time-Optimization und gestrippt; das TSX-Executable enthält die QuickJS-Runtime, der App-Code ist kleiner als 1 KB; das Paket ist die gezippte .app auf macOS, das .tar.gz auf Linux und das .zip auf Windows; im Web das, was der Browser herunterlädt, Runtime und App. Der vollständige Performance-Bericht

TSX mit 0 Abhängigkeiten

Eine App besteht aus den unten stehenden Dateien. Die nsh-Kommandozeile bringt ihren eigenen Bundler und ihre eigene Toolchain mit, und die Module, die du importierst, sind nativ.

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

my-app/
  App.tsx
  nsh.json
  tsconfig.json
  • Ein nsh-Executable erstellt, startet, testet und paketiert
  • ~120 ms vom Speichern einer Datei bis zur laufenden neuen Version
  • nsh check prüft Typen mit dem nativen tsc von 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 Plattformen, jede mit den eigenen Controls des Systems

NSH baut jede UI aus dem, was die Plattform bereits mitbringt. Texteingabe, Auswahl, Eingabemethoden und Barrierefreiheit kommen vom System, und was eine neue OS-Version dazu beiträgt, erreicht die App automatisch mit.

PlattformViewsTextTexteingabeVoraussetzung
macOSAppKitCoreTextNSTextViewmacOS 14+
LinuxGTK 4PangoGtkTextViewGTK 4.14+
WindowsWin32, Direct2DDirectWriteDer Editor von NSH, IMM32Windows 10 1809+
WebHTML, CSSVom Browser<input>, <textarea>Moderne Browser
iOSUIKitCoreTextUITextViewiOS 15+
AndroidAndroid-ViewsStaticLayoutEditTextAPI 28+
TUIratatuiDie Schrift des TerminalsReadline-Tasten, EingabemethodenmacOS, Windows, Linux
GPUIGPUIDas Textsystem von GPUIDer Editor von NSHIn GPUI-Kit-Apps eingebettet

Karten, Web Views, Video und jede native View, die der Host registriert, sind eine weitere Subview in derselben Hierarchie: Sie werden zusammen mit dem Rest der App layoutet, beschnitten, gescrollt und nehmen Touches entgegen. Das Backend jeder Plattform

Eine App, in der eigenen Form jedes Geräts

Derselbe kompilierte Code läuft hier zweimal, nur das Gerät unterscheidet sich. Mit einem Zeigegerät ist es ein Fenster mit den Unterhaltungen an der Seite; auf einem Smartphone schweben die Buttons und der Composer in Liquid Glass, während der Thread darunter scrollt; in einem Terminal sitzt es auf dem Zeichenraster. Die App wird nur einmal geschrieben.

DesktopLive: Tippe eine Nachricht
SmartphoneLive: Tippe eine Nachricht
TerminalTUI entdecken
+ 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                                                │
                     │ ╰───────────────────────────────────────────────────────────────╯

Desktop und Smartphone laufen live in deinem Browser auf der Web-Runtime von Native Shell. Das Terminal zeigt die echte Ausgabe von nsh run --target tui.

Dieselbe Engine in Rust, wenn du willst

Rust ist eine erstklassige Sprache für ganze Apps: UI, Logik und Komponenten werden zu nativem Code kompiliert, bereit für anspruchsvolle Geschäftslogik. Beide nutzen dieselben Elemente und Signals, und TSX-Screens importieren deine Rust-Komponenten.

Mit Rust entwickeln

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())),
        )
}

Nur die geänderten Views werden angefasst

Jedes Element ist eine View, die die Plattform vorhält. Eine Änderung führt nur die Ausdrücke aus, die das geänderte Signal lesen, in einem Batch pro Frame. Der Main Thread wartet nie auf JS, und native Animationen laufen ohne ihn, sodass Scrollen und Animation 120 FPS halten und die App im Ruhezustand nahezu im Leerlauf ist.

So bleibt es schnell

Die beiden Texte, die die Signals lesen, ändern sich und der Verlauf erhält eine Zeile; keine andere View wird angefasst.

$ 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

Nach dem Release kann deine App noch neue UI aufnehmen

Dein Team kann sie schreiben, oder ein Modell kann sie für jede Anfrage generieren. Sie erreicht das Gerät als signiertes Modul, läuft in einer vom Host festgelegten Sandbox und wird nativ dargestellt.

  1. Schreiben

    Dein Team oder ein Modell schreibt ein TSX-Modul.

    App.tsx
  2. Prüfen

    Typen prüfen, dann die Tests headless ausführen.

    nsh check nsh test
  3. Signieren

    Ein mit Ed25519 signiertes .nshpkg, dessen Release-Key von einem Offline-Root zertifiziert ist.

    nsh publish
  4. Vertrauensgrenze

    Ausführen

    Das Gerät prüft Signatur, Zertifikat und Widerrufe. Jede View erhält eine VM mit Limits für Speicher, Aufrufzeit und Nodes sowie nur die Capabilities, die der Host gewährt.

    NshAppView NshView AppView

Drei Wege auszuliefern, eine Engine

Eigenständige Apps

Schreibe sie in Rust, TSX oder beidem und paketiere eine installierbare iOS-, Android-, macOS-, Windows- oder Linux-App oder eine statische Website.

$ 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
Loslegen

Dynamische UI und Plugins

Bette eine View in jeden Screen ein und lade zur Laufzeit signierte TSX-Module hinein, neben den eigenen nativen Komponenten des Hosts.

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
Einbettung, je Plattform

KI-generierte UI

Ein Modell schreibt pro Anfrage ein Modul, sodass die App mit einer Oberfläche antwortet. Dein Server prüft und signiert es.

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

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

Das Verhalten von NSH, das Aussehen von dir

nsh/base enthält ungestylte Basiskomponenten, die State, Fokus, Tastatur und Barrierefreiheit verantworten, und die App stylt jeden Teil. Eine nsh-Kommandozeile erledigt den Rest.

Ungestylte Basiskomponenten

Navigation, Dialoge, Menüs, Popovers, Tabs, Selects, Datentabellen, ein Code-Editor und ein Rich-Text-Kernel. Style jeden Teil mit Tailwind-Klassen oder typisierten Styles.

nsh/base

Eine Toolchain, für Menschen und Agenten

Ein nsh-Executable erstellt, baut, prüft Typen, lädt per Hot Reload nach, testet, paketiert und signiert. Deklarationen werden aus den Rust-Quellen generiert und die Doku wird als llms.txt bereitgestellt, sodass ein Agent die gesamte Schleife mit denselben Befehlen durchläuft.

nsh run, nsh test, nsh package

Auf jedem Target geprüft

Dieselben Tests laufen headless sowie in echten Fenstern, einem iOS-Simulator, einem Android-Gerät oder einem Browser, mit der plattformeigenen Eingabe.

nsh test --target ios

Native Views und Interaktion,
dein visuelles Design

Installiere nsh und lass deine erste TSX-App in einer Minute laufen.