import TerminalUI

A real view system for the terminal.

SwiftUI's authoring model — body-only views, recursive layout, identity-keyed state, focus routing — applied to terminal apps. Built on a strict 7-phase rendering pipeline.

The view system is real. The runtime is real.

Layout primitives, controls, presentations, focus routing, an ActionScope-based command surface, charts, and image presentation across PNG, JPEG, and GIF. The pipeline is the same on terminal, WASI, native macOS/iOS, and the browser.

Status Shipped surface
Layout · VStack · HStack · ZStack · LazyVStack · LazyHStack · ScrollView · List · OutlineGroup · Table · TabView · Layout protocol · GeometryReader
Controls · Button · Toggle · Stepper · Slider · TextField · TextEditor · SecureField · Picker · Menu · DisclosureGroup · ProgressView
Presentations · alert · confirmationDialog · sheet · toast
Commands · Panel · .keyCommand · .paletteCommand · .toolbar · .toolbarItem
Charts · BarChart · ColumnChart · Sparkline · Timeline · Meter · ThresholdGauge · Legend · HeatStrip
Deferred: NavigationStack · richer popover presentation · animated GIF playback · namespace-scoped focus APIs

The DSL is SwiftUI. Not a sketch of it.

Views have bodies. State is identity-keyed. Layout is recursive — parents propose, children choose. Commands attach to scopes, not to a global hotkey table.

DeployApp.swift swift
import TerminalUI
import TerminalUICLI

@main
struct DeployApp: App {
  var body: some Scene {
    WindowGroup("Deploys") {
      DeployList()
    }
  }
}

struct DeployList: View {
  @State private var deploys = Deploy.recent()
  @State private var selection: Deploy.ID?
  @State private var showDetail = false
  @FocusState private var search: Bool

  var body: some View {
    VStack(alignment: .leading, spacing: 1) {
      TextField("filter", text: .constant(""))
        .focused($search)
      List(deploys, selection: $selection) { deploy in
        LabeledContent(deploy.environment, value: deploy.status)
      }
    }
    .keyCommand("Open", key: .return) { showDetail = true }
    .sheet(isPresented: $showDetail) {
      DeployDetail(id: selection)
    }
  }
}

One codebase. Terminal, macOS, iOS, web.

Same rendering pipeline, different host chrome. The terminal runtime, SwiftUI host, and Bun-based web host all ship in the repo.

Parity in syntax and implementation.

Recursive layout. Structural environment propagation. Identity-based state. Scene ownership. Explicit lifecycle boundaries.

Same authoring surface

@State, @Binding, @FocusState, @Observable, environment values, Layout protocol, Scene declarations. The types you already know.

Same layout contract

Parents propose, children choose. Modifier order matters. Measurement and placement are recursive — no terminal shortcuts.

Same identity model

State keyed by tree identity plus source location. View-local state survives rerenders. Lifecycle is identity-driven.

Terminal-native runtime

Input parsing, focus routing, alternate-screen ownership, lifecycle staging, commit planning, and incremental presentation.

Three claims worth verifying.

The project's design discipline lives in the docs, not in the marketing. Each claim below links to the design essay that proves it.

It feels at home next to tmux, Zellij, WezTerm,

Neovim, Yazi, and Lazygit.

— Terminal-Native Doctrine, success criterion #1