macOS · Linux · Windows · iOS · Android

Toolkit for building native desktop apps

Write app logic in TypeScript and views in Native markup. The toolkit compiles them to native code and renders the interface in OS windows. Zig cores and embedded web content are also supported.

$ npm install -g @native-sdk/cli
The Soundboard example app rendered by the Native SDK engine (light theme)

Components and themes

Configure components with design tokens

Native SDK provides native-rendered components with named tokens for colors, spacing, and typography. These examples use the same widgets and playback logic with different themes.

The Soundboard example app rendered by the Native SDK engine (light theme): a clean music library with album covers and a playback bar
The Deck example app rendered by the Native SDK engine: the same music player rebuilt as a fixed 512 by 264 chromeless hardware unit in cream enamel with smoked-glass display bays, a phosphor seven-segment timecode, a spectrum analyzer, and a rotary volume knob

Two themes for the same app

Every difference between examples/soundboard and examples/deck is design tokens and a chrome pass — same widgets, same engine. One is an airy app window that follows the site theme; the other is a dense 512×264 enamel-and-glass hardware unit with one finish by design.

Components

Buttons, text inputs, lists, tables, dialogs, and charts.

Design tokens

Configure colors, spacing, typography, and themes by name.

Native rendering

The toolkit renders views in OS windows; web content is optional.

App state

Typed messages drive updates; views derive their content from the model.

Native markup

Declare layout, bindings, and message dispatch in .native files.

Automation

Inspect accessibility snapshots, send input, and capture screenshots.

App model

Events. Messages. State. Interface.

Events dispatch typed messages to the update function, which produces the next model and any effects. The view reads the committed model. TypeScript cores compile to native code; markup changes can reload while the app runs, preserving state.

src/app.native
<column background="background">
  <row height="{header_height}" padding="12" gap="10" cross="center"
       background="surface" window-drag="true" label="Inbox header">
    <spacer width="{chrome_leading}" />
    <spacer grow="1" />
    <if test="{doneCount}">
      <button variant="ghost" on-press="clear_done">Clear done</button>
    </if>
  </row>
  <separator />
  <column grow="1" gap="12" padding="16">
    <row gap="8" cross="center">
      <text-field text="{draft}" placeholder="New task…"
                  on-input="draft_edit" on-submit="add" grow="1" />
      <button variant="primary" on-press="add">Add task</button>
    </row>
    <tabs gap="8">
      <for each="filters" as="f">
        <button size="sm" selected="{f == filter}"
                on-press="set_filter:{f}">{f}</button>
      </for>
    </tabs>
    <scroll grow="1">
      <column gap="2">
        <for each="visible" key="id" as="t">
          <row gap="8" padding="6" cross="center">
            <checkbox checked="{t.done}" on-toggle="toggle:{t.id}"
                      label="Done" />
            <text grow="1">{t.title}</text>
          </row>
        </for>
      </column>
    </scroll>
  </column>
  <status-bar>{openCount} open · {doneCount} done</status-bar>
</column>
src/core.ts
export type Msg =
  | { readonly kind: "add" }
  | { readonly kind: "toggle"; readonly id: number }
  | { readonly kind: "set_filter"; readonly filter: Filter }
  | { readonly kind: "clear_done" }
  | { readonly kind: "draft_edit"; readonly edit: TextInputEvent };

export function update(model: Model, msg: Msg): Model {
  switch (msg.kind) {
    case "add":
      return addTask(model);
    case "toggle":
      return {
        ...model,
        tasks: model.tasks.map((task) =>
          task.id === msg.id ? { ...task, done: !task.done } : task,
        ),
      };
    case "set_filter":
      return { ...model, filter: msg.filter };
    case "clear_done":
      return { ...model, tasks: model.tasks.filter((task) => !task.done) };
    case "draft_edit":
      return { ...model, draft: applyDraftEdit(model.draft, msg.edit) };
  }
}
The ui-inbox example app running in a native macOS window: the window controls share the header band with a Clear done action, above a text field, filter tabs, a checklist of tasks, and a status bar
The ui-inbox reference captured running on macOS. The pixels come from Native SDK’s engine; the window and scroll physics come from the OS.

Examples

Explore the example apps

Dashboards, editors, tools, internal apps, creative software — every screenshot is rendered by Native SDK’s deterministic engine from the example apps in examples/, the same state captured once per color scheme. Flip the site theme and the apps flip with it — deck alone stays dark, by design.

The Markdown Viewer example app rendered by the Native SDK engine (light theme)

A split-pane editor whose preview is native widgets.

Headings, tables, task lists, links, and blockquotes on the right are ordinary widgets rendered live from the editor on the left — keystroke for keystroke, with no WebView and no HTML.

Platform integration

OS windows and platform services

Native SDK renders widgets in OS windows and integrates with platform menus, dialogs, text input, and scrolling. Available capabilities vary by host; see the platform support matrix for details.

Native UI Guide →
OS scroll physics

momentum and rubber-band overscroll on macOS

Context menus

declare one menu in markup or Zig; the OS presents it natively, with an automatic anchored fallback

Menu bar & tray

app menus and menu-bar extras driven by the model

Dialogs & file drop

native open/save panels and drop events as messages

IME composition

real text input on macOS, Linux, and Windows

HiDPI rendering

crisp scale-factor-aware pixels on every display

any agent, any running app
$ native automate wait$ native automate snapshotrole=button name="Add task" …$ native automate widget-click canvas 3$ native automate assert 'gpu_nonblank=true'$ native automate screenshot

Automation

Inspect and drive a running app

Enable the automation server to expose accessibility snapshots, send input commands, assert on app state, and capture screenshots. The CLI includes agent skills for app authoring and inspection.

Automation →

Distribution

Build and package your app

Native markup and app logic compile into the executable. Packaging includes app assets and metadata. Apps that embed web content also include the configured frontend assets and, when selected, a web engine.

Packaging →

Cross-platform

Desktop and experimental mobile hosts

Native SDK has hosts for macOS, Linux, and Windows. Mobile support is experimental, and capabilities and verification differ by platform. Check the support matrix before choosing a target.

macOS

Native

Metal presentation, OS scroll physics, native context menus, menus, tray, and dialogs. The primary development platform.

Linux

Software presentation

GTK windows driven by the deterministic software renderer, with pointer, keyboard, scroll, IME composition, and HiDPI.

Windows

Software presentation

Win32 host with IME composition. Cross-compiled and exercised in CI under Wine, including real input injection.

iOS

Experimental

Apps compile into an embed library and present via CAMetalLayer. Verified on the iOS Simulator; device support is in progress.

Android

Experimental

Cross-compiles with the full embed ABI and a NativeActivity shim. On-device runs are not yet verified.

WebViews

Coexisting

System WebView apps and panes on macOS, Linux, and Windows; bundled Chromium (CEF) on macOS.

Full Support Matrix →

Build something native

Scaffold an app, open a real window, and edit the view while it runs.

terminal
$ native init my_app$ cd my_app && native deva real window opens — edit src/app.native while it runs