Esta página foi traduzida automaticamente e pode conter erros. Ler o original em inglês

Native Shell

Construa uma vez, nativo em todo lugar

Seu app fica no centro. Cada arco ao redor é uma plataforma.

Escreva apenas TSX e entregue clientes nativos que acompanham o ritmo do Rust. Uma única base de código roda em 8 plataformas, cada uma com a UI e a interação do próprio sistema.

FPS
120
primeiro frame
~1 ms
plataformas
8

Um cliente escrito em TSX, ao lado do Rust

No NSH, apenas o código do seu app é JS. O grafo reativo, o renderizador, o layout e todos os módulos são Rust. Apps em TSX e em Rust compartilham o mesmo pipeline de execução nativo.

120 FPS
22 sparklines ao vivo, um order book e um tape atualizando juntos, frame p95 abaixo de 4 ms
~0.1 ms
Inicialização do engine (75–155 µs)
~1 ms
Primeiro frame de um app contador
~0.12 ms
Um toque, do evento ao commit
< 1 KB
Código do app de um hello world
~1.1 MB
Download de um app TSX na web (runtime Wasm)
Apps pequenos medidos: alguns MB acima da janela de sistema pura
TSXRustJanela de sistema pura
Consumo de memória (footprint), macOS~20 MB~19 MB~17 MB
Memória private dirty, Linux (GTK, GL)~48 MB~44 MB~38 MB
Acima da janela de sistema, macOS / Linux+3 / +9 MB+2 / +5 MB
Working set privado, Windows~15 MB~14 MB
Tamanho em cada plataforma: hello world do nsh init
Executável TSXPacote TSXExecutável RustPacote 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 de download——

Builds de release. Memória em repouso: footprint no macOS em um Apple M3 (o app contador e o template Rust em 1200 × 800; a janela de sistema contém um label em 480 × 640); memória private dirty no Linux em uma NVIDIA RTX 3060 Ti (os templates TSX e Rust do nsh init e uma janela GTK com um label, todos em 480 × 640); working set privado no Windows. A medição de cada plataforma, com RSS e USS, está no relatório. Tamanhos: builds de release do nsh package, com link-time optimization e stripped; o executável TSX contém o runtime QuickJS, e o código do app tem menos de 1 KB; o pacote é o .app compactado em zip no macOS, o .tar.gz no Linux e o .zip no Windows; na web, o que o navegador baixa, runtime e app. O relatório completo de desempenho

TSX com 0 dependências

Um app são os arquivos abaixo. A linha de comando nsh traz seu próprio bundler e toolchain, e os módulos que você importa são nativos.

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

my-app/
  App.tsx
  nsh.json
  tsconfig.json
  • Um único executável nsh cria, executa, testa e empacota
  • ~120 ms entre salvar um arquivo e a nova versão rodando
  • nsh check faz a checagem de tipos com o tsc nativo do 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 plataformas, cada uma com os controles do próprio sistema

O NSH constrói cada UI a partir do que a plataforma já tem. Entrada de texto, seleção, métodos de entrada e acessibilidade vêm do sistema, e o que uma nova versão do SO traz para eles chega ao app junto.

PlataformaViewsTextoEntrada de textoRequisitos
macOSAppKitCoreTextNSTextViewmacOS 14+
LinuxGTK 4PangoGtkTextViewGTK 4.14+
WindowsWin32, Direct2DDirectWriteEditor do NSH, IMM32Windows 10 1809+
WebHTML, CSSO do navegador<input>, <textarea>Navegadores modernos
iOSUIKitCoreTextUITextViewiOS 15+
AndroidViews do AndroidStaticLayoutEditTextAPI 28+
TUIratatuiA fonte do terminalTeclas do Readline, métodos de entradamacOS, Windows, Linux
GPUIGPUISistema de texto do GPUIEditor do NSHEmbutido em apps GPUI Kit

Mapas, web views, vídeo e qualquer view nativa que o host registrar são mais uma subview na mesma hierarquia: elas fazem layout, recorte, rolagem e recebem toques junto com o resto do app. O backend de cada plataforma

