zgui
Architecture

Architecture overview

What zgui is made of, how a frame gets from a pointer movement to pixels, and the three ideas the design turns on.

This section explains how the framework works inside. You do not need any of it to write an application. It is here because it explains the rules the guide states without justifying them: why a component runs once, why a signal write settles at the end of a frame, and why changing a colour costs less than changing a width.

It assumes the whole of the guide.

The shape of it

zgui is retained. Nothing is rebuilt per frame that did not change: not the document, not the computed styles, not the box tree, not the shaped paragraphs, not the display list, and not the pixels. Every stage keeps its result and is handed a description of what became invalid.

Components and signalszgui-view · zgui-view-macro · zgui-elements · zgui-reactive
The documentzgui-dom
The cascadezgui-style · zgui-css
The box tree and layoutzgui-layout · zgui-text · zgui-text-parley
Paintzgui-paint
The rendererzgui-render · zgui-render-wgpu

The renderer contract, a GPU implementation, and a vector rasteriser.

A surfacezgui-platform · zgui-platform-winit · zgui-platform-headless
The one-way architecture of zgui

The arrows are one way. A stage never reaches back up: layout does not mutate the document, paint does not consult the cascade, and the renderer knows nothing about elements.

That rule is what makes each stage testable alone, and it is why every horizontal edge in the diagram is a value type rather than a shared object.

One frame

zgui-runtime is the crate that runs the diagram. One frame, in order:

Input. The platform reports an event. The input system resolves what was under the pointer from the previous frame's fragments, and builds the capture, target and bubble path. The runtime calls the listeners on it.

Reactive settle. Listener bodies write signals. Writing marks observers; it does not run them. Once dispatch is finished, the frame flushes the reactive graph, and the effects that run mutate the document through the same seam a view builds through.

Restyle. The style engine walks only the elements that owe a restyle, computes their styles, and turns what changed into obligations for the stages below. A colour change is repaint damage; a width change is relayout.

Layout. Box-tree patches are applied for the subtrees that changed, the layout algorithm runs over the dirty region, and paragraphs are shaped or re-broken only where their content or their available width moved. The result is a fragment tree.

Paint. The stacking-order walk replays the display-list recording for fragments that did not change, re-emits only those that did, and culls against the damage rectangles.

Draw. The renderer is handed the finished display list and the damage set, and composes into a target it keeps between frames. Outside the damage, the last frame's pixels are still correct and are not touched.

Publish. The accessibility tree is diffed and published, and the frame probe — the seam the inspector attaches to — is called once with the window as it was left.

Then the loop parks. It burns nothing until one of exactly four things asks for another frame:

  • a document mutation;
  • an input event;
  • work completing on another thread;
  • a deadline, such as an animation or a timer.

A frame that raises several of those inside itself costs one more frame, not several. The frame takes this apart step by step.

Crates, by layer

Dependencies can point within a layer or to a lower layer. They do not point to a higher layer. The layer of a crate is stated at the top of its manifest, and the manifest graph is checked mechanically.

LayerCratesWhat the layer is
L0 foundationzgui-geom, zgui-color, zgui-arena, zgui-interned, zgui-bits, zgui-profileCoordinate spaces, colour, storage whose addresses hold still, interned names, invalidation bits, counters. No policy.
L1 contractszgui-vocab, zgui-css, zgui-scene, zgui-render, zgui-atlas, zgui-platform, zgui-reactiveThe traits and value types the rest of the tree agrees on. Nothing here implements anything replaceable.
L2 backendszgui-render-wgpu, zgui-render-vector-vello, zgui-render-vector-coverage, zgui-platform-winit, zgui-platform-headlessImplementations of L1 contracts. Every one is replaceable, and every one has a sibling.
L3 documentzgui-domOne arena of nodes, safe to read from many threads while the cascade runs over it.
L4 engineszgui-style, zgui-layout, zgui-text, zgui-text-style, zgui-text-parley, zgui-paint, zgui-svgThe stages that turn a document into a display list.
L5 systemszgui-input, zgui-scroll, zgui-a11y, zgui-anim, zgui-editBehaviour over a laid-out document: hit testing and dispatch, scrolling, the accessibility projection, transitions, text editing.
L6 frontendzgui-view, zgui-view-dom, zgui-view-macro, zgui-elementsHow an interface is described, and the three seams it is described against.
L7 runtime and toolingzgui-runtime, zgui, zgui-testkit-scene, zgui-testkit-view, zgui-conformanceThe frame pipeline, the umbrella crate an application depends on, and the instruments.
L8 productzgui-ui, zgui-ui-primitives, zgui-ui-tokens, zgui-ui-icons, zgui-devtools, zgui-bench, zgui-examplesThe component library, the inspector, the measurement harness, the worked applications. Ordinary consumers of the public API.

zgui is the crate an application depends on. Everything else is reachable through it, and an application that only describes an interface never names any of the others.

The crate map covers every crate and the rule that keeps the arrows pointing one way.

The seams

A seam is a trait with an implementation on each side and no third party allowed to reach across it. These are the seams a consumer is most likely to meet.

SeamCrateWhat plugs in
Rendererzgui-renderA device that puts a display list on a screen.
VectorRasterzgui-renderA path rasteriser whose output the renderer composites.
Surface, AppHandler, Clock, Waker, Clipboardzgui-platformA windowing system, or the absence of one.
Dom, ViewHost, EventSinkzgui-viewThe node tree, the engine that laid it out, and where a handler's commands go.
SheetLoader, ReplacedContent, LinkResolver, PresentationalHintszgui-domThe four things a document language brings that a document core cannot define for itself.
FontSource, FontMetricsSource, ParagraphShaper, GlyphRasterzgui-textA font engine, or a fixed-metrics stand-in for tests.
HostBindingzgui-runtimeAn embedded script engine's event, frame and shutdown hooks.
FrameProbezgui-runtimeA reader of the window as each frame left it.
MeasureContentzgui-layoutThe measurement of anything layout cannot size itself.

Most of these seams have two in-tree implementations. HostBinding is the exception: zgui provides the no-op binding, and a downstream script engine provides the active binding.

Windows

An application owns one reactive scope above all its windows. Each window below it owns a separate document and frame pipeline. Application contexts and their signals can be shared; node handles and window-local contexts cannot cross document identities.

Window creation and destruction are deferred to an event-loop turn that has a platform context. The default graphics factory gives each surface a renderer while sharing its device and compiled pipelines where the adapter supports that surface. Window-sized targets, buffers, and atlases stay per window.

See Multiple windows for the public API and The frame for the lifecycle.

The three ideas the design turns on

Invalidation is a lattice, not a flag

A node carries what it owes — restyle, relayout, repaint, and the subtree half of each — and every stage retires exactly the obligations it serviced as it walks. A stage never has to ask "did anything change?" globally; it is handed the set.

Invalidation has the exact bits and the propagation rules.

A description is a value

The display list is a value with no renderer in it. A computed style is a shared pointer that two elements which cascaded alike hold the same copy of. A fragment tree is data.

Everything crossing a stage boundary can be printed, compared and asserted on with no device and no window. That is why most of this framework's tests run headless, and it is what makes testing an application practical.

Cost is proportional to change

A signal write invalidates precisely its observers. A restyle visits the elements that owe one. A frame emits the primitives the damage rectangles reach.

There is no per-frame full traversal anywhere in the pipeline, and the absence of one is measured rather than assumed. Performance gives the numbers.

Next

On this page