Skip to content

AcceptedOwner sparkles:ui-appReviewed 2026-08-07

sparkles:ui-app — Overview ​

Abstract ​

sparkles:ui-app is the application host for the Sparkles user-interface toolkit: the layer that turns an interface description into a running interactive program. It decides whether the program runs in a terminal or a desktop window, gives every application the same window and font command-line options, and runs the loop that reads input and draws frames. An application written against the host never names a backend, so one program serves both targets. The same loop also runs headless over scripted input, so an application's behavior is testable without a window or a terminal.

Introduction ​

The sparkles:ui toolkit describes an interface as data and paints it through small backends. A backend is the code that serves one target, such as a terminal or a GPU window, and by design the toolkit knows nothing about which one is running. An interactive program still needs someone to make that choice and act on it. Someone must pick the target for this process, open a window and load its fonts, and read the user's window and font options. Someone must drain input, decide when a frame is drawn, and perform platform errands such as setting the pointer shape, the clipboard and the window title. Every Sparkles application with an interface needs this layer, from the hue code viewer to the terminal emulator and the diagram board.

Written privately inside each application, the layer drifts. Two programs that each declare font and window flags end up with different spellings, defaults and resolution orders for the same job. A platform rule such as "on Android the window is the whole application, so there is no terminal to choose" lives in one program's comments, where the next program never sees it. Each hand-written frame loop settles resize, quit and repaint its own way. Worst, a loop that opens a real window or terminal cannot run in a unit test, so the application logic written inside it is checked only by hand. Yet folding input, routing the pointer and deciding whether to draw are pure or nearly pure.

The host owns that layer once, as a sibling package of the toolkit rather than a layer inside it, so the toolkit gains no dependency. An application supplies a function that presents its state and one that handles each event; the host does everything else. Choosing the backend is a pure decision over an injected policy of command-line flags, terminal presence and display presence, and reading the environment is a separate function, so every combination is testable. The host, never the application, is specialized per backend at compile time instead of being dispatched through an interface, so the frame path has no indirection and inherits each backend's guarantees. Besides the terminal and the window, the host offers a third target: the recording target takes a scripted list of events and records the frames, draw operations and platform calls they cause, so a whole session is assertable in an ordinary unit test. On every target, an application hands over as much of drawing as it wants, at one of three render levels. It gives the host a widget tree to lay out and paint, appends to a display list, or takes the concrete drawing surface for a renderer of its own.

This specification covers backend selection, the shared window and font options with the order in which a window is set up, the host's frame loop and contract, the package's build configurations, and the testability obligations the host places on the applications that use it. Widget composition, layout and theming belong to the toolkit, and drawing primitives, glyph atlases and cell grids to its backend packages. The event vocabulary belongs to sparkles:input, and argument parsing to sparkles:core-cli, to which the host contributes options but no parser. Waiting, timers and background work belong to sparkles:event-horizon; the host's live loops run on it, while the host keeps the frame policy. Native windowing belongs to sparkles:wsi, and what to render is always the application's decision. The backend vocabulary also names non-interactive HTML and ANSI output, which the host reports rather than runs; UIAPP-O3 tracks whether it should own those outputs too.

This page lists what the host owns, its render targets, the three render levels and the package graph, and defines the status, ID and traceability schemes of every page in the tree. Feature requirements holds the requirements by area: architecture, backend selection, the options, the host contract and testability. Terminal view specifies sparkles:terminal-view, the terminal emulator's core as a component any application can embed. Open issues records deferred decisions, and the delivery plan holds delivery order and progress. Relationship to existing specs places the host among the specifications it depends on and serves.

What it owns ​

ConcernModuleRequirements
Backend selectionbackend.dBKD
Window/font CLIgui_options.dCLI
Window/font setupgui_setup.dCLI
Frame/event looprun.d, host.dHST
Component entryrun_app.dHST
Backend armstui_loop.d, gui_loop.dAPP
Headless test targetrecord.dTST

Render targets ​

The host instantiates one Host per target. All three satisfy the same shape, so an application's present/handle pair is written once:

TargetCanvasInputNotes
GUIRaylibCanvasRaylibEvents.pollpolls once per frame; Host.skipFrame() suppresses the buffer swap
TUIGridCanvasTerminalSessionblocks on input unless a frame was requested or an idle tick is set
recordingRecordingCanvasa scripted Event[]no window, no tty — the seam that makes an app's loop testable

The recording target is the loop-level analogue of the toolkit's RecordingCanvas (TGT10 asks that a widget tree be renderable through every target in a test; this extends that to a whole session).

The three render levels ​

