Table of contents

Rendering and UI

PreviewPwshUpdated 2026-10-01

The console model, the device rendering probe, input consumption and resize reflow have passed their gates (see the roadmap). The integrated terminal, the tab surface and the general composited UI described here are planned; Managed UI and console preview defines their gates.

Scope

Pwsh needs a terminal console and a general UI. Neither replaces the other.

The device is touch-first. Graphical applications and Android services use the host without constructing a console.

Component ownership

Component Owns Dependency boundary
Managed runtime host Component lifetime, event routing, runspace admission, startup guard and recovery state Starts without SMA, terminal state or graphical UI
Android bindings NDK exports, JNI dispatch, window/input/looper operations and fixed Java forwarders Platform mechanisms; no terminal or application policy
Managed retained UI Layout, focus, hit regions, scene state, damage and tab controls Client of the host; ordinary coordinates, not cells
Managed console VT/ANSI state, transcript, editor, selection, reflow and terminal draw commands Pane content; optional to the retained UI and host
PowerShell session adapter Pipeline invocation, host interaction, streams and completion SMA references stay behind this boundary
Application scripts Application behavior and composition Use admitted platform capabilities

Composition: cells only where VT needs them

Only the terminal's text area is a grid of monospace cells, because VT/ANSI semantics (cursor addressing, erase, scroll regions) are defined over one. The tab strip, overlays and everything else are separate layers, sized in dp and composited over or beside the grid.

The preview renders through Android hardware Canvas, reached through owned JNI bindings, for both retained controls and console panes. Software rasterization is not a production fallback. A hardware Canvas buffer is not preserved between frames, so every submission covers the whole surface; damage decides when a frame is requested, not how much of it is drawn.

The renderer executes a display list. Retained controls record rectangles, text, icons and drawing-state operations in UI coordinates. Terminal panes contribute background runs and text runs derived from cells, with one drawText per merged same-format span. PowerShell decides state changes; lowered code builds and executes the repeated layout and drawing work.

Event bus

One queue, drained on the main thread. Producers (local input, shell runspaces, timers, remote input) add an event and signal an eventfd registered with the main looper. The looper callback drains every queued event, applies each to state, and produces one frame if anything is damaged. Bursts coalesce into one frame. Nothing polls and nothing waits on a timeout; the looper is the wait, because blocking the main thread would stall input and lifecycle. Animation requests one display-refresh callback at a time while something moves and stops when it settles.

Frame contract

The engine publishes frames, not pixels. Each display renders at its own size and density.

Consumer Sends or draws Rendered Client needs
Local display Canvas calls on the window surface on the device nothing
Contract stream changed rows of the frame on the client, at its density a Pwsh client
RDP graphics-pipeline region updates (MS-RDPEGFX) from an encoder surface on the device the Windows App client
Video H.264 from the same encoder surface on the device any video player

RDP and a foreground service need manifest declarations fixed at the release freeze (INTERNET, the service and its types, POST_NOTIFICATIONS). TLS needs the crypto initialization from the emitted NativeActivity subclass.

Text input

Traced in AOSP frameworks/base at android-14.0.0_r1 (commit 299fe6f5):

Intents

Scripts reach the Android intent system through owned bridges: constructing any Intent, starting activities (including for a result) and sending broadcasts. Receiving uses a declared, disabled, frozen manifest:

Interaction rules

Applications

A graphical application is a module that declares, with no host setup and no loop:

Function Purpose
Get-AppInfo title, icon, default size
New-AppState its data
Show-App $Context $State $Bounds records drawing and hit regions using theme tokens
Invoke-AppAction $State $Action $Arguments updates state and returns what changed

Themes are .psd1 data (palette, layout constants, fonts, radii). Each application may run in its own runspace behind the dispatcher, so an application's exception stays in its window.

Prior art