Um app, na forma própria de cada dispositivo

O mesmo código compilado roda duas vezes aqui, e só o dispositivo muda. Com um ponteiro, é uma janela com as conversas ao lado; no celular, os botões e o campo de composição flutuam em Liquid Glass com a conversa rolando por baixo; em um terminal, ele se acomoda na grade de caracteres. O app é escrito uma só vez.

DesktopAo vivo: digite uma mensagem
CelularAo vivo: digite uma mensagem
TerminalExplorar o 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                                                │
                     │ ╰───────────────────────────────────────────────────────────────╯

Desktop e celular rodam ao vivo no seu navegador, no runtime web do Native Shell. O terminal é a saída real de nsh run --target tui.

O mesmo engine em Rust, quando você quiser

Rust é uma linguagem de primeira classe para apps inteiros: UI, lógica e componentes são compilados para código nativo, prontos para lógica de negócio exigente. Ambas usam os mesmos elementos e signals, e as telas em TSX importam seus componentes Rust.

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

Apenas as views que mudaram são tocadas

Cada elemento é uma view que a plataforma mantém. Uma mudança executa somente as expressões que leem o signal alterado, em um único lote por frame. A thread principal nunca espera pelo JS e as animações nativas rodam sem ele, então a rolagem e as animações mantêm 120 FPS e o app fica quase ocioso em repouso.

Como ele se mantém rápido

Os dois textos que leem os signals mudam e o histórico ganha uma linha; nenhuma outra view é tocada.

$ 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

Depois do lançamento, seu app ainda pode receber nova UI

Sua equipe pode escrevê-la, ou um modelo pode gerá-la a cada requisição. Ela chega ao dispositivo como um módulo assinado, roda em um sandbox definido pelo host e é exibida de forma nativa.

  1. Escrever

    Sua equipe ou um modelo escreve um módulo TSX.

    App.tsx
  2. Verificar

    Faça a checagem de tipos e depois execute seus testes em modo headless.

    nsh check nsh test
  3. Assinar

    Um .nshpkg assinado com Ed25519, cuja chave de release é certificada por uma raiz offline.

    nsh publish
  4. Limite de confiança

    Executar

    O dispositivo verifica a assinatura, o certificado e as revogações. Cada view recebe uma VM com limites de memória, tempo de chamada e nós, e apenas as capacidades que o host concede.

    NshAppView NshView AppView

Três formas de entregar, um só engine

Apps independentes

Escreva em Rust, TSX ou ambos, e empacote um app instalável para iOS, Android, macOS, Windows ou Linux, ou um site estático.

$ 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
Primeiros passos

UI dinâmica e plugins

Incorpore uma view em qualquer tela e carregue nela módulos TSX assinados em tempo de execução, ao lado dos componentes nativos do próprio host.

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
Incorporação, por plataforma

UI gerada por IA

Um modelo escreve um módulo por requisição, e assim o app responde com uma interface. Seu servidor a verifica e a assina.

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

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

O comportamento vem do NSH, o visual é seu

nsh/base reúne componentes base sem estilo que cuidam de estado, foco, teclado e acessibilidade, e o app estiliza cada parte. Uma única linha de comando nsh faz o resto.

Componentes base sem estilo

Navegação, diálogos, menus, popovers, abas, selects, data tables, um editor de código e um kernel de rich text. Estilize cada parte com classes Tailwind ou estilos tipados.

nsh/base

Uma toolchain, para pessoas e agentes

Um único executável nsh cria, compila, faz a checagem de tipos, recarrega a quente, testa, empacota e assina. As declarações são geradas a partir do código-fonte Rust e a documentação é servida como llms.txt, de modo que um agente executa todo o ciclo com os mesmos comandos.

nsh run, nsh test, nsh package

Verificado em cada target

Os mesmos testes rodam em modo headless e em janelas reais, em um simulador de iOS, em um dispositivo Android ou em um navegador, com a entrada própria da plataforma.

nsh test --target ios

Views e interação nativas,
seu design visual

Instale o nsh e tenha seu primeiro app TSX rodando em um minuto.