Skip to content

Concepts ​

A view is a whole snapshot. Window.Set replaces the previous one, and any style you leave out returns to its default. Give each element an ID that is nonzero and stable within its view: stable IDs are what keep focus, hover and input state attached to the same control between snapshots.

Revision 1Revision 2Revision 3, ID changedDiv 1Text 2 "Count: 0"Input 10Div 1Text 2 "Count: 1"Input 10Div 1Text 2 "Count: 1"Input 11Native state for ID 10focus, selection and composition carry overNo state for ID 11starts fresh

Native state belongs to an element ID. Keep the ID and the state survives each snapshot. Change it and the element starts over.

Handlers are registered on the client and referenced from the tree by ID. Go closures are never called during rendering. They run later, in order, on the goroutine that calls DispatchEvents, so application state can stay on that goroutine without locks.

Goyour goroutineRustGPUI on the main threadrender() builds a treeHandler changes your stateSnapshot checked, installedGPUI lays out and paintsGPUI hit tests the clickWindow.SetDispatchEventsprotobuf over Sable

One trip around the loop. Go describes the view, and Rust owns everything on screen.

GPUI framesYour goroutinePainting revision 1Revision 2Handler AHandler B, slowWindow.Settime

GPUI paints the latest installed snapshot without waiting for Go, so a slow handler delays the next update but does not stall a frame. Handlers run one at a time, in order.

go
count := 0
var window *client.Window
var increment uint64

render := func() *scene.Node {
	return scene.Div(1,
		scene.Text(2, fmt.Sprintf("Count: %d", count)),
		scene.Div(3, scene.Text(4, "Increment")).Style(&scene.Style{
			Padding:      scene.Padding(12),
			Background:   scene.RGB(0x4f46e5),
			CornerRadius: scene.Ptr[float32](8),
		}).OnClick(increment),
	).Style(&scene.Style{
		Padding:       scene.Padding(32),
		Gap:           scene.Pixels(20),
		FlexDirection: scene.FlexColumn.Enum(),
	})
}

increment = app.OnClick(func(ctx context.Context, _ *client.Event) error {
	count++
	return window.Set(ctx, render())
})
defer app.RemoveHandler(increment)

var err error
window, err = app.OpenWindow(ctx, client.WindowOptions{
	Title: "Counter", Width: 560, Height: 420,
}, render())
if err != nil {
	return err
}
return app.DispatchEvents(ctx)

Styles ​

The style reference lists every field. Use scene.Ptr for optional scalar style fields: nil means absent, and an explicit zero stays present. Width and similar lengths come from scene.Pixels, scene.Percent, scene.Rems and scene.Auto.

Cancellation ​

Requests are not retried automatically. If a call such as Window.Set is canceled, the update may already have been applied, so treat that outcome as unknown. A successful Set means the snapshot was installed, not that it has been presented on screen.

Released under the Apache License 2.0. The optional Zed editor component is GPL-3.0-or-later.