An application defers as much of the pipeline as it wants, mirroring the toolkit's own three levels (UIA2):

LevelCallThe host doesConsumer
widgetshost.paint(tree, theme)layout → buildDisplayList → paint(canvas)hue's chrome, diagram's menus
display listhost.ops() ~= opreplays the host-owned buffer into the canvasdiagram's board
direct canvashost.canvasnothing — the app drives isCanvas primitives itselfterminal's per-cell VT renderer

The third level is why apps/terminal can migrate at all: its renderer is a per-cell drawSolid/drawBox/drawGrapheme walk over a libghostty screen, and routing it through a DrawOp stream would be a rewrite of a benchmarked hot path.

Package graph ​

sparkles:ui-app  → ui, input, core-cli        config "tui":  + ui-tui
                                              config "gui":  + ui-raylib, version UiAppGui
                                              config "full": + both

sparkles:ui gains no dependency and no knowledge of the host — the direction of PKG1 is preserved.

Native WSI and Graphite evolution ​

The graph above is the shipped phase-1 raylib host. The accepted next graph is specified by sparkles:wsi: native Wayland, X11, Win32, and AppKit windowing joins this host's existing Event Horizon loop, then Skia Graphite supplies Vulkan rendering on Linux/Windows and Metal on macOS. SDL 3 and raylib remain explicit compatibility configurations; they are never silent fallbacks behind the native selection. Applications still call the same runApp contract and do not import a window system or renderer.

Documentation map ​

PageWhat it covers
Overview (this page)what the host is · why it exists · targets · render levels · the status/ID scheme
Feature requirementsthe requirement tree: architecture (APP), backend selection (BKD), the CLI (CLI), the host contract (HST), testability (TST)
Delivery planexecution: the four phases, their dependencies, the acceptance gates, and what each phase makes testable
Terminal viewphase 2's apps/terminal extraction: the core as an embeddable runApp component (TVW), the paint hook, and the parity/perf gates
Open issuesdeferred decisions and the constraints behind them

Status scheme ​

Identical to the sparkles:ui scheme — not started · researched · partial · full (<sha>) · decided — so the trees cross-reference without translation. Phase 1's rows are full; the remaining open rows (TST3, TST4) belong to the phase-2 migrations.

ID scheme ​

<AREA><n>, unique within a document:

AreaMeaning
APParchitecture and package graph
BKDbackend selection — the flags, probes and platform facts behind the pick
CLIthe shared window/font command-line vocabulary and setup order
HSTthe host contract — the loop, the frame, and the platform errands
TSTtestability: the recording target and the coverage obligations

Traceability ​

Planned files, each owned by at least one requirement. The table is the code → requirement direction; the "Traces to" column of each row is the reverse.

Planned source fileAreas
libs/ui-app/src/sparkles/ui_app/backend.dBKD1–BKD5
libs/ui-app/src/sparkles/ui_app/gui_options.dCLI1–CLI3
libs/ui-app/src/sparkles/ui_app/gui_setup.dCLI4–CLI6
libs/ui-app/src/sparkles/ui_app/host.dHST1–HST8
libs/ui-app/src/sparkles/ui_app/run.dHST1, HST9, BKD5
libs/ui-app/src/sparkles/ui_app/run_app.dHST10–HST12
libs/ui-app/src/sparkles/ui_app/display.dBKD3
libs/ui-app/src/sparkles/ui_app/event_source.dHST9
libs/ui-app/src/sparkles/ui_app/tui_loop.dAPP4, HST6, HST7
libs/ui-app/src/sparkles/ui_app/gui_loop.dAPP4, HST6, HST7
libs/ui-app/src/sparkles/ui_app/record.dTST1–TST3
libs/ui-app/dub.sdlAPP2–APP4

Relationship to existing specs ​

SpecRelationship
sparkles:uithe toolkit this hosts; PKG1/TGT6 are the constraints that make the host a sibling rather than a layer inside it
sparkles:ui backendsthe isCanvas targets the host instantiates; TGT5 capability declaration is what the host forwards to the app
sparkles:inputthe event vocabulary the host drains; phase 0 extends it with key levels and the frame fold
sparkles:wsithe future native GUI window/input source; its events are normalized here and its sources attach to this host's Event Horizon scheduler
sparkles:event-horizonthe one scheduler, wait, timer, wake, and background-work loop shared by TUI and every GUI host
hue UI architectureUIA7/UIA8 named the window and terminal seams; this spec is the layer above them
hue GUI, hue TUIthe two hosts being migrated onto this contract

→ Feature requirements · Delivery plan · Open issues