rendering pipeline

How a SwiftTUI frame becomes terminal cells.

Every frame follows the same path: resolve, measure, place, semantics, draw, raster, and commit. The split keeps app code predictable: layout decides geometry, semantics decide interaction, drawing decides visible content, and presentation decides terminal bytes only after the frame is data.

/exampleOne authored view

The same declaration feeds every phase.

You author a View. SwiftTUI handles the pipeline. You only reach for pipeline artifacts when you want previews, test assertions, or detailed debugging output.

struct BuildSummary: View {
  var body: some View {
    VStack(alignment: .leading, spacing: 0) {
      Text("Deploy Queue").bold()
      Divider()
      ProgressView("Release", value: 18, total: 24)
      LabeledContent("Owner", value: "infra")
    }
    .padding(1)
  }
}
/phasesStep by step

What each phase answers.

  1. 01

    resolve

    What views exist in this frame?

    SwiftTUI evaluates the authored View body and records structure, modifiers, environment values, identity, and presentation declarations. Nothing has a size yet. The result is a tree that says what the interface is made of.

    example

    A VStack with a title, Divider, ProgressView, and two LabeledContent rows becomes a resolved tree with those children and their modifiers attached.

    ResolvedNode tree
  2. 02

    measure

    How much cell space does each subtree want?

    Parents propose a cell size, and children choose the size they need inside that proposal. Text wrapping, fixed sizes, spacing, custom Layout values, and controls make their sizing decisions here.

    example

    Given a 40-column proposal, the title can stay on one row while a long label may wrap or report a taller measured size.

    MeasuredNode tree
  3. 03

    place

    Where does each measured view land?

    The layout engine assigns each measured subtree an integer-cell rectangle: x, y, width, and height. This is the first phase with final geometry.

    example

    The title might land at row 0, the divider at row 1, and the progress view at row 2, all within the same 40-column window.

    PlacedNode tree
  4. 04

    semantics

    How can the user interact with this frame?

    SwiftTUI walks the placed tree and extracts focus targets, button actions, key commands, pointer hit regions, scroll routes, selection routes, drop targets, and accessibility nodes.

    example

    A focused TextField contributes an editing route and caret position; a disabled Button stays visible but does not contribute an activation route.

    SemanticSnapshot
  5. 05

    draw

    What should be painted?

    Placed views become drawing commands: text runs, dividers, borders, shapes, chart marks, table chrome, image placeholders, and style tokens. Drawing commands still are not terminal bytes.

    example

    The divider becomes a horizontal rule command, and the progress view becomes text plus filled and empty bar segments with semantic styles.

    DrawNode commands
  6. 06

    raster

    Which styled cells are visible?

    Draw commands are packed into a grid of terminal cells. Each cell records a character and style information. The raster surface is host-neutral data, so terminal escape sequences are still outside this phase.

    example

    A 40 by 8 preview frame becomes 320 cells, including blank cells, divider glyphs, bar glyphs, and styled text cells.

    RasterSurface
  7. 07

    commit

    What runtime work follows this frame?

    SwiftTUI packages lifecycle transitions and handler installation for the runtime. This is where appeared and disappeared identities, task starts and cancellations, and current input handlers become explicit work.

    example

    If a sheet opens, the commit plan installs overlay handlers and starts any newly appeared task after the frame is ready to present.

    CommitPlan
/boundaryTerminal presentation

Terminal escape sequences happen after raster.

The raster surface is a styled cell grid, not a stream of terminal control codes. Terminal capability decisions such as truecolor, ANSI fallback, Kitty graphics, Sixel graphics, and OSC 8 hyperlink emission happen at the presentation boundary.

That boundary is also where SwiftTUI sanitizes authored text and hyperlink destinations before writing bytes to a terminal stream. Layout, routing, and raster data stay independent from terminal escape-sequence safety rules.

/inspectWhen you need artifacts

Use DefaultRenderer for previews and assertions.

App code usually does not call pipeline phases directly. For a preview, test, or diagnostic path, render a view on the main actor and inspect the returned frame artifacts.

let renderer = DefaultRenderer()
let frame = renderer.render(
  BuildSummary(),
  proposal: .init(width: 40, height: 8)
)

let surface = frame.rasterSurface
let routes = frame.semanticSnapshot
let work = frame.commitPlan