# MyGo architecture

This guide explains how MyGo is put together: the layers, the threading
model, how Go talks to the native toolkits without cgo, how pages and Go
exchange typed messages, how MyGo draws native UI, and how to extend the
framework safely. Read it before changing anything under `internal/`.

## Goals and constraints

* **Low overhead.** A hello-world app is a \~7 MB binary with a \~35 MB
  physical footprint on macOS (mostly AppKit/WebKit), \~62 MB with the
  processes WKWebView runs for its page, GPU and network, and idles at 0%
  CPU. A window of native UI starts no webview process: idle, a small one
  takes 44 MB on macOS, and the counter example 65 to 67 MB on Linux, tiled
  to half of a 4K display at scale 2, 15 MB of it the window's buffer,
  without loading Mesa (122 to 155 MB with it). Nothing
  polls: all work is driven by native events or explicit wake-ups. A
  window of native UI whose content settled asks for no frame and arms no
  timer (`TestSettledWindowSleeps`): the display link pauses, Go's
  scheduler sleeps, and the counter example idles at about 0.005% of a
  core on macOS (an AppKit window, 0.002%) and wakes no thread under X11.
* **No cgo.** Everything builds with `CGO_ENABLED=0`, so any platform can be
  cross-compiled from any machine. Native APIs are called at run time through
  [purego](https://github.com/ebitengine/purego) (`dlopen` + assembly
  trampolines) on macOS and Linux and through the `syscall` package on
  Windows, never through `import "C"`.
* **Two kinds of windows.** Web pages show in the system webview:
  WKWebView on macOS, WebKitGTK 4.1 (4.0 as a fallback) on Linux, WebView2
  on Windows (amd64 and arm64); no browser engine is bundled. Native UI is
  drawn by MyGo itself, in Go, with Metal, Direct3D 11 or OpenGL, or on the
  CPU, and text from the system's own engines (see [Native UI](#native-ui-ui));
  an app whose windows all show it needs no webview at all, and runs in
  browsers too, compiled to WebAssembly, on canvases drawn with WebGL 2
  (see [Browsers](#browsers-internalweb)). On unsupported
  platforms, 32-bit Windows and Linux among them, the `internal/unsupported`
  backend makes `App.Run` fail with a clear error while everything still
  compiles, so every file of a backend, and of the text engine it pairs
  with, names the backend's architectures in its build constraint.
* **Bun is dev tooling only.** It builds and tests the TypeScript bridge, and
  installs and runs the web template's tools (Vite, TypeScript, the
  mygo-cli package); projects of native UI need none. Nothing Bun-related
  ships in an app.
* **Great DX over API parity.** The API has the feel of Electron (app
  lifecycle, windows, menus, dialogs) but is Go-first: typed IPC with a
  generated TypeScript client, `http.Handler` for custom protocols, typed
  event structs, blocking calls that are safe from any goroutine, and native
  UI written in Go alone.

## Repository layout

```
.                       package mygo: the public API
├── app.go              lifecycle, quit sequence, Dock, paths (paths.go)
├── window.go           Window: the native window, its options, state and events
├── flyout.go           NewFlyout: windows owned by a parent, placed next to an anchor
├── page.go             Page: the web page a window shows, its loading, Eval and events
├── content.go          Content: windows showing native UI instead of a page
├── webview.go          WebView: web pages in windows of native UI, under it
├── ipc.go              Bind/BindAs, method calls, Event[T], CallerWindow
├── plugin.go           Plugin and Use: services bound as "plugin:<name>"
├── channel.go          Channel[T]: values streamed to a call's page
├── typescript.go       GenerateTypeScript / WriteTypeScript (uses internal/tsgen)
├── protocol.go         custom schemes served by http.Handler, FileServer
├── frontend.go         the app's frontend: relative URLs, devUrl, mygo://localhost
├── menu.go             Menu/MenuItem model, roles, native item updates
├── cookies.go          Cookies: the pages' cookies, checked, keyed by name, domain and path, filtered by CookieFilter
├── session.go          Session: website data stores chosen per page (PageOptions.Session), ClearData by kind
├── recent_docs.go jumplist.go: recent documents (Open Recent and the system's lists), the jump list
├── dialog.go modules.go clipboard.go: shell, clipboard, screen, theme, tray, shortcuts, notifications
├── watch.go watch_scan.go: WatchFiles, and what a watch saw of its directory
├── document*.go        NewDocuments: documents, their saving, recovery copies, watches, menus
├── loop.go             main-thread queue: postMain / onMain / await
├── events.go           listener lists and the Preventable event types
├── single_instance.go  RequestSingleInstanceLock over a Unix socket
├── dev.go signal_*.go  IsDev, the `mygo dev` ready signal, quitting on SIGINT/SIGTERM
├── backend_*.go        picks the backend per GOOS
├── internal/
│   ├── platform/       the contract every backend implements
│   ├── darwin/         macOS: AppKit + WKWebView through the Objective-C runtime
│   ├── linux/          Linux: GTK 3 + WebKitGTK through dlopen
│   ├── windows/        Windows: Win32 + WebView2 through syscall and COM
│   ├── schemehost/     maps custom scheme URLs to the http://*.localhost URLs WebView2 serves them at
│   ├── schemestream/   the bounded pipe custom scheme bodies stream to WebView2 through, and media ranges narrowed
│   ├── web/            browsers (js/wasm): native UI on canvases, through syscall/js
│   ├── unsupported/    stub for other platforms
│   ├── fake/           in-memory backend for unit tests
│   ├── automationcli/  mygo-automation, the command line client of plugins/automation's socket
│   ├── watchdriver/    the goroutine that runs a backend's file watcher
│   ├── bridge/         embeds bridge.js, built from packages/bridge
│   ├── surface/        the connection between a window and its native UI
│   ├── pacing/         whether frames wait for the display (MYGO_UNCAPPED)
│   ├── scene/          display lists and glyph atlases, what renderers draw
│   ├── media/          the contract between ui's VideoPlayer and ui/video's engines
│   ├── text/           fonts, shaping, line breaking, editing, glyph rasterization
│   ├── rope/           the persistent tree of text chunks text buffers keep
│   ├── diff/           line and word diffs: histogram, Myers, git's indent heuristic
│   ├── vec/            the coverage rasterizer of glyphs and paths
│   ├── raster/         the CPU renderer of scenes
│   ├── gpu/            the instances GPU renderers draw, and gputest/ for their tests
│   ├── gpu/d3d11/      the Direct3D 11 renderer of scenes, and device/ for its devices
│   ├── gpu/metal/      the Metal renderer of scenes
│   ├── gpu/gl/         the OpenGL and WebGL 2 renderer of scenes
│   ├── shader/         the compiler of shaders in Go's syntax, forked from Ebitengine's Kage
│   ├── shaderir/       its IR; glsl/, hlsl/ and msl/ write it for the GPU renderers, interp/ runs it on the CPU
│   ├── svg/            SVG parsing and drawing, for icons and images
│   ├── tsgen/          TypeScript client generator
│   ├── nativegen/      native modules: reads their Go interfaces, writes their Go, Swift, Rust and Zig
│   ├── i18ngen/        checks catalogs of messages, writes their Go and TypeScript functions
│   ├── i18nlink/       what package i18n gives MyGo's own catalog only: a catalog that links no dates
│   ├── l10n/           MyGo's own strings: the catalog of the controls and menu roles
│   ├── nativelib/      mygo-plugin.json, libraries' file names, where they are built and cached
│   ├── accelerator/    parses "CmdOrCtrl+Shift+K"
│   ├── menuicon/       menu items' PNG icons as premultiplied, scaled pixels (Windows)
│   ├── update/         update manifests, signatures, archives and delta updates
│   ├── idlemem/        measures apps' memory once idle, for the benchmarks
│   ├── inputlatency/   measures how long input takes to reach the screen in native UI (macOS)
│   └── e2e/            GUI tests and benchmarks against the real backend (MYGO_E2E=1)
├── packages/           Bun workspace (with the examples' frontends):
│   ├── bridge/         the runtime injected into pages (→ internal/bridge/bridge.js)
│   ├── runtime/        mygo-runtime, the npm package apps and generated clients import
│   └── cli/            mygo-cli, the npm package of the CLI, and in npm/ its
│                       per-platform binary packages
├── plugins/            official plugins, each a Go package and its npm
│                       package (@mygo-plugins/<name>) side by side: fetch,
│                       websocket, sqlite, watch; and Go only: updater, the
│                       update window, a web page or native UI (updater/native),
│                       terminal, a view of native UI running programs with
│                       libghostty-vt, glass, game, what games need
│                       beyond what apps do (game/gamepad), loading,
│                       loading.dev's indicators for native UI,
│                       automation, a socket other processes drive the
│                       app through, for end-to-end tests, with its
│                       command line client for agents
│                       (automation/cmd/mygo-automation), and
│                       permissionflow, the system's permissions and a
│                       guide to System Settings, after PermissionFlow
├── ui/                 native UI: views, layout, widgets, text editing, Tester;
│                       ui/chart: charts without a look, on ui's public API;
│                       ui/editor: the code editor and the diff viewer;
│                       ui/shader: shaders in Go's syntax, on every renderer;
│                       ui/video: video with the system's media framework
├── i18n/               languages: matching, CLDR plural rules and parent locales,
│                       formatting of numbers and dates (generated by
│                       i18n/internal/gen), ICU MessageFormat, catalogs
├── ffi/                native libraries (Rust, Zig, C) that packages name in
│                       mygo-plugin.json: finding, loading and binding them
├── transfer/           immutable data items, representations, lazy providers and drag effects
├── netproxy/           the proxy of the system's settings, for Go's HTTP clients
├── native/             the runtime of native modules: Go interfaces implemented in Swift, Rust or Zig
├── audio/              sound: players, the mixer, the output of each platform, WAV;
│                       audio/vorbis and audio/mp3 decode Ogg Vorbis and MP3,
│                       audio/mp4 MP4 (fragmented too) with ALAC, audio/aac
│                       AAC, audio/flac FLAC
├── cmd/mygo/           the CLI: init, generate, dev, build, native build, doctor
├── examples/           hello, todo, frameless, native; counter-native, vibrancy,
│                       effort-slider, flyout, menubar-flyout, piano, farm
│                       and mayoi (games), code-editor and gallery (native
│                       UI), timeline (motion on one playhead); webview (web
│                       views in native UI); launcher (a Spotlight-like panel,
│                       native UI); wind (a texture of glyphs lit by a
│                       wind, two shaders of ui/shader); loading (the
│                       loading plugin's indicators); video (a GIF
│                       looping behind a window's content, a trailer
│                       with controls over it); permissionflow
│                       (the permissions, asked for and guided to);
│                       native-module (native modules in Swift, called from native UI);
│                       rust-native (a Rust crate the CLI builds, called
│                       through ffi)
├── docs/               the user guides, the official plugins' pages
│                       (plugins/), and this architecture guide
└── website/            the website, with these docs: TanStack Start, prerendered
                        and served by Cloudflare Workers as static assets
```

## Layers

```
 user code ──► package mygo ──► platform.Backend ──► darwin | linux | windows | web | unsupported
                 ▲    │               ▲                  │
                 │    └─ handlers ────┘ (AppHandler,     └─ purego ─► AppKit/WebKit, GTK/WebKitGTK
                 │                       WindowHandler)
 page (JS) ◄── bridge.js ◄── Eval (batched) ─┘
     └──── postMessage(JSON) ──► WindowHandler.Message
```

* **`package mygo`** owns all behavior that is not platform specific: option
  defaults, the window registry, event listeners, the quit sequence, IPC
  routing and encoding, menus, protocol handling, trust checks. It never
  calls a native API directly.
* **`internal/platform`** is a small, synchronous contract: a `Backend`
  (event loop, window factory, menus, dialogs, clipboard, …), a `Window`
  (chrome + webview), and two handler interfaces the core implements to
  receive events (`AppHandler`, `WindowHandler`). Options arrive fully
  defaulted; backends never invent policy.
* **Backends** translate the contract to native calls. They keep native
  objects alive, map native callbacks back to Go objects and report events.

Keeping policy in the core is what lets `internal/fake` test almost all
behavior without a GUI, and keeps each backend a thin translation layer.

## Threading model

Cocoa and GTK must be driven from the thread that started the process. The
rules are:

1. **The main goroutine is locked to the main thread** (`runtime.LockOSThread`
   in `mygo.go`'s `init`), and `App.Run` must be called from it. `Run`
   initializes the backend and blocks in the native event loop. Before
   that no backend is initialized (the Linux one has not even loaded GTK),
   yet `main` already runs on the main thread, where `onMain` calls
   functions directly, and generate mode never initializes it. So a public
   method that reaches the backend either keeps its value in the core
   until the backend can take it, for settings (`SetActivationPolicy`
   through `AppOptions`, `SetMenu` once ready, `Theme.SetSource`,
   `Theme.SetGTKCSS` and `Dock.SetMenu` right after `Init`), or starts
   with `needsApp`, which
   panics on the main thread before `Run` with the name of the call,
   rather than letting it crash on Linux, hang in `await` or answer wrong
   on macOS. Only calls that work before `Init` on every backend (`Locale`,
   packaging info, login items, URL schemes, `IsOnBattery`) do neither.
2. **Every `platform` method is called on the main thread, and every handler
   callback runs there.** The backend never needs locks for its own state.
3. **Every public method is safe from any goroutine.** `loop.go` provides:
   * `postMain(fn)` appends to a FIFO queue and calls `Backend.Signal`, which
     makes the backend call `AppHandler.Dispatch` (→ `loop.drain`) on the main
     thread. macOS uses a `CFRunLoopSource` added in all common modes (so it
     fires while menus track, windows resize and modal panels run); Linux uses
     `g_idle_add`, deduplicated with an atomic flag.
   * `onMain(fn)` runs `fn` directly when already on the main thread, else posts
     it and waits. After shutdown posted work is dropped instead of
     deadlocking.
   * `await(ch)` waits for an asynchronous native result. Off the main thread
     it is a plain channel receive. **On the main thread it pumps native events
     with `Backend.Step`** until the value arrives; whoever produces the value
     calls `deliver`, which sends and then `Backend.Wake`s the loop. This is
     what makes `Page.Eval`, `CapturePage` and dialogs usable from event
     listeners without deadlocking. Nested runs of the dispatch source are
     expected and safe. A nested loop started inside a run loop observer
     is not: CFRunLoop never runs that observer again meanwhile, and in
     the one AppKit displays views and Core Animation commits in, no
     window, panel or sheet would show. So native UI's frames, whose
     handlers (`Clicked`) may show a dialog, draw outside it on macOS,
     but those AppKit asks for, as a resize's (`drawSoon` in
     `internal/darwin/surface.go`).
4. **Event listeners run on the main thread**, synchronously, so cancelable
   events (`OnClose`, `OnBeforeQuit`, `OnWillNavigate`, …) can answer the
   native toolkit immediately. **IPC calls run on their own goroutines**, so
   bound methods may block.
5. **Validate in the caller's goroutine.** Anything that can panic on bad
   input (for example `WindowOptions.BackgroundColor`) is checked before
   hopping to the main thread, so the panic points at the user's call.

Main-thread-only fields are marked as such in comments (for example
`Window.native`, `Window.trusted`). Fields shared with other goroutines are
guarded by a mutex or atomic.

File watches (`watch.go`) don't use the main thread: each runs on a
goroutine of its own, and the backend's watcher on another (see
[Watching files](#watching-files-watchgo)).

## Native interop without cgo

purego gives three primitives, used everywhere:

* `purego.SyscallN(fn, args...)` for integer/pointer arguments. Fast, no
  reflection; it allocates only the array of its arguments, which escapes.
  Floats cannot be passed this way, nor structs, but for those C passes in
  integer registers, as Core Foundation's `CFRange`, which goes as its two
  fields, and comes back as `r1` and `r2`.
* `purego.RegisterFunc(&typedFn, addr)` for signatures with floats or
  structs (`NSRect`, `CGFloat`, `GdkRGBA*` …). These are created once at
  startup; calling them uses reflection, so they are kept off hot paths.
* `purego.NewCallback(fn)` turns a Go function into a C function pointer. At
  most \~2000 callbacks can exist per process and they are never freed, so
  **callbacks are created once per signature at startup** and user data (a
  window id, a request id) identifies the target. Never create callbacks per
  window, per request or per call.

Package `ffi` gives apps and plugins the same for their own libraries (a
Rust crate, a Zig package, C): `ffi.New(name, manifest)` finds the library
of the package's embedded `mygo-plugin.json` (`$MYGO_NATIVE_<NAME>`, the
app's resources, the executable's directory and, outside packaged apps,
the CLI's builds in `.mygo/native/<goos>-<goarch>` of the working
directory's module, then the published file in the user's cache,
downloaded when missing), loads it once (`dlopen` with `RTLD_LOCAL`,
`LoadLibrary` on Windows), and `Bind` sets a struct's function fields with
`purego.RegisterFunc`, by tag or by the field's name in snake case, turning
purego's panics on unsupported signatures into errors. `Bind` and
`BindFunc` bind a pointer once, under the library's mutex, and remember
the result in a `sync.Map`, so that functions can call `Bind` before each
use from any goroutine without locking. The terminal and SQLite plugins
find their libraries through it. Elsewhere than macOS, Linux and Windows
on amd64 and arm64 it reports `errors.ErrUnsupported`. Apps that do not
import it link none of it, and production builds (`mygo_nodownload`, set
by `mygo build` with `mygo_noinspector`) leave out its downloader and
`net/http` with it, about 1.9 MB, as packaged apps never download.

### macOS (`internal/darwin`)

* `objc.go` loads the frameworks, caches selectors and classes, and wraps
  `objc_msgSend`: `send(obj, "selector:", args...)` for integer arguments and
  pre-registered typed variants (`msgRect`, `msgSetFloat`, `msgInitWindow`,
  …) for the rest. On amd64, methods returning structs larger than 16 bytes go
  through `objc_msgSend_stret`.
* Classes are defined at run time with `objc.RegisterClass`: `MyGoWindow`
  (borderless-friendly `NSWindow`), `MyGoWebView` (records the last
  `mouseDown:` for drag regions; `window_drag.go` follows the press with a
  local event monitor: `StartDrag` asks the window server
  (`performWindowDragWithEvent:`) while the pointer has not moved, and
  moves the window itself when it has, or when the window server did not
  begin, which `windowWillMove:` tells, not the window's frame: it lags),
  `MyGoWindowDelegate` (window, navigation,
  UI and script-message delegate in one object per window), the app delegate,
  scheme handler, menu and tray targets. Only protocols that exist at run
  time are adopted (`WKScriptMessageHandler` is not registered, and WebKit
  does not need it).
* **Overrides call super with `sendSuper`** (`sendSuperSize` for an
  `NSSize`), naming the class they are defined in, never purego's
  `objc.ID.SendSuper`: that resolves super from the object's class, which
  key-value observing replaces with a generated subclass, so the override
  would call itself until the stack overflows. `TestSuperFromDefinedClass`
  rejects it.
* **The web view is not the content view.** A plain `NSView` is, holding the
  web view and, with vibrancy, an `NSVisualEffectView` behind it. WebKit
  docks the inspector next to the web view in its superview; were that the
  window's frame view, AppKit would draw a broken legacy title bar from then
  on. Liquid Glass is an `NSGlassEffectView` there instead, which shows
  what is under it in the window rather than behind it: an opaque window
  is made clear while it shows one, and so is the content view a rounded
  window's color went to (`clearForGlass`), the color given back once the
  glass goes.
* **Memory is managed by hand.** Objects created with `alloc`/`init` are owned
  (+1) and must be released; convenience constructors return autoreleased
  objects. Code that creates temporary objects runs inside `withPool`,
  which keeps the goroutine on its thread until it pops the pool: a pool
  belongs to the thread that pushed it, and a goroutine other than the
  main one, as those reading the bundle for `App.Name`, may otherwise
  resume on another thread, where popping it crashes.
  Delegates and windows are released with `autorelease` from
  `windowWillClose:` because AppKit still uses them while closing.
* **Blocks.** Completion handlers passed to Apple APIs are created with
  `objc.NewBlock` and released right after the call (the callee copies
  them). Blocks received from Apple (decision and completion handlers) are
  invoked with `callBlock`; when they are called later they are
  `_Block_copy`d first and released after use.
* **Coordinates.** AppKit's origin is the bottom-left of the primary screen;
  MyGo's is the top-left. `rectToMac`/`rectFromMac` convert.
* **Quitting.** Cmd+Q ends in `applicationShouldTerminate:`, which runs the
  core quit sequence and then stops the run loop so `App.Run` returns (the
  reply is `NSTerminateCancel`; AppKit never calls `exit`). Quit Apple Events
  (Dock > Quit, AppleScript, logout) are handled by our own handler installed
  in `applicationWillFinishLaunching:`, so senders get a success reply, or
  error -128 when a listener cancels.

### Linux (`internal/linux`)

* `ffi.go` `dlopen`s GLib, GObject, GIO, GDK, GTK 3, cairo, GdkPixbuf
  and, when installed, AppIndicator. WebKitGTK 4.1 (4.0), JavaScriptCore
  and libsoup 3 (2.4), which only windows showing web pages need, load
  with the first such window (`webKit`), or to clear browsing data: an app
  that shows only native UI never maps them and the 75 or so libraries
  they bring, some 7 MB and 20 ms of startup. Without them, `errWebKit`
  says what to install when such a window is created. Symbols from newer
  WebKitGTK versions are bound optionally and feature-detected
  (`webkitWebViewCallAsyncJavascriptFunction != nil`).
* Signals are connected with `g_signal_connect_data`, passing the window id as
  user data; `Backend.window(data)` resolves it and ignores closed windows.
  GDK event structs are read at fixed 64-bit offsets (`field[T]`).
* The main thread is the one that called `gtk_init_check`; `IsMainThread`
  compares `gettid`. `Step` is `g_main_context_iteration(NULL, TRUE)` and
  `Wake` is `g_main_context_wakeup`.
* `Init` names the program after its executable (`g_set_prgname`) before
  `gtk_init_check`, which would name it after `argv[0]`: GTK names the
  class of the windows and the app id after the program, as the desktop
  entry does (`StartupWMClass`), and WebKitGTK the directories of the
  pages' data. Started through a link of another name, as `linux.command`
  puts in `/usr/bin`, the app is then the same program.
* `Bounds` are those of the frame a reparenting X11 window manager puts
  around the window (`gdk_window_get_frame_extents`): GTK positions the
  frame (NORTH_WEST gravity) and sizes the window inside it, without the
  frame. `ContentBounds` are where the content widget is
  (`gdk_window_get_origin` plus its offset below the menu bar). The
  frame's extents are known once the window manager framed the window
  that shows, which its first synthetic configure report tells; until
  then a window expects the frame it had, or the one seen last around a
  decorated window that is resizable or not as it is (openbox: 1, 20, 1
  and 5 px at the bottom, or 1). Wayland has no frame in `Bounds`.
* GTK geometry changes are asynchronous: `SetBounds` remembers the requested
  rectangle, within the sizes GTK gives the window (`constrain`), with the
  frame it expects, as does a window about to show, which X has where GTK
  created it, or where it was, until the window manager places it;
  `Center` moves that rectangle along. `Bounds` reports that rectangle
  until a configure event reports its size and, on X11, its position, or
  the window manager's own (synthetic) report of the size comes, or
  another size, which the window manager or the user chose. A window being
  placed waits for the window manager's report: a reparenting one first
  puts its frame where it created it. If the frame is not the one
  expected, the rectangle grows with it around the size asked for inside
  it (`SetContentBounds`, `UseContentSize`, a window that showed before),
  or GTK is asked for the size inside the new frame. A report of the
  previous size was sent before the window manager took the request
  (openbox sends one when the size hints change); GTK would ask for that
  size again from it, so the backend asks for the new one again.
* On Wayland, the configure event that activates a window can carry the
  size of the last buffer it drew, from before a resize GTK already took
  (Mutter sends one when native UI drawing with GL resizes from its first
  frames), and GTK goes back to that size. So a window drawing with GL
  keeps the latest bounds asked for while it is not focused, and once it
  is, an idle callback asks for them again if the window went back to the
  size it had, unless it is maximized, full screen or tiled. GTK skips a
  request for the size it asked for last: the callback first takes the
  configure and asks for the size the window has.
* A window the user cannot resize is never smaller than its default size,
  which `SetBounds` sets too, and `SetResizable(false)` to the size it has,
  or than its natural size, which GTK makes 200x200 when the window's child
  has none, as the web view: the box around the web view asks for 1x1.
* On Wayland, GTK decorates a frameless window, or one with a hidden title
  bar, itself (`useCSD`): `gtk_window_set_titlebar` with a `GtkBox` that
  never shows gives it client-side decorations without a title bar, so GTK
  draws its shadow and border around the page, resizes the window from
  them, and drops them while the window is maximized or in full screen.
  GTK sizes the window without them (`gtk_window_get_size`, the default
  size, the geometry hints), so the page keeps the size asked for, and
  Wayland has no positions they would shift. A window with `DisableShadow`,
  a transparent one (the decorations would outline the rectangle around a
  page that shows its own shape; GTK draws them on an app-paintable window
  too), panels and flyouts, a hidden title bar on a compositor that
  decorates windows itself, and every window on X11 stay undecorated
  (`gtk_window_set_decorated`): an X11 window that decorates itself has
  its shadow inside its X window, which the frame extents that `Bounds`
  counts do not tell, and Mutter puts its own shadow around opaque
  undecorated windows there. GTK styles the decorations once, so the
  shadow comes with the window: `SetHasShadow` changes nothing on Linux.
* GTK gives windows without decorations no resize borders, so the outer
  5 px of the page of an undecorated frameless window, or one with a
  hidden title bar, resize it (16 px along the edges from a corner resize the corner). The web view's `motion-notify-event` shows
  a resize cursor there, keeping WebKit's cursor to restore, and its
  `button-press-event` calls `gtk_window_begin_resize_drag` with the press,
  as a Wayland compositor requires; neither event reaches WebKit. Nothing
  resizes a maximized or full screen window, and a tiled one only resizes
  at the edges the window manager allows, as with GTK's own decorations.
* `gtk_window_realize` announces server-side decorations to a Wayland
  compositor that speaks `org_kde_kwin_server_decoration` (KWin, COSMIC,
  Sway) for every window GTK does not decorate itself, one without
  decorations too, and the compositor draws its title bar on it. A
  frameless window GTK does not decorate itself is realized before it
  shows and announced client-side
  instead (`gdk_wayland_window_announce_csd`, looked up at startup): GDK
  keeps that for the `GdkWindow` and requests it again whenever the window
  maps or the compositor answers with another mode, so the window gets no
  title bar unless the compositor decorates every window. Without the
  protocol (Mutter), or on X11, which reads the hint of
  `gtk_window_set_decorated`, nothing decorates the window anyway.
* A hidden title bar (`titlebar.go`) is a window without decorations whose
  web view is in a `GtkOverlay`, under a `GtkHeaderBar` for each side of
  `gtk-decoration-layout` that names window buttons. Each bar shows only
  that side's minimize, maximize and close (`decoration-layout`), and CSS
  clears its background and, with `TitleBarHeight`, its minimum height.
  GTK makes the buttons (they need the bar inside a `GtkWindow`) and hides
  those the window cannot use, and they act as a header bar's: iconify,
  toggle maximized, close. The bars are measured before the web view
  exists, from their natural size, for the script that tells the first
  page, then from their allocations; a change of the layout setting
  rebuilds them. A Wayland compositor that decorates windows itself
  (`gdk_wayland_display_prefers_ssd`: the default mode of
  `org_kde_kwin_server_decoration_manager`, server on KWin, Hyprland and
  Sway) gets no bars: such a window keeps GTK's announcement of server-side
  decorations, unlike a frameless one, so the compositor's title bar, or a
  tiling compositor's lack of one, stands for the buttons, whatever the
  layout says.
* The app's GTK style sheet (`Theme.SetGTKCSS`, `style.go`) is a
  `GtkCssProvider` of its own for the default screen, at
  `GTK_STYLE_PROVIDER_PRIORITY_USER`: GTK 3 looks providers up from the
  highest priority, and among equal ones from the last added, so it wins
  over the theme, MyGo's own provider (600) and the user's `gtk.css`.
  Each sheet loads into a new provider, which replaces the one before only
  once it parsed (`gtk_css_provider_load_from_data` with a `GError`, which
  takes GTK's first parse error instead of a warning). The core reaches it
  through `platform.StyleBackend`, which only Linux and the fake backend
  implement, so apps that never set a sheet do not link it; one set on the
  main goroutine before `Run` waits in `pendingGTKCSS` until `Init`.
* `WEBKIT_DISABLE_DMABUF_RENDERER=1` is set before GTK starts unless the
  user set it, which avoids blank webviews on NVIDIA drivers, VMs and
  containers, at the cost of drawing pages on the CPU. `App.SetDMABUFRenderer`
  (`AppOptions.DMABUFRenderer`) leaves it unset: always (`on`), or where
  `dmabufSafe` (`dmabuf.go`) finds Wayland and a GPU of Mesa's outside
  containers and virtual machines (`auto`, whose call links that probe in
  with `LinkDMABUFProbe`).
* XDG desktop portal calls go through `portalCall` (`portal.go`), which
  first registers the app's ID, the name of its desktop entry, with
  `org.freedesktop.host.portal.Registry`: the portal only accepts that
  before any other call, and needs it for apps outside a sandbox that the
  desktop did not launch. Methods that may involve the user answer with a
  `Response` signal on a request object; `portalRequest` routes it to a
  callback by the object's path.
* On Wayland, where apps grab no keys, global shortcuts go through the
  `GlobalShortcuts` portal (`hotkey_portal.go`). A session binds its
  shortcuts once, so every change closes the session and creates one that
  binds them all; the ids are canonical accelerators and the session token
  is named after the app, so desktops keep the keys the user picked. The
  portal may ask the user to confirm new shortcuts and needs the app's ID
  (portals from 1.21 refuse without it), so the app must be installed.
  KDE Plasma 5 binds the shortcuts listed in `CreateSession`'s options, as
  the portal's drafts had it: portals before 1.17 pass them on, later ones
  drop them and Plasma 5 then binds nothing; MyGo logs the shortcuts the
  desktop bound no keys to. The activation token of an `Activated` signal
  becomes the display's startup notification id while the callback runs,
  so the window it shows or focuses may take the focus.

#### Why not GTK 4

The backend uses GTK 3 because a GTK 4 backend would do less, run on
fewer systems and give apps nothing they lack on GTK 3, at the cost of
rewriting most of `internal/linux`.

**It would do less.** Some of what MyGo's API promises has no GTK 4
counterpart, not even a renamed one:

* **Window placement.** GTK 4 has no `gtk_window_move`,
  `gtk_window_get_position`, `gtk_window_set_position` or
  `gdk_window_get_frame_extents`, on X11 too: an app cannot put a window
  anywhere or ask where it is. `Bounds`, `SetBounds`, `Center` and the
  frame handling above rest on them, and flyouts are anchored to a
  rectangle with `gdk_window_move_to_rect`, of a `GdkWindow` GTK 4 has no
  more.
* **Window hints.** `gtk_window_set_keep_above`,
  `gtk_window_set_skip_taskbar_hint` and `gtk_window_set_type_hint` are
  gone: no always on top, no windows kept out of the taskbar, no utility
  or popup menu windows for flyouts and panels.
* **Tray icons.** AppIndicator, which draws them, takes a `GtkMenu`,
  which GTK 4 removed with `GtkMenuBar`, and has no GTK 4 version: the
  backend would serve StatusNotifierItem and dbusmenu over D-Bus itself.

Only X11 could get placement and hints back, through Xlib and EWMH beside
GTK (`XMoveWindow`, `_NET_WM_STATE_ABOVE`, `_NET_WM_STATE_SKIP_TASKBAR`),
and GTK 4.18 deprecated its X11 backend, to be removed in GTK 5: a
GTK 4 backend would rest those features on what GTK is dropping. Wayland is no
reason to move either: no GTK version places windows there.

**It would run on fewer systems.** GTK 4 replaced ATK, which native UI's
accessible tree implements (`surface_access.go`) and GTK 3 bridges to
AT-SPI, with `GtkAccessible`, and only GTK 4.14 lets an app expose text it
draws itself (`GtkAccessibleText`), which screen readers need to read
native UI's text fields and editors. Ubuntu 22.04 ships GTK 4.6 and
Debian 12 GTK 4.8, both still supported, where GTK 3 gives native UI the
same accessibility as everywhere else. GTK 4 also means WebKitGTK 6.0,
which replaces 4.1 and 4.0 rather than adding to them, so apps could no
longer fall back to the WebKitGTK 4.0 of older distributions.

**It would give apps nothing.** A MyGo window shows a web page or native
UI, which MyGo draws itself; GTK's own widgets show only in title bar
buttons, menus and dialogs. WebKitGTK 6.0 is the same WebKit as 4.1,
built from the same releases, so pages render and behave the same.

**And it would cost the rewrite.** Beyond the above, GTK 4 replaced the
`button-press-event`, `motion-notify-event`, `key-press-event` and
`configure-event` signals with event controllers and made `GdkEvent`
opaque, where the backend reads its fields at fixed offsets (`field[T]`);
removed `gtk_widget_event`, which hands Tab to the web view, and
`GtkLayout`, which holds the web views over native UI; turned
`GtkClipboard` and `gtk_drag_*` into `GdkClipboard` and
`GtkDragSource`/`GtkDropTarget`; made menus `GMenuModel`s in popovers; and
removed `gtk_dialog_run` and `gtk_native_dialog_run`, which run the main
loop until a message or file dialog is answered so that the call that
opened it returns the answer. The window manager quirks the bounds
handling above works around would have to be found again on GTK 4, across
the same X11 window managers and Wayland compositors.

GTK 3 is still maintained, installed on every desktop MyGo targets, and
what WebKitGTK 4.1, AppIndicator and gtk-layer-shell are built against.
The trade turns once WebKitGTK stops releasing 4.1, GTK 3 leaves the
distributions apps ship to, or those that are still supported all have
GTK 4.14: then a GTK 4 backend loses nothing GTK 3 still gives, and the
features GTK 4 lacks become X11-only code beside it.

### Windows (`internal/windows`)

* Win32 is called through `syscall` (`LazyDLL` procs; system DLLs are loaded
  by absolute path from the system directory). `IsMainThread` compares the
  thread id recorded during package initialization. The loop is
  `GetMessageW`; `Signal` and `Wake` post messages to a hidden top-level
  application window, which also receives tray, hot key, theme
  (`WM_SETTINGCHANGE`) and display broadcasts. `Quit` posts `WM_QUIT`, which
  modal loops (dialogs, menus) forward, so quitting works while they run.
* **COM.** `comCall` calls vtable methods; its indices come from
  `WebView2.h` (constants in `webview2.go`). Handler objects (event and
  completion handlers) share one vtable whose callbacks are created once and
  route `Invoke` to a Go function per object; the objects live in a map until
  COM releases them. Call wrappers are `go:uintptrescapes`, so
  `uintptr(unsafe.Pointer(&x))` arguments stay valid.
* **WebView2 without a loader DLL.** `createEnvironment` finds the Evergreen
  runtime in the registry (`EdgeUpdate\ClientState\<channel>\EBWebView`)
  and calls `CreateWebViewEnvironmentWithOptionsInternal` of its
  `EmbeddedBrowserWebView.dll`, as `WebView2Loader.dll` does; a loader next to
  the executable wins. `internal/webview2` finds the runtime, for the backend
  and for `mygo doctor`: a directory holding that library for this
  architecture and the browser process `msedgewebview2.exe` at its root (the
  library alone is the Edge browser's, whose environments fail with
  `ERROR_NOT_SUPPORTED`), and EdgeUpdate's record of a runtime outlives its
  files. The first window that shows a web page starts
  the environment (`startEnvironment`), and fails without a runtime: windows
  that show native UI need none, so an app whose windows all do runs
  without WebView2. The environment and each controller are created
  asynchronously: window methods that need the webview wait in `pending`.
  A creation that fails is tried again, three times in all, a second
  then two apart, as Microsoft advises unless it failed with
  `ERROR_INVALID_STATE`: under load, WebView2 fails some with `ERROR_BUSY`
  or `CO_E_SERVER_EXEC_FAILURE`. When the webview never comes, the calls
  that report a result (Eval, CapturePage, PrintToPDF) get the reason, as
  later ones do: the window closed, or WebView2 could not create it.
  User data lives in `%LOCALAPPDATA%\<name>\WebView2`. The direct path applies
  `WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS` and `WEBVIEW2_USER_DATA_FOLDER` as
  the loader does; it does not read the channel variables or policy keys.
* **Custom schemes** load from `http://<scheme>.localhost/`, and their
  other hosts from `http://<host>.<scheme>.localhost/` (`internal/schemehost`:
  hosts of DNS labels, lower-cased, without a port), which WebView2
  lets the app answer through `WebResourceRequested`. Chromium treats
  `*.localhost` as a secure origin, and unlike `https`, `http` blocks no
  mixed content, so pages reach `ws://` and `http://` URLs as with the
  custom schemes of the other backends. The backend maps URLs both ways, so
  the core only sees `<scheme>://<host>/`.
  See "Custom protocols" for how responses reach WebView2. `LoadHTML`
  with a base URL serves the document from that URL the same way.
* **Eval** goes through the DevTools protocol (`Runtime.evaluate` with
  `awaitPromise`), which reports syntax errors and ignores the page's CSP.
  Edit roles run `document.execCommand` with a user gesture, except Paste:
  `Input.dispatchKeyEvent` carries Chromium's `paste` command on an
  `Unidentified` raw key-down, followed by key-up once it completes. The
  page sees these events without modifiers, avoiding its Ctrl+V handlers,
  and a paste event with the clipboard's formats. The controller gets
  focus first, after the menu closes. Paste and Match Style still inserts
  the clipboard's text with `Input.insertText`.
* Scripts injected at document creation run in every frame, so the
  main-frame-only ones (the bridge) are wrapped in `window === window.top`.
  Iframes get no `chrome.webview` handler.
* **ABI.** On x64, structs over 8 bytes are passed by reference and Go
  mirrors the first integer arguments into the XMM registers, so doubles can
  be passed as bits. On ARM64, 16-byte structs travel in two registers and
  `syscall` cannot pass floats, so zoom falls back to CSS (`abi_*.go`);
  `comCallFloat` calls methods taking a double through purego instead,
  as `put_Expires` of cookies. Go callbacks read only integer registers:
  the two methods of UI Automation that take doubles enter through thunks
  in assembly (`uia_*.s`), which move the doubles' bits to the integer
  registers of their positions, touching only registers a call may
  change, and jump to the callbacks.
* DPI: the process is per-monitor aware (v2); the backend converts sizes
  between pixels and DIPs with the window's or monitor's DPI, and points
  and rectangles of the screen (windows' bounds, the displays, the cursor,
  tray icons) through one space of DIPs in which displays never overlap
  and a point names one display (`dipSpace`, in `dips.go`, which builds
  on every platform for its tests): a display's DIPs start at its
  top-left pixel scaled by the smallest scale of the displays, as Qt
  anchors them at that pixel, and go on in its own scale. The primary
  display's DIPs, and those of displays that all have one scale, are the
  screen's pixels at that scale. A window takes the scale of the display
  it is the most on, whose DPI Windows gives it; it is created on its
  display, at its rectangle, and `place` moves it, keeping its rectangle
  in `WM_DPICHANGED`, whose suggested one would scale the size, already
  in the new display's scale, a second time (#1039). Frameless windows, and
  those with a hidden title bar, drop the caption in `WM_NCCALCSIZE` but
  keep the side and bottom borders, which Windows 10+ draws invisibly
  outside the window, so they still resize. On Windows 11 a hidden title
  bar keeps one pixel of its top, under the window's border, without which
  the maximize button opens no snap layouts while the window is not
  maximized. Windows 10, which has no snap layouts, keeps none: over a
  window that keeps any of its top it draws its whole title bar. A
  resizable frameless window on Windows 10 takes the visible pixel of its
  borders into its client area too, where the content covers the line DWM
  draws there, white whatever the content (#916), and its frame is not
  extended for the shadow, which its invisible borders cast: extended, it
  shows as a white line along the top. Other windows without a caption
  extend it by a pixel, without which a window with no borders has no
  shadow. The build comes from `RtlGetVersion`, which no manifest changes.
* The top edge of a window without a caption (`topedge.go`), which
  `WM_NCCALCSIZE` gives to the client area, where the webview's or the
  surface's window answers `HTCLIENT`, is a child window above them: a
  layered window without a bitmap (`WS_EX_NOREDIRECTIONBITMAP`), as tall
  as the sizing frame, that answers `HTTOP`, and `HTTOPLEFT` and
  `HTTOPRIGHT` near the corners it reaches, and sends the window's presses
  on, so it resizes; Windows Terminal's caption works the same way. Below
  it, `--app-region: drag` still moves the window. It spans a frameless
  window and stops at a hidden title bar's buttons, and hides while the
  window is maximized, in full screen or not resizable.
* A hidden title bar (`titlebar.go`) gets its controls from a child window
  above the webview's, beside the top edge. The buttons are a layered
  window (`UpdateLayeredWindow`, premultiplied BGRA): Segoe Fluent Icons
  glyphs (Segoe MDL2 Assets on Windows 10) drawn white on black with GDI
  give their coverage, over backplates of Chromium's alphas. It answers
  `WM_NCHITTEST` with `HTMINBUTTON`, `HTMAXBUTTON` and `HTCLOSE`, passes
  `WM_NCMOUSEMOVE` to `DefWindowProc`, which opens Windows 11's snap
  layouts over maximize, and runs the buttons itself from the non-client
  button messages, sending the window `WM_SYSCOMMAND`. The webview's
  window is created later, so the controls and the top edge go back to the
  top of the z-order when it appears. A window without a caption has no
  room for its menu bar: Alt and F10 open a popup holding the bar's own
  submenus.
* **Menus** are Win32's (`menu.go`). Popup menus follow the appearance
  through uxtheme's preferred app mode (ordinal 135); the menu bar follows
  nothing, so the window draws it, and covers the light line below it when
  dark, from the UAH messages menus send their window (`darkmenu.go`).
  Windows 11 still draws Win32 menus as Windows 10 did, so there MyGo draws
  the items in the style of its own menus (WinUI's `MenuFlyout`, File
  Explorer's), in either appearance (`menudraw.go`): popup items are
  owner-drawn (`MFT_OWNERDRAW`, measured and drawn in `WM_MEASUREITEM` and
  `WM_DRAWITEM` of the window the menu shows for, or of the application
  window for trays), each into a bitmap with its highlight's rounded
  corners antialiased, then copied, and excluded from the DC after, which
  keeps Windows from drawing the submenus' arrows over the chevrons;
  `WM_INITMENUPOPUP` gives the menu the background of the items. Windows
  widens every owner-drawn item past the width it asks for, by as much as
  it doesn't tell (not `SM_CXMENUCHECK`, #922): items ask for all they need
  until one draws, whose width less the widest asked for in its menu is
  that widening at the DPI, and for that much less after. Labels are
  measured by their advance and drawn unclipped (`DT_NOCLIP`), into the
  item's padding where their ink reaches past it (Microsoft YaHei UI,
  Chinese Windows' menu font, by a pixel, #1028). The items
  keep their strings, which mnemonics, screen readers and the tests read.
  A menu with owner-drawn items loses Windows 11's frame, its window square
  under its class's drop shadow (`CS_DROPSHADOW`) along two sides: while
  menus show (`WM_ENTERMENULOOP` to `WM_EXITMENULOOP`, and around
  `TrackPopupMenuEx`, which creates its window before), a `WH_CALLWNDPROC`
  hook of the main thread rounds the windows of class `#32768` in their
  `WM_CREATE` (`DWMWCP_ROUND`, WinUI's 8 pixels), gives them one outline
  (`DWMWA_BORDER_COLOR`: a pixel of WinUI's `SurfaceStrokeColorFlyout`
  over the menu's background, `#00000019` in the light appearance and
  `#FFFFFF19` in the dark, a color of its own rather than the accent) and
  takes the shadow off the class, for DWM's around the window. It also
  subclasses them: on Windows 11 22H2 with transparency effects on, no
  contrast theme, energy saver off, outside remote sessions and with a
  GPU (`glassConditions`: DWM draws no material when the first DXGI
  adapter is Microsoft's Basic Render Driver or a software one, unless
  its `ForceEffectMode` policy is 2), a window that says (`MN_GETHMENU`, before it shows
  or paints) that it shows a menu MyGo draws gets Acrylic
  (`DWMSBT_TRANSIENTWINDOW`, in the appearance through
  `DWMWA_USE_IMMERSIVE_DARK_MODE`) with the frame extended over all of
  it, and is framed active (`WM_NCACTIVATE` to `DefWindowProc` as active
  with an lParam of -1, again once shown and whatever it is told after,
  as Firefox's popups with Acrylic are): DWM draws a system backdrop as a
  flat grey in a window it frames inactive, as a menu's window, never
  activated, otherwise is. Its background brush turns black, which DWM
  shows as transparent, its border too (`WM_NCPAINT`, and `WM_PRINT` for
  animations), and its items wear the veil of WinUI's Acrylic tint over
  the material: the fallback color at the opacity of its luminosity layer
  (`acrylicLuminosity`, 85% in either appearance), so that a menu is as
  light as the shell's flyouts over a dark desktop, the material showing
  a seventh of the way through, and the highlights and separators are
  WinUI's translucent fills over it, their rounded corners leaving DWM's
  window to show. The labels, the shortcuts and the icons go over the
  veil's own color, opaque, and once: what shows is the text as GDI draws
  it on the color the shell's menus draw theirs on, its ClearType
  blending with it, rather than the grayscale antialiasing of text drawn
  over black and over white for unblend to tell its alpha, and the pixels
  GDI leaves no alpha to take the item's. A window that shows another
  menu, as Windows' window menu, stays as it is, and so do its items.
  Elsewhere a menu MyGo draws has WinUI's solid background, the fallback
  of its Acrylic (`#F9F9F9`, dark `#2C2C2C`), its window's own border
  painted in it, for that one outline to be the menu's only border. Tray
  menus open on Windows 11 as the system's do, centered on the icon 12
  DIPs from the taskbar (`ABM_GETTASKBARPOS`, aligned by
  `TrackPopupMenuEx` and kept off the taskbar by its `rcExclude`), and at
  the pointer on Windows 10 or for an icon not on the taskbar.
  The bar grows from `WM_UAHMEASUREMENUITEM` and its items get inset
  backplates with rounded corners. A contrast theme keeps the system's
  colors: the bar is Windows' again, the popup items take the system's.
  Windows 10 keeps its menus.
* **Vibrancy** sets `DWMWA_SYSTEMBACKDROP_TYPE` (Windows 11 22H2) and
  extends the frame over the client area, behind a transparent webview or
  native UI.
  The material shows only in a window created without a redirection
  bitmap (`WS_EX_NOREDIRECTIONBITMAP`, which Windows neither adds nor
  removes later), whose opaque surface would cover it, so `SetVibrancy`
  shows one only in windows created with `Vibrancy`. A transparent window
  of native UI (`Transparent` with `Content`) is created without one too,
  as a flyout is, where DirectComposition is available: what its frames
  leave transparent shows what is behind the window. Such a window shows
  nothing GDI draws: it has no menu bar, like a window without a caption,
  and the buttons of its hidden title bar, layered without a bitmap too,
  show their pixels through DirectComposition (`compositor.go`), on a
  Direct3D 11 device the windows share (`internal/gpu/d3d11/device`,
  which links none of the renderer). A device found invalid after a
  failed draw, or whose GPU device signals its removed event
  (`ID3D11Device4::RegisterDeviceRemovedEvent`, waited for by a
  goroutine), is made again, and every window's buttons draw again;
  buttons that could not draw retry on a timer of the application
  window, a second later and longer after each failure in a row. Without
  DirectComposition, a window with a hidden title bar or native UI keeps
  its bitmap: what it draws shows, and the material does not. Native UI
  there draws on the GPU into a swap chain for composition, premultiplied
  by its alpha (`d3d11.NewComposed`), on a DirectComposition device of the
  renderer's own, and its frames drawn in memory show as the window
  controls do. A renderer about to draw takes the surface's window over
  from those (`Surface.Native`): a window has one DirectComposition target
  at most. `ui.Context.Vibrancy` tells the view whether the material shows
  (`platform.MaterialSurface`).
* Message boxes are task dialogs (comctl32 v6, activated from shell32's
  manifest for executables without one); their structs are packed and laid
  out by hand. Notifications are notification-area balloons, which Windows
  10+ shows as toasts.

### Browsers (`internal/web`)

With `GOOS=js GOARCH=wasm`, `backend_js.go` picks `internal/web`, which
shows windows of native UI (`WindowOptions.Surface`) on a page; windows of
web pages, menus, trays, notifications, global shortcuts and file dialogs
report `errUnsupported` or do nothing, as the browser has nothing to stand
for them. Building for browsers adds nothing to desktop builds: the
backend, `load_js.go` and `canvas_js.go` are `js` only, and the contract
gained one field, `SurfaceNative.Canvas`.

* **Size.** What only web pages use would make most of a build for
  browsers, which servers send whole (Cloudflare's static files are at
  most 25 MiB): the root's files for pages leave it out. `ipc.go`,
  `channel.go`, `bridge.go` (what windows say to the bridge: its script,
  messages, `Eval`), `protocol.go` (custom schemes, the frontend's, their
  downloads), `typescript.go`, `updater.go` (and `relaunchNow`),
  `single_instance.go`, `window_state.go` and `random.go` have twins
  (`_js.go`) that keep their API and do nothing, or report that there is
  no page, without the packages they need: net/http, net, crypto,
  encoding/json, internal/tsgen with go/parser, internal/update. Only
  `Protocol.Handle`, `HandleFunc` and `FileServer`, which take net/http's
  types, are missing there. `Bind` binds nothing, so nothing calls
  `reflect.Value.Method`, which would make the linker keep every exported
  method of every type in an interface. `internal/platform` takes an
  `http.Header` as its type, `map[string][]string`, so that ui does not
  import net/http either (importing it alone adds 2.3 MB), and
  `gpu.SourceSum`, for shaders compiled ahead of time, is not built for
  browsers, with crypto/sha256. The root's tests and `internal/e2e` are
  for desktops. What stays is mostly the runtime, ui and its packages,
  and the image codecs (`ui.Image`): `website/docs-demo` comes to about
  9.8 MB (2.6 MB with gzip).

* **Threading.** Go's main goroutine, which calls `Run`, is the main
  thread, told by its goroutine ID as `internal/fake` does. JavaScript
  calls Go's functions (`js.FuncOf`) on goroutines of their own, while
  the browser's event loop waits: `Backend.sync` hands the event to the
  main goroutine through `tasks` and waits for it, so that a handler can
  still call `preventDefault`. A callback that a call from Go to
  JavaScript sets off (a `focus()` firing `focus`) runs on the calling
  goroutine, the main one, and so runs at once. `Step`, for nested loops
  (`await`, `PopupMenu`), takes tasks as `Run` does, so the browser's
  events go on meanwhile; a nested loop must not start in a task, whose
  callback holds the browser's event loop, but from `Dispatch`.

* **Windows** are elements of class `mygo-window` filling the element with
  the ID `mygo`, or else the page, each holding a canvas and a textarea.
  The page sets their size; `Bounds` reads the element's. The surface's
  size is the canvas's CSS size (DIPs) and `devicePixelRatio`, which a
  `ResizeObserver` and the window's `resize` watch; its backing store is
  set before each frame to the frame's size, `ceil(width × scale)` as
  package ui computes it. `RequestFrame` asks `requestAnimationFrame`;
  `Occluded` is `document.hidden`, where browsers give no frames, and
  `visibilitychange` brings `SurfaceShown`, or `SurfaceHidden`.

* **Drawing.** The canvas's WebGL 2 context (`gl.NewContext`: premultiplied
  alpha, no depth, stencil or antialiasing) is current while a frame is
  handled, as a GtkGLArea's is in its render signal, and
  `SurfaceNative.Canvas` names it for `ui/gpu_js.go`. WebGL names its
  objects by JavaScript objects and GL by numbers: `load_js.go` numbers
  them (the number also a property of the object, which reads
  `FRAMEBUFFER_BINDING` back) and implements the GL functions `gl.go`
  calls on the current context, copying Go's bytes into one reused
  `Uint8Array` for uploads, which the pixel store's unpacking (tracked
  from `glPixelStorei`) sizes. With `WEBGL_blend_func_extended` the
  shader writes the second color as on desktops; without it (one color
  blended) subpixel glyphs could not draw, which browsers' text never
  has. A lost context is kept (`preventDefault`) and, once restored,
  renumbered (`Context.Renew`), which makes the renderer start over.
  Where the browser has no WebGL 2, the canvas takes a 2D context and
  `PresentPixels` puts the frames drawn in memory into an `ImageData`.

* **Text** (`internal/text/canvas_js.go`) is the browser's: a 2D context
  measures and draws it, so that it finds fonts, falls back and shapes as
  for pages. Canvases give widths, not glyphs: the engine's glyphs are
  grapheme clusters (go-text's segmenter), each ending where the text of
  its word through it ends and starting its own width before, so that the
  word's kerning moves the cluster it applies to; they are drawn alone,
  with the font at the size they were measured at and the canvas scaled
  (at the pixels' size the system's font may take another optical size,
  as SF Pro Display for Text, whose glyphs the advances would not fit),
  their coverage read back (`getImageData` of a `willReadFrequently`
  context) and cropped to the ink. A line of text draws as the browser's
  `fillText` draws it whole, pixel for pixel. Fonts are shaded: a glyph is
  drawn in a gray of its text's shade, as Chrome's text, like AppKit's,
  is bolder the lighter its color (dark text drawn with white glyphs looks
  too bold), Thick in white; emoji take an unshaded twin of their font.
  Runs of scripts whose letters join or reorder (Arabic, the scripts of
  India, Thai, …) are one glyph each, shaped whole. Lines break at
  UAX #14's opportunities, and go-text's bidi package gives runs' levels,
  which the engine reorders (UAX #9's L2). Glyph IDs number the clusters'
  texts. Glyphs blend in turn (`join` false), at quarter-pixel positions,
  as Skia draws them. Chrome picks the optical size of the system font
  inconsistently between pages and canvases, so text of native UI can be
  wider or narrower than a page's in the same font.

* **Input.** Pointer events (captured on press) are the pointer, with
  clicks counted from presses close in time and place, buttons 3 and 4
  the back and forward keys. Those of a pointer that is not the primary
  one (`isPrimary`), as a second finger, are left out, as no second finger
  presses on the desktops; a button going down or up while another is
  held, which comes as a `pointermove` with its `button`, is a
  `PointerDown` or `PointerUp` as on the desktops (`chord`); their
  `pointerType` and `pressure` are the device and the pressure
  (`device`). `pointercancel`, the browser taking the pointer, as a touch
  it scrolls the page with, is a `PointerCancel`, not a release. `wheel` events scroll, lines and pages
  turned into DIPs, notches of 120 not `Precise`. The textarea, out of
  sight at the caret (`SetTextInput`), has the keyboard: `keydown` and
  `keyup` are keys, by what they type (`key`) and else by where they are
  (`code`); `beforeinput` brings typed text, which it cancels so that the
  textarea stays empty; composition events are the input method's. The
  browser keeps its defaults for keys that type, its own keys (F5, F11,
  F12) and those copying and pasting: the content copies on the key and
  the `copy` event that follows carries its text (the backend's
  clipboard) to the system's, while the clipboard's text comes with
  `paste`, which then sends the paste command. On a Mac, Command is
  `ModCtrl` and Control `ModSuper`, as package ui takes browsers for
  another system than macOS.

* **Files dropped** (`files.go`): `dragover` on the canvas, with files,
  is `FileDragOver`, whose answer is the `dropEffect`, and the browser's
  default (opening the file, leaving the app) is always prevented; a
  `drop` reads the files' bytes (`arrayBuffer`, settled together; folders
  have none) before `FileDrop` gives their paths, `/mygo-drop/<n>/<name>`.
  Go's syscall package calls the `fs` object of `wasm_exec.js`, whose
  functions fail in browsers: the backend wraps `open`, `read`, `fstat`,
  `close`, `stat`, `lstat` and `readdir` to answer for those paths,
  synchronously, as an app reads a drop in its handler, while the browser
  waits on the callback that sent the drop, and passes other paths on.

* **Context menus** (`PopupMenu`) are HTML, styled as macOS's, in a nested
  loop until an item is chosen, a press lands elsewhere, Escape is pressed
  or the page loses focus; the choice goes to `MenuItemClicked`.

* **Themes**: `IsDark` and `Preferences` read `matchMedia`, whose changes
  call `ThemeChanged`; the root's `data-mygo-theme` (watched by a
  `MutationObserver`) chooses the appearance over the media's. `ShowMessageBox` uses `alert` and `confirm`.

* **History** (`ui/router_js.go`): the first `ui.Router` a window (not a
  `Tester`) shows claims the tab's history, through hooks the router calls
  (`browserHistory`, nil elsewhere). Its location goes in the URL's
  fragment and the number of its entry (`Router.base + at`, `base`
  counting the entries dropped past `maxHistory`) in `history.state`:
  `Push` is `pushState`, `Replace` `replaceState`, `Go` `history.go`,
  whose `popstate` finds the router there already. A `popstate` of the
  browser's own buttons goes to the entry of its number; one just before
  the router's first or after its last, as after a reload (which takes
  the number of the browser's entry for the router's), becomes the
  router's; a fragment typed in, without a state, is pushed.

## IPC

### The page runtime (`packages/bridge` → `internal/bridge/bridge.js`)

`packages/bridge/src/bridge.ts` is bundled by Bun into an IIFE
and committed, so building an app never needs Bun. The core wraps it with the
window's configuration (`bridge.Script`) and every backend injects it at
document start into the main frame. It installs:

* `window.mygo`: `call(method, ...args)`, `on(event, fn)`, `once`, the
  `window` controls (`minimize`, `toggleMaximize`, `close`, …), `platform`,
  `windowId`, `version`. Frozen, so pages cannot tamper with it.

* `window.__mygo.receive(messages)`, used by Go to deliver messages.

* dom-ready notification and `--app-region: drag` handling for frameless
  windows (the mousedown is reported, the backend starts a window drag
  from the recorded mouse event while the button is down).

* The `--mygo-titlebar-*` CSS variables of a window with a hidden title
  bar, in a constructed style sheet (a `<style>` element where engines
  lack them), from the `mygo:title-bar` event: the room its controls take
  (`Window.TitleBar` of the backend, in CSS pixels). Each backend delivers
  the event at document start, in a script after the bridge, so the first
  page lays out around the controls before it paints; the core sends it
  again when the room changes and once the DOM of any later page is ready.

* File drops (`Window.OnFileDrop`, `onFileDrop` in mygo-runtime). Unlike
  Tauri, whose native drop handler takes drops away from the page (on
  Windows, HTML5 drag and drop needs it turned off), MyGo leaves the page's
  drag and drop alone and reads the paths next to it. A capture listener on
  `drop` posts `{t:"drop", x, y}` when the drop carries files; the core then
  takes the paths the backend recorded just before the page saw the drop:
  `performDragOperation:` of the web view subclass (calling super) on
  macOS, `drag-data-received` then `drag-drop` (before WebKit's own
  handlers) on Linux, and on Windows the File objects the bridge posts with
  `postMessageWithAdditionalObjects` (`ICoreWebView2File.Path`), with
  WebView2's own drop handling left on. Drags that start in the page are
  ignored (`dragstart`/`dragend` tracking), and so are drops the page
  handles; where the page does not handle dragged files, bubbling
  `dragover`/`drop` listeners cancel them, so a drop reaches Go instead of
  the engine replacing the page with the file. Paths go to Go listeners and,
  as the `mygo:file-drop` event, to trusted pages only. Event names starting
  with `mygo:` are reserved.

* The page's theme color (`theme-color.ts`, `Page.ThemeColor`): the first
  `<meta name="theme-color">` of the head whose `media` matches and whose
  content is a color, which a canvas's `fillStyle` parses (a color it does
  not serialize as sRGB is drawn and read back), posted as
  `{t:"theme-color", v:"#rrggbbaa"}` (`""` for none) when it changes. A
  `MutationObserver` watches the head, not the body, so pages that change
  their body pay nothing, and `matchMedia` the metas' media, so a change of
  appearance picks another. Before DOMContentLoaded it posts only colors,
  then whatever it found, before dom-ready: the core keeps the previous
  page's color from the commit until then, so pages of the same color
  change nothing, and drops it at the load's end for a page that never
  told one (no bridge, as an image). The same in every engine: WKWebView's
  `themeColor` (macOS 12+) would need KVO, and WebView2 and WebKitGTK have
  none.

* Fitting a window to its content (`fit-content.ts`,
  `FlyoutOptions.FitContent`, `WindowOptions.FitContent`): the bridge
  configuration's `fit` (the limits, in the CSS pixels of the page's zoom,
  which `mygo:fit-content` updates as the zoom changes) adds
  `:where(:root){width:max-content;min-width;max-width;min-height}` to
  MyGo's style sheet, without specificity so that a page's own size for
  `html` wins, with the room of a vertical scrollbar left out of the
  widths while the content is taller than the maximum height. At DOMContentLoaded, before dom-ready, and then from a
  `ResizeObserver` on the root and the window's `resize` events, it posts
  `{t:"content-size", w, h, sw, sh}`, the root's border box and the
  scrollbars' room in CSS pixels, when it changes; `sh` only while the
  content is wider than the root (the body overflows), as at the maximum
  width. The core turns it into DIPs at the page's zoom (a fraction of a
  pixel takes one) and clamps it. The vertical scrollbar's room counts
  only where the content is taller than the window may be (its maximum
  height or the work area): the page shows one for a moment whenever the
  content grows before the window does, and counting it then would undo a
  size the user just gave the window. It resizes a
  flyout where it goes, or a window's content bounds, only in the
  dimension that changed and not while maximized or in full screen,
  within its display's work area; a size equal to the last it took does
  nothing, so a user's resize holds. The same in every engine: WebKit's
  private `-[WKWebView _setSizeToContentAutoSizeMaximumSize:]` is not
  used. A flyout of native UI fits without the bridge: its
  `surface.Conn` gets `FitWidth` (the width's limits and the work area's
  width, from the display the flyout is on) and `ContentSize`, through
  `fitContent.native`, which `NewFlyout` sets so that apps without such a
  flyout link none of the core's side, and
  `ui/fit.go` measures the root as each frame lays out, right after
  `layoutTree`: `contentWidth(root, true)` within those widths, and
  `contentHeight` at that width, the non-committing layout flex columns
  measure their items with, so percentages and `Grow` measure as their
  content, as `height: auto`; absolutely placed elements and the
  inspector take none of it. It tells a size only when it differs from
  the last it told, and the core clamps it as a page's (`fitNative`),
  then resizes and places the flyout after the frame (`postMain`, as the
  backends' resizes may send the surface events at once): the surface's
  `SurfaceResize` brings the frame laid out at the new size. A frame laid
  out at a new size that measures the size told before the last one
  holds, so that a view building its content after `Context.Size` does
  not resize the flyout back and forth. A hidden window draws no frames,
  so `Show` and `ShowInactive` of a hidden flyout first call
  `fitContent.show` (`fitBeforeShow`), which `NewFlyout` sets with
  `native`: where the content waits to draw a frame, `surface.Conn.Fit`
  builds and lays it out at once, as a capture does, and the flyout
  takes the size it measured before the platform shows it; the
  surface's next frame draws it at that size. `Fit` builds nothing
  within the content's frame or before its first, so the view never
  runs within `NewFlyout`.

* Find in page (`find.ts`, `Page.FindInPage`): the bridge walks the
  visible text nodes, marks matches with the CSS Custom Highlight API (a
  constructed style sheet, which a Content Security Policy allows) and
  scrolls to the active one; engines without the API get the active match
  selected instead. Being JavaScript, it works the same in every engine.

The transport is `window.webkit.messageHandlers.mygo.postMessage` on both
WebKit platforms and `window.chrome.webview.postMessage` on WebView2.

### The `mygo-runtime` package (`packages/runtime`)

Apps reach the injected runtime through the `mygo-runtime` npm package:
`call`, `on`/`once`, typed `event<T>(name)`, `currentWindow` controls,
`isMyGo`, `isCallError`, `runtime()` (which throws a helpful error outside a
MyGo window) and the public types (`Runtime`, `WindowControls`, `Platform`),
which the bridge shares. It holds no transport of its own: it delegates to
`window.mygo`, so the injected script stays the single implementation of the
protocol. The template depends on `^<version>` from npm, released in step
with the Go module.

### The `mygo-cli` package (`packages/cli`)

The CLI is also published to npm, so that projects pin it in package.json
and run it from their scripts. Like esbuild, each platform's binary is a
package of its own, `@egoist/mygo-cli-<os>-<cpu>` in `packages/cli/npm` (npm
takes unscoped names such as `mygo-cli-win32-x64` for spam), with `os`
and `cpu` fields; `mygo-cli` lists them all as optional dependencies, so
package managers install only the matching one, and its `bin/mygo.js`
resolves that package and replaces itself with the binary
(`process.execve` in Node.js 23.11 and later and in Bun; elsewhere it spawns
the binary, waits and passes its exit status on). `MYGO_CLI_BINARY` points
it at another build.

### Wire protocol

Page → Go (a JSON string per message, prefixed with the window's secret; see
Trust):

| message                                                                                          | meaning                                                                                                                                                       |
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `{"t":"call","id":N,"k":token,"m":"Service.Method","a":[...]}`                                   | call a bound method                                                                                                                                           |
| `{"t":"chan-ack","c":N,"k":token,"n":S}`                                                         | the page took the values of channel N up to the S-th                                                                                                          |
| `{"t":"chan-close","c":N,"k":token}`                                                             | the page closed channel N                                                                                                                                     |
| `{"t":"dom-ready"}`                                                                              | DOMContentLoaded fired                                                                                                                                        |
| `{"t":"theme-color","v":"#rrggbbaa"}`                                                            | the page's theme color changed; `""` for none                                                                                                                 |
| `{"t":"content-size","w":W,"h":H,"sw":SW,"sh":SH}`                                               | the size of the content of a window that fits it, and the room of its scrollbars, in CSS pixels                                                               |
| `{"t":"drag"}` / `{"t":"dblclick"}`                                                              | mousedown / double click on a drag region                                                                                                                     |
| `{"t":"context-menu","x":X,"y":Y,"l":link,"lt":text,"i":image,"m":media,"s":selection,"e":true}` | the page's `contextmenu` event, not cancelled, at X, Y in CSS pixels: what it opens on, empty parts left out (kept only while `OnContextMenu` has a listener) |

Go → page, batched into one `__mygo.receive([...])` evaluation per
main-loop turn. JavaScriptCore runs a script of that shape, `a.b(JSON)`,
with its JSON parser instead of compiling it, which is several times
faster, unless the inspector is enabled (development builds):

| message                                                   | meaning                                                  |
| --------------------------------------------------------- | -------------------------------------------------------- |
| `{"t":"reply","id":N,"k":token,"ok":true,"v":value}`      | successful call                                          |
| `{"t":"reply","id":N,"k":token,"ok":false,"e":"message"}` | error or panic                                           |
| `{"t":"chan","c":N,"k":token,"p":value}`                  | a value of channel N; `"a":1` asks for an acknowledgment |
| `{"t":"chan","c":N,"k":token,"end":true}`                 | Go closed channel N                                      |
| `{"t":"event","n":"name","p":payload}`                    | typed event                                              |

`k` is a random per-page token: a reply meant for a page that has since
navigated away can never resolve a promise of the new page.

### Calls

1. `WindowHandler.Message` runs on the main thread. Messages starting with
   `{"t":"call",` are handed to a goroutine (`handleCall`) together with the
   page context and the page's trust decision, captured on the main thread so
   a racing navigation cannot change them. Everything else is decoded on the
   main thread.
2. `handleCall` decodes the envelope with `encoding/json/v2`, looks up the
   method, decodes each argument into the parameter type, calls it and
   encodes the result. Panics are recovered, logged with a stack trace and
   returned as errors. Large values are copied as little as possible: the
   arguments are raw values that share the message (`rawValue`), decoded
   from it in place, and the result is encoded into a part of the reply
   (`message`), which the flush copies into the script once.
3. The reply is queued with `Window.enqueue(msg, false)` and flushed on the
   main thread.

Bound methods may take a `context.Context` first: it carries the calling
window (`CallerWindow`) and is canceled when the page navigates or the window
closes. `Bind` validates every parameter and result type up front
(`tsgen.Validate`), so unsupported types fail at startup, not at call time.

`Bind` lists a service's methods with `reflect.Type.Method`, and a program
that does that keeps every exported method of every type in an interface,
since the linker cannot tell which it calls: about 2.5 MB of a native UI
app. So only apps that call `Bind` (or `Use` a plugin with a service) link
it. MyGo's own service, `mygo:window` behind `window.mygo.window`, is bound
by `bindFuncs`, from funcs, without it; `go build -ldflags=-dumpdep`
prints `<ReflectMethod>` on what does it.

JSON options (`jsonOptions` in `ipc.go`) are shared by calls and events:
json/v2 defaults (nil slices encode as `[]`, case-sensitive names),
`time.Duration` as nanoseconds, and U+2028/2029 escaped for JavaScript.

### Events

`NewEvent[T](name)` registers a typed event. `Emit` and `Broadcast` encode
once and enqueue per window. **Events are held until the page reports
dom-ready** (bounded to 1024 per window) and the hold resets on every
navigation, so events sent right after creating a window, or during a
navigation, are delivered once listeners exist. Replies are never held:
module scripts may `await` a call at top level, and DOMContentLoaded waits for
them.

### Channels

A `*Channel[T]` parameter (`channel.go`) streams values to the page that
made the call. The page's `Channel` goes into the call's arguments as an
id it chose; `method.call` creates the Go side for that page, registered
in `Window.channels`, and closes it when the method returns, before the
reply is queued, so the page gets the values, the end, then the result.
The page may close it earlier, which cancels the call's context, a context
derived from the page's for calls with channels; so does the page going
away. The page may even close it before the call's goroutine made it
(aborting a request right after starting it): the window remembers such
closes (`closedEarly`, bounded, reset with the page) and the call closes
the channel as soon as it makes it. Values are queued in the window's outbox like replies, so they are
batched and stay in order with them.

Flow control keeps a producer faster than the page from piling up
messages: every half MiB of messages, a value asks for an acknowledgment,
which the page sends once it took that value (handled it, or yielded it to
an iterator), and `Send` waits while more than a MiB is unacknowledged. It
never waits on the main thread, which receives the acknowledgments.

### Eval

`Page.Eval(code)` uses the webview's native async-function API
(`callAsyncJavaScript` on macOS, `webkit_web_view_call_async_javascript_function`
on Linux), which awaits promises and ignores the page's Content Security
Policy. The code is first wrapped as `return JSON.stringify({ok, v: await (code)})`;
if that fails to compile the code is not an expression, and it is run again as
a function body. A compile error means nothing executed, so code never runs
twice. The result travels as a JSON string and is decoded in Go. A page whose
window closed never answers, so a window closing fails the evals waiting for
it, and an eval with the quit under way fails at once.

### Trust

Every page gets the runtime, but only trusted pages may call Go: the
frontend (`mygo:` and the `mygo dev` server), custom-scheme pages
(`Protocol.Handle`), `file:` and `about:` pages, loopback `http(s)` dev
servers in development, and origins listed in `PageOptions.TrustedOrigins`
(`"*"` trusts everything). The decision is
recomputed on every committed navigation. Untrusted calls are rejected
without running any Go code.

`PageOptions.Untrusted` (`Window.untrusted`, fixed when the window or web
view is made) makes `isTrusted` false whatever the URL, for a plugin's UI
served from a custom scheme. The core then drops the page's messages above
`maxUntrustedMessage` before stripping the secret, rejects its calls on
the main thread instead of a goroutine each, ignores its drag regions,
leaves it out of `Broadcast` and of `Emit` to the window its web view is
in, and refuses what other pages get by default without a handler:
permissions (through `isTrusted`), new windows and the browser, downloads,
and main-frame navigations the page starts to another origin than its
committed page's (`Window.origin`). `serveScheme` puts the asking page in
the request's context, under the keys of `CallerWindow` and `CallerPage`,
so a scheme's handler knows which page sent a request: that's the channel
of untrusted pages to the app.

The message handler is reachable from every frame, while trust is decided
by the main frame's URL, so an iframe of another origin must not be able to
talk to Go: each window has a random secret (`crypto/rand`), passed only to
the bridge's closure in its configuration, which prefixes every message;
`handleMessage` drops messages without it. macOS additionally only accepts
messages from the main frame (`WKScriptMessage.frameInfo.isMainFrame`);
WebKitGTK exposes no frame information, so Linux relies on the secret.

### Plugins

`Use` binds a plugin's service as an internal service named
`plugin:<name>`: calls reach it like any bound method (trust checks,
contexts, channels), but `GenerateTypeScript` skips it, since the plugin's
own npm package is its client. A call to a plugin that is not used fails
with an error naming `mygo.Use`. The official plugins in `plugins/` keep
each Go package next to its npm package, built into `dist/` by `bun run
build` like mygo-runtime and released with the same version.

* **fetch** streams a response through a `Channel`: the head first (status,
  headers, final URL), then base64 chunks of the body as Go reads them. The
  JavaScript side builds a `Response` around a pull-based `ReadableStream`
  over the channel's iterator, so the page's reading paces Go through the
  channel's flow control. Aborting, canceling the body or the page going
  away closes the channel, which cancels the request's context. Request
  headers go through a plain `Headers`, which, unlike a `Request`'s, drops
  no forbidden names.

* **websocket** is an RFC 6455 client of its own (no dependency) on top of
  `net/http`, which keeps upgrade requests on HTTP/1.1 and hands the
  connection over as the body of the 101 response, so proxies and the
  client's TLS settings apply. `Connect` streams the connection's events
  through a channel for as long as it lasts; the page sends with `Send`
  calls numbered in order, since calls run on goroutines of their own and
  would otherwise race, and Go writes them in that order. Connections are
  keyed by window and a random id the page chooses.

* **updater** is the update window, in the manner of Sparkle, built on
  `mygo.Updater` alone. A *session* is a check and what follows it (the
  release notes, the download, the offer to relaunch): a goroutine that
  sets the session's *view* (title, message, progress, release notes,
  buttons) and waits for responses, whether or not the window shows, so
  that a background check shows it only when it has something to offer and
  a "Check for Updates…" during one just shows it. The window's page, one
  embedded HTML file loaded with `LoadHTML` (an `about:blank` page, so
  trusted), watches the views through a `Channel` (`Watch`) and answers
  with `Respond`; each set of buttons has a prompt number and only the
  first answer to the current prompt counts, so a double click cannot
  answer the next view. The plugin's service rejects calls from other
  windows. Release notes are Markdown parsed in Go (`internal/markdown`),
  which keeps all HTML as text and only links http(s) and mailto URLs; the
  page gets them rendered as escaped HTML, and a Content Security Policy
  with a nonce runs only the page's own script: the page may call Go, and
  the notes come from the unsigned manifest. Links open in the browser
  (`OnWillNavigate`). Views with release notes have a fixed size; status
  views ask for the height of their text (`Fit`). The window gets an empty
  menu of its own, so it has no menu bar on Linux and Windows.
  A window sees its session through `internal/frontend`: the session
  creates it (`NewWindow`: its size, its menu, the session canceled when
  it closes), and the window shows the views (`Current`), answers
  (`Respond`) and asks for a size (`Fit`). `plugins/updater/native` is
  the same window in native UI: `native.New` builds the plugin with a
  window of its own through a hook package updater sets
  (`frontend.Plugin`), so package updater links no native UI and has no
  API for other windows. Its view rebuilds when the session's view
  changes, measures the boxes of a layout in the next frame (`Bounds`) to
  ask for the size the page's script would, and builds the notes'
  paragraphs of inline text elements, their links of `ui.Link`. `updater.json` in `PathUserData` keeps the
  preferences, the skipped version and the time of the last check, and
  a change that alters them calls the functions of `OnChange` on the main
  thread, from a goroutine of its own so that no caller waits for the main
  thread; the next check is due an interval after it, or an hour after a failure, and
  is rescheduled on resume since timers stop while the computer sleeps. An
  update installed while the app runs is remembered, so that checks offer
  to relaunch instead of installing it again. The texts are `Strings` in
  the language that best matches `Options.Language` or `App.Locale`
  (`matchLanguage`: language, script, region; Chinese scripts inferred
  from regions such as TW; another variant of the language before
  English), among the plugin's translations (`translations.go`) and the
  app's, whose empty fields fall back to the plugin's, then English. The
  page gets `lang`, which picks CJK fonts, and `dir`; status texts use
  `unicode-bidi: plaintext` and the notes `dir="auto"`, as either may be
  in another language than the window. The page reports the width its
  buttons need too, as translations can be long.

* **sqlite** runs SQLite in a native module, `internal/sqlitecore`,
  whose Zig compiles SQLite's C amalgamation, which `zig/build.zig.zon`
  pins by its hash, with SQLite's symbols hidden in the library (WebKit
  loads the system SQLite globally on Linux). The module's `Engine` opens
  a `Conn`, which runs one statement a call, prepared with the rest of the
  SQL compiled first so that extra SQL never runs, and returns its rows in
  one reply. An authorizer denies transaction control, ATTACH and VACUUM
  INTO outside the calls that allow it. Package sqlite's connections
  serialize operations and validate values in Go; canceling an operation,
  or closing the connection, calls `Conn.Interrupt` (`sqlite3_interrupt`,
  which the busy handler checks too) and waits for it before the next one.
  Transactions hold one connection through BEGIN IMMEDIATE, COMMIT or
  rollback. The page client preserves int64 and BLOB values with tagged
  cells and confines database files to the Go-configured directory.
  Connections belong to their page and close on navigation or app quit.
  Go and native UI apps can also open connections directly.

* **watch** gives pages `mygo.WatchFiles` watches of the directories and
  files the app names, by their names (`Roots`, or `Resolve` for those
  granted while it runs). `Watch` streams a part per batch through a
  channel for as long as the watch lasts, and returns how it ended, a code
  the page turns into a `WatchError`. A page's watches count against its
  quota by `mygo.CallerPage` while their call's context is not done, as
  navigating ends the page context before the watches have stopped; they
  stop with it.

* **terminal** is a terminal for native UI: a `Terminal` runs a program in
  a pseudo-terminal and emulates it with libghostty-vt, Ghostty's terminal
  emulator, and `View` draws it with package ui and takes its input.
  * *The library* is loaded with purego (`internal/vt`): `dlopen`, or
    `LoadLibrary`, then a symbol table; functions taking structs or floats
    by value go through `purego.RegisterFunc`, the rest through `SyscallN`.
    The Go mirrors of the C structs are checked against the layouts the
    library describes in JSON (`ghostty_type_json`) as it loads, as are the
    enum values the package hardcodes, and packed cells (`GhosttyCell`) are
    read by the bit positions it reports, so that a library of another
    version fails to load. Its callbacks (writing to the pty, the title,
    the bell, the clipboard, synchronized output, device attributes, …) are
    made once and find their terminal by the userdata.
  * *Pseudo-terminals* (`internal/pty`) are opened in pure Go: `/dev/ptmx`
    with the ioctls of `grantpt`, `unlockpt` and `ptsname` (`TIOCPTYGNAME`
    on macOS, `TIOCGPTN` on Linux), the program in a session of its own
    with the slave as its controlling terminal; ConPTY on Windows
    (`CreatePseudoConsole`, a process attribute list), whose console the
    terminal closes once the program exits. The user's shell starts as a
    login shell (`-zsh`), when the first frame of a view sizes the screen
    (or after half a second without one), so that it starts at its size.
    A key the view takes tells Windows' backend to open no menu for the
    `WM_SYSCHAR` of Alt and the key.
  * *Threads.* A goroutine reads the program's output and writes it to the
    emulator under the terminal's lock, then asks the view for a frame;
    another writes what is typed, from a queue, so that a program that does
    not read cannot block the reader, which answers its queries. Callbacks
    of the app run after the lock is released. A frame takes the lock only
    to copy the emulator's state into a render state (`render_state`'s
    first phase); a second lock guards the render state, which a program's
    synchronized update (mode 2026) holds: the render hold callback copies
    the screen as the update starts, and frames show that copy until it
    ends, or for a second at most. Locks are taken in that order.
  * *Drawing.* The view sizes the grid in device pixels from the font
    (cells as wide as the widest ASCII glyph, as tall as the line) and
    rebuilds only the rows the render state marks dirty: runs of cells of
    one font and color, shaped with `ui.Shape` (through an LRU of shaped
    text, as output repeats) and placed in their cells, the glyphs of a
    cell centered there and shrunk when too wide, as emoji are; backgrounds
    and lines merge across cells. Box drawing, blocks and Powerline's
    separators are drawn, as in Ghostty, so that lines join across cells.
    Frames paint every row from these caches, the cursor (its cell's text
    again in the cursor's text color under a block), the selection (its
    text clipped to its cells and drawn again in the selected text's color
    when the theme has one), an input method's composition and a scroll
    bar.
  * *Themes.* `ghostty_themes.go` holds the themes the Ghostty it binds
    ships (iTerm2-Color-Schemes' archive that its `build.zig.zon` names),
    as 22 colors each in the generated theme data.
    `GhosttyTheme` looks for a theme file of the user's first, in
    Ghostty's themes directory, as Ghostty does.
  * *Input* comes as it happens (`ui.Element.HandleInput`): keys are
    encoded by libghostty-vt's key encoder, set from the terminal's modes
    (legacy, modifyOtherKeys, the Kitty keyboard protocol). A key that
    types text waits for the text, which macOS and Windows send after it,
    to encode both; text that comes alone, as on Linux or from input
    methods, finds its key from US layout. Mouse reports go through the
    mouse encoder while the program asks for them; otherwise a selection
    gesture of libghostty-vt turns presses and drags into selections, with
    the clicks it counts itself. Keys meet the terminal's keybinds before
    the encoder: Ghostty's defaults for the platform with the app's over
    them, as Ghostty layers its config. A paste reads the clipboard on the
    main thread as it starts (every format for `OnPaste` or a program in
    mode 5522, else the text), and the terminal keeps a snapshot: the
    program's read (OSC 5522) is answered during `Write`, on the reader's
    goroutine under the terminal's lock, where waiting for the main
    thread could deadlock. The binding gathers the library's reply and
    hands it over in one piece, which the input queue writes in pieces
    that report their progress. Any other read of the clipboard
    (`ClipboardRead`: OSC 52's "?" and OSC 5522, unless a paste granted
    it) is queued instead: the binding holds the library's own refusal
    back, and the view, on the main thread, reads the clipboard and
    writes the answer, which the reader's lock makes safe.
  * *Shipping the library.* `native/` is a Zig package whose
    `build.zig.zon` pins Ghostty at a commit and whose `build.zig` installs
    its `ghostty-vt` artifact (`emit-lib-vt`, stripped), built like any
    native library with `build` (needing macOS 13, `"macOS": "13.0"`).
    `mygo-plugin.json` names its build for each platform, published as
    release assets with their SHA-256 and source hashes. The CLI puts them
    into apps (see the CLI's resources); other programs download theirs
    into the user's cache once, which packaged apps never do.
    `internal/themes` writes `ghostty_themes.go` from the themes archive
    the pinned Ghostty names.

* **game** has what games need beyond what apps do, opt-in, out of core
  `ui`, on its public API only. `View` is a focusable box that keeps its
  loop in `ui.Local`: its input handler gathers keys (by `PhysicalKey`),
  buttons and wheel into the `Input` of the next step, and its draw
  function asks for the next frame (`AnimationFrame`), adds the time since
  the last frame (`Painter.Now`, at most a quarter of a second) and runs
  the steps it covers before `Draw`. `Camera` is a `ui.Transform`, snapped
  to device pixels when unturned.
  Its package `gamepad`, like `audio`, stands apart from windows and the
  main thread. One mutex guards the pads. `Pads` asks the platform's `scan` for
  the devices connected at most once a second, handing it the devices it
  has so that it reuses them, and a device that is gone, from a scan or
  when read, disconnects its pad. `State` reads a device on the calling
  goroutine into the standard layout (`State.Buttons` in the W3C's order,
  `Axes` with y down):
  * macOS: GameController.framework through purego's objc: `GCController`
    `controllers` with an `extendedGamepad`, each element's `value` read
    inside an autorelease pool, after `respondsToSelector:` for the buttons
    older systems lack. The framework finds controllers on the main run
    loop.
  * Linux: evdev, opened non-blocking where `EVIOCGBIT` shows `BTN_SOUTH`;
    reading drains the events waiting into key and axis arrays, with axes
    scaled by `EVIOCGABS`'s range. Xbox controllers (Microsoft's and Valve's
    vendor IDs, or the `xpad` driver) report X and Y under BTN_NORTH's and
    BTN_WEST's codes, which are swapped back.
  * Windows: XInput's four slots, through `XInputGetStateEx` (ordinal 100)
    for the Guide button where it exists. Empty slots, slow to ask, are
    asked only by scans.
  * Browsers: `navigator.getGamepads()` by index, the standard mapping
    matching the package's order.
    Tests replace `scanDevices` with fake devices; on Linux, `TestEvdev`
    (`MYGO_UINPUT=1`) makes uinput pads in the test container, and on macOS
    `TestGameController` reads a controller from `controllerWithExtendedGamepad`.

* **glass** is Liquid Glass for native UI, as macOS 26 and later draw it:
  `glass.Glass`, a `ui.Material` (interactive glass builds with its
  element, following its press with `Animate`, and paints itself grown
  while pressed, as macOS 27's: by a fixed 1.1 DIPs left and right and
  0.45 above and below, measured from `NSGlassEffectView`), paints an
  effect (`glass.Effect`, see Effects under Native UI), whose parameters
  are a pane's material in device pixels. Its shader (`glass.metal`,
  `glass.hlsl`, `glass.glsl`, and `pixels.go` for the CPU) takes what is
  behind the pane, blurred, sampled where the curved surface refracts it:
  displaced toward the middle within the bezel by Snell's law through
  Apple's squircle profile (`lens`, along `normal`), which mirrors what is
  just inside the rim; then maps its lightness and colors (`tone`; the CPU
  keeps its curve in a table, as its power is slow there), tints it, and
  lights the rim by how its normal faces the light. The defaults follow
  macOS 27's, measured from
  `NSGlassEffectView` over test patterns; the optics follow the
  open-source reproductions of Liquid Glass. `glass.Blur`, a backdrop
  blur, is a second effect (`blurEffect`): what is behind the element,
  blurred, with its alpha (the effect samples the backdrop's texels
  itself, as the heads' `sampleBackdrop` gives no alpha), so over nothing
  it stays transparent. Masked by a `LinearGradient`, the blur varies as
  the gradient's alpha (`blurLevels`): the element paints levels in turn,
  each blurring what the levels before painted (blurs add as their
  variances do), shown where the blur wanted is above its band, by how far
  into the band, so a level's top doubles from at most 2 pixels to the
  blur's most and a pixel between two levels mixes their blurs. A level of
  a square element covers only where it shows (`blurWanted`), and so
  reads less. Bounding the levels after the first to the element, so that
  they read no unblurred content around it, measured worse against a blur
  varying per pixel than leaving them reading it: the repeated edge biases
  more than what is around. A level may tone what it shows (`blurTone`:
  saturation, an offset, an opaque color over it), which the hard style of
  `glass.ScrollEdge`, macOS's scroll edge effect, frosts with in one
  level; the soft style is a gradient of the background, as macOS 27's
  replays its window's background under a mask, with no blur (measured
  from SwiftUI's `safeAreaBar` over test patterns, its layers dumped).
  Both effects' shaders are compiled ahead of time on macOS
  (`shaders_darwin.go`) and on Windows (`shaders_windows.go`), with
  `internal/gen`. `glass.Group` paints one surface over a row of elements:
  a shader of package `ui/shader` (Kage, compiled for every renderer and
  the CPU) takes up to 8 rectangles and radii, unions them with a smooth
  minimum (so panes that nearly touch bridge), and draws the glass once
  around the union's bezel. `Glass{Native: true}` asks the window's
  surface for the system's glass: `ui.NativeGlassMaterial`, noted when the
  frame commits (`ui/nativeglass.go`), tells the surface where the glass
  is (`platform.GlassSurface.PlaceGlass`). On macOS the surface puts an
  `NSGlassEffectView` under the content and above the web views, and the
  material leaves a hole where it shows, so the glass samples a web view's
  page or the window's material, never the frame's own pixels; elsewhere,
  and with Reduce Transparency, the shader draws it. The materials read
  `ui.Painter.Preferences`: Reduce Transparency draws opaque surfaces,
  Increase Contrast lights the rim. Window-level glass takes a tint
  through `NSGlassEffectView`'s `tintColor`.

* **loading** is loading.dev's 29 indicators (`loading-dev`, React and
  CSS) for native UI, on ui's public API only. Each is a box of
  `RoleProgress` whose draw function asks for the next frame
  (`AnimationFrame`) and computes its pose from how many cycles it has
  run: since it first showed (its start in `ui.Local`, as a CSS animation
  starts with its element), or held while `Paused`. Parts are staggered as
  loading-dev's negative `animation-delay`s, keyframes eased stretch by
  stretch with CSS's `cubic-bezier` (`frames`, `bezier`), and shapes built
  as `ui.Path`s in the SVG's viewBox through an affine transform (`affine`,
  `shape`), arcs as cubic Béziers, which an affine transform keeps exact:
  Atom's rings turning in 3D are ellipses, Flip's square is projected in
  perspective point by point. Round caps are `StrokePath`'s; flat ones
  fill the stroke's outline. Gradients are conic ones (Comet, Orbit), and
  Radar's radial fade is sectors of growing radii over each other, each as
  opaque as makes its band the gradient's opacity, so that no two edges
  meet inside the beam. With `ReduceMotion` an indicator draws
  loading-dev's pose for reduced motion and asks for no frames. The
  indicators were checked against loading-dev rendered by a browser at the
  same points of their cycles, with every option.

## Typed client generation (`internal/tsgen`)

`mygo generate` builds the app and runs it with `MYGO_GENERATE=<file>`;
`App.Run` then writes the client (`WriteTypeScript`) and returns before
touching the GUI. It reaches the generator through what `Bind`, `BindAs`
and `NewEvent` register (`ipc.writeClient`): an app that binds nothing
writes no client, and links neither the generator nor go/parser (375 KB).
The generator combines:

* **Reflection** for correctness: types follow json/v2 encoding (embedded
  structs are inlined with v2's conflict rules, `omitempty`/`omitzero` become
  optional fields, pointers become `T | null`, `[]byte` is a base64 string,
  `time.Time` a string, types with JSON methods `unknown`, text marshalers
  `string`, generic instantiations get names like `PageTask`).
* **Source code** for readability, when available: the entry PC of each bound
  method (`runtime.FuncForPC`) locates its file, which is parsed with
  `go/parser` to recover parameter names and doc comments (JSDoc). Named
  string/number types with constants become union types (`"all" | "done"`),
  including simple `iota` sequences. Packages not reached through a PC are
  located with `go list`. Without sources (e.g. `-trimpath` binaries) the
  client is still correct, just with `arg0` names and no docs.

The output imports `call` and `event` from `mygo-runtime` and declares the
interfaces, one object per service with camelCased methods, and an `events`
object. `WriteTypeScript` only rewrites the file when its
content changes, so dev servers don't reload needlessly.

## The language the app shows (`locale.go`)

The app shows one language, which `localeState.shown` holds with the
user's languages and regional formats: an atomic pointer the main thread
replaces (`updateLocale`), so that `App.Locale`, the menus, the catalogs'
`i18n.Locale` and native UI read it from any goroutine for nothing. The
first read works it out on the main thread. `updateLocale` reads the
backend's `PreferredLanguages`, `Region` and, once, the saved language
(`SavedLocale`, where the system keeps one, else the file `locale` in
PathUserData; `MYGO_LOCALE` over both), resolves it with `i18n.Match`
against `App.Languages()`, and, when it changed, tells: windows of native
UI (`Conn.LocaleChanged`, after which `ui` reads `Conn.Locale` and
`Conn.Region` and sets the text system's language), pages (the event, and
`Page.SetUserScripts` with a bridge configuration of the new language, for
pages loaded later), menus (`relabelMenus`: items whose label is still
their role's take `internal/l10n`'s), the backend (`SetLanguages`: the app's
language, then the user's others) and the listeners. `SetLocale` calls the
main thread may not have reached yet show the last tag only (a
generation counter). `ChosenLocale` reads the choice (`override`, after
`loadLocale`) on the main thread, behind the `SetLocale` calls queued
before it. A backend's `LocaleChanged` reports changes of the
system's languages or formats, which `updateLocale` compares.

The text engine takes a language per style and span (`text.Style.Lang`),
and one of the system for those without (`System.SetLanguage`, a new
generation of layouts): Core Text's `kCTLanguageAttributeName`,
DirectWrite's locale of text formats and of ranges
(`IDWriteTextLayout::SetLocaleName`), Pango's language attributes. Han
characters in a language that does not write them get the engine's own
choice (`langRuns`), as Chromium's `LocaleForHan` does; Core Text does so
by itself. DirectWrite's choice goes by the locale of the user's regional
formats (`GetUserDefaultLocaleName`), whose fallback for English mixes Yu
Gothic UI and Microsoft JhengHei UI in one Chinese text: where that locale
writes no Han characters, they take the first of the user's preferred
languages that does (`userHanRuns`, `userHanLanguage`), read once, the
first time a text has Han characters in no language that writes them
(`dwrite.userHan`), so that apps without them read nothing: the display
languages (`GetUserPreferredUILanguages`), else the languages of the
user's profile, which list languages without their language pack too, as
Chinese below English on English Windows (`resolveUserHanLanguage`). The
profile's are read from the registry (`HKCU\Control Panel\International\User
Profile`, value `Languages`), where Windows keeps what
`GlobalizationPreferences.Languages` returns, in microseconds and on any
thread, rather than through the Windows Runtime.

WebView2's environment takes the language through
`ICoreWebView2EnvironmentOptions`, a COM object of ours
(`webview2_options.go`) whose vtable's callbacks are made once; a runtime
that fails with it is asked for an environment without it.

## Catalogs of messages (`i18n`, `internal/i18ngen`, `internal/l10n`)

Package `i18n` is a leaf (it imports golang.org/x/text/language only):

* **CLDR data** is generated, never written by hand: `go generate ./i18n`
  runs `i18n/internal/gen`, which reads the npm tarball of cldr-core at the
  version it pins, checked against its SHA-256, and writes `tables.go`.
  Plural rules are compiled to Go, a `switch` per kind (cardinal, ordinal)
  over the distinct rule sets with a sorted table of languages, so nothing
  is built at init; an operand of more than 18 digits keeps its last 18
  plus 10^18, which keeps its remainders by powers of ten and equals no
  constant of the rules. Rules are looked up by truncation, as ICU does
  (CLDR's parent locales of plurals are empty); messages fall back along
  `Parent`, CLDR's main parent locales with its nonlikelyScript rule. The
  tests check every sample CLDR gives and ICU's categories for 200 numbers
  in every language (`scripts/plurals-golden.ts`, run with Node, whose ICU
  is upstream; Bun on macOS uses Apple's, which differs).
* **Formatting data** of CLDR's modern locales (effective coverage
  "modern", 430 locales) comes from cldr-dates-full, cldr-numbers-full and
  cldr-localenames-full, pinned like cldr-core (`format.go` of the
  generator writes `format_tables.go`). A locale's data is a record of
  slots (month and weekday names by context and width, day periods, eras,
  date, time and date-time patterns, the availableFormats of the
  skeletons MyGo formats, time zones' GMT formats, number symbols,
  patterns and digits of the default numbering system and of latn); each
  locale stores only the slots in which it differs from its nearest
  ancestor of the list (or from a synthetic root of the values most
  locales have), as indexes into a pool of strings. The slots come in
  two halves, each with its own entries and pool, packed with DEFLATE in
  a constant of its own: the numbers with the locales and their parents
  (`fmtPackedNumbers`, 3 KB), which every app links, as MyGo's own strings
  format numbers, and the dates with the names of languages
  (`fmtPackedDates`, 77 KB), which only apps that format dates or name
  languages link. At run time `cldr.go` inflates each once and puts a
  locale's record together on its first use (an atomic pointer per
  locale), its dates on the first date it formats (`withDates`); `keyOf` caches what a tag formats with (its data locale, by
  `Parent` and likely scripts, and its `-u-hc`, `-u-fw`, `-u-nu`). Week
  data, time data and day period rules are small tables by region.
  `dtpg.go` ports ICU's DateTimePatternGenerator (dtTypes, distances,
  the pattern map keyed by base skeleton and types in ICU's order,
  adjustFieldTypes, date and time put together with the atTime glue), and
  `date.go` V8's handling of styles and hour cycles; `number.go` writes
  decimal strings, so that rounding is decimal as ICU's. Formatters are
  kept per locale and options in maps under a read lock.
  `scripts/format-golden.ts` records Node's `Intl` (upstream ICU) for
  every locale; `TestFormatMatchesICU` compares, and `knownDifference`
  lists, with reasons, the cases that differ on purpose.
* **Relative times** (`relative.go`) use dateFields from the same pinned
  cldr-dates-full tarball, written to `relative_tables.go` in a compressed
  blob of their own: runs of slots as `recordSections` writes them, by
  style, unit, and words for offsets -2 to 2 or past/future plural form.
  Only `NewRelativeTimeFormatter` reaches it, so formatting dates or
  numbers links none of it. The formatter uses the number formatter
  (half-even, as ICU's RelativeDateTimeFormatter does), the plural form
  of its rounded number, and ICU's rounding of offsets to hundredths
  when choosing words with `Auto`. `scripts/relative-time-golden.ts`
  records Node's Intl for every formatting locale, with the full matrix
  compressed in `testdata/relative_time_icu.json.gz`; the tests name the
  CLDR/ICU data differences explicitly.
* **MessageFormat** (`message.go`, `format.go`) parses ICU's syntax as
  ICU's MessagePattern does (apostrophe mode DOUBLE_OPTIONAL, `#` only in
  a plural's own cases), and formats numbers and dates with the
  formatting above; a plural case is picked on the number as `#` writes
  it. Dates go through `timeFormat`, which `NewCatalog`,
  `NewLibraryCatalog` and `ParseMessage` set (`linkTimes`): MyGo's own
  catalog, which every app formats and which has no dates (its test
  checks), is made through `internal/i18nlink`, which does not, so an app
  that formats no date links no date formatting. `mygo-runtime/i18n` is its TypeScript twin over `Intl` (skeletons
  turned into `Intl`'s options, as V8 turns them back);
  `i18n/testdata/messages.json` holds the cases both test.
* **Catalogs** read a language's file once, on its first message
  (`sync.Once`), and cache the tags a locale looks keys up in. A library's
  catalog (`NewLibraryCatalog`) looks a key up in the registered catalogs
  of the app under `<namespace>.<key>` before its own, at each tag of the
  chain. `Register` declares the languages, which package mygo reads with
  `Languages`; `SetLocaleFunc` is how package mygo tells the language the
  app shows to `Locale`, which the generated functions read.

A catalog keeps each message formatted without arguments, by locale and
key, as of the registry's version: the controls of native UI say theirs
every frame (`l10n.In(c.Locale()).Undo()`), for a map lookup under a
read lock and no allocation. `ui`'s `context.formats` works out, once per
change of the language or the system's formats, the region the controls
follow (CLDR's for the language when the system says none) and its
`Region.FormatLocale`; `context.formatted` keeps the dates and numbers the
calendar, the date and time fields and the color picker write, so a frame
formats nothing it formatted before.

Backends say a few words of their own (the buttons of pages' alert,
confirm and prompt panels, file dialogs' titles, the about panel's
title): package mygo gives them in the app's language through
`platform.SetTexts` as the language changes, so that `internal/<os>`
does not import `internal/l10n`.

`internal/i18ngen` checks catalogs and writes their functions:
`catalog_gen.go` in the catalogs' directory (an embed, the catalog,
registered for apps, and a function and a method of `Messages` per key)
and the TypeScript module, which carries the messages with each
language's fallback chain. `internal/l10n` is MyGo's own catalog,
generated by the same code (`go generate ./internal/l10n`, with
`i18ngen.Options.Own`), whose keys apps change as `mygo.<key>`; the CLI
checks those keys against it (`l10n.FS`, the files as written, which only
the CLI links). It embeds English only, as `messages/en.json`, which the
generator writes from `en.json` without the descriptions (7 KB of 28): each translation is a package,
`locales/<tag>`, that adds its file to the catalog as it is imported
(`i18n.Catalog.Add`), so that an app links only the languages it ships.
The generator writes those packages and `l10n.Languages`; the CLI passes
that list to `internal/i18ngen`, whose Go code imports the translations
that suit the app's languages, and package mygo tells an app that ships
one of them without the translation, as it starts. The
CLI (`cmd/mygo/i18n.go`) writes the functions before anything compiles,
in `generate`, `build` and every build of `dev`, where the catalogs'
directory is watched and the generated Go file is not, so writing it does
not trigger another build.

## Custom protocols

`Protocol.Handle(scheme, http.Handler)` lets pages load `<scheme>://localhost/…`
like a web origin (fetch, ES modules, relative URLs). `Protocol.serve` runs the
handler on a goroutine with a `schemeWriter`: headers and body are buffered
and handed to the main thread in 256 KiB chunks (and on `Flush`), the content
type is sniffed when missing, panics become 500 responses. Backends that
implement `platform.SchemeBodyWriter` take the body on the handler's
goroutine instead, where they may block it, and the chunk buffer is reused.
Backends turn responses into native ones:

* macOS: `WKURLSchemeHandler`; `didReceiveResponse:`/`didReceiveData:`/
  `didFinish`. A task stopped by WebKit cancels the request context and later
  writes are ignored (touching a stopped task raises an Objective-C exception).
* Linux: WebKitGTK wants a `GInputStream`, so the response body is streamed
  through a pipe (`g_unix_input_stream_new`), which WebKit reads on the main
  loop, 8 KiB at a time. The handler's goroutine writes the body into the
  pipe (`WriteBody`), waiting while it is full, so the main loop never
  blocks and a response WebKit reads slowly does not pile up in memory.
  Custom schemes are registered as secure and CORS-enabled.
* Windows: the handler's goroutine writes the body into a pipe
  (`internal/schemestream`, `WriteBody`) that holds at most 1 MiB not
  read. A body that ends within it is answered whole at `Finish`
  (`SHCreateMemStream`), as WebView2's documentation asks of a response
  whose deferral completes. A larger one is answered as the pipe fills,
  with an `IStream` of Go's (`bodyStream`, `scheme_stream.go`) whose
  `Read` waits for the handler: WebView2 reads response streams on a
  background thread of its own (one for all of them, as reported in
  WebView2Feedback#3519), and the stream is agile (`IAgileObject`, and
  the free-threaded marshaler aggregated for `IMarshal`) so that it is
  called there, not through a proxy on the UI thread. A `Read` that comes
  on the UI thread anyway waits at most a second, then breaks the response
  off. The final `Release` cancels the request's context; the window's
  closing cancels those of handlers still running. WebView2 seems to give
  a response to the page only once it read all of it, and asks open
  ranges for media, so the backend narrows `Range: bytes=X-` of media
  requests to 4 MiB (`schemestream.ClampRange`): the element asks for
  what follows (#1502).

Schemes are registered per webview at creation time, so call
`Protocol.Handle` before creating windows. `FileServer(fsys)` serves an
`fs.FS` with an index.html fallback for client-side routing.

## The frontend (`frontend.go`)

Apps load their web UI with URLs without a scheme (`WindowOptions.URL: "/"`,
`LoadURL("/settings")`), which `resolveURL` resolves against the frontend,
as in Tauri:

* during `mygo dev`, the dev server: `MYGO_DEV_URL`, from `devUrl` of the
  configuration (only honored when `IsDev`);
* otherwise `mygo://localhost/`. The `mygo` scheme is registered with every
  webview and, unless the app handles it with `Protocol.Handle`, serves the
  files given to `SetFrontend`. `mygo build` calls `SetFrontend` from a
  generated file that embeds `frontendDist` (see CLI), so app code has no
  `//go:embed` and development builds need no built frontend. During
  `mygo dev` without a dev server it serves `MYGO_FRONTEND_DIST` from disk,
  and with nothing to serve, a page explaining how to get a frontend.

## Windows, lifecycle and quitting

* `NewWindow` validates options, waits for readiness when called off the main
  thread, builds `platform.WindowOptions` (all defaults applied, bridge and
  preload scripts, registered schemes) and registers the window.
* Called on the main thread, `NewWindow` leaves showing a window of
  native UI to the main loop's next turn (`showLater`, `settleShow`), so
  that its view first runs once `NewWindow` returned and can use the
  window kept from it (#1053): shown within `NewWindow`, a window draws
  its first frame at once on
  some systems, as AppKit may display a window it orders in, and Windows
  a window maximized as it shows (`WM_SIZE`). The frame the content asked
  for draws on that turn too, while the window is still hidden, as a
  window made `Hidden` draws its first (`drawSoon`, `drawHidden`), or as
  it shows. A method acting on the native window (`do`, `get`) shows it
  first, so that it finds the window as `NewWindow` returned it, but not
  from within a frame (`framing`), whose view may call one (`Title`): a
  frame drawn as the window shows would run inside it. `Show`,
  `ShowInactive` and `Hide` take the deferred show's place, so `Hide`
  right after `NewWindow` keeps the window from showing. Called from
  another goroutine, which `NewWindow` returns to while the main thread
  goes on, `NewWindow` shows the window before it returns, as it does a
  window of a page, whose page loads later anyway.
* A window's page API is on `Page`, a handle on the window that
  `Window.Page` returns unless the window shows native UI; the page's state
  stays in `Window`, where IPC and the backend's callbacks reach it.
* The user's close (`WindowHandler.ShouldClose`) and `Window.Close` both emit
  `OnClose`, which can be prevented. `Destroy` skips it. The backend reports
  `Closed` synchronously; the core unregisters the window, closes child
  windows, cancels the page context and, when it was the last window and no
  quit is in progress, runs `OnWindowAllClosed` listeners or quits.
* The quit sequence (`Application.prepareQuit`) is: `OnBeforeQuit` → close
  every window (any `OnClose` can cancel) → `OnWillQuit` → stop the loop →
  `App.Run` returns → `OnQuit`. It is used for `App.Quit`, Cmd+Q, quit
  Apple Events, and SIGINT/SIGTERM alike (`signal_unix.go`; a second signal
  exits immediately).
  When the OS ends the session instead (`AppHandler.Terminating`:
  `WM_ENDSESSION` on Windows, `applicationWillTerminate:` on macOS), the
  loop does not stop first: `Application.endSession` calls the same
  listeners, with `QuitEvent.SessionEnding` set and what they prevent
  ignored, then `finish`; it skips them when a quit's sequence ran or is
  running (`quitting`, `stopping`). Linux has no such path: the session's
  end arrives as SIGTERM.
* Taskbar state on Windows (`taskbar.go`) lives on the window and is
  applied when Explorer sends `TaskbarButtonCreated` (first show, Explorer
  restarts), so progress and a hidden button set before showing stick.
* `WindowOptions.StateKey` (`window_state.go`) remembers a window's normal
  bounds and maximized/full screen state in `window-state.json` in
  `PathUserData`, like Tauri's window-state plugin, or in the app's
  `WindowStateStore` (`App.SetWindowStateStore`), which loads all the
  states once and saves them all, on the main thread. The state is captured
  300 ms after the last move/resize/state event (transitions resize the
  window on the way, and the normal bounds only change in the normal
  state) and when the window closes; it is saved when a window closes
  and when the app quits, if it changed, and kept for the next save when
  saving fails. `App.ClearWindowStates` saves an empty map and sets
  `windowStates.cleared`, after which windows capture nothing for the rest
  of the run, so the quit's saves (as windows close, and in `finish`
  before `OnQuit`) cannot bring the states back. A saved window that would not show on any
  display keeps its size and is centered. On Windows, where a window's
  position in DIPs changes with the displays' scales (`dipSpace`), and
  earlier versions' could not tell displays of different scales apart,
  the state also keeps the window's
  rectangle in pixels (`platform.WindowStateWindow`), and the backend
  creates the restored window at it, on its display
  (`platform.WindowStateBackend`, `WindowOptions.StateBounds`); a state
  without pixels is restored in DIPs where every display has the same
  scale, and centered elsewhere. `WindowOptions.Maximized` starts
  a window maximized: `zoom:` on macOS, `gtk_window_maximize` before
  mapping on Linux, `SW_SHOWMAXIMIZED` on the first show on Windows, where
  `Maximize` on a hidden window also waits for it to be shown.
* Deep links (`deeplink.go`). `mygo build` and `mygo dev` link the name,
  version, identifier and `urlSchemes` of the configuration into the binary
  (`-X …packageName=…`), which is how Linux builds know them (`IsPackaged`,
  `Name`, `Version`) and every platform knows which launch arguments are
  deep links. URLs of those schemes, and of ones registered with
  `RegisterURLScheme`, reach `OnOpenURL`: from Apple Events on macOS, from
  the launch arguments once the app is ready, and from the arguments a
  second instance forwards. `RegisterURLScheme` writes
  `HKCU\Software\Classes\<scheme>` on Windows and, on Linux, a hidden
  `<id>.url-handler.desktop` in `$XDG_DATA_HOME/applications` made the
  default in `$XDG_CONFIG_HOME/mimeapps.list` (what `xdg-mime default`
  does); on macOS it calls `LSSetDefaultHandlerForURLScheme` for a scheme
  the Info.plist declares. The Linux `.desktop` of `mygo build` also
  declares the schemes (`Exec=… %u`, `MimeType=x-scheme-handler/…`).
* Starting at login (`login.go`): `SetOpenAtLogin` registers the bundle
  with `SMAppService.mainAppService` on macOS 13+ (a launch agent running
  `open -a` on macOS 12; both need a bundle), writes an XDG autostart entry
  on Linux, and a value of `HKCU\…\CurrentVersion\Run` on Windows, where
  `OpenAtLogin` also honors Task Manager's `StartupApproved` (odd first byte:
  disabled). The Linux, Windows and launch agent commands pass
  `--mygo-opened-at-login`, which the package removes from `os.Args` at
  init and `WasOpenedAtLogin` reports; macOS login items are recognized by
  `keyAELaunchedAsLogInItem` in the launch Apple Event instead.
* `Relaunch` runs the quit sequence, then (after `OnQuit`, which releases
  the single instance lock) starts the executable again with the same
  arguments, or those passed to `Relaunch` in their place
  (`relaunchArguments`), and the working directory it started in: on macOS
  through `open -n <bundle> --args …`, or, with an update staged, through
  the update's helper, which reads `open`'s arguments from the
  `relaunch` file of its work directory (a `set --` line of the shell,
  quoted), written only then. A development build exits with code 75
  instead, after writing `Relaunch`'s arguments, each ended with a NUL
  byte, in the file that `MYGO_DEV_RELAUNCH` names
  (`.mygo/dev/relaunch-args`), and `mygo dev` starts the same build again
  with them, also when that happens before it was ready.
* Updates (`updater.go`, `internal/update`, `cmd/mygo/updates.go`), in pure
  Go on every platform. `mygo keygen` creates an Ed25519 key pair; with
  `updates` in the configuration (the public key, and a GitHub repository or a base
  URL) `mygo build` links the manifest URL of the target and the public key
  into the app, and when the private key is available
  (`MYGO_UPDATER_PRIVATE_KEY` or `updates.privateKey`) archives the app as
  installed (the bundle, else everything next to the executable) into
  `<name>-<version>-<target>.tar.gz` (Linux builds always get it, for
  `install.sh`), signs its SHA-256, and writes
  `update-<target>.json` with the `## <version>` section of CHANGELOG.md as
  notes. `Updater.Check` fetches the manifest (HTTPS only, loopback HTTP for
  tests) and compares versions semantically; `Update.Install` streams the
  archive next to the app, verifies size and signature, unpacks it (files,
  directories and relative links only) and swaps it in: the bundle is
  renamed on macOS, the entries of the app directory on Linux and Windows,
  where the running executable is renamed away and removed at the next
  launch. There the app directory holds `update.FileList` (`.mygo-files`),
  its top-level entries as installed, one per line: `mygo build` writes it
  into the app (so the archive, installer and packages have it), and
  `swapFiles` rewrites it in the update with the update's entries before
  swapping it in with them. The entries that the installed list names and
  the update lacks are renamed aside first, as replaced ones are, and
  deleted once the swap succeeds, so a failed swap puts them back; entries
  that no list names (the user's, the uninstaller) and all of an app
  without a list stay, and so does the running executable. Deltas never
  make the list from the installed one, which the updater rewrote.
  `App.Relaunch` then starts the new version from the path the app
  started from. Development builds are never updated. Delta updates work
  as Sparkle's (`internal/update/delta.go`): `mygo build` fetches the
  published manifest of the target, downloads the archives of up to
  `updates.deltas` versions (that manifest's, and those it lists as
  `previous`, which the new manifest passes on), checks their signatures
  and writes a signed delta from each. Its index lists the tree of the new
  app, inside the bundle on macOS, with each file's size and SHA-256 and
  how to make it: a copy of a file of the old app with the same content
  (at its path, or elsewhere for moved files), else a patch of the file at
  its path or its own bytes, whichever is smaller. The stapled ticket
  (`Contents/CodeResources`) is never made from the old app: the archives'
  bundles are stapled, but the bundle a user copies from the disk image is
  not, as `buildDMG` staples the app after copying it into the image.
  Patches are bsdiff's
  (`bsdiff.go`, with the qsufsort suffix array of `suffix.go`), their
  three streams compressed apart so that they are read from the delta
  file in place. `Update.Install` takes the delta whose `from` is the
  running version, makes the new app next to the old one through
  `os.Root`s, and fails on any file that does not match, then downloads
  the archive; the delta also names the versions it updates and makes.
  The tree made is the signed one byte for byte, so bundles keep their
  code signature. `mygo build -upload` publishes to `updates.github` with
  the `gh` CLI: it creates the release `<tagPrefix><version>` as a draft
  with the changelog section as notes, uploads installers, update
  archives and deltas, then the manifests, and leaves
  publishing the draft (which makes the manifests "latest") to the
  developer once every platform is there. With a `tagPrefix` other than
  `v` the repository may hold other releases, so apps are built with a
  feed naming the manifest in the release `<tagPrefix>{version}`
  (`update.TaggedFeed`), which `update.ResolveFeed` turns into the manifest
  of the newest published, non-prerelease release with that prefix, from
  the GitHub API's list of releases, newest first. `Updater.Check` and the
  delta step resolve it in Go, and `install.sh` in sh (`latest_tag`, which
  reads the `tag_name`, `draft` and `prerelease` fields in order). Such
  drafts are made with `--latest=false`, and published the same way, so
  the repository's latest release stays the others'. While the app turns
  prereleases on (`Updater.SetPrereleases`, an `atomic.Bool` that `Check`
  reads once), `Check` resolves the feed of the latest release (with the
  prefix `v`) and tagged feeds alike with `update.ResolvePrereleaseFeed`
  instead: the manifest of the release with the highest version
  (`update.Compare`) that is not a draft, among the pages of releases up to
  the one holding the newest release that is not a prerelease. With `updates.s3` it puts the
  same files, manifests last, into a bucket of S3 or a compatible service
  (`cmd/mygo/s3.go`): one `PUT` per object, signed with AWS Signature
  Version 4 in pure Go (`crypto/hmac`), its SHA-256 payload hash checked
  by the service; the bucket goes in the host name on AWS, and in the path
  with a custom `endpoint` or a bucket name with dots, unless `pathStyle`
  says otherwise. An app with an update service of its own gives
  `Updater.SetSource` an `UpdateSource` (an `atomic.Pointer` that `Check`
  reads once): `Check` reads the manifest from its `Manifest` in place of
  the feed, and the `Update` keeps the source, whose `Open` downloads the
  archive and deltas in place of `httpGet`. The configured feed is itself
  a source (`feedSource`), so parsing, sizes, signatures, staging and the
  swap are the same either way; `Enabled` still needs a build with
  `updates`, for the public key.
* File associations (`fileAssociations` in the configuration) are declared by the
  packages (see the table below) and their extensions linked into the
  binary; like deep links, files of those extensions among the launch
  arguments and those a second instance forwards reach `OnOpenFile`
  (paths relative to the working directory, and file URLs from `%U`).
* Downloads (`downloads.go`): links with `download`, and responses a page
  cannot show or that are attachments, become downloads. `OnWillDownload`
  gets the URL, the suggested name and a default path in Downloads (a
  unique name), which it may change or cancel; `OnDownloadDone` reports
  the result. WebKit cannot turn what a custom scheme handler serves into a
  download, and WebView2 would fetch it over the network, so those are
  canceled and the core serves the URL again through the scheme's handler
  into the file (`SchemeDownload`).
* Permissions (`permissions.go`): the backends route camera, microphone,
  location and notification requests to `WindowHandler.PermissionRequested`;
  `SetPermissionHandler` decides them, and by default trusted pages (the
  app's own, `TrustedOrigins`) are granted and others denied. Custom scheme
  pages are secure contexts with a real origin on every platform, which
  these APIs need. `macos.infoPlist` adds keys such as the camera and
  microphone usage descriptions macOS requires.
* Sign-in and certificates (`auth.go`): the backends route HTTP
  authentication challenges (Basic, Digest, NTLM, Negotiate, the server's
  or a proxy's) to `WindowHandler.AuthRequested`, which `SetAuthHandler`
  answers with credentials, or none to get the server's refusal; without
  a handler the answer is `Default`, the web view's own handling.
  Server certificates that do not verify go to
  `WindowHandler.CertificateError`, false unless `SetCertificateErrorHandler`
  allows them; macOS checks certificates itself
  (`SecTrustEvaluateAsyncWithError`) only while
  `HandlesCertificateErrors` is true, and Linux and Windows extract the
  certificate only then. Client certificates go to
  `WindowHandler.ClientCertificateRequested`, which
  `SetClientCertificateHandler` answers with one of the offered
  certificates or an empty response to refuse; without a handler the
  answer is `Default`, the web view's own handling. Linux lists no
  certificates to offer (WebKitGTK has none), so a handler there can
  only refuse, and a refusal ends the load as a cancellation, which
  `OnDidFailLoad` does not report. macOS lists the keychain's identities
  only while `HandlesClientCertificates` is true, for the keychain asks
  the user for them.
* Active windows (`active.go`): a window is drawn as active, the one the
  user's input goes to, while it or a flyout of it (through flyouts'
  parents) has the keyboard (`windows.focused`), always while
  `SetActiveAppearance` keeps it so, and so are panels and flyouts
  without a parent; a flyout with one is as active as its parent, and a
  window that never had the keyboard nor showed without it
  (`focusKnown`) counts as active, so that the first frame of a window
  about to take it draws active, which package `ui` assumes too. No
  backend reports it: `Focused` and `Blurred` post `updateActive` once
  (`scheduleActive`), which works out every window's state after the
  native event returns, so that a window blurred by its flyout taking
  the keyboard in the same event (AppKit's resign and become key,
  Win32's `WM_ACTIVATE`s, GTK's focus events before an idle source)
  never shows inactive for a frame. A change reaches native UI through
  `surface.Conn.Active` and `ActiveChanged`, and pages, and those of the
  window's web views, as the `mygo:window-active` event (true or
  false); pages start active, and one whose DOM is ready in an inactive
  window is told so. The bridge keeps it for mygo-runtime's
  `windowActive()`, telling listeners of changes only, and sets the
  `data-mygo-window-inactive` attribute of `<html>` while it is false.
  The system draws the materials itself: macOS's `NSVisualEffectView` of
  a window follows AppKit's active state
  (`NSVisualEffectStateFollowsWindowActiveState`), the main window's
  look, which agrees for flyouts (a panel never becomes main) and differs
  while a sheet or one of AppKit's own panels (Fonts, Colors) is key: the
  material stays active there while the content is not. Panels',
  flyouts' and those of windows `SetActiveAppearance` keeps active stay
  `NSVisualEffectStateActive`, as they did for all windows before;
  `NSGlassEffectView` has no such state and follows AppKit's. DWM draws
  Mica and Acrylic as a solid fill in a window it frames inactive: a
  window whose focusable flyout Windows activates, as a window of its
  own, keeps its frame active (`keepsActive`: `WM_NCACTIVATE` passed to
  `DefWindowProc` as active, and its drawn caption), until the
  activation leaves the flyout for another app's window
  (`ownersInactive`, `flyoutLeft`). GTK styles a window `:backdrop` by
  GDK's focus, which a focusable flyout takes from its parent: the
  window's own title bar then shows it, while its content stays active.
  In browsers, a window is active while its canvas has the focus.
* Flyouts (`flyout.go`, `internal/platform/flyout.go`): `NewFlyout`
  creates a window with `platform.WindowOptions.Flyout`, which backends
  make a borderless, transparent popup owned by its parent, and place
  with `Window.PlaceFlyout` against an anchor in the parent's content
  area. `Flyout.Place` resolves the placement in the work area of a
  display as GDK does for `gdk_window_move_to_rect` (`maybe_flip_position`,
  then slide, then resize, per axis), and `WorkAreaFor` picks the display
  as GDK's `get_monitor_for_rect`; macOS, X11 and Windows (in physical
  pixels) use it, Wayland hands the anchor to the compositor's
  positioner. The core places a window's flyouts again as it moves or
  resizes (owned windows on Windows and X11 popups do not follow), and
  as `SetAnchor` and `SetSize` change them. A focusable flyout closes
  through `WindowHandler.ShouldClose` when it loses the keyboard: as its
  panel resigns key (macOS), on a press outside it or a broken grab, or
  as the compositor dismisses the popup (GTK, as `GtkMenu`), and as
  another window is activated (Windows), whose activating click its
  owner eats (`MA_ACTIVATEANDEAT`), as menus' and WinUI's flyouts'. On
  macOS a local monitor eats a press on a panel's anchor, which only
  closes it, as `NSPopover` eats one on its positioning rect: the press
  would make the parent key, which closes the flyout before the release
  clicks the anchor and opens it again. An
  Escape the content leaves closes a flyout too: native UI reports one
  no shortcut took (`surface.Conn.Escape`), neither one of the last
  frame (`routeKeys`) nor one the frame handling the key builds, which
  takes it in the next frame (`settleKeys`): a key pressed as the view
  changes, before a frame shows the change, goes where the view now
  sends it, so an Escape typed ahead of the frame that builds a
  flyout's shortcut for it never closes the flyout. The bridge reports
  one no handler of the page cancelled (an `escape` message). `Flyout.Popover` shows one in an
  `NSPopover` (`internal/darwin/popover.go`), whose window AppKit makes
  as it shows, and whose transient behavior asks `popoverShouldClose:`.
  `Flyout.Tray` anchors one to a tray icon's `Bounds` instead, without a
  parent: the panel at `NSPopUpMenuWindowLevel` or an `NSPopover` shown
  from the status item's button (macOS), a topmost unowned popup
  (Windows), and on Linux, whose AppIndicator tells no bounds, an
  undecorated utility toplevel in the middle of the work area, which a
  focusable one closes as it loses the keyboard. A press on the icon
  does not dismiss its flyout (`tray.pressed` on resigning key, the
  cursor over `Shell_NotifyIconGetRect` on Windows), so its click
  toggles it, but a popover's: AppKit eats a click on a transient
  popover's positioning view, the status item's button, whatever
  `popoverShouldClose:` answers, so the button sends no action, and the
  click closes the popover (AppKit asks on the release on macOS 26, on
  the press elsewhere: one kept open there stayed open for good, #1050).
  A global monitor of mouse downs
  closes macOS's focusable panels on clicks outside the app, which a
  panel taking the keyboard of an app that was not activated never
  hears as the key window changing. A window modal to a flyout
  (`WindowOptions.Parent`, `Modal`) is centered over it by the core
  (`overFlyout`), in its display's work area, and keeps it open: the
  flyout's dismissals skip a flyout a window is modal to (`modalChild`
  on macOS and Linux, `hasModal` on Windows, where `EnableWindow`
  disables the owner as for any modal window). macOS attaches the window
  as an AppKit child window at the flyout's level rather than a sheet,
  and a local monitor eats the flyout's mouse and key events while it
  shows (`watchModalInput`); `popoverShouldClose:` keeps a popover.
  Windows makes it topmost over a topmost flyout. On X11 the popup lets
  its grab go while the window shows and grabs again as it hides
  (`enterFlyout`, `leaveFlyout`); a tray's flyout, a toplevel, does not
  close as it loses the keyboard to it. The design follows GPUI's
  `WindowKind::AnchoredPopup` and winit's `WindowType::Popup`, which
  model xdg_positioner too.
* Panels (`WindowOptions.Panel`), the windows of launchers: the core makes
  them always on top, out of the taskbar, unable to minimize, maximize or
  go full screen, and closes them on an Escape the content leaves, as
  flyouts. macOS makes a `MyGoPanel`, an `NSPanel` with the nonactivating
  style from `initWithContentRect:` on (the window server learns that a
  window never activates its app from the style it is created with; a
  style set later needs the private `_setPreventsActivation:`, as Electron
  and tauri-nspanel found), never the main window, on every Space as a
  full-screen auxiliary, outside Mission Control and the window cycle, at
  the floating level (above it, input methods' candidate windows would
  show behind the panel); `Show` and `Focus` make it key without
  `activateIgnoringOtherApps:`, and its `cancelOperation:` does nothing
  (NSPanel's closes it past `windowShouldClose:`). The key window of a
  nonactivating panel gets the keys and the main menu its key
  equivalents, though the app is not frontmost (`NSApp.isActive` reports
  it active then). Windows makes a topmost tool window owned by the hidden
  application window (a tool window alone may get a button on other
  displays' taskbars, as PowerToys found), its corners rounded as
  Windows 11 rounds other windows'; one the app maximizes fills the work
  area (`maximizeInWorkArea`), where Windows would give a window without
  a maximize box the whole monitor, over the taskbar; the key press of a `RegisterHotKey`
  shortcut lets the process take the foreground, and hiding the panel
  gives it back. Linux makes a sticky utility window, kept above, or on
  Wayland a surface of the overlay layer (`internal/linux/layer.go`):
  `libgtk-layer-shell.so.0` is loaded with the first panel, if it is
  there (0.9 patches GTK 3's private structures and intercepts nothing
  of libwayland, so it may load after GTK), and used where
  `gtk_layer_is_supported` says the compositor speaks wlr-layer-shell, as
  Ulauncher does. `gtk_layer_init_for_window` must come before GTK
  realizes the window. A position is the top and left margins from the
  edges of the output there (`gdk_display_get_monitor_at_point`), and
  without one the compositor centers the surface; gtk-layer-shell sizes
  it by its size request, not its default size. It asks for the keyboard
  exclusively while it shows: compositors give none to an on-demand
  surface as it maps, and Sway takes it back from one that goes from
  exclusive to on demand. Neither Linux nor Windows shows the application
  menu in a panel.
* `window.open()` and `target=_blank` go through `SetWindowOpenHandler`. By
  default http(s) URLs open in the default browser. Allowing one creates a
  window around the configuration or related view WebKit provides, with its
  own content manager so scripts and messages never leak between windows.
  On Windows the request's deferral holds the popup until the new window's
  web view is set up (its scripts, handlers and filters), which then becomes
  the popup (`put_NewWindow`) before WebView2 navigates it, so the page keeps
  its opener. On Linux the new window loads the URL as an independent page.
  `UserInitiated` says whether a user's gesture made a request, and so
  does `NavigateEvent` for navigations: on
  macOS WebKit's private `-[WKNavigationAction _isUserInitiated]` (looked
  up with `respondsToSelector:`; without it, a link or a form's
  `navigationType`), which sees a click whose handler calls
  `window.open()` or sets `location.href`; on Linux
  `webkit_navigation_action_is_user_gesture`, though WebKitGTK refuses a
  `window.open()` without one itself before asking
  (`javascript-can-open-windows-automatically` stays off), so the handler
  sees those only on macOS and Windows; on Windows the event arguments'
  `get_IsUserInitiated`, WebView2 having no pop-up blocker. Only main-frame
  navigations reach `OnWillNavigate`: on Linux the action's target frame
  says so (`webkit_navigation_action_get_target_frame_info`, 2.56+, bound
  when present); before it WebKitGTK tells no navigation's frame, and
  `mainFrameNavigation` takes all for the main frame's but `about:srcdoc`,
  which only an iframe shows.

## Menus

`Menu`/`MenuItem` are plain Go values built from templates. Roles expand into
labels, accelerators and submenus per platform (`roleDefaults`,
`roleSubmenu`); macOS-only roles are hidden elsewhere. Items get a process
unique id and are registered with weak pointers, so discarded context menus
can be collected. The core sends immutable snapshots (`platform.Menu`) to the
backend, which:

* builds native menus and tracks native items per owner (app menu, window menu
  bar, tray, popup) so `UpdateMenuItem` can change label/state in place and
  rebuilt menus release their items,
* performs edit roles natively (first responder on macOS,
  `webkit_web_view_execute_editing_command` on Linux; on Windows a page
  keeps their keys, which WebView2 performs, and the menu items run
  `document.execCommand` through DevTools, except Paste, which runs
  Chromium's paste command with the clipboard's formats, and Paste and
  Match Style, which inserts text), or sends them to a window showing
  native UI as a `SurfaceCommand`, and reports everything
  else through `WindowHandler.MenuItemClicked` for a window's menu, or
  `AppHandler.MenuItemClicked` for menus without one; the core toggles
  checkbox/radio state, performs window and view roles and calls `Click`
  with the menu's window, even while a submenu has focus instead,
* enables the edit roles' items of native UI as the content answers a
  `SurfaceCommandEnabled` (package ui's `commandEnabled`, which follows
  `editEvent`): on macOS the menus holding them validate their items
  (`autoenablesItems`), the surface answering `validateMenuItem:` and the
  menu target keeping the app's state, which a disabled role's item
  targets; Windows and Linux ask as a menu opens (`WM_INITMENUPOPUP`, a
  submenu's `map`, a popup before it shows), and again before a role's
  shortcut runs.

Item icons (`MenuItem.Icon`, made by `NewMenuIcon`) travel as a
`*platform.MenuIcon`, which the core shares between the icons of the same
PNG (interned by content, held weakly): backends tell a change by the
pointer and decode an image once (`MenuIcon.Native`), freeing what they
made with `runtime.AddCleanup` or with the menus that show it. Their code
is linked by `NewMenuIcon` (`LinkMenuIcons`), not by the backends' menus.
Backends that keep a snapshot to build menus from later (Windows' trays,
the application menu of new windows) keep it current with the updates they
get (`Menu.Apply`).

macOS gets a default menu bar (App, File, Edit, View, Window), which is what
makes Cmd+C/V/Q work; other platforms get none unless the app sets one.

A page's own context menu (`context_menu.go`, `Page.OnContextMenu`) goes the
other way: while a listener is set (`WindowHandler.HandlesContextMenu`), the
backend describes the menu the web view is about to show as a
`platform.ContextMenu` whose items carry a `Native` number and a `Name`,
and asks `WindowHandler.ContextMenu`. The core makes a `Menu` of template
items of them (`Menu.transient`, which refreshes no installed menu), fires
the listeners, and answers `Default` when the snapshot still shows the
web view's items as they were, none when prevented, else the snapshot,
each native item at most once. A native item the app gave a `Click`
leaves the snapshot as an item of the app's. What the backend does not tell
of the target comes from the bridge's `context-menu` record of the page's
`contextmenu` event, which arrives just before the backend's request on the
same connection, and is taken only when its point, times the page's zoom,
is the menu's (a frame's click never reaches the page's document); a new
page drops it. macOS and Linux change the native menu in place; Windows
draws a changed menu itself (see [Platform
differences](#platform-differences)). Its code is linked by `OnContextMenu`.

## Clipboard and drag data (`transfer`)

`transfer.Data` is the immutable serialized model shared by clipboard writes
and native drags: ordered items with alternative byte representations, MIME
formats, file/URI lists, and lazy providers. Each clipboard write or drag
starts an independent provider cache; discovery reads no bytes, and success,
errors and recovered provider panics are cached once. Typed `Drag(value)`
remains process-local, resolved by the core's temporary drag registry; its
token is rejected by clipboard writes.

`clipboard.go` owns validation, main-thread dispatch, provider reentry guards,
and deferred, exactly-once release hooks. `platform.Clipboard` accepts a
snapshot, returns materialized reads, discovers formats without rendering,
and flushes/closes native ownership. A concealed write
(`ClipboardOptions.Concealed`) carries each platform's mark for clipboard
managers next to its data, on write and on flush, and macOS writes it for
the current host only. Clipboard providers belong to the app,
not a source window. Quit flushes them before stopping the loop, and finish
releases remaining providers. Linux requires a clipboard manager for data
to remain after exit; a failed provider prevents flushing its offer.

macOS owns NSPasteboardItemDataProvider objects until AppKit finishes them,
with eager NSPasteboardItems after flush. GTK uses application-owned selection
get/clear callbacks and owner-change generation checks; clipboard-only apps
bind selection primitives without requiring a surface. Windows shares the
drag adapter's IDataObject, vtables, native conversions and reference-counted
objects with OleSetClipboard/OleFlushClipboard; foreign reads hold a Win32
clipboard lock. Callback signatures are allocated once and routed by native
object or user data. Native reads copy bytes so application data outlives
native handles. See [Clipboard and drag data](https://mygo.egoist.dev/docs/data-transfer.md) for API and
format mappings.

Native UI's `Context.WriteClipboardThen` writes its text with `WriteData`
and posts the error to the main thread for the next frame. A browser's
clipboard answers later: the web backend's is a `platform.LaterClipboard`,
whose `WriteTextThen` keeps the text for the page's own pastes and
answers once `navigator.clipboard.writeText` settles (it rejects without
transient user activation, and outside secure contexts there is no
`navigator.clipboard` to write).

## Audio (`audio`)

Package `audio` is independent of windows and the main thread: it neither
goes through `internal/platform` nor needs the app running. Players are
voices (`audio/mixer.go`) under one mutex. Each reads frames from a source,
an in-memory sound or a stream that a goroutine of its own decodes about a
second ahead into a ring (`audio/source.go`); the mixer never waits on a
stream, playing silence for one that is late. Voices resample to 48 kHz
stereo at their rate times their speed, and ramp their gains (a 2×2 matrix
of volume and pan) over 5 ms on every change, pause and resume. Looping
happens in the source, so a loop has no gap; the voice counts frames past
it modulo the length for `Position`.

Up to one source frame an output frame, a voice interpolates with a
Catmull-Rom spline. Faster (a sound above 48 kHz, or one sped up), a spline
would fold what is above 24 kHz back below it, so the voice interpolates
with a Kaiser-windowed sinc (`audio/resample.go`), a low-pass at the
output's rate: 32 output frames either side, -6 dB at 22 kHz, flat to
20 kHz and 80 dB down from 24 kHz, as many times wider in source frames,
and its cutoff as many times lower, as the source is faster. Its weights
are a bank the voice computes when its step changes, for 128 phases an
output frame (fewer source frames apart, the faster), from a table of the
kernel made once; it interpolates between the two phases either side, so a
frame costs two multiply-adds a source frame and channel, about 1% of a
core at 96 kHz. Past 8 source frames an output frame, the kernel stops at
256 frames either side: its window narrows to those, and its cutoff comes
down so that its stopband still starts at 24 kHz, as far as it can (to
48× it does). The voice keeps the frames around where it is in a ring of
512, stored twice over so that its kernel's are in a row, and reads its
source as far ahead as the interpolation reaches; `Position` stays where
the output is, not where the voice read to, and a seek clears the ring.

A player that preserves pitch (`SetPreservesPitch`) gets a stretcher
(`audio/stretch.go`) between its source and its resampler, which then
resamples at the rate alone. It is WSOLA: hops of about 16 ms, each a
Hann crossfade from the natural continuation of the last segment into a
new one, which the speed puts a hop times the speed further on and a
search within about 10 ms moves to where the waveforms match best
(normalized cross-correlation in mono, every frame of about 16 kHz, then
each frame around the best; the natural continuation itself when in reach,
so at 1× it passes the source through). Its buffers are allocated once,
the first time; it reads ahead what a step needs, skipping what fast speeds
leave out, reads silence past the source's end and fades out once the
speed puts the next segment there, and tags each
frame it gives with the source frame the speed puts it at, which the voice
keeps beside its four frames of history for `Position`. Turned off, it
passes the source through from the natural continuation, and a voice keeps
it, so that voices that never preserved pitch pay one nil check.

`Position` is where a voice is heard, not mixed. The mixer counts the
frames it mixed and, of the latest, those the device holds: as many as it
was written, up to its latency, from when it opened (`setHeld`). Each
voice marks the output's frame and its own source frame where each mix
starts and ends, and forgets the marks the output played; `Position`
interpolates them at the frame heard, which carries speed changes, a
stream waiting for its decoder, and a pause playing out. A seek or a
stop drops them, so the position is the target at once and stands there
until the output plays what it mixed since.

The output (`audio/output.go`) is a goroutine locked to one thread that
opens the device when a voice starts, mixes 10 to 21 ms at a time and
writes it with a call that blocks while the device holds enough, and
closes the device after five idle seconds. `audio.SetLatency` chooses how
much the device holds ahead, 40 ms or 250 ms; the output opens it again
when that changes. Each platform gives one `openDevice`, which takes it:

* macOS: an Audio Queue of buffers of 512 frames, as many as hold that (4
  or 24), started once all hold audio; its callback, created once, hands
  buffers back over a channel. A theme change can keep every thread of an
  app waiting for up to 0.2 s, which 4 buffers do not ride out.
* Linux: `pa_simple_write` of PulseAudio's simple API (`libpulse-simple`,
  which PipeWire serves too) with that as its target, else ALSA's
  `snd_pcm_writei` on `default`, both through purego.
* Windows: WASAPI in shared mode, event driven, with a buffer of that,
  `AUTOCONVERTPCM` and the default-quality resampler; it compares the
  default endpoint's ID every 500 ms and fails the write when it changed,
  which reopens the device.
* Browsers: an AudioWorklet from a Blob URL that queues chunks of 1024
  frames (three, or twelve) and posts a request whenever it used one; the
  output waits for a request before mixing the next, and asks more or
  answers fewer when the latency changes. One AudioContext serves the
  page, with the `latencyHint` it began with; closing suspends it, and the
  first pointer or key input resumes it.

Where `openDevice` fails, a null device takes the frames on the wall
clock and fails after two seconds, so the output tries the device again;
`audio.Err` reports the failure. Formats register a magic prefix and a
constructor as `image` does: WAV is built in, `audio/vorbis` and
`audio/mp3` wrap pure Go decoders, and so do `audio/aac` and `audio/flac`.
A file that starts with an ID3 tag is matched by what follows it.
`audio/mp4` reads the container and leaves its packets to a codec
registered by the sample entry's type (`mp4.RegisterCodec`): ALAC, an
in-package port of Apple's decoder, `mp4a` from `audio/aac`, `fLaC` from
`audio/flac`, so that the LGPL of go-aac stays with the apps that import
`audio/aac`. It places packets from the sample table, or, of a fragmented
file, from each `moof`'s `trun` as playing reaches it, with the length
from the `sidx`; AAC's packets it places 1024 frames apart whatever their
durations say, since that is what each decodes to, and a seek decodes one
packet before the one it lands in, whose sound overlaps it.

## Watching files (`watch.go`)

`WatchFiles` keeps what it saw of its directory (`watch_scan.go`): for
every file and directory, by path, a `fileWatchEntry` of 40 bytes without
pointers (the identity `os.SameFile` compares, size, modification time and
mode) rather than its `os.FileInfo`, whose `syscall.Stat_t` the collector
would scan: 220 to 260 bytes an entry, with the path and its name in its
directory's set. It is read through an `os.Root` so that a path can't lead
out of it, and symlinks are not followed.
Each directory is opened as an `os.Root` of its own from the one that has
it, and what is in it is looked at by name relative to it, one call each,
as watchman and @parcel/watcher crawl with `openat` and `fstatat`: a
root opens every directory of a deeper path in turn. On Unix, reading a
directory opened in a root stats its entries already
(`fileWatchEntryInfo`). Looking at everything again lists each directory
from the one that has it. A directory replaced by a symlink, which a root
follows only within itself, is a replacement, wherever it leads.
The backend's watcher (`platform.FileWatch`) is given targets, the entries
the core enrolls, and reports notices: a target, or a child of a directory
target by name, changed. A notice says where to look, not what happened:
after the debounce, the core lists again the directories that notices
named and stats the files, and the events are the differences between what
it sees and what it saw (`fileWatchDiff`). An entry whose identity
(`os.SameFile`) moved is a rename, unless a hard link makes it ambiguous,
and what moved with a directory renamed above it says nothing more. A
file replaced at its path by another file, as an atomic save replaces it,
is a write, not a removal and a creation: apps that follow a document
would take it for deleted. The
entries are paired by looking their identity up (`fileWatchIDs`: device
and inode, or on Windows the volume and file index `os.SameFile` reads),
so a directory of n files renamed costs n lookups, not n² comparisons;
an entry whose identity can't be read is compared with every other one. When
the system lost changes (an inotify queue overflow, Windows'
`ERROR_NOTIFY_ENUM_DIR`, FSEvents' `MustScanSubDirs` or a dropped event),
the core lists every directory again rather than stopping. Enrolling is
checked against the scan: the backend opens a target
and compares its identity with what the scan saw, then the scan stats it
again, so that an entry replaced in between (an editor's atomic save) is
looked at again rather than watched in place of the other.

A watched file is watched through its directory, enrolled as `..` with
the file as `.`: the scan's `os.Root` is the directory, and notices of the
directory naming other entries are dropped. A file replaced at its path is
reported as written. `Ignore` is asked from the directory listing's
type, before an entry is enrolled, so an ignored directory is never opened;
the directories it ignored are kept per listed directory, so that the
notices of a `Subtree` target about what is in them are dropped.

`HintsOnly` swaps the scan for `fileWatchHints` (`watch_hints.go`), behind
the same `fileWatchLooker` the watch's goroutine drives: no snapshot, only
the directories it enrolls. A notice naming an entry hints at the
directory holding it; one naming an enrolled directory, or the directory
itself, has the next update check that it is still what was enrolled and,
if not (moved, removed, replaced), drop the targets under it; a name that
may be a new directory is enrolled with what is beneath it. An overflow
hints at `.` and enrolls the tree again. Hints under one another collapse
into the shallowest. On Linux the directories are listed with `getdents`
types (`watch_hints_linux.go`), as notify walks them, so files are never
stat'ed; elsewhere a recursive watch is the root's `Subtree` target alone.
It is opt-in because it gives up what the snapshot is for: exact events,
renames, writes told from metadata, and which file.

An entry the scan can't look at, a directory without permission or a
file Windows holds (`pagefile.sys`, a sharing violation), is left as it
was seen, if at all, and what is in it unwatched, rather than ending the
watch; only the watched directory itself must be readable.

`Next` returns a batch, the events of one update. An update doesn't run
while a batch waits for `Next` (`taken` tells the goroutine when one was
taken): notices still mark what to look at, a set that falls back to
looking at everything past `MaxEntries`, so a slow reader loses nothing
and holds one batch. A directory gone ends the watch with a `FileRemove`
of `.` and `io.EOF`, as `Close` and the watch's context do.

The watch's goroutine is the only user of its scan and of its backend's
watcher, whose methods `internal/watchdriver` runs on a goroutine of its
own: it adds and removes targets between waits for the system, which
`Wake` interrupts, and calls the core's `notice` with what the system
reports; `notice` hands it to the watch's goroutine over a channel, and a
full channel makes the watch look at everything again. Neither uses the
main thread, so watches work before the app runs and don't wait on it.

* macOS: an FSEventStream per directory target, which covers the whole
  tree beneath it, so nothing is opened per file, and a file target is
  covered by the stream of its directory. A target below a stream already
  watching its tree needs no stream of its own, which keeps a watch of a
  directory that isn't recursive at one stream. The stream names what
  changed (`kFSEventStreamCreateFlagFileEvents`) and hears of the root
  itself (`kFSEventStreamCreateFlagWatchRoot`), delivering through one
  callback created at startup, on one serial dispatch queue of the
  process, never the main thread. `Subtree` targets report paths at any
  depth; one without it drops what changes deeper than its entries. The
  stream's path is resolved with `realpath`, as FSEvents names what is
  on disk, which a path given on a case-insensitive volume may not. The
  notices are hints: `MustScanSubDirs` or a full queue makes the core look
  at everything again, as an overflow does elsewhere, and the stream's
  10 ms latency is under the core's debounce, which does the coalescing an
  app sees; with `kFSEventStreamCreateFlagNoDefer` the first event after a
  quiet period comes at once, and those that follow it within the latency
  are batched. The stream starts `SinceNow`, but fseventsd can report a
  change made just before it started; the core's snapshot is taken as
  targets are enrolled, so nothing comes of it.
* Linux: one inotify instance for the process, as fsnotify, with a watch
  per directory, which names the child that changed: watches cost watch
  descriptors, not instances, of which many systems allow 128 per user
  for all apps. A goroutine reads it through the runtime's poller and
  queues each watch's notices, which its driver's `Wait` returns. The
  same directory added twice, by one watch or several, shares a watch
  descriptor, and a removed descriptor's events still queued before its
  `IN_IGNORED` must not be taken for a new one's, so the backend keeps
  generations of targets, each its watch and ID, per descriptor; the
  last target of a descriptor removes it.
* Windows: `ReadDirectoryChangesW` on overlapped handles, completing on a
  completion port per watch. Windows refuses to rename a directory while a
  handle is open on something beneath it, so a recursive watch is one
  `Subtree` target on its directory, which reports paths; other backends
  return `ErrUnsupported` for `Subtree` and get every directory. The
  directory's own handle says nothing when it is renamed, so the core also
  watches its parent and looks at the directory when the parent names it.
  The handles can't be given to the os package, which would tie them to the
  Go runtime's completion port. A handle closed still completes its I/O,
  which writes to its buffer, so a session lives until its completion.
  A drive's root has no parent to watch, and can't be renamed. The
  directories that `Lstat` takes for directories are watched, which leaves
  out junctions and mount points but not the placeholders of cloud files
  (OneDrive), reparse points that are no name surrogates.

Backends report a write (`FileWatchWrite`) only for content: FSEvents'
`ItemModified` on a file (its `ItemCreated`, which APFS also sets on an
`O_TRUNC` write, stays dirty and lets the core's comparison report the
change), inotify's `IN_MODIFY` and `IN_CLOSE_WRITE`,
and Windows without `FILE_NOTIFY_CHANGE_ATTRIBUTES`. Attribute changes are
dirty, and the core compares only size and modification time, so that
indexers and antivirus touching metadata report nothing.

## Documents (`document*.go`)

`NewDocuments` follows NSDocument and NSDocumentController for the
bookkeeping and SwiftUI's 2026 `Document` for the shape (a snapshot on the
main thread, the I/O on goroutines), with the recovery copies of VS Code
and Zed. Everything is in the core; backends only show a window's
document (`Window.SetRepresentedFile`, `SetDocumentEdited`) and replace
files (`Backend.ReplaceFile`). The menus reach documents only through the
functions the first kind registers (`linkedDocuments`), so that apps
without documents do not link them through the File menu's roles and Open
Recent (about 290 KB).

* *State.* `Document[T]` embeds `docBase`, the state that doesn't depend on
  the content's type, under one mutex: a change counter (`changes`), the
  change the file has (`savedAt`) and the recovery copy (`backedUp`), the
  edited flag, and the file's stamp (modification time and size) as last
  read or written. `docOps` is what the generic half gives the rest:
  `capture` takes the content and its change (on the main thread with a
  `Snapshot`), `markSaved` makes a written snapshot the saved one (with
  `Equal`, the document stays edited only if the content differs), so
  edits made during a write stay unsaved, as NSDocument's change count
  tokens and Zed's `did_save` keep them.
* *Writes* of a document's file and of its recovery copy hold its `io`
  mutex, which checks of the disk take too, so a watch never mistakes the
  document's own write for another app's. `writeFileSafely` writes a
  sibling, flushes it and replaces the file through the backend
  (`NSFileManager`, `ReplaceFileW`, rename with mode and owner on Linux),
  in place for hard links and folders the user can't create files in.
  Save and autosave stat the file first: a stamp other than the one known
  is a conflict.
* *Pacing.* One timer per document fires after the edits stop: the
  autosave delay for a document saved in place, a second for a recovery
  copy, shortened so that a document edited without a pause is written at
  least every 30 or 5 seconds (`dirtySince`).
* *Recovery copies* live in `PathUserData/Recovery/<kind>/<session>`, a
  session per running instance with an index of the copies, locked with
  `flock` or `LockFileEx` while the instance runs; at launch an instance
  takes the sessions whose lock it gets, reopens their documents edited
  (in conflict when the file's stamp changed), writes them into its own
  session, then removes only the old copies it restored. A copy it skips or
  cannot read, and one whose new copy cannot be written, stays for the next
  launch.
* *Watches.* One `WatchFiles` per file of open documents, shared by
  reference count, which costs the same whatever else its folder holds: a
  watch covers the folder, not each file in it. A batch
  makes the document look at the disk (`checkDisk`), as focusing its
  window does, and so does the watch once it started. A removal looks in
  the folder for the file's identity, to follow a rename.
* *Closing and quitting* never nest an event loop: `OnClose` of a
  document's window prevents a close that must save or ask, does it on a
  goroutine (dialogs are sheets on macOS), then destroys the window. The
  quit's `OnBeforeQuit` listener prevents a quit with edited documents,
  saves them in place, writes their recovery copies or asks, then calls
  `App.Quit` again (`docQuit.resolved` lets that one through), and
  windows closing during a quit no longer ask.
* *Launch.* `whenLaunched` runs once the launch arguments were delivered:
  the kinds restore their recovery copies, the files queued by
  `OnOpenFile` open, and then, with no document open, an untitled one.
* *Menus.* The document roles go to `documentRole` before the window
  roles; `refreshDocumentMenus` enables them for the focused window's
  document when focus or a document's state changes, and
  `updateRecentMenus` rebuilds the Open Recent submenus from
  `recent-documents.json` (`recent_docs.go`), which `App.AddRecentDocument`
  and `ClearRecentDocuments` write, for documents and other apps alike,
  before telling the system; in an app without documents an item goes to
  `OnOpenFile`.

## Native UI (`ui`)

The public API keeps one stable `*Context` per window. Child builders share
it and temporarily change its parent. `Element` is a 16-byte checked value:
a direct owner record, arena slot and 32-bit generation. The owner detaches
from the engine on close and retires before generation wrap. Old elements
cannot alias recycled nodes. A closed window keeps nothing of what it
showed (#1281): `mygo.Window` keeps only that it shows Content, handing the
Content to its surface as it attaches, and the closed engine drops its view,
the last frame's elements, states and scene, and the host its last scene,
renderers and placements, in case anything still holds them. Development builds and `Tester` diagnose stale
use; production methods return empty results or ignore it. `Handle` stores
persistent control identity separately for each window. Focus queries read
identity without depending on construction order; focus requests wait for a
hidden control. `Services` offers persistent clipboard, URL and redraw access.

Constructors build and style controls eagerly. `Context.Key` supplies an ID
before state initialization. A control takes its input as the public
constructor that built it returns, as Dear ImGui's widgets do, so what it
binds, a local copy too, holds the edit when the next statement reads it
(`value_input.go`). The generated facade brackets each constructor with
`beginBuild` and `endBuild`; a control's queued input records how many
constructors were under way, and `endBuild` finalizes the input queued
deeper than the constructors still under way: a container's (a radio
group's arrow keys) waits aside until the call that built its children
returns, and each entry is visited once. Input queued outside public
constructors, by the engine's own controls, is finished at once, and what
remains applies after construction. Input follows the options of the build
the user acted on: a constructor resets its fluent options (`ReadOnly`,
`OnPaste`, a slider's `Step`) for this build after keeping the last build's,
which edits apply by (`editor.withShown`, `sliderSettings.shown`), and the
retained `flagDisabled` is last build's. `Changed`, `Submitted`, click and
shortcut queries apply finished input before answering.
`ComboboxParts.Chosen` applies input and reports a choice in the same
pass; it is not carried into a later rebuild. `OnChange` and `OnSubmit` run after construction and bound
input, before rebuilding. Notices are cleared before another pass so an
edit cannot be reported again on a fresh local binding. Callback actions
consume input once and rebuild before paint.
The private render tree uses `node` and `context`; `internal/uigen` generates
the checked public facade. `FocusBind` binds desired focus to app data; `FocusedValue` reads actual focus independently of a hidden
control's pending request.

See the [migration guide](https://mygo.egoist.dev/docs/ui/migration.md) for the breaking element API,
`mygo migrate-ui`, and the Go type-aware lifetime checks in `mygo vet`.

A window with `WindowOptions.Content` shows a user interface MyGo draws
itself instead of a web page. The layers stay as everywhere else: the
toolkit (`ui`) is plain Go above the platform contract, a backend only
provides a surface to draw on and its input, and renderers know nothing of
either.

```
 view (Go) ──► ui: build, layout, paint ──► internal/scene ──► internal/gpu: d3d11 | metal | gl, or internal/raster
                 ▲       └─ internal/text: DirectWrite | Core Text | Pango | canvas, glyph and mask atlases
                 │
 internal/surface.Conn ◄── content.go (package mygo) ◄── platform.Surface: darwin | linux | windows | web | fake
```

* **The surface.** With `platform.WindowOptions.Surface`, a backend creates
  a view MyGo draws in place of the webview: a layer-backed NSView on
  macOS, a GtkGLArea on Linux (a GtkDrawingArea where OpenGL would not
  run on a GPU), a child window of class `MyGoSurface` on Windows.
  `platform.Surface` gives its native handles (for a swap chain, a layer,
  or the GtkGLArea while its `render` signal draws a frame, with its
  context current), size and scale, and the refresh rate of the display
  showing it (`RefreshRate`: the screen's `maximumFramesPerSecond`, GDK's
  `gdk_monitor_get_refresh_rate`, the display mode's frequency from
  `EnumDisplaySettingsW`); asks for a frame (`RequestFrame`: a
  paused `CADisplayLink`, whose ticks draw frames that follow each other
  themselves while a frame after a pause draws at once, in the same pass
  of the run loop, from the backend's queue (`drawSoon`), as does the
  first frame of a window out of sight, which the link does not tick
  for (`platform.FirstFrameSurface`): a window made hidden draws it
  while hidden, which makes it ready to show, and a resize's
  when AppKit displays the view, before macOS 14 an `NSTimer` at the
  display's rate, `gtk_widget_queue_draw` or a tick callback of GTK's
  frame clock,
  `InvalidateRect`); presents
  pixels drawn on the CPU (`PresentPixels`: a CGImage as the layer's
  contents, cairo in the `draw` signal, `SetDIBitsToDevice` in `WM_PAINT`;
  on Linux `PresentDamage` too, with what changed);
  sets the cursor; and turns the input method on and off at the caret
  (NSTextInputClient, GtkIMContext, IMM32), with the text around it, up to
  512 runes on each side (`SetTextInput`). Everything else comes through
  `WindowHandler.SurfaceEvent`, in DIPs: frames, resizes, the pointer, the
  wheel, keys, text, compositions, focus, the edit roles of menus
  (`SurfaceCommand`), files dragged and dropped, and assistive technology.
  The back and forward buttons of a mouse come as the keys `KeyBack` and
  `KeyForward`, as do the keys of keyboards that have them: buttons 3 and 4
  of `otherMouseDown:` on macOS, and `swipeWithEvent:`'s swipes, left
  going back as in Safari, which touchpads swiping between pages send and
  mice's makers' software sends for their buttons (Logi Options+), buttons 8 and 9 and `XF86Back` and
  `XF86Forward` on Linux, and `WM_XBUTTONUP` (taken, so that
  DefWindowProc sends no `WM_APPCOMMAND` as well), `VK_BROWSER_BACK` and
  `VK_BROWSER_FORWARD`, and `WM_APPCOMMAND`'s browser commands on Windows.
  A key held down repeats as `KeyPressed` with `Repeat`, which the
  shortcut that takes it tells (`shortcutReg.repeat`,
  `Context.ShortcutRepeated`): `isARepeat` on macOS (and the current
  event's, for the Edit menu's commands that reach shortcuts), bit 30 of
  `WM_KEYDOWN`'s lParam on Windows, `KeyboardEvent.repeat` in browsers.
  GdkEventKey flags none, so the Linux surface notes the hardware
  keycodes held (`keysDown`, before the input method sees the key): a
  press of one held already, with no release between, is a repeat, as X11
  with detectable auto-repeat (which GDK turns on) and GTK's own repeat on
  Wayland send them.
  A key typed while the input method composes is the input method's
  alone, as Enter choosing a candidate: on macOS `keyDown:` sends no
  `KeyPressed` while there is marked text, as GTK's input method filters
  such keys on Linux and IMM32 makes them `VK_PROCESSKEY` on Windows.
  A composition an input method gives up, as with Escape, goes: the
  Microsoft Japanese IME sends `WM_IME_COMPOSITION` with neither
  `GCS_COMPSTR` nor `GCS_RESULTSTR` then, which empties the marked text
  (`InputComposition.Cancel`) before `WM_IME_ENDCOMPOSITION` unmarks it.
  A composition the content does not take (`SurfaceEvent` returns false
  for `TextComposition`) macOS gives up (`discardMarkedText`, once
  `interpretKeyEvents:` returns), as the terminal leaves the dead key ´
  of Option-E that it sent as Alt, so that the next key is not composed
  with it.
  Input methods name what text and compositions replace in the text
  around the caret (`Replace`, `From`, `To`): NSTextInputClient's
  replacement ranges, GtkIMContext's `delete-surrounding`, IMM32's
  reconversion (`IMR_CONFIRMRECONVERTSTRING`). Files dragged over the
  surface (NSDraggingDestination, a GTK drag destination, an OLE
  `IDropTarget`) are `FileDragOver` events, whose answer the drag source
  shows, and a drop a `FileDrop`; files the content does not take go to
  `OnFileDrop`. On Linux the area takes the touchscreen's touches
  (`GDK_TOUCH_MASK`, in its `event` signal, before GTK's `touch-event`
  handler makes the first finger the mouse), which `touch.go` turns into
  what the mouse and a touchpad do: a tap clicks where it landed, held
  still half a second it right-clicks, as Windows's press and hold; a
  finger moving past 8 DIPs scrolls (`Precise`) the content under it
  along with it, and two fingers zoom (`PointerZoom`) between them and
  scroll as their midpoint moves. Button and motion events from a
  touchscreen are dropped once the area has had touches.
* **Assistive technology.** Once it asks for a surface's content, the
  backend sends `AccessibilityOn`, and the engine describes every frame
  (`ui/access.go`) as a `platform.AccessTree`: nodes in pre-order with
  roles, names, values, ranges, states, bounds and actions, under
  `UpdateAccessibility`. Backends keep a native object per node ID and
  tell the system what changed between trees: subclasses of
  `NSAccessibilityElement` and AppKit's notifications on macOS; on Linux,
  ATK objects of GObject types registered through purego below the
  accessible of a `GtkGLArea` or `GtkDrawingArea` subclass, with ATK's
  signals, which GTK bridges to AT-SPI; on Windows, UI Automation
  fragments, COM objects with control patterns, answering `WM_GETOBJECT`,
  with UI Automation's events.
  What assistive technology does comes back as `AccessAction` events,
  which the engine performs as the pointer or the keyboard would.
  An element ignoring input (`IgnoreInput`: a field of the node, as
  the flags are all taken, and of its state, which the elements inside
  it inherit at commit) adds no hits nor stop of Tab and drops the focus,
  but stays in the tree, its presses counted as any other's; it offers no
  focus, nor the increments that go through the keys. One hidden from
  assistive technology (`AccessHidden`, a field of the node and of its
  inherited state, as `IgnoreInput`; inert ones count too) paints and
  takes input, but `accessElement` skips it with what is inside it, as an
  invisible one, its text names no ancestor (`innerText`), and its
  state drops what `AccessAction` sends it.
  One only unavailable (`AccessDisabled`, ARIA's aria-disabled, a
  field of the node and of its inherited state too) keeps
  `flagDisabled` off, and so its hits, its stop of Tab and its look,
  but its node is `AccessDisabled`, which the backends already map
  (`AXEnabled`, ATK's enabled and sensitive states, UI Automation's
  `IsEnabled`), still `AccessFocusable`, with no actions but the focus
  and scrolling into view, and its state drops the others; UI
  Automation's `SetFocus` reaches a disabled element that offers the
  focus, as Chromium's does one aria-disabled.
  `AccessTree.Announcements` are texts to read out once
  (`Context.Announce`, toasts, routers): `AXAnnouncementRequested` posted
  on the application with a medium priority on macOS, AtkObject's
  `announcement` signal (ATK 2.46), which AT-SPI carries as
  `Object:Announcement`, on Linux, and on Windows a polite live region at
  the end of the tree holding the text, raising `LiveRegionChanged`, as
  Flutter's alerts: `UiaRaiseNotificationEvent` returned `S_OK` but its
  events reached no client, unlike the provider's automation events.
  Statuses, as toasts, are polite live regions too (`LiveSetting`).
  Widgets of an app's own set what the bases set with element methods
  (`Checked`, `Mixed`, `Expanded`, `Value`, `Range`, `Level`,
  `ActiveDescendant`, `Busy`, `Current`, `AutoComplete`,
  `PositionInSet`). `AccessSelected` is `Selected` without its accent
  background and text color: it sets the same state (`checked`, which
  is `AccessChecked`, read as selected on tabs, options, rows, cells and
  tree items), so every bridge, a table's or a grid's choice of cells
  and rows included, reads it as it reads `Selected`'s. `PositionInSet`
  (`accSet`, aria-posinset and aria-setsize, each 0 for not given) wins
  over the `setPos` and `setSize` the bases give their items, which
  count those built, but not over a List's rows, whose place among all
  its rows also places them in their table on macOS and Windows. `Busy`
  (`AccessBusy`, ARIA's aria-busy) is WebKit's `AXElementBusy`, with `AXElementBusyChanged`, on
  macOS, ATK's busy state, and `busy=true` in UI Automation's
  AriaProperties; `Current` (`AccessNode.Current`, aria-current's
  kinds) is WebKit's `AXARIACurrent`, ATK's `current` attribute with the
  active state, as Chromium's, and `current=page` in AriaProperties. Both
  bring a generic element into the tree as a group, as ARIA's global
  states do. `AutoComplete` (`AccessNode.AutoComplete`,
  aria-autocomplete's inline, list and both; none writes nothing) is
  WebKit's `AXAutocompleteValue`, answered through
  `accessibilityAttributeValue:`, ATK's `autocomplete` object attribute
  with the supports-autocompletion state, as Core-AAM maps it (and as
  IAccessible2's object attribute and state), and `autocomplete=list`
  in AriaProperties, which UI Automation has for ARIA's properties
  without one of its own: Core-AAM maps nothing in UI Automation nor in
  AX API, and Chromium nothing in UI Automation; `Combobox`,
  `Autocomplete` and a `TokenField` with suggestions set it to list.
  `RoleDescription` (`AccessNode.RoleDescription`,
  aria-roledescription) is AppKit's `accessibilityRoleDescription`,
  which elements override, ATK's `roledescription` attribute and UIA's
  LocalizedControlType; `Controls` (`AccessNode.Controls`, the IDs of
  the elements, aria-controls) is `AXLinkedUIElements`, ATK's
  `controller-for` relation and `controlled-by` back, from the nodes'
  `ref_relation_set`, and UIA's ControllerFor; `DescribedBy`
  (`AccessNode.DescribedBy`, aria-describedby) adds the text of the
  elements to `Description` (their Label, else the texts inside them,
  hidden or not, joined by spaces, after the element's own), and is
  ATK's `described-by` relation with `description-for` back, and UIA's
  DescribedBy beside FullDescription; AX API has no relation for it,
  only the text in `AXHelp`. `ErrorMessage` (`AccessNode.ErrorMessage`,
  aria-errormessage) is given only while the element is invalid
  (`Invalid` sets `AccessInvalid` alone, or `Error`), puts the text
  first in `Description`, as `Error` does its message, and is WebKit's
  `AXErrorMessageElements`, answered as `AXInvalid` is, ATK's
  `error-message` relation with `error-for` back, and UIA's
  ControllerFor, as Core-AAM maps it; UIA also raises
  IsDataValidForForm and FullDescription changing, as a field turns
  invalid as it blurs. `Orientation` (aria-orientation) sets
  `AccessVertical` or `AccessHorizontal` on any element: `AXOrientation`,
  ATK's vertical or horizontal state and UIA's Orientation, a slider and
  a separator across unless told, others without one. `Search` on a
  text input sets `AccessSearch`: `AXSearchField`, ATK's
  `xml-roles:searchbox` and `text-input-type:search`, UIA's Edit with
  "search box" and the searchbox AriaRole. `RoleDeletion` and
  `RoleInsertion` (ARIA's deletion and insertion) are `AXGroup` with
  `AXDeleteStyleGroup` and `AXInsertStyleGroup`, ATK's content deletion
  and content insertion with `xml-roles`, and UIA's Text named
  "deletion" and "insertion". `RoleTabPanel` (ARIA's tabpanel, the
  content a tab's `Controls` points to) is `AXGroup` with the role
  description "tab panel", ATK's scroll pane with
  `xml-roles:tabpanel`, and UIA's Pane with "tab panel" and the
  tabpanel AriaRole; `HasPopup`
  (`AccessNode.HasPopup`, aria-haspopup) is `AXPopupValue`, answered as
  `AXInvalid` is, with `AXShowMenu` pressing the element, ATK's
  has-popup state and `haspopup` attribute, and UIA's ExpandCollapse
  with `haspopup=` in AriaProperties; `Sort` sets a header's
  `AccessSortAscending`, `AccessSortDescending` or `AccessSortOther`
  (ATK's `sort:other`, UIA's ItemStatus and `sort=` in AriaProperties,
  AppKit's unknown direction). A cell (`RoleCell` or a header) that
  `Checked` or `Selected` marks is `AccessSelectable`, chosen while
  `AccessChecked`, as ARIA's gridcells with aria-selected, and the
  table around it `AccessSelectable` too: `AXSelected` and the table's
  `AXSelectedCells` (with `AXSelectedCellsChanged`), ATK's selectable
  and selected states rather than checked, UIA's SelectionItem in the
  table's Selection. `RoleNavigation`, a landmark (`Breadcrumbs`), is
  `AXGroup` with the subrole `AXLandmarkNavigation`, ATK's landmark with
  `xml-roles:navigation`, and UI Automation's Group with the navigation
  LandmarkType and AriaRole. Native UI in browsers has no accessibility
  tree yet (`UpdateAccessibility` is empty in `internal/web`), so there
  is no ARIA to map them to. The other landmarks, live regions and rules
  map as WAI-ARIA's Core Accessibility API Mappings do: `RoleRegion` is
  one only with a name (a group without), `AXLandmarkRegion`, ATK's
  landmark with `xml-roles:region`, and UIA's custom LandmarkType;
  `RoleSearch` is `AXGroup` with `AXLandmarkSearch`, ATK's landmark
  with `xml-roles:search`, and UIA's Group with the search LandmarkType;
  `RoleMain`, `RoleBanner`, `RoleContentInfo` and `RoleComplementary`
  are `AXGroup` with `AXLandmarkMain`, `AXLandmarkBanner`,
  `AXLandmarkContentInfo` and `AXLandmarkComplementary`, ATK's landmark
  with `xml-roles` main, banner, contentinfo and complementary, and UIA's
  Group with the main LandmarkType, or the custom one named "banner",
  "content information" and "complementary";
  `RoleArticle`, no landmark, is `AXGroup` with `AXDocumentArticle`,
  ATK's article, and UIA's Group named "article";
  `RoleLog`, `RoleTimer` and `RoleAlert` are `AXGroup` with
  `AXApplicationLog`, `AXApplicationTimer` and `AXApplicationAlert`,
  ATK's log, timer and notification, and UIA's Group named "log",
  "timer" and "alert"; `RoleSeparator` is `AXSplitter`, ATK's separator
  and UIA's Separator, vertical when taller than wide (`AccessVertical`,
  with `AXOrientation`, ATK's vertical state and UIA's Orientation);
  `RoleRowHeader` is `AXCell`, ATK's row header and UIA's HeaderItem,
  named by its content but keeping what is inside it, as a cell does
  (ARIA's rowheader is not children-presentational).
  Live regions (`AccessRole.Live`) say how they are read: `AXARIALive`,
  `AXARIAAtomic` and `AXARIARelevant`, answered as `AXInvalid` is; ATK's
  `live`, `atomic` and `relevant` attributes, with their `container-`
  forms on what is inside them; UIA's LiveSetting. Screen readers read
  the platforms' live regions in web content alone (WebKit's and
  Chromium's `AXLiveRegionChanged`, Orca's web scripts), so the engine
  reads them out itself (`ui/access_live.go`): it compares each frame's
  tree with the last, announces what a log that showed gained, joined
  for each log, and puts the text an alert shows that no alert showed
  in the last tree into `AccessTree.Alerts`, which interrupt:
  `AXAnnouncementRequested` with a high priority, ATK's `notification`
  signal with `ATK_LIVE_ASSERTIVE` (ATK 2.50, else an announcement), and
  an assertive live region beside the announcements' on Windows. Alerts
  are told apart by their text, as an element's ID shifts when others
  appear before it; the tree assistive technology first gets, and a log
  first showing, read nothing out. Menus drawn in the window are AppKit's `AXMenu`,
  `AXMenuBar` and `AXMenuItem`, whose choice shows as
  `AXMenuItemMarkChar` (answered through `accessibilityAttributeValue:`,
  as `AXInvalid` is), ATK's menu, menu bar, menu item, check menu item and
  radio menu item, and UI Automation's Menu, MenuBar and MenuItem, with
  Toggle for the items showing a choice; headings are WebKit's
  `AXHeading`, whose value is their level, ATK's heading with the `level`
  attribute, and UI Automation's Text with `HeadingLevel`. A vertical
  slider says so (`AccessVertical`: `AXOrientation`, ATK's vertical state,
  UI Automation's Orientation). A range's step, how far the keys move
  its value (`AccessNode.Step`), is UI Automation's SmallChange (and
  LargeChange at least as much) and ATK's minimum increment, through
  `get_minimum_increment`, as purego's callbacks return no floats for
  `get_increment`; AppKit has none, and its increments go through the
  keys. A read-only text input is
  `AccessReadOnly`, without `ActionSetValue`; a text box of your own (`Role(RoleTextField)`
  with no editor of MyGo's) says so through `ReadOnly` and `Multiline`
  (aria-readonly, aria-multiline). `ReadOnly` is reported by the roles
  aria-readonly is for, on elements without a widget of MyGo's behind them:
  text box, combo box, check box, switch, slider, stepper, radio group,
  list box, grid and tree grid, and the cells and headers inside a grid or
  tree grid (`reportsReadOnly`, the nearest `tabular` ancestor decides; a
  table's cells do not have it). Such a node has no `ActionSetValue`,
  `ActionIncrement`, `ActionDecrement` (nor `ActionPress` on a check box
  or switch); ATK adds `read-only` to the states of any role with
  `AccessReadOnly`, UI Automation's `IsReadOnly` follows the state, and
  AppKit's `AXValue` is not settable. AppKit finds an element's
  value settable when its class overrides the setter, whatever
  `isAccessibilitySelectorAllowed:` says, so elements answer the older
  `accessibilityIsAttributeSettable:` themselves, as AppKit would but for
  that value: `NSAccessibilityElement` has no implementation to call.
  The keys that press or focus an element (`KeyShortcuts`, ARIA's
  aria-keyshortcuts) are formatted as `ui` writes a menu's shortcuts
  (`shortcutText`) as the view builds, so that an app not giving any
  links no formatting, and reach the backends as one string
  (`AccessNode.KeyShortcuts`): WebKit's `AXKeyShortcutsValue`, answered
  through `accessibilityAttributeValue:`, ATK's `keyshortcuts` object
  attribute and UI Automation's `AcceleratorKey`, as Chromium's.
  The rows of a `List` (list items) and a `Table` (rows) are named by
  their content and say which of all the rows they are (`PosInSet`,
  `SetSize`, the list giving its total), as only those in view are built;
  rows built beyond the view are `AccessOffscreen`, and what is in a scroll
  container scrolls into view on request (`AccessScrollIntoView`), a row
  of a list by its place, which builds it. A list choosing rows has the
  focus for them: the tree's `Focus` is the chosen row while the list has
  the keyboard focus, so the arrows are read as they move the choice, and
  focusing a row chooses it, as screen readers expect of an active
  descendant. On macOS, lists are tables (`AXTable`) of rows
  (`AXTableRow`), as AppKit's, with `AXIndex`, `AXRowCount`,
  `AXVisibleRows`, `AXSelectedRows` and `AXSelectedRowsChanged` (a
  list without a `SetSize` or `RowCount` of its own counting as many rows as its
  items' `SetSize` says, if more than it holds), and
  `AXScrollToVisible`, an action of AppKit's older API, which elements
  then answer for all their actions; on Linux, a list choosing rows is a
  list box with `AtkSelection` and `selection-changed`, rows carry the
  `posinset` and `setsize` object attributes (as any item's), and `AtkComponent`'s
  `scroll_to` (ATK 2.30) scrolls; on Windows, rows have `PositionInSet`,
  `SizeOfSet`, `IsOffscreen`, `SelectionItem` (raising `ElementSelected`)
  in their list's `Selection`, and `ScrollItem`. A list choosing several
  rows is `AccessMultiselectable` (ATK's `multiselectable`, UIA's
  `CanSelectMultiple`, rows then raising `ElementAddedToSelection` and
  `ElementRemovedFromSelection` unless chosen alone), and its focus is on
  the row last chosen. `RoleListBox` and `RoleOption`, a list box of an
  app's own (ARIA's `listbox` and `option`), are `RoleList` and
  `RoleListItem` with `AccessSelectable`, as a `ComboboxBase`'s popup and
  its options (`choosesItems`, `flagChoosable`) and a `SelectBase`'s
  are, so the bridges show them as the lists above, selected with
  `Checked`; unlike `flagChoosable`'s rows, they take the focus only
  when `Focusable`. A `SelectBase`'s options are selected while
  highlighted, the trigger's `ActiveDescendant` the one highlighted, as a
  native select's popup: assistive technology focusing one
  (`focusHighlights`) notes it on its state (`focusAsked`), which the
  select highlights as it builds it, rather than clicking it, which
  would choose it. Grids and tree grids (`RoleGrid`, `RoleTreeGrid`)
  are tables to the backends (`AccessRole.Tabular`), whose rows a `List`
  shown as one makes rows rather than list items; a row of an app's own
  saying whether it is chosen (`Checked`, `Selected`) is
  `AccessSelectable`, as is the table or grid holding it, which holds
  its cells' choice too. The counts and indexes an app gives a grid built only where it shows (`RowCount`,
  `ColCount`, `RowIndex`, `ColIndex`, ARIA's aria-rowcount and the like)
  go to WebKit's `AXARIARowCount` and the like, and the rows' `AXIndex`
  and the table's `AXRowCount` where `PosInSet` and `SetSize` say
  nothing; to ATK's `rowcount`, `colcount`, `rowindex` and `colindex`
  attributes beside `xml-roles` `grid` or `treegrid`, as Chromium's; and
  to UI Automation's `Grid`, `GridItem`, `Table` and `TableItem`
  patterns of tables and their cells (`uia_grid.go`), which count from 0
  as the app gave them, else as rows say which of all they are after the
  header rows above them, else by what is built, found as a client asks;
  their `RowHeader`s are the `Table` pattern's row headers. A cell's
  `ColumnSpan` and `RowSpan` (`node.cellSpan`, from the layout's
  `gridCell`, whether or not its row is a grid) are `AccessNode.ColSpan`
  and `RowSpan` (aria-colspan, aria-rowspan): the lengths of its
  `AXColumnIndexRange` and `AXRowIndexRange` (`placeCells`, which puts
  the next cell after the columns it covers), ATK's `colspan` and
  `rowspan` attributes, and `GridItem`'s `ColumnSpan` and `RowSpan`,
  `Grid.GetItem` finding the cell at each place it covers.
* **The connection.** `content.go` attaches the content to its window
  through `internal/surface.Conn`, which carries the surface and, as
  functions, what the content needs of the app (the clipboard, dragging
  the window, the appearance, the room of a hidden title bar's controls,
  opening URLs, context menus), so `ui` imports neither
  `mygo` nor a backend, and an app without native UI links none of it.
  `Window.Update` and `Invalidate` coalesce redraws asked from any goroutine
  into one frame on the main thread, which `Conn.Changed` asks the content
  for, so that it builds anew. Page methods return `errNoPage` or do
  nothing.
* **Frames.** The engine (`ui/runtime.go`) calls the view to build a frame,
  again (up to three times) when a handler changed the state while it built,
  so the frame shows the outcome. A window that closes during a frame (a
  close button's click; backends report `Closed` at once) keeps its engine
  until the frame ends: the rest of the view builds with a working
  `Context`, no further callback runs, nothing is laid out or painted, and
  the engine closes as the frame ends. Observing `Pressed` when a pointer press
  begins also rebuilds before painting, so selection made on press and its
  focus colors appear together; holding the pointer asks for no further
  build passes. The engine lays it out with flexbox (`layout.go`) or
  as a grid (`grid.go`, CSS grid's placement and track sizing for fixed,
  fractional and content-sized tracks, with the items' percentages of
  their grid areas, as auto while the tracks are sized), laying out again
  only what changed since the last frame (see below); commits the boxes to the elements'
  states with the hit list in paint order, the focus order and the labels;
  paints a `scene.Scene`; and presents it. The pointer finds what it is
  over in the hit list, last first (`appendHitChain`, `contains`): an
  element whose visible part, clipped as commit found it (`state.vx`..),
  does not hold the point is passed by before its transform is inverted,
  unless its scroll containers moved or a pose moved it since
  (`state.reposed`), so that a move over a large tree costs little;
  `TestHitFilterMatches` compares with every box tested
  (`engine.noHitFilter`). Input between frames goes to the
  states of the last frame's elements. A release that comes with moves no
  pass read waits in the element's state (`releaseLater`) for the pass
  that reads them, which applies it as it ends (`forgetInput`): the view
  sees the element still pressed where the pointer let go, and released
  in the pass after. An element's identity hashes its
  parent's with its position or `Key`, so focus, scroll offsets, editors and
  animations survive rebuilding. Each pass lists the states it looks up
  (`engine.built`, `nbuilt` of them, `lookState`, less those `unlook`
  gives back): `forgetInput` visits those alone, `prune` looks for states
  to drop only when the pass built fewer than there are, and the formats
  of native drop targets are gathered only in a pass that made one
  (`noteTarget`), so that what a frame costs past building follows what
  it built rather than every state of a map; ui's tests check the lists
  each frame (`checkFrames`, `checkBuilt`), its benchmarks do not.
  `prune` drops the states the frame did
  not build (but those of pages Routers keep) and recycles them; a state
  with `Local` values that are `io.Closer`s (`state.closes`, which
  `Local` fills as it makes one, so that other states cost nothing) hands
  them to `engine.dropped`, which `endFrame` closes on the main thread
  once the frame ended, last made first. Those of an element whose copy,
  or an ancestor's, leaves with an `Exit` wait in `engine.exits` until
  the transition's record is gone or no longer holds that copy (the
  exit ended, or the element came back), and the engine's `close` closes
  every state's as the window closes. An element's `OnUnmount` keeps its
  function in such a `Local`, under a key of its own (`unmount`,
  `ui/local_close.go`), whose `Close` runs the function given last.
  `Context` is stable for the window; `Element` values expire between build
  passes and validate their owner, slot and generation before accessing storage. `ListState` resolves
  its focus owner only for the current context, frame and pass, exposing
  focus and shortcuts without retaining an element in app state. Scroll
  offsets move in the layout too
  (`ui/scroll.go`): elements that asked to `ScrollIntoView`, and the focus
  as the keyboard or the app moved it (`node.focus`; a click does not,
  nor the app while a pointer button is held or with
  `FocusOptions.PreventScroll`),
  come into view before the boxes are placed, lined up as its options say
  (or glide there as a wheel's notches do, by what they went each frame,
  `glideScroll`), and placing keeps each offset within its content; a
  `ScrollState` mirrors an offset both ways, and a frame that moved one
  builds another for what read the old one. A container that snaps
  (`ScrollSnap`, `ui/snap.go`) finds the places its elements mark as it
  is placed, from their boxes relative to it, and
  keeps the offset at the one it rests at; a notch or a key heads for the
  next place at once, a touchpad's scrolling once it has been still for a
  moment (not every platform tells when the fingers lift or a fling's
  momentum ends), along a spring that the frames advance (`glideSnaps`).
  Only `ScrollSnap` installs what snapping takes (`placeSnapper`, the
  `snapper` interface of the container's state), so apps that do not snap
  leave it out. Frames
  happen only when asked: input, `Invalidate`, `After`, or `AnimationFrame`
  while something moves.
  The view builds the whole tree each frame, but layout reuses what did not
  change (`ui/layoutcache.go`), as Blink reuses the layout result of a box
  not marked as needing layout in the same constraint space and Flutter
  skips a render object whose constraints are those of its last layout.
  Nothing marks a rebuilt tree, so before laying out `sameLayout` compares
  each element with what its state kept of it from the last frame: its
  `layoutStyle` (the fields of `node` that lay it out, embedded in it), the
  flags and inherited text styles the layout reads, its grid's tracks, its
  spans, its image's size, and its children, the same elements in the same
  order, each the same in turn. `layoutBox` then reuses the last layout of
  an element that is the same when it gets a box of the same size: its
  text's layout and its children's boxes, laying out again any child laid
  out at another size since; what was measured of it (its content widths
  and heights) is reused too, so that a container laid out again measures
  its unchanged children at once. The state of a text element also keeps
  the widths of its text and its last two layouts (`heldText`), found
  again by their parameters, as Taffy keeps a node's measurements: an
  element laid out anew whose text is the same, as the rows of a List
  each frame, asks nothing of the text system's cache, whose key costs
  more to hash than to compare, and one laid out at another width asks
  for it from the last (`text.System.LayoutFrom`). A grid measures the
  widths of only the items its columns read (`contributes`): none for Fr
  columns with room known, as CSS's minmax(0, 1fr), unless they are
  `MinContent`; a minimum (`Track.Min`) measures nothing. Transforms and scroll
  offsets of other containers apply after layout and change nothing
  there. Elements that lay
  out by more than they are built with are never reused, nor anything
  around them: a List (rows built as it lays out), a Form, a Table's
  fitted columns and a toolbar (which change elements inside them as they
  lay out, so neither is anything inside those), an input, an element
  attached to another. A field added to `node` must say whether layout
  reads it (`TestLayoutInputs`); `TestLayoutCacheMatches` lays random trees
  out with and without the cache (`engine.noLayoutCache`) as they change
  at random, frame after frame.
  A frame asked for only by drawings that move (`Painter.AnimationFrame`,
  `Painter.After`, as spinners and progress bars of unknown length do)
  paints the elements of the last frame again at its own time
  (`repaintFrame`), without building or laying out; elements out of view
  are not painted, so they ask for none. Nor are the others, mostly
  (`ui/repaint.go`): the frame painting the window keeps, for each Draw or
  DrawOver callback that asked for frames, the operations it painted and
  the painter as it was (`paintPart`), and a frame that only paints again
  runs those callbacks alone and splices what they paint into the last
  frame's scene in place of what they painted (`repaintParts`). It paints
  the window whole when anything else asked (a pose moving, a drawing
  painting into a layer or a canvas, as `engine.untracked` notes), while
  the inspector shows or a drag moves, and once the parts have added more
  glyphs, stops and words than `partsGrowth` past what the whole frame
  held. `TestRepaintPartsMatchWhole` compares the frames with those
  painted whole (`engine.noParts`). Such a frame is asked for with
  `redraw` set, which every event of the surface clears (`buildNext`), so
  that the frame builds anew in case the event changed what the view
  shows; anything asking for a frame built anew clears it too (`askBuild`),
  and the frame `Painter.After` has due with it, which the frame asked
  for replaces: `requestFrame`, `Conn.Changed` (`Window.Update`,
  `Invalidate`, and `After`'s timer through them) and a change of the
  appearance. An event that asks for no frame, as the pointer moving over
  elements that do not look at it, leaves that frame due.
  A hover that only changes looks paints the last frame's elements again,
  whole, rather than building the view (`lookDue`, `askLook`), as browsers
  restyle and repaint for `:hover` without running a page's scripts: a
  button the pointer comes over in a window of thousands of elements costs
  a paint, not the whole view. `Hovered` notes who reads it: the view, as
  it builds (`state.hoverBuilt`, reset as the pass looks the state up), or
  painting (`hoverLook`, reset as `Painter.element` paints it), as the
  controls' styleFns pick hovered backgrounds and borders and scroll
  containers show their bars. `hoverNeeds` looks at the elements that
  came under the pointer or left it alone (those hovered still see no
  change): one read as built, showing a tip, with a `Transition` (whose
  colors move in frames built anew), or looking at its hover
  (`flagHover`) without having told how, builds anew, as do elements
  following the pointer (`flagTrackPointer`) anywhere in either chain and
  a window the inspector shows; one read only as painted paints. A frame
  built anew asked for since (`buildAsked`) shows the hover, so none is
  asked then, and asking for one clears `lookDue`; a move bringing other
  modifier keys builds anew, as views may show what they do. The frame
  that builds a scroll's rows under a still pointer paints their looks
  already (`rehover(false)`); after it presents, a hover moved by `prune`
  asks for a frame painting (`rehover(true)`). A styleFn, and a
  `Transition` moving colors or shadows, change the element's colors,
  opacity and shadows as it paints; `Painter.element` puts back those it
  was built with once it painted (`builtStyle`), so that painting it again
  starts from them, not from what the last painting chose (a moving
  shadow points to the transition's own array, never into the built one).
  `TestHoverLookPaintsAsBuilt` compares each frame painted for a hover
  with the frame built anew, over many controls.
  What the frame writes after the build into fields the view builds goes
  in the journal (`ui/journal.go`): a table's, a form's and a toolbar's
  fits, a List's offset, an attached element's origin and hiding, the
  spans a paragraph merges from the texts inside it, the parent of exit
  copies, and whole elements before a transition, a magic move or the
  inspector's edits change them (`journalKeepNode`). The journal goes
  as the next build begins, its elements built anew; it is what lets an
  element kept to a later frame without being built again go back to
  what it was built with (`rollback`) before that frame lays it out
  (#1599). What the frame computes in fields of its own needs none: the
  boxes, `world`, `ink`, the measures and layout records, the inline
  fragments and the tree's links. ui's tests (`TestMain`) check after each
  frame that the other fields, the journal rolled back, are what the view
  built (`checkBuilt`, `builtcheck_test.go`, comparing their bytes and the
  elements of their slices); `MYGO_BUILT_COLLECT=1` checks after each
  phase and lists what changed rather than failing, to find the writer. A frame of another size, or after the text
  system forgot its layouts (`text.System.Generation`, as it lets go of
  fonts the elements' layouts hold), builds anew all the same. The timers
  the last frame built armed stay; the host arms them (`afterTimer`,
  `repaintTimer`), and `Painter.After`'s posts to the main thread.
  A drawing asking for fewer frames (`Painter.AnimationFrameRate`) has
  those frames come every so many of the display's refreshes, the fewest
  that give it as many frames a second at least (`engine.pace`), unless
  anything else in the window asks for each: `Painter.AnimationFrame`, a
  pose moving, the view animating. The refreshes between draw nothing
  (`paceSkips`) unless something else asked for a frame since, and the
  surface is told of the rate (`platform.FrameRateSurface`): macOS sets
  its display link's `preferredFrameRateRange`, which has a ProMotion
  display refresh as often while nothing else on it asks for more. A
  surface whose frames asked for come at once rather than at the next
  refresh (`platform.ImmediateFrameSurface`: Windows, where presenting
  paces frames) would ask again and again until the frame is due: the
  repaint timer asks for it then instead, and the frame it brings keeps
  the pace's times, as the timer fires a little late. With the display's
  rate unknown (browsers), frames come at each refresh.
  While nothing of the window shows (`platform.OccludableSurface`: a macOS
  window hidden, minimized or covered by other windows, whose display link
  still ticks while it is covered, at the display's rate for half a
  minute, then at about 40 Hz, but not while it is hidden or minimized,
  where a timer draws the frames `RequestFrame` asks for instead, a
  refresh after the last, and the backend's queue (`drawSoon`) the one
  after a pause; a minimized window on Linux, as GDK's `window-state-event` tells
  on X11, and on Windows, as `WM_SIZE` does, where no `WM_PAINT` comes
  and `RequestFrame` draws the frame from the queue as well), what moves asks for no frame, and a frame asked for by a change of
  the state waits (`holdFrame`; both `held`), as browsers draw nothing for
  windows out of sight and as Apple asks of Mac apps: the view function,
  `Draw` and the work `After` drives wait until some of the window shows.
  `SurfaceShown`, sent as some of the window shows again
  (`windowDidChangeOcclusionState:`), draws what changed, and has a held
  animation go on from where the time puts it; a video (`VideoPlayer`)
  goes on from where it stood instead, counting its time from then
  (`engine.shown`), as one the view stopped building does. Its frames
  decode on a goroutine, two ahead, into frames handed back for it to
  decode into again; the view takes the last frame due, passing over the
  others, has the bitmap show it (`Bitmap.Update`), and asks for the next
  with `After`, or waits for the goroutine to wake the window (`waiting`)
  when it has no frame due yet. A video of the system's media framework
  (`ui/video`, below) moves on by the framework's clock instead; a muted
  one holds still out of sight, as a decoder's does. The window shows its last
  frame until then, about a refresh: captures of it meanwhile, as sharing
  its window in a video call, see that frame. A frame still builds after
  input (`input`, as keys typed into a key window another app's covers),
  as assistive technology turns on, and for `CapturePage`, which builds
  the frame waiting, held or asked for and not come
  (`windowHost.waitsOutOfSight`), as the surfaces of macOS draw none for
  a hidden window, nor for any behind the locked screen, whose display
  link does not tick (a frame built outside the surface's asks for one
  to show it, `unshown`, which builds nothing more); and none waits
  before the window's first frame
  reached its surface (`windowHost.occluded`), which a window made hidden
  waits for to become ready to show. `Context.WindowHidden` reads
  `occluded`; once a view asked (`hiddenAsked`), `SurfaceHidden`, which
  the surfaces send as none of the window shows any more, builds one
  frame out of sight, as input does, for the view to stop its work, and
  `SurfaceShown` one whether a frame was held or not.
  The window gaining or losing the keyboard focus draws a frame only when
  the last frame read it (`windowFocus`, as a focus ring, a caret, a
  selection's color or a focused text input's IME state do): a window
  hiding or showing again draws nothing it would draw the same. So does
  the window becoming active or inactive (`windowActive`, which the
  widgets read through `context.emphasized` and `context.accent` where
  they would fill with the accent, and `Context.WindowActive`), told by
  `surface.Conn.ActiveChanged`. Each
  frame matters on macOS, where the Metal driver takes 30 to 45 MB of the
  process's footprint ("owned unmapped (graphics)") for the first command
  buffer encoding anything after a pause, and gives them back a second or
  two after the last, as a bare Metal app does.
  A frame allocates next to nothing once the view builds what it built
  before: elements come from the context's arena, the default theme is
  copied for each pass, the states that pruning frees go to new elements
  (as rows coming into a list's view take those of rows that went out of
  it), without keeping their local resources, editors or callbacks.
  The arena uses chunks of 32 elements, releases unused chunks after a
  smaller frame, and keeps one empty chunk for growth; unused elements
  and the spare arena of exit transitions give up their references after
  the frame copied what it needs. A text keeps in its state what it made
  of its spans
  (`spanCache`: their text, the styles of their layout, encoded, and where
  each ends), which a frame compares rather than makes again. With
  `MYGO_FRAME_STATS` set, frames slower than its threshold log how long
  each part took, which path drew them, what the process allocated and
  whether the collector ran (`ui/framestats.go`).
  With `MYGO_UNCAPPED=1`, which `internal/pacing` reads once (`Uncapped`),
  frames wait for no refresh, for benchmarks, profiling and the least
  latency (#1496): the next frame asked for starts once the last was
  presented. Only the frames asked for come sooner, so an idle window
  still draws nothing. The host holds no frame drawn in memory to the
  refreshes (`refreshPresented`) and counts every surface's frames as
  coming at once (`framesAtOnce`), so `Painter.AnimationFrameRate` keeps
  its pace with the repaint timer; the backends and renderers each skip
  their own wait: Direct3D's swap chain has no frame latency object, three
  buffers and, where DXGI allows it, tearing, and presents every frame
  with sync interval 0, without `waitComposed` or `waitRefresh`
  (`internal/gpu/d3d11/uncapped.go`); macOS draws each frame from a
  timer firing at once (`surface.frameSoon`), not the display link, into
  a CAMetalLayer whose `displaySyncEnabled` is off; Linux tells GTK's frame
  clock a refresh interval of a microsecond (`paceFrameClock`) and, on X11,
  sets the GLX swap interval of the window GDK paints to 0
  (`gl.UnsyncGLXSwaps`); browsers keep requestAnimationFrame's pace. On
  Windows a live resize presents paced, from the window's first change of
  size until the swap chain settles (`presentsUncapped`): no tearing, a
  frame of a new size waiting for DWM to show it and the others for the
  composition that shows each, as uncapped frames queued for DWM while it
  resized the window, and one present took 2 s. Each of those waits is
  bounded, the frame of a new size's at two refreshes, with DwmFlush called
  on another thread (`waitShown`): called on the main thread within
  `SetWindowPos`, it was the one wait with no bound when a present took
  2 s at the start or end of a resize the app made. Nor does Present wait
  long then: with no frame latency object to tell when the swap chain has
  room, Present waited for it on the main thread, and a frame redrawn in
  part still took 2 s in 2 resizes of 12, most likely queued behind
  buffers DWM held. While resizing, frames present with
  `DXGI_PRESENT_DO_NOT_WAIT`, tried for a refresh at most (`showSoon`);
  one Present still refuses waits, unpresented, for the next composition
  while the main thread takes its messages, or gives way to the next frame
  drawn (`holdFrame`, `presentHeld`). One still not taken after `maxHeld`
  (100 ms) presents without the flag, waiting as long as DXGI has it, on
  another goroutine (`presentAside`, `goAside`), and until DXGI takes a
  frame at once with the swap chain settled (`gaveUp`), frames stay paced
  with the flag and the buffers resize, to settle or to grow, on another
  goroutine too (`resizeAside`). Meanwhile the main thread makes no call
  to the context nor the swap chain: a frame drawn then is put off, the
  frame after waits (`Ready`), `Release` waits for the call (2 s at
  most), and once it returned the frame after draws, or the window is
  asked for one (`askFrame`). A resize's last frame held for good otherwise left nothing
  drawing; dropping it and drawing on had the settle frame take 994 ms on
  the main thread, in `ResizeBuffers` or a plain Present; and putting such
  frames off until DXGI took one with the flag and an event query said the
  GPU was done, waiting on nothing (0338404), put every frame off for good
  in 4 resizes of 70: nothing the app did without waiting ended DXGI's
  refusal, while the call that waited did, so such a call is now made, off
  the main thread. Uncapped, the refresh period is read from DWM on
  another goroutine (`readPeriodAside`).
  With `MYGO_FRAME_STATS` too, the engine logs how many frames came each
  second (`frameStats.rate`), counted anew after a pause or a frame as long
  (250 ms), and each frame's path says uncapped.
* **Video of the system's media framework** (`ui/video`,
  `ui/engine_video.go`, `internal/media`, `scene.Surface`). A
  `media.Engine` plays one video: AVFoundation's `AVPlayer` with an
  `AVPlayerItemVideoOutput` on macOS, Media Foundation's `IMFMediaEngine`
  in frame-server mode on Windows, GStreamer's `playbin` with an `appsink`
  on Linux, a video element in browsers, each reached without cgo
  (purego, COM vtables through `syscall`, `syscall/js`) and loaded with
  the first video opened. The engine decodes, plays the sound and keeps
  the clock; `VideoPlayer` (`videoEngine`) asks it, as each frame builds,
  for the picture due at the frame's time (`Engine.Frame`) and shows it
  in its bitmap as a `scene.Surface` (`Bitmap.showPicture`), which
  renderers sample where the decoder left it: Metal wraps a
  `CVPixelBuffer`'s IOSurface planes with a `CVMetalTextureCache` and
  keeps the `CVMetalTexture`s until the frames in flight that read them
  completed; Direct3D opens the engine's shared texture (an NT handle,
  BGRA, which the engine converts into on its own device) once by its
  `NativeID` and reads it under its keyed mutex (key 0) within the frame;
  GL uploads NV12 planes, 1.5 bytes a pixel, or in browsers the element,
  GPU to GPU. NV12 is converted in the shaders' YUV image class (the
  matrix in the instance's params, the chroma in texture slot 10 or 11),
  which the CPU renderer samples the same way (`raster.sampleNV12`).
  `Bitmap.UpdateYUV` shows an app's own frames so (`YUVImage.surface`):
  NV12's planes as they are, and I420's with its Cb and Cr interleaved
  into a plane of NV12's chroma that the bitmap keeps, a quarter of the
  frame's bytes, so that the renderers and their shaders know one layout
  of planes. The
  window asks for the next picture with `After` at the engine's interval,
  or an engine that knows when one comes (GStreamer's appsink, the
  element's `requestVideoFrameCallback`) wakes it (`Engine.SetWake`),
  as it does for a change of state. A muted video holds its engine paused
  while out of sight, under less motion, and once a frame that built the
  view did not show it (`engine.sweepVideos`); one with sound plays on.
  On Windows, arm64's doubles go through two thunks of machine code, as
  `syscall` passes and returns only integers there.
* **Visual transforms and motion** (`ui/transform.go`, `ui/motion.go`). An
  element's transform, 2D, or 3D in a 4×4 matrix (`mat4`) that it flattens
  into its parent's plane as CSS's flat transform-style does, composes
  with its ancestors after layout as a projective map
  (`scene.Affine`, with G and H in perspective); boxes keep their original
  layout space. A `scene.Affine`'s divisor is 1 at its origin, or -1
  (`Behind`) when the origin is behind the viewer though what is drawn is
  in front: a turn in perspective around an element far from the
  window's origin puts the window's origin past the turned plane's
  horizon (#1406). Products and inverses keep the divisor's sign, and the
  shaders take it from the instance (`Transform2.z`). Elements and
  `Painter.Transform` flatten a 3D transform around its own origin and
  move it there in 2D. A transform that puts all of its plane behind the
  viewer (`TranslationZ` as far as `Perspective`'s distance, not turned)
  flattens to a singular map, which shows nothing; `BackfaceHidden` tests the normal through the whole 4×4
  inverse, perspective included (`facesAway`, as Chromium's
  `IsBackFaceVisible`). `TranslatePercent` stays apart from the transform
  (`translatePct`): `transformAt` resolves it from the box as laid out,
  after the transform and before the pose, as a pose's percents
  (`showPose`) and a `Motion`'s (`tbox.moved`) are. Painting stores the composed transform on scene
  operations and clips, and committing keeps it on the state for
  inverse-mapped pointer input, carets, accessibility bounds, and overlays
  attached to visual bounds. The CPU renderer inverse maps pixels for
  transformed primitives and clips, and leaves what a projective map puts
  behind the viewer. GPU builders retain local geometry and send three
  transform rows with every instance; the vertex shaders project the quad
  in homogeneous coordinates, so that local coordinates interpolate in
  perspective, and fragment shaders integrate coverage in device space:
  from screen derivatives for affine maps, and, in perspective, at the
  CPU renderer's sample points, mapped back from the pixel's center
  through the inverse. Nested
  transformed or rounded clips use cached masks, independent of content
  moving within them, once they hold content that a transform does more
  than move (`scene.Reshaped`), or a clip reaching into their rounded
  corners (`scene.ClipCorners`, which the scissor rectangles of outer
  clips would not cut); hard clips in the drawing's coordinates,
  and clips around content only moved, evaluate on the GPU. Stationary
  clips reducible to one rounded rectangle also evaluate on the
  GPU, even around scaled, rotated or perspective content, as a sidebar
  against the side of a rounded frame does (#1511). A fractional
  hard edge can remove whole corners; overlapping antialiased edges,
  transformed clips and image/gradient masks retain their existing mask
  path, as do continuous corners on the renderers whose shaders don't
  draw them (all but Metal's, `gpu.Builder.SplitCorners`). Backdrop
  effects map local samples into the frame. With a GPU, every frame draws
  there, including resting changes to transformed content.
  Metal retains wide colors under transforms. See
  [Transforms](https://mygo.egoist.dev/docs/ui/transforms.md#rendering) for rendering details.
* **Masked clips** (`ui/mask.go`, `scene.ClipShapeOf`). A clip
  (`OpPushClip`) may carry a gradient paint, whose alpha masks it
  (`MaskLinearGradient` and the others, around the element's inset
  rectangle from `ClipInset`), or an image, whose alpha masks it over its
  rectangle (`Painter.ClipPath`: the path's coverage, rasterized by
  `internal/vec` once for each shape and kept by the engine while paints
  use it). The GPU builders draw such clips into the cached clip-mask
  textures, as transformed or rounded clips do (`raster.ClipMask`), and
  never evaluate them in the shaders, so no shader changed for them. The
  CPU renderer multiplies the clip's coverage by the mask
  (`raster.clipMasking`). Each op under a mask is masked on its own,
  rather than through a group layer as `Opacity` fades (below). A clip moved
  by a translation moves its gradient with it (`scene.MovedClipOp`), and
  damage compares the version of its image.
* **Motion** (`ui/motion.go`): every animated value of an element
  (`AnimateTo`, `Animate`, `AnimateWith`, `Spring`, `Jump`) is a `channel`
  by key, with a value, a velocity and the time they hold for, moving
  along a curve or a spring. Springs solve damped oscillators analytically
  (`solveSpring`), so frames however far apart follow one path; a channel
  samples its path at the frame's time before taking a new target or kind
  of animation, so position and velocity survive interruptions (a curve's
  velocity is its easing's slope). A delayed target waits in the channel
  while the old path goes on. `Jump` sets values and derives a velocity
  from successive ones; presses keep their last moves (`dragTrack`), in
  the element's axes and the window's, for `DragVelocity` and
  `DragEnded`, and their button (`state.pressButton`, `PressedButton`):
  `Pressed`, `Dragged` and the controls that follow the pointer (sliders,
  `Draggable`, value drags) take the primary button's alone
  (`pressedPrimary`), a right or middle press only clicking or opening a
  menu. Keyframe sequences keep one sequence per
  key with an explicit replay token. All ask for frames only while moving,
  and end at their targets under reduced motion, but for those whose
  `NonMotion` (of `Animation`, `KeyframeOptions`, `TimelineOptions`) says
  they move nothing, which play on. Poses (`ui/pose.go`,
  `AnimatePose`) are channels sampled as frames commit, into a transform
  after the element's own (`poseM`) and a fade; frames that only paint
  (`repaintFrame`) move the posed elements of the last frame built on
  (`repose`) and set their subtrees' transforms again (`updateWorld`), so
  they move without the view running. `Draggable` (`ui/draggable.go`)
  keeps two channels of an offset (`dragRec`) that `showPose` adds to the
  pose's translation: as the pointer drags the element, they hold where
  the press's move in the window (`dragTrack`), mapped into the parent's
  axes through the inverse of its last world transform, takes the offset
  from where the press caught it, so they are the same in every build
  pass of a frame; once let go, a spring starts at the release's velocity
  for where `Snap` chooses from the projected throw, and goes on in frames
  that only paint, the view building once more when it comes to rest. Content transitions (`ui/content.go`)
  keep what an element showed, and fade or roll it into what it shows as
  it paints, counting paintings (`engine.paints`) rather than frames
  built, so frames that only paint move them on too.
* **Transitions** (`ui/transition.go`) animate elements FLIP-style, after
  the layout of each frame and before `place` turns boxes into window
  coordinates: an element given a `Transition` keeps, by its ID, where the
  layout put it relative to its parent, its size, and what it shows, and
  goes from what it showed to a new place or size over the transition
  (parents first, as one resizing lays out its content anew at each size,
  which then moves itself). Moving with a parent or a scroll offset is no
  change; resizing the window animates nothing, and reduced motion only
  fades and colors. Each moving component (position, size, opacity, and a
  `Motion`'s scale, rotation and blur) is a motion `channel`, so a spring keeps
  its velocity through changes and a delay holds them. A blur goes with
  the opacity, as it moves nothing, and adds to the element's `Blur` as
  Gaussians compose, which `paintEffect` draws on every renderer. Colors move as
  elements paint, after their `styleFn`, mixed premultiplied in sRGB, or
  in Oklab (`mixLab`) with the `Oklab` of their `Animation`. A `Match` moves an element
  appearing where another of the same identity showed the frame before
  (`ui/match.go`, `matchRec`, in window coordinates) after `place`
  (`matches.move`), laying it out anew at each box on the way, or scaling
  it (`ScaleContent`), across parents and scroll offsets, from the colors
  the other showed (`matches.claim` notes them before `animateExits`
  forgets it). With `Fly`, it blends the other's corners, opacity, text
  color and transform into its own (decomposed as CSS does, in 3D into a
  quaternion slerped the short way, whose sign holds at half a turn), and
  the transform of the
  elements around the other into that of its own (`worldAround`, shown
  with a transform of its own, `under`). The element it came from goes
  with it if it flies too, fading out as it fades in (Motion's crossfade
  curves): itself while still built, as in a page going away, else a copy
  that `matches.claim` takes, in place of its `Exit`, from the arena of
  the frame before, which frames with an element flying keep as those
  with an `Exit` do, with the text style and the theme of the elements
  around it; copies of its ancestors going away hide theirs. Both are
  `lift`ed, over the rest of their layer: the window's content, which the
  root paints them over before the overlays, or the overlay they are in,
  which its layer paints them over (`matches.paint`), out of their
  ancestors' clips and opacity, in the theme of the `Themed` around them.
  `commit` lists their hits there too (`engine.liftHits`, put over each
  layer as the next starts), where `contains` stops at them the clips
  around them, so that they take the pointer where they paint. Each is
  placed where its content sits on the pixels as at rest, and shown where
  it is with a translation (`matches.pin`), which elements flying inside
  it take into account, so that its text moves as one, smoothly, and ends
  as text at rest; a flight ends with its look, its box within a quarter
  of a point of its own. One gone with an ancestor going as its `Exit`
  says flies on as its copy in the ancestor's (`matches.flyOn`), from
  where it showed to where that copy has it, its colors going on as its
  transition moved them, fading as that copy fades; other copies of
  elements flying (`ghostOf`) no longer fly. A text flying with
  `ContentTransition`'s `Morph` takes the other's text layout into its
  content transition instead, whose `morph` (`ui/morph.go`) pairs the
  glyphs it comes from (`morphGlyph`, the old layout's, colored by the
  spans its rich text last painted with, which `morphRest` keeps) with
  the clusters of its layout (their longest common sequence, then the
  nearest of the same characters left) and moves, scales and recolors the
  glyphs of each pair, fading the others, the old text's going with the
  element's box, and the lines and highlights of both texts' styles and
  spans. It places each glyph as text at rest where the box goes would
  (`text.System.Origin`), drawn at the quarter of an octave nearest the
  size it shows, and moves it from there with a transform, so that the
  glyphs move smoothly and together, rather than each a pixel at a time,
  and end as text at rest. A text sent back to the one it morphs from
  before it got there morphs back from as far from the end as it was from
  the start, which shows the same; one that another text takes over
  morphs from its glyphs as they showed (`snapMorph`, from the same walk
  of them, `morphPairs.each`, as painting them). `ContentTransition`
  links `morph` only for a `Morph`, so that apps without one link none of
  it. A frame without an
  element on its way notes only where each `Match` showed and the element
  that showed it (`matchRec.node`), whose look and the transform of the
  elements around it an element flying from it reads in the next frame,
  from the arena kept, rather than each frame noting them. The engine has
  its `matcher` only once a `Transition` has a `Match` or `ScaleContent`,
  so that apps without them link none of it. An element appears with
  its `Enter` only in a parent the frame before had; the overlay layer,
  built only while it holds something, counts as the root there. One no longer built,
  whose parent still is, goes with its `Exit` as an inert copy, laid out
  and painted under its siblings of its z-index without taking room; the frames after
  one in the overlay layer, or its copy, build the layer, empty but for
  the copies, which lets the pointer and the focus through
  (`engine.overlayExits`). Frames that built
  elements with an `Exit` leave their arena to the next frame, which
  builds in the other (`Context.spare`), so that the next one copies those
  gone (`ghostOf`), with states of their own and nothing referring to the
  app's state. The parent's `ChildExit` in the frame it goes
  (`context.childExits`) takes the place of its `Exit`. An element
  appearing with `AfterExits` waits unseen (`transition.held`,
  `flagInvisible`) while copies leave under its parent (`ghosts`, which
  `animateExits` sets after the elements built have moved), and comes in
  with its `Enter` in the frame they are gone. Siblings are not laid out around a size moving; they move
  with their own transitions, in step when they share it.
* **The inspector** (`ui/inspector.go`, `inspector_details.go`,
  `inspector_panel.go`, `inspector_overlay.go`), as Chrome's developer
  tools. A window whose DevTools are on (`surface.Conn.DevTools`, from
  `PageOptions.DevTools`) opens it for the Toggle Developer Tools role
  (`Conn.ToggleDevTools`), F12, or Alt+Cmd+I (Ctrl+Shift+I), and picks
  for Shift+Cmd+C (Ctrl+Shift+C). It is a panel built with the view's
  elements as the last child of the root, keyed, which is narrower by
  the panel's width (the view sees a narrower window); hits and paint
  cover the whole window. Its theme is a copy of the default one in
  Chrome's colors, light or dark, whose accent colors the tree's chosen
  row. After each frame is laid out, it notes the tree of elements, the
  keys given them while it is open (`rekey`), and the details of the one
  chosen (`describe`: its styles as CSS rules, own and inherited, its box
  model, computed values and properties), and asks for another frame when
  a hash of them changed, which the panel then shows; frames whose
  elements stay the same draw no more, and the times of frames, which
  the Performance tab draws against the display's refresh, ask for
  none. The tree is a `List` of the opening and closing tags of the nodes
  shown. Picking takes the pointer
  over the content before the elements do. Painting highlights the
  element hovered, or chosen while the tree has the focus, over the
  content, with a tooltip. The source of the element chosen is the first
  frame outside package ui on the stack as it is created or keyed
  (`callSite`), only for that one. Two elements keyed alike under one
  parent share one state: `rekey` reports it (`duplicateKey`), logged
  once and listed as an issue, and in a `Tester` it panics
  (`engine.strict`), without package testing in apps.
  The Styles tab edits (`inspector_edit.go`): a view builds its elements
  anew each frame, so edits are kept by element ID and applied to the
  frame's elements after the view and before layout (`applyEdits`), through
  `setStyle` and `unsetStyle`, which `ownStyles` must read back; a property
  they don't know stays read-only (`styleKnown`). `describe` then overlays
  what the elements can't show: values as typed, declarations turned off or
  not understood (`overlayEdits`). Rules are keyed by their element, as the
  bar of changes comes above them. Closing the inspector drops the edits.
  `changesAsGo` (`inspector_gocode.go`) writes them as calls of package ui,
  whose methods a test looks up on `Element`, from what `setStyle` parsed.
  `:hov` forces states by element (`inspector.forced`): `Hovered`, `Pressed`,
  `Focused`, `FocusVisible`, `FocusWithin` and `ringShown` ask `isForced`,
  which the stub of `mygo_noinspector` answers with false.
  The tree's `flex` and `grid` badges show layouts over the content
  (`inspector_layout.go`). A grid's tracks exist only as it lays out, so
  `gridLayout` gives them to `noteGridTracks`, behind the constant
  `inspectorBuilt` since an empty stub would still grow its frame and code,
  with the layout cache off while a badge is on for it to run.
  Laying a grid out again after `place` would move its baseline items, which
  are in window coordinates by then.
  `main.go:42` opens in the developer's editor (`inspector_editor.go`):
  `MYGO_EDITOR`, `VISUAL` or `EDITOR` names the command, started in a session
  of its own so that it outlasts `mygo dev` restarting the app, and failures
  go to the Issues tab. Browsers and phones keep `os/exec` out
  (`inspector_editor_none.go`).
  Production builds of `mygo build` leave the inspector out with the build
  tag `mygo_noinspector` (`inspector_off.go` stands in for it, never
  open), added to the tags of `GOFLAGS`, unless `-debug` or
  `MYGO_INSPECTOR=1`.
* **Automation.** `plugins/automation` drives the app from another
  process over a Unix domain socket (`MYGO_AUTOMATION`), gated with the
  inspector. Core gives it one hook: the plugin's `init` sets
  `surface.Automate` only when the variable is set, and `ui`'s
  `AttachContent` (`windowHost.automate`, empty under
  `mygo_noinspector`) hands it each window's `surface.Conn` and a
  `surface.Automated`, which reads the last frame's access tree with
  the elements' keys (`node.key`, which `rekey` sets too), tells
  whether a frame was asked for and has not come (`windowHost.frameAsked`),
  and in a window out of sight builds the frame that waits to build there
  (`Settle`, `windowHost.waitsOutOfSight`), which the surface may draw only
  once the window shows: the plugin settles before it reads the tree and
  after it acts or sends input, so that a press reaches the view.
  Only the plugin calls `Automated`'s methods through the interface, so
  apps that don't link it don't link them. Actions and input go to
  `Conn.Event` on the main thread, as the backend's events do; menu items
  are chosen through the backends' test hooks (`TestPerformMenuItem`,
  `TestActivateMenuItem`); captures and scripts through `Window`'s and
  `Page`'s methods. `mygo-automation` (`plugins/automation/cmd/mygo-automation`, its code
  in `internal/automationcli` so that `internal/e2e` runs it in process)
  is a client of the socket on Go's standard library alone: it prints
  trees as lines with refs (`@e7`) that a session's file maps to windows
  and element IDs, gives a number once per session so that a stale ref
  never names another element, and after `--settle` (`idle`, then
  `tree`) diffs the elements by ID against what the session saw last.
  Its guide, `SKILL.md`, is embedded in the command (`skills`), so that
  it matches the version installed.
* **Input taken as it comes.** An element with `HandleInput` gets its
  input on the main thread as the backend reports it, before the frame
  (`ui/handler.go`): keys (with their releases, which ui otherwise
  ignores), text, compositions and edit commands while it has the focus,
  unless a `Shortcut` around it claims the key, and the pointer pressed on
  it, moving over it or scrolling over it; once it takes a press, the
  moves and the release come to it, as to a pressed element, and the
  release comes as the window loses the focus or once a frame builds the
  element no more (not built again, or built over by an element without
  `HandleInput`, as when the press moved it into a split), so that the
  next press starts anew. Those releases, and a press the system takes
  (`platform.PointerCancel`: a browser's `pointercancel`, a pen's or a
  finger's `WM_POINTERUP` with `POINTER_MESSAGE_FLAG_CANCELED`, or
  `WM_CAPTURECHANGED` while a button is down, on Windows, which
  `WM_CANCELMODE` brings too, GDK's `GDK_GRAB_BROKEN` of the pointer on
  Linux, a context menu's loop that takes the release on macOS), are
  `InputEvent.Canceled`: the handler still gets its release, so that
  what holds a press lets go, but the engine commits nothing of it
  (`pointerUp`'s `canceled`): no click or right-click, no drop (the
  value's drag is given up, as with Escape), no `DragEnded`, no context
  menu waiting for the release, and `PressCanceled` reports it, which
  sends `Draggable` back to where the press took it. A cancel coming
  while nothing is pressed does nothing, so a backend sends it whenever
  it loses a press, but not as a data drag of its own takes the pointer
  (OLE's loop, `gtk_drag_begin`), whose end ends the press. The Linux
  touchscreen's `GDK_TOUCH_CANCEL` taps nothing (`touch.go`), as its
  taps press only once the finger lifts. The pointer's events carry their device and
  pressure (`SurfaceEvent.Pointer` and `Pressure`), which the engine
  keeps with the buttons they leave down (`engine.pointerDevice`): a
  device that tells no pressure presses 0.5 while a button is down and 0
  otherwise, as Pointer Events have it, a move that changes the
  pressure alone is a move, and the element pressed keeps the device and
  pressure of its press's last move for `PressedPointer`
  (`state.pressPointer`). Its
  `TextCaret` turns on the input method at that caret, with no text around
  it; `InputMethod(false)` (`TextInputState.NoInputMethod`) keeps text on
  but input methods off, as winit's `set_ime_allowed(false)`: macOS skips
  `interpretKeyEvents:` and inserts the event's `characters`, Windows
  disassociates the IMM context and keeps `WM_CHAR`, and GTK takes the
  focus from the IM context and sends the keyval's character; browsers
  cannot. A composition fn leaves (returns false for `InputCompose`), the
  input method gives up on macOS. `ui.Shape` lays out text without the
  cache of layouts, for widgets that keep their glyphs, and
  `Painter.Glyphs` draws them where they placed them.
  `ObserveInput` has an element see, without taking it, what comes to
  the focus while the focus is it or inside it (keys up and down, text,
  compositions, edit commands), and the presses and releases over it:
  `observeFocus` and `observePointer` (`ui/handler.go`) walk the focus or
  hit chain, outermost first, before anything handles the event, and do
  nothing while the last commit found no element observing
  (`engine.observers`).
  A text input's `OnTextKey` gets the keys that type no text as they
  come too, after `HandleInput`, but first applies the input queued for
  the editor (`widgetTextInput.prepare`, as the platform's queries do),
  so that fn reads the text typed before the key; a key it takes is
  taken as `HandleInput`'s are. Shortcuts around the focus claim keys
  first unless the editor wants them (`editor.wants`), as Enter.
  `HandleTextInput` connects a custom element's application-owned
  `TextInputClient` to the same platform services. A stable, focus-checked
  adapter supplies absolute UTF-16 text ranges, selection, marked text,
  mutation callbacks, range geometry and hit testing. It is invalidated on
  replacement/disposal, and focus changes unmark the old client and reset
  native composition. Revealing the element, as the focus does, scrolls
  to the client's caret (`clientCaret`), not the element's box, which a
  code editor as high as its lines makes as tall as the file. GTK and
  IMM32 use bounded surrounding context while
  macOS can query arbitrary document ranges directly. `ShapeText` and
  `ShapeRichText` retain per-paragraph `TextLayout` geometry, its lines
  included (`Lines`), as a paginating reader needs; an application
  owns its buffer, selections, rendering, editing and undo policy.
* **Sticky elements** (`ui/sticky.go`). `Sticky` sets `layoutStyle.sticky`,
  which keeps the insets of an element in the flow from moving it as
  relative positioning (`relative`); `place`, which reaches an element
  after its parent and the scroll containers around it, then moves it and
  what is inside it by `stickyShift`, as CSS Positioned Layout's sticky
  positioning does: per axis, the padding box of the nearest container
  scrolling that way (or following one, `ScrollWith`), or the window's,
  less the insets, is where its margin box stays, within its parent's
  content box (the content it scrolls, for a scroll container), the
  start's inset winning (`stick`). Unlike CSS, which makes a container
  scrolling one way scroll both, each axis looks for its own container,
  as one here scrolls only the ways it says. Being in window coordinates
  once placed, the box is where hits, ink, accessibility bounds and the
  focus ring read it; `laidOutOrigin`, which overlays attach by before
  `place`, and `reveal` add the same shift, so that a popover follows it
  and the focus coming to it where it shows scrolls nothing. It paints in
  its parent's second pass, among the absolute children, and commit moves
  its hits there (`stickyHits`), while it commits in the flow, so that
  Tab and assistive technology keep its place among its siblings.
* **Paint order** (`ui/zindex.go`). `ZIndex` sets `node.zIndex` and, on
  the parent, `zOrder`, which `add` sets too for a child added with one
  (a copy leaving); a parent without it paints and commits its children
  as before, in two passes, with no sorting nor allocation. One with it
  paints and commits them through `zPaint` and `zCommit`, which `ZIndex`
  sets, so that an app never calling it links none of this. It paints
  them in `paintOrder`: the two passes' order sorted stably by
  z-index, so that equal values keep it, the copies leaving, which keep
  the z-index their elements had, first among those of theirs,
  and, of the root, the overlay layer and what follows it last
  (`zPinned`), so that overlays stay above the content and keep their
  order (the overlay layer's own children are never sorted). Commit
  (`commitByZ`) commits them in the usual order, which the focus order
  and the labels follow, noting each child's hits and web views, and
  then moves them, child by child, to the same order (sorting pointers to
  the notes, whose code all slices of pointers share), the web views'
  indexes into the hits with them, so that the pointer and what covers a
  web view agree with the paint. The order is among siblings alone: a
  child with a z-index moves with its subtree, inside its parent's clips,
  and makes no stacking context that would mix it with its parent's
  siblings. The engine's `zScratch` holds the buffers, as a stack for the
  paint's nesting; the scene's order changing makes a `Cache` layer draw
  again, as its `scene.Differ` sees.
* **Right to left** (`ui/direction.go`). Each element has a direction
  (`node.dir`): built, it takes its parent's, and the root the window's,
  which `surface.Conn.RightToLeft` gives (package `mygo` from the app's
  language), unless `MYGO_DIRECTION` or the inspector's toggle
  (`engine.dirOverride`) override it; `Element.Direction` gives an element
  its own (`dirSet`), which those already inside take (`setDir`), and
  `AttachTo` and `Overlay` give what they build the direction of where it
  was asked for. The coordinate system is not mirrored, as Godot's: the
  layout places right to left. Flexbox turns a row's main axis
  (`flipMain`, which `Reverse` turns back) and a column's cross axis
  (`flipCross`), as `row-reverse` and `wrap-reverse` do; grids place items
  from the right of the content, which is as wide as the columns where its
  width is not known; absolute elements go to the right without insets,
  and `Right` wins over `Left` there and for relative positioning, as CSS
  says. Logical edges (`PaddingStart`, `MarginEnd`, `Start`, ...) write the
  physical side of the element's direction as they are set, noting which
  (`node.logical`), so that a later direction swaps them; logical anchors
  resolve as they are placed (`Anchor.physical`). A container scrolling
  sideways keeps its offset from the start (`scrollLeft` turns it into the
  physical one for placing, revealing and the bars), content narrower
  than it moves to its right, its wheel and keys negate their horizontal
  delta (`scrollBy`), and its vertical bar goes on the left
  (`scrollBars`). Text gets `text.Params.RTL`, the direction of
  paragraphs without a strong character, and lines start at the right
  (`text.Right`) whatever they read, while left to right each paragraph
  starts where it reads from, as before. Widgets read the direction as
  they build (`node.rtl`, `arrows`, `state.rtl` for input between frames)
  to draw and step what is directional, and context menus carry
  `platform.Menu.RightToLeft` to the backends (NSMenu's
  `userInterfaceLayoutDirection`, and the surface view's while the menu
  shows, as AppKit pops a menu up from its view's top right corner then,
  `TPM_LAYOUTRTL | TPM_RIGHTALIGN`,
  `gtk_widget_set_direction` and a north-east anchor, the web's `dir`).
  Accessibility needs nothing more: bounds are window coordinates.
* **Themes of a subtree** (`Themed`, `ui/context.go`). An element given a
  theme (`node.themed`) builds its children with it, as `Toolbar` flips
  `c.buttons` for its controls: `Children` sets `c.theme` and restores
  it, or the window's (`c.window`, the root's, which `SetTheme` sets) when
  the scope began at the window's theme and `SetTheme` was called inside.
  Its own text style holds the theme's color, size and family, as the
  root's does the window's, so that text inside resolves through the
  ancestors unchanged. What reads the theme after building finds it
  there too: `Painter.Theme` is that of the innermost themed element
  painting (`Painter.theme`, which canvases inherit), and the commit
  keeps a scroll container's bar width in its state (`barWidth`) for the
  input that hits its bars. Overlays opened in a scope are children of
  the overlay layer, above the root: `Overlay` gives those built while
  `c.theme` is not the window's that theme as their own. A copy leaving
  with an exit transition copies its theme.
* **Preferences.** `platform.Theme.Preferences` reads the settings of the
  desktop that controls follow: on macOS, `controlAccentColor` and
  `NSWorkspace`'s accessibility display options, with their notifications;
  on Windows, DWM's `AccentColor`, `SPI_GETCLIENTAREAANIMATION`,
  `SPI_GETHIGHCONTRAST` and Accessibility's `TextScaleFactor`, with
  `WM_SETTINGCHANGE`; on Linux, GTK's `gtk-enable-animations` and the
  settings portal's accent, contrast and GNOME's text scaling factor
  (`ReadAll`, `SettingChanged`). What the pointing devices can do
  (`Pointer`, `AnyPointer`, `NoHover`, `NoAnyHover`, Media Queries 4's
  interaction features), whose zero is a mouse's, as macOS's always is,
  comes from the media queries in browsers; on Linux from the sources of
  the default seat's pointing devices (`gdk_seat_get_slaves`), followed
  through its `device-added` and `device-removed`; on Windows from
  `SM_MOUSEPRESENT` and `SM_DIGITIZER`, the touch screen primary in
  tablet mode (`SM_CONVERTIBLESLATEMODE`, whose `ConvertibleSlateMode`
  setting changes), as Chromium tells them, primary the finest. A change
  goes through `Handler.ThemeChanged`, as the appearance's does; package `ui` reads them
  once until the next, the default theme follows them (`Theme.follow`), and
  `Animate` follows reduced motion. Package `mygo` reads them the same way:
  `Theme.Preferences()` keeps them until the next change, with reduced
  transparency too, which package `ui` does not follow, and without the
  pointing devices, which pages' own media queries answer. Pages get them as
  `ThemePreferences`' JSON (its `MarshalJSON`, the accent a CSS color or
  `null`), which is mygo-runtime's `ThemePreferences`: `tsgen` imports that
  type for it rather than declaring one (`runtimeTypes`). A user script
  after the bridge delivers the `mygo:preferences` event at document start;
  the bridge keeps the latest for `preferences()` and sets the
  `--mygo-accent` and `--mygo-text-scale` CSS variables, the accent left
  unset where the desktop has none. When they change, the core sends the
  event to every page and replaces that script (`Page.SetUserScripts`:
  WebKit's content controllers remove all their scripts, WebView2 by the
  ids it reports), so a document loaded later paints with the new values
  from the start.
* **Lists** (`ui/list.go`) build only the rows in view and keep their
  place by a row, the anchor, and how far its top is above where the
  content starts, not by an offset into their content: rows are measured,
  grow, come and go (found again by key, `ListState.Key`, within a
  thousand rows of where they were), and those in view stay put. Building,
  a list makes the rows its place shows as far as the heights it knows
  tell, and the row holding the focus and the header it pinned; laying out
  (`layoutList`, in place of flexbox), it measures them, places them from
  the anchor, a request (`ScrollTo`) or the end it follows, builds the rows
  still missing, so that no frame shows a gap, and keeps the content's
  ends at the list's. Heights measured live in blocks of 64 rows, made as
  rows are measured, and the others are estimated as their average; the
  content's size, and its offset, are where those heights put the rows,
  in float64, as all scroll offsets are, so that millions of rows scroll
  by fractions of a DIP. Following its end with a `FollowAnimation`, a
  list notes where the top of its last row was placed; as rows grow or
  come, that row goes up, and the rows show as far below their place,
  which a motion channel takes back to nothing (`glideToEnd`), counted
  as at the end. Rows are placed relative to the list, the offset
  they were placed at kept as `scrollBase` for placing and revealing. An
  offset the wheel, the keys, the scroll bar or the app changed moves the
  place by as much when it is a step (up to two views), so rows not
  measured yet scroll by the step; a jump goes where the heights known put
  it once the rows built are measured, and the end to the end. A reveal
  (the focus, `ScrollIntoView`) lays a list out anew from the row it
  shows, the window's ScrollState-set offset of a list built anew is a
  jump, and each element remembers the `ListState` that placed it last. A
  scroll bar's thumb keeps the content's size of when it was grabbed until
  it is let go, as rows measured meanwhile change it, and a frame that
  moved a list whose `Visible` or `AtEnd` the view read builds another.
  Rows built as a list lays out handle their input as the view's do,
  which `layoutTree` then forgets, asking for a frame if they changed
  anything, and lays out what they put in the overlay. Rows a `ScrollTo`
  shows at the top go below the header pinned over their section. A list
  without a size is as high as its rows, as the heights known tell, and
  one without rows lays out what else was built in it, as a scroll
  container. `Table` is a header of columns over a list, whose rows are as
  high as their tallest cell, and which takes the focus and the keys for
  the list. Lists choosing several rows hold them by key in a
  `Selection[K]`, through the unexported methods of the `Selector`
  interface, so that the app reads its own keys back typed; the row last
  chosen (the cursor: `Selected`, or the list's own), and the row Shift
  extends from, follow their items by key as the choice does. Typing to
  choose a row goes through the engine: letters, digits and spaces that no
  shortcut takes add up in the focused list's state (`typed`, reset after
  a second), which the list matches against `ListState.Label`.
* **Menus.** Context menus and menu buttons share the machinery of
  `ui/menu.go`: an event asks for an element's menu (`askMenu`, with
  whether it is a menu button's), the next frame runs the element's menu
  function to collect the items, the host shows the system's menu after
  the frame (`popupMenu`), and the item chosen comes back to the function
  in the frame after, matched by place and label. A menu button opens as
  the primary button goes down on it, taking the release, as AppKit's and
  GTK's pop-up buttons do, and for Enter, Space and Down. A toolbar's
  overflow menu asks for an overflowed menu button's menu after the pass
  built the button (`askMenuLater`), so the next pass builds it.
* **Routers** (`ui/router.go`). A `Router` is a history of entries, each
  a location (an escaped path and its query) and the pages showing it, one
  per level of views: `View`'s, then each `Route.View` inside a layout's
  page, made as first built. An entry pushed shares the pages of the
  layouts whose part of the path it keeps (each entry notes how many parts
  each of its layouts took), and all of them for another query of the same
  path. Each view keeps which entry it showed (the router, or the layout
  page's element for a `Route.View`), so a change transitions only the
  level whose page changed. A view builds the page shown in a column keyed
  by the page, flagged `flagPage`: committing marks
  each element's state with the page around it (`state.page`), and
  `prune` keeps the states the frame did not build when a page around
  them, through nested pages, is one the routers built in the frame kept
  (`engine.kept`): the ten pages of the history nearest the one shown, a
  layout's view keeping those inside the same layout.
  The focus does not stay in a page kept out of sight. As the page shown
  changes, the router remembers the element of the page left that had the
  focus, and moves the focus into the new page, to the element it
  remembers there, else to the page (`flagFocusTarget`: focusable, not a
  stop of Tab), unless an element of the page took it as it was built
  (`AutoFocus`), or the focus was outside the router, where it stays and
  the page's title is announced. A page deeper in the paths slides in
  over the page left, the one going away built too, inert (`flagInert`:
  painted, without hits, focus, labels, accessibility nor `Context`
  shortcuts), absolutely positioned over the one in flow, both offset by
  their insets as relative positioning; others fade in alone. With
  `TransitionMatch`, the page going away is built too, inert, fading out
  under the page coming, absolutely positioned and fading in, while the
  elements of a `Match` move between them: those of the page going away
  that flew with the page's show no more (`inert`, in `match.go`). The first
  router of a frame takes the back and forward keys for the window, each
  one also for the focus inside it, which comes first.
* **Comboboxes** (`ui/combobox.go`). A combobox is a text input with a
  popup of options in the overlay, without a backdrop: the input keeps
  the focus while the user types and picks, as presses in the popup do not
  move the focus (`flagKeepFocus`), and the popup closes as the input loses
  it. The option the arrows are on is the input's active descendant,
  which has the focus in the accessibility tree, as a list's chosen row
  does, and reads as which of how many it is. Fields around an input (a
  combobox's, a search field's, a token field's) name it with their
  Label (`nameFrom`). Backends treat combo boxes as text fields (macOS
  `AXComboBox`, ATK combo box with AtkEditableText, UIA ComboBox with
  Value and ExpandCollapse); `AccessSearch` makes a text field AppKit's
  `AXSearchField`.
* **Disclosures** (`ui/collapsible.go`). A collapsible's trigger is a
  `RoleDisclosure`, expanded while open: AppKit's `AXDisclosureTriangle`,
  whose value is 1 while open; a toggle button that is expandable, and
  checked and expanded while open, as GTK's expanders; a UIA Button with
  ExpandCollapse. Its panel animates `Progress` with `Animate`, which
  follows reduced motion: while it moves, the panel is clipped to that
  share of the height its content had in the last frame, and its content
  is built until it has closed.
* **Text areas** (`ui/textarea.go`, `ui/textbuffer.go`). An editor
  holds its text as the string of the app's value, which it shares, and
  where each paragraph starts in runes and in bytes (`buffer`): the frame
  compares the value with it at once while it is the same string, and an
  edit copies the bytes once, where converting the whole text between
  runes and a string took milliseconds for a few megabytes. Undo keeps the
  changes of each step (`undoStep`), not copies of the text; a text the app
  sets makes the last step one change from the text before it, which
  undoing takes back, so that a log the app keeps setting holds two texts
  there, not one a frame. Deleted fragments own their bytes, and
  discarded history and input events give up their references, so a
  one-character deletion does not retain an entire old document.
  The paragraph index is allocated for the newline count up front;
  scanning ASCII counts runes a word at a time, with the standard UTF-8
  decoder for other text. A much smaller replacement releases the large
  paragraph and height indexes. Grapheme boundaries come from the
  paragraph of the caret. A text area lays its
  text out a paragraph at a time (`area`), as the text system breaks
  lines anyway, so that the lines are those of the text laid out whole:
  each paragraph keeps its layout until an edit changes it or the width
  does, those in view are laid out from the paragraph the view starts in
  (the anchor) down, those far from view give their layouts up and keep
  their heights, and layouts own their paragraphs' text rather than
  keeping old document strings alive. The heights not measured are
  estimated by those measured. Two Fenwick trees, of the heights measured and of how many are
  not, give the top of a paragraph and the paragraph at a height in
  O(log n) whatever the estimate. The area scrolls as a scroll container,
  its offset the state's (`flagScrollY`, the content as high as its
  paragraphs), kept by the anchor as heights above the view are measured;
  an edit, a move of the caret or a press reveals the caret once.
* **Editing layers.** `ui/editor.go` holds the widget's editing state;
  `editor_history.go` owns delta undo, `editor_selection.go` the visual
  range set and caret affinity, `editor_navigation.go` keys and pointer
  gestures, and `editor_layout.go` layout and painting. `textinput.go`
  builds the public string widgets. They use the same `TextInputClient`
  contract as custom controls through `editor_input.go`: native callbacks
  query and mutate state synchronously, while the widget publishes its
  bound string during its next build, preserving change propagation in
  composed controls. Preedit is a virtual document insertion, and its
  replacement and commit form one delta undo transaction. The paragraph
  index carries rune, byte and UTF-16 starts; bounded native queries own
  their bytes so they do not retain old document allocations.
  Single-line controls retain their current layout themselves, keeping
  changing input strings out of the system's cache of display text.
  `internal/text/caret.go` keeps both logical edges of bidi boundaries and
  wrapped lines, and moves between whole graphemes in visual order.
  Selection gestures produce logical range sets: highlight, copy,
  replacement and undo use the same ranges, preserving unselected gaps.
* **Indexed text storage.** `internal/rope` is a persistent AVL tree of
  bounded, owned UTF-8 chunks, summarized by byte, rune, UTF-16 and newline
  counts, and `rope.Text` the value reading lines, offsets and UTF-16
  ranges from it, and lines a batch at a time; `ui/text_buffer.go` and the
  code editor's buffers keep their texts in it. Edits copy affected chunks
  and tree paths; snapshots share other chunks, and export can stream
  them. `TextInputBuffer`/`TextAreaBuffer` in
  `textbuffer_input.go` bind those roots to the existing editing client.
  Native mutations publish a new root immediately, using a version check
  to preserve concurrent program edits. External root changes refresh the
  widget and clear stale history. The indexed buffer adapter derives line
  starts from the text tree rather than moving every later paragraph's
  absolute offsets. Paragraph layout and height caches remain with the
  widget; newline-count changes update those indexes. Full text is produced
  for explicit export/value queries, never as a binding update per edit.
* **Charts** (`ui/chart`) use ui's public API alone: scales return
  fractions, the plot places marks in percentages, and paths turn those
  into DIPs while drawing. Log and SymLog (`nonlinear.go`) add only
  standard-library math: log domains stay on one side of zero, symlog's
  `log1p`/`expm1` keep a linear region around it. Reversed domains and
  clamping share the same normalized-coordinate contract. A separately
  generated D3 fixture checks mappings, inverses, ticks and nice domains;
  constant log domains intentionally keep one tick even where D3 omits it.
* **Code editor and diff viewer** (`ui/editor`, `internal/diff`). Package
  `editor` is built on ui's public API, as `ui/chart` is, with four hooks
  for it: `Painter.TextLine` paints a shaped line with a color per
  cluster, `Painter.Visible` gives the clip to cull rows, `KeepFocus`
  keeps the focus in the editor while its completions and find bar are
  pressed, and `Access` describes its text to assistive technology only
  while it reads the window. Its design follows Zed's:
  * *Buffers* (`buffer.go`) keep a `rope.Text` and a log of the changes
    of each version, in bytes and lines, old and new. Editors, the
    highlighter and the diff follow a buffer by the versions they last
    saw (`sync`): selections, folds, diagnostics and caches move through
    the changes since, with a bias at insertions, so that one buffer is
    shown by several editors and both sides of a diff. A step of undo
    keeps the edits that take it back, a list for each version it made,
    grouped while typing of one kind by one editor goes on within 300 ms,
    and the selections of the editor that made it. Taking a step back
    applies its lists from the last, logging a version for each, whose
    text is its changes' as tree-sitter needs, and keeps the edits taking
    each back as the step of redo. `EditRemote` makes a version outside
    the history and moves both stacks past it, from the top
    (`rebase`): the edit's ranges (`span`) and a step's lists are of one
    text, so each moves past the other (`rebaseEdits`), and the ranges go
    on down. A step that overlaps them leaves the history, the text
    staying as it is, so the steps under it move past that step and the
    ranges together (`composeSpans`). The cost is a few integers for
    each edit of the history, whatever the size of the text; a step's
    replaced text is a string, so undoing `Set` builds the text again
    where it used to swap versions.
  * *Display* (`display.go`, `view.go`). Every line is a row, several
    when it wraps, none when folded or collapsed by a diff; blocks are
    rows between lines (a diff's deleted lines, spacers, separators,
    annotations). A line's top is arithmetic on sparse sums: the extra
    rows of wrapped lines in a Fenwick tree, and the heights of blocks
    and hidden lines with their prefix sums; lines are found at a height
    by bisection. Only the lines in view are laid out and shaped, kept
    for two frames as Zed's line layout cache is. Wraps are measured with
    cached advances of characters (monospaced ASCII is arithmetic) near
    the view first, a frame's budget at a time, and estimated elsewhere.
    A character shaped alone misses the room the text engine leaves
    around it in context, as Core Text does between Han and Latin
    letters and around CJK punctuation in the app's language when it is
    Chinese or Japanese (`System.SetLanguage`): laying a line out shapes
    each row as it is painted, and ends it at an earlier place to break
    while it is wider than the editor (`fitRow`), so lines out of view
    may count a row too few until they show. Closing CJK punctuation
    starts no row, nor opening punctuation ends one (`canBreak`). A new
    generation of the text system measures and shapes everything anew.
  * *Replacements* (`replace.go`). A range shown as something else is a
    segment of a line's displayed text, as a tab or an inlay is: its Text,
    nothing, or for an element an object replacement character the text
    system gives the element's width (`faceRun.obj`, `Span.ObjectWidth`),
    so that shaping, carets, selections and wraps need no case of their
    own, lines not laid out yet counting it too. Their elements are built
    over the text at the places the lines laid out give, a frame painting
    them elsewhere building again (`replacementsMoved`). Lines covered
    through their newline join the hidden spans. Replacements move as
    selections do, and a change lays out again only the lines of those
    that differ, so that an app can set them every frame.
  * *Highlighting* (`syntax.go`). A `Highlighter` follows the buffer's
    edits and gives tokens per line; the default tokenizes lines from the
    state the line above ended in (`lexer.go`, `lexers.go`), keeping the
    states, and after an edit goes on below it only until a line starts
    as it did before. A patch's texts start each hunk in state 0, at
    lines the buffer moves with its edits (`setRestarts`) and its
    snapshots carry (`Snapshot.Restarts`), for a `Language.Highlighter`
    to start them as well. Optional
    interfaces give a parser's structure to Select Larger, folding,
    brackets and indentation, so that tree-sitter can plug in as a
    `Language.Highlighter` without the editor changing.
    Brackets are matched by scanning lines a batch at a time
    (`rope.Text.EachLine`), skipping strings and comments by their tokens,
    and only lines holding brackets are tokenized for it.
  * *Snippets* (`snippet.go`). `ParseSnippet` reads the flat tab-stop and
    placeholder subset of TextMate/LSP into an immutable template;
    unsupported constructs return errors. Inserting a template, directly
    or as a `Completion.Snippet`, makes each occurrence of the active
    stop an ordinary selection. Existing typing, input methods and undo
    handle them together. A session follows only its next local buffer
    change, through `apply`/`sync`; external edits end it. Fields move in
    template order, preserving ownership at adjacent boundaries, and
    linked deletions stay separate before the editor merges overlapping
    deletions. Tab ends the typing group and selects the next numbered
    stop, 0 last; undo, Escape or leaving the fields ends the session.
  * *Diffs* (`internal/diff`, `diffmodel.go`). Lines are interned and
    compared with git's histogram algorithm, falling back to Myers' with
    xdiff's cost limit, then slid by git's indent heuristic; changed
    lines are paired by similarity and their words diffed, words one
    character apart joined (Pierre's word-alt). An edit re-diffs only the
    region of the hunks it touched, extended to the unchanged lines
    around. The split view is two editors sharing their scroll, their
    lines aligned by spacer blocks, unchanged lines too where the sides
    wrap at unlike widths; the unified view one editor of the new text,
    with blocks painting the deleted lines from a view of the old one.
    The split view's sides share its width by `SplitPercent`, across a
    divider that moves as `ui.Split`'s does. The view lays both editors
    out in its `Draw`, before they paint, to align them, so the build
    gives the sides factors of growth from nothing (`diffSplit`), whose
    widths the `Draw` works out with the layout's own arithmetic, to the
    bit: a width off by a rounding would wrap a line otherwise and build
    the view again, frame after frame. The sides' minimum is kept
    against the last frame's width, and a resize builds the view again
    to keep it at the new one. Unchanged runs collapse into hidden spans under separator
    blocks. The split view's editors scroll as it is drawn, the unified
    view's as it is built; a frame whose layout or build moved the scroll
    builds the view again (`rebuildIfMoved`, `DiffView`), as one laying
    an editor out at another height does (`builtViewH`), so that what
    read `ScrollY` or `ViewportHeight` before, as an app's minimap,
    follows.
  * *Parts* (`parts.go`, `diffparts.go`). The bars and popups around the
    text (find, go to line, completions, hovers) and a diff's separators,
    actions on changes and gutter button are elements the editor places
    with the behavior they need, as ui's bases are: `shield` hands presses
    on to what is inside them rather than to the editor's handler, and
    `KeepFocus` keeps the typing in the editor. The app's render function
    fills each, else the exported default, given a handle to the part's
    state and actions (`FindBar`, `DiffSeparator`, ...), whose values
    the editor reads back after the build, as a query typed. Separators
    are built by the diff view across both sides, over the room their
    blocks leave.
* **Markdown** (`ui/markdown`), on ui's public API as `ui/editor` is, whose
  tokenizers highlight its code. The parser, `ui/markdown/parser`,
  imports nothing of ui, so that `ui/richtext` reads Markdown without the
  view; the view reaches it through its exported methods only
  (`Source`, `Footnote`, `Block.Revision` and `Healed`). It follows cmark-gfm's two
  phases over flat blocks and inlines with byte offsets: a block parser
  with a stack of open blocks, line by line, closing those a line does not
  match before adding a block, so that blocks go in document order; and
  inlines parsed per block when first asked, with cmark's guards against
  quadratic inputs (the bottoms of openers, backtick runs, comments and
  math remembered unclosed). Appending text truncates the blocks from the
  outermost block open after the last complete line (`restart`), which
  CommonMark makes sound: no rule looks ahead, and those rewriting an
  earlier block touch only open ones; the partial last line never decides
  what is closed. Definitions made or unmade parse anew the inlines of the
  blocks that looked their labels up, and the inlines of blocks parsed
  again are reused when their text is the same. An edit parses from the
  top-level block before it until a top-level block starts with nothing
  open (`quiet`) where one did, and splices the old ones after, shifted.
  Streaming completes the tail's inlines from the openers the parser left
  (`heal.go`) and holds back lines that may still change. The view keeps
  the document in its root's local state and the spans of each paragraph
  by block, links as inline `Link` elements, a code block's tokens by line
  and its text in chunks of 32 lines; it reveals text at a pace, fading it
  by span colors and element opacity, which only paint, and `Revealed`
  reads from the root's state whether the frame showed all of the source
  with no fade left, a query rather than a callback, as the frames
  that change it are those the reveal already asks for. A `Selectable`
  root's `CopyData` and `SelectedTexts` map paragraphs' runes back to
  source offsets, to copy text with block separators, Markdown, and the
  HTML of that Markdown parsed again, which `ui/richtext` pastes with its
  formatting, as it reads Markdown with the same parser
  (`ParseMarkdown`). Links open in the system only when `ui.SafeToOpen`
  allows them, in both.
* **Rich text** (`ui/richtext`). Package `richtext` edits attributed text
  on ui's public API, as `ui/editor` does: a focusable box with a text
  input client, `HandleInput`, `Draw`, `Access` and its own scrolling, and
  four hooks of ui for it: `ShapeRichTextWith` aligns and indents a
  paragraph's lines, `Element.SetChanged` reports its edits as `Changed`,
  `Services.ReadClipboardData` and `WriteClipboardData` carry its formats,
  and `InputSelect` takes a selection assistive technology made.
  * *The text* (`text.go`, `seq.go`). A `Text` is a value: its characters
    in an `internal/rope` tree, and beside it a persistent sequence of its
    paragraphs (an AVL tree of chunks of 32, `seq`), each with an
    identity, a style and its runs: attributes over its runes and, last,
    its newline's, which an empty paragraph types in, as Word's paragraph
    mark. Runs are kept maximal. An edit splits and joins both trees,
    copying the chunks and paths it touches; paragraphs joined or split
    take the style of the one their first rune comes from, as AppKit's
    `fixParagraphStyleAttributeInRange:`, but for the app's `ID`, which
    follows the text and never comes from what is inserted. Lists are
    flat, an indent per item, as Quill and Automerge keep them, which
    leaves room for a CRDT.
  * *The document* (`document.go`, `commands.go`). A `Document` holds a
    text, the selection, the typing attributes, and the steps of undo as
    the texts before and after each, which share all they did not change,
    with the region each changed and the selections. A log of changed
    regions by version lets the editor lay out again only the paragraphs a
    change of the app touched. Typing derives the typing attributes as
    NSTextView does (the character before the caret, the one after at a
    paragraph's start, links, code and tags only inside), measured by a
    Swift probe of NSTextView.
  * *The editor* (`view.go`, `edit.go`, `input.go`, `ime.go`, `paint.go`).
    It lays out a paragraph at a time with `ShapeRichTextWith`, keeping
    each layout for the runs, style and composition it was made of, and
    places them by heights in two Fenwick trees from an anchor paragraph,
    as a text area does: the first in view, or the caret's while the editor
    is focused and scrolled, which keeps the line being typed still as
    what is above it grows. Every edit goes through the document, as a step
    of undo or part of the action's; typing joins typing's step.
    Attachments are inline objects of the text system; a first line's
    indent is the layout's (`TextShape.Indent`), on the side the
    paragraph starts at, the right of one reading right to left.
    `Document.VisibleParagraphs` and `Document.CaretRect` lay out what is
    in view as they are read, as painting does, and the paint that finds
    the paragraphs or the caret elsewhere than read asks for a frame
    (`Services.Invalidate`), as `ListState.Visible` builds another.
  * *Formats out of the process.* The clipboard carries the editor's JSON,
    HTML (`golang.org/x/net/html` reads what is pasted) and plain text;
    browsers carry each text format through the clipboard events. The
    runs' formats go to assistive technology as `AccessNode.TextRuns`:
    `AXAttributedStringForRange` on macOS, ATK's run attributes on Linux,
    and UI Automation's Text pattern on Windows (`uia_text.go`), whose
    ranges are COM objects of their own.
* **Text selection** (`ui/textselection.go`). `Selectable` on a text
  selects that paragraph; on a container it gives its text descendants
  one selection. The window keeps endpoints as stable element IDs and
  rune offsets, and each frame collects participating paragraphs in
  build order. After layout the shared range is projected onto their
  editors, whose layouts paint the highlights. Pointer gestures,
  keyboard extension, native editing commands and context menus use
  the same endpoints. Nested containers have independent scopes;
  controls and `Unselectable` subtrees do not participate. A drag near
  a scroll edge asks for frames until scrolling stops. Inline children
  contribute to their paragraph once, and preparation waits for their
  final text so a rebuild preserves the selection. A paragraph whose text
  only grew at its end keeps the selection, as a reply streaming in. A
  container's `CopyData` makes what Copy writes from the parts
  `SelectedTexts` returns: each paragraph's ID, text and runes selected.
* **Tables** (`ui/table.go`, `ui/editable.go`). A table's rows are a
  `List`'s that scrolls both ways: the list lays its rows out at least as
  wide as the columns ask (`rowMinW`), and the header, outside the list,
  follows its horizontal offset as it is placed (`followX`). The order
  and the widths the user gives the columns live in the `ListState`
  (`TableLayout`), by column ID. Dragging a header moves its column once
  the pointer went a few DIPs, past a neighbor whose middle it passes; a
  double click on a header's edge fits the column as the table lays
  out, from the intrinsic widths of the cells the frame built
  (`tableFit`). Sorting is the app's: the table sets `ListState.Sort`,
  or `SortBy` for several columns (a new slice each time, which
  `sortClicked` makes), and shows it, to assistive technology as well
  (`AccessSortAscending` and `AccessSortDescending`: AppKit's
  `AXSortDirection`, ATK's `sort` attribute, UIA's ItemStatus). An
  `EditableText` in a row reads the row being built (`Context.row`): the
  list, which keeps the focus, asks for the chosen row's text to be
  edited on Return (macOS) or F2, which it takes only once a row has such
  a text; a click on the text of a row chosen before the click edits it
  once the double-click time has passed.
* **Outlines** (`ui/outline.go`). An outline flattens the open part of
  its tree into rows every frame (`OutlineState.flatten`), which a `List`
  or a `Table` builds as they show, keyed by their items. Rows are tree
  items, with how deep they are (`AccessNode.Level`) and whether they
  have children (`AccessExpandable`), open or not: on macOS, the rows of
  an `AXOutline` with `AXDisclosureLevel` and `AXDisclosing`, which keeps
  its rows as a table does; on Linux, the `level` attribute and the
  expandable state; on Windows, Level, and ExpandCollapse with LeafNode
  for items without children. `OutlineState.Prefix` builds the start of
  the rows in place of the indentation and the arrow (`prefix`), with
  `OutlineRow.Arrow` the arrow's click and Option-click.
* **Trees** (`ui/tree.go`). `TreeBase` builds every item that shows, in
  the order the app builds them, each `Group` a column keyed by its item
  so the items inside keep their IDs as items above open and close; the
  `Tree` widget is `TreeBase` with its look. The tree is a `FocusGroup`,
  one stop of Tab, with the items taking the focus themselves. An item's
  keys open and close it as it is built; those moving the focus, and the
  first letters typed (`flagTypeSelect`, carried over to the item they
  move to), apply once the view is built (`treeBuild.finish`, from
  `context.onBuilt`), against this pass's items in order, which also
  says to assistive technology which of how many each is, as an
  outline's rows.
* **Drag and drop within a window** (`ui/dragdrop.go`). An element
  dragging a value notes it in its state (`Drag`), or a function giving it
  as a drag starts, as a list's rows chosen. The engine starts the drag
  once the pointer pressing it moves a few DIPs (`dragMove`), and follows
  the innermost element under the pointer whose `accepts` takes the value,
  which `Drop` and `DragOver` set from their type. Releasing drops the
  value on it and is no click (`dragEnd`); Escape gives up. Each frame
  scrolls the scroll container under the pointer near its edges, and
  paints the source's element of the frame again under the pointer,
  shifting it there and back, with a count beside the pointer for
  several rows. Lists and grids take their own rows (`rowDrag`,
  `itemDrag`), placing them by the middles of the rows of the last frame.
* **Native data drags** (`transfer`, `drag.go`, `ui/data_drag.go`). An
  element with `DragData` promotes the gesture to the native drag tracker.
  `transfer.Data` holds immutable items with MIME-tagged representations;
  providers are advertised lazily and cached per session. `DropData`
  accepts matching formats with a negotiated copy/move effect. The core
  owns one live source, identified by a random token: backends transfer the
  token as data, never a Go pointer. Only the core resolves it to the
  original items and optional typed value, while the source lives. A
  completion or cancellation invalidates the token and calls Done once.
  `Surface.StartDataDrag`, `CancelDataDrag` and `SetDropFormats` translate
  to AppKit sessions/pasteboard item providers, GTK selections, or OLE
  IDataObject/IDropSource/IDropTarget. GTK collects accepted formats through
  asynchronous callbacks after drop; OLE runs its native modal tracker
  after the source input callback returns. None waits on the main thread
  for data that needs that thread. Dropped bytes outlive native objects;
  unhandled file transfers still reach the existing file-drop path, with
  copy semantics. The unsupported backend cannot create windows/surfaces,
  and continues to fail at Init without linking any native drag code.
* **Grid views** (`ui/gridview.go`). A grid view is a `List` of rows of
  items, whose columns it takes from the width its rows had in the last
  frame: the layout asks for another frame when the width calls for
  others (`gridFit`). The list's own state holds the rows' place; the
  grid chooses items itself, takes the keys, and tells assistive
  technology about its items rather than its rows, which are RoleNone:
  a list of all its items, the item chosen its active descendant.
* **Sidebars** (`ui/sidebar.go`). A sidebar is one element taking the
  focus, whose items note their IDs as they are built: the keys choose
  among those of the last frame, and the item chosen is the sidebar's
  active descendant, with the focus for assistive technology, as a
  combobox's option. Sections and items are tree items, the sections'
  RoleNone containers leaving them all in the sidebar's tree, whose rows
  macOS keeps as an outline's.
* **Feedback** (`ui/feedback.go`, `ui/toast.go`). An alert dialog is a
  modal overlay as a dialog's, which a click outside leaves, as AppKit's
  alerts beep: an alert role (AppKit's `AXApplicationAlertDialog`, ATK's
  alert, UIA's dialog pane) named by its title and described by its
  message. A find bar is keyed, for its state, which focuses its field
  as it opens, to go as it closes. A checkbox group finds its check boxes
  as they register with it (`Context.checks`), then applies a click to
  them all. A text input notes the modifiers of the Enter submitting it
  (`submitMods`), as the editor takes Shift+Enter: the find bar goes back
  with it. A toast keeps the time it showed (`spent`) and since when it
  runs (`at`): its time stops while the pointer rests on the toasts or
  the keyboard focus is in them with the window's (`toastsPaused`), and
  runs on while the window is in the background: a toast whose time is
  over by then closes on the next frame, before the toasts build.
* **Dates, times and colors** (`ui/date.go`, `ui/timeinput.go`,
  `ui/colorpicker.go`). `DateInput` and `Calendar` share one month's grid,
  whose day under the keys is its active descendant. A time input's
  hours and minutes are spin buttons named after the field, typed into
  through type-to-choose (`flagTypeSelect`). A color picker keeps its
  color as hue, saturation, value and alpha, as a color of red, green
  and blue loses the hue of its grays, and takes the app's color anew
  when the app sets another. A color well is AppKit's `AXColorWell`, a
  button on Linux and Windows, its value the color in hex.
* **Indicators** (`ui/indicators.go`). Meters and steppers have a value
  in a range, as sliders and progress bars do (`AccessRole.Ranged`):
  a meter is AppKit's `AXLevelIndicator`, ATK's level bar and UIA's
  ProgressBar; a stepper AppKit's `AXIncrementor`, ATK's spin button and
  UIA's Spinner, taking increments. A range slider's knobs are sliders of
  their own, named after it (`nameJoin`).
* **Forms** (`ui/form.go`). A form notes the label boxes of its fields as
  they are built, and makes them as wide as the widest before the layout
  first measures or lays it out (`intrinsic` and `boxLayout` call
  `alignLabels`), its fieldsets' fields too. The row of a field in a form
  lines up the first baselines of its label and control after laying them
  out (`alignBaselines`), from the text layouts of the frame; a control
  without text centers on the label's line. Fields name their control
  with their label (`nameFrom`). `Description` and `Error` reach
  assistive technology as `AccessNode.Description` and `AccessInvalid`:
  `AXHelp` and `AXInvalid` on macOS (the newer API has no invalid state,
  so the element answers it through `accessibilityAttributeValue:`), the
  ATK description and `invalid-entry` on Linux, UIA's FullDescription,
  HelpText (unless a placeholder takes it) and IsDataValidForForm on
  Windows. Tooltips describe their element as AppKit's and GTK's do.
  Committing a frame marks disabled the state of what is inside a
  disabled element, which a fieldset disables after building it: input
  in the next frame then finds it disabled (`Element.disabled`).
* **Focus groups** (`ui/focusgroup.go`). Committing a frame notes the
  outermost focus group (`FocusGroup`) each element of the focus order is
  in, beside its dialog. Tab skips the elements of a group but its entry,
  the one that had the focus last, else the radio button or tab chosen,
  else the first, and leaves the group; the arrows, Home and End move the
  focus among its elements when no element around the focus takes them as
  a shortcut, and click the element they reach in a radio group.
  `Toolbar` lays out (`layoutToolbar`) the controls that fit, takes the
  others out of the flow (absolute and invisible, `collapsed`), and lists
  them, by label, for its overflow menu, whose choices click them after
  the pass (`clickLater`).
* **Overlays** (`ui/scope.go`) scope the keyboard. Committing a frame
  notes the dialog each focusable element is in (an element made `Modal`,
  as `DialogBase`'s backdrop, `flagModal`; a popover is in its anchor's),
  the dialog on top (`engine.modal`, and `modalLayer`, the element at the
  top of the overlay holding it), and moves a popover's elements after its
  anchor in the focus order. Tab cycles the dialog on top, the focus moves
  into it while it is outside, the window's shortcuts built outside it do
  not fire, and the accessibility tree is the dialog's layer and what is
  above it. Overlays register Escape as overlay shortcuts
  (`OverlayShortcut`), which the keys the focus and the elements around it
  leave reach, the last registered (the overlay on top) first. An element
  takes one key a frame (`routeKeys`): from a second key for it, the keys
  wait for the next frame, which the first changed, as a Down and an
  Enter typed quickly into a menu, the Enter choosing the item the Down
  highlighted. Each element
  built at the top of `Overlay` notes the focus as it opens (`openers`),
  which pruning gives back once it is gone with the focus that was in it.
  An element attached to another (`AttachTo`, which `PopoverBase` and the
  popups of selects and comboboxes use) is that element's popover
  (`Element.popover`, and `state.anchor` once committed): its layout
  (`attachTo`) finds where the target will be in the window from the boxes
  laid out before it, the scroll offsets around it, and for an inline
  target the paragraph's layout (`laidOutBox`), so that a popover follows
  its anchor in the frame that moves it; then it goes to the other side, or
  the other way along the target, where that leaves the window less, and
  moves along the target into the window (`alongTarget`); one that scrolls
  vertically is first cut to the room the window has (`roomAlong`), as a
  select's long list of options. Popovers have no
  backdrop: the engine notes what each press went down on (`downs`, for a
  pass), and `PressedOutside` walks from the last through parents, and from
  a popover to its anchor, which keeps presses in popovers of elements
  inside the panel, and on its anchor, inside it, as the press goes on to
  what is under it; a press on the anchor after one elsewhere in the same
  pass, as on a web view's page, leaves open the popover it opens, and an
  element the frame first builds was pressed outside of by none, as the
  press opening it is still in `downs` when a quick click opens it. A select's popup keeps a backdrop taking the presses outside,
  as the system's pop-up menus do.
* **Web views** (`webview.go`, `ui/webview.go`, `webview.go` of each
  backend). `Window.NewWebView` makes a web view of a window showing
  `Content`, whose page lives in a `Window` of its own that no list holds,
  with `host` set: calls, channels, events, `Eval`, custom schemes,
  downloads and permissions go through the code of windows' pages
  unchanged, `CallerWindow` returns the host, `CallerPage` the page, and
  the bridge has the host's id, so the window controls of the page act on
  it. Its native side (`webViewNative`) takes page methods from the
  backend's `platform.WebView` and window methods from the host's, which
  drag regions use. `ui.WebView` places it: committing a frame notes where
  each web view's element shows (`noteWebView`: its content box on whole
  pixels, clipped as its hits are, with the hole's corners and, under a
  transform that only moves and scales, the size the page lays out at,
  `WebViewPlacement.Width` and `Height`, which `Frame` shows scaled; under
  another transform, the bounds, upright), and painting it makes a hole
  (`OpHole`) through what the window painted, rounded as the border's
  inner edge and cut by the clips around it, so that what paints after
  the element paints over the page. The native web view is under the
  surface, which shows it through its transparent frames; what shows over
  it blends with it as over any pixels. After presenting a frame, the
  engine gives the surface each web view's frame and clip and the boxes
  of the hits after its own within its clip, as they show (`Covers`): the
  pointer is the page's where it shows, inside its corners (`Radii`), and
  nothing painted over it takes the pointer (`WebViewPlacement.At`), as a
  dialog's backdrop does over all of it. Backends cut the page to the
  corners and show it scaled, keeping its layout, so that it shows as its
  hole does over a transparent window too. A
  press there goes to the page and comes to the content as `WebViewPress`,
  which notes it for `PressedOutside` and moves the focus to the web
  view's element, unshown; the engine sets no cursor while the pointer is over a web view
  (`cursorUnknown`), whose page sets it. Web views the frame does not build
  hide and keep their pages. Glyphs over a hole are not on an opaque
  background (`Painter.holes`), so that subpixel ones do not color the
  page. Below full opacity a hole takes only that much of what is under
  it away (`OpHole`'s `Opacity`), so the page blends over it. The element
  is a Tab stop: focusing it gives the page the keyboard
  (`WebView.TabInto`, from its end going back), and Tab past the page's
  ends comes back as `WebViewTabOut`, from which the focus moves on. A
  key the page leaves unhandled comes as `WebViewKey`: the engine moves
  the focus to the web view's element, if it was elsewhere, and takes the
  key as from the keyboard (`webViewKey`), so that the shortcuts around
  the element and the window's see it; Tab never comes. The
  access tree has a node for each page, inside its element
  (`AccessNode.WebView`), which the backends fill with the page's own
  accessibility, as SwiftUI's `WebView` is in place. Backends:
  * macOS: the WKWebView is in a flipped clip view (`MyGoClipView`, its
    layer masking to its bounds) placed at the clip, under the surface in
    the content view, in paint order, in a pane (another) at its frame,
    whose bounds are the page's size: AppKit draws it scaled and finds the
    pointer in it as in any view of scaled bounds, and the pane's layer is
    cut to the corners (`cornerRadius`, continuous, and `maskedCorners`;
    a `CAShapeLayer` mask for corners of different radii), in the layer's
    units and orientation, which `convertPointToLayer:` tells, whatever
    AppKit does to scale it. The Metal layer is not opaque, and
    frames drawn in memory have their alpha. The surface's `hitTest:`
    returns nil where a web view takes the pointer, so AppKit finds the
    page under it. A web view's tracking areas get the mouse's moves
    wherever its frame is: `MyGoWebView` drops `mouseMoved:`,
    `mouseEntered:` and `cursorUpdate:` where the content painted over it,
    and as the pointer goes there from the page sends WebKit an exit
    outside the view, which WebKit takes as a move there, unhovering the
    page; WebKit sets its cursor only where `hitTest:` finds the web view,
    and the surface sets none over a page. `TabInto` puts the web view
    after (before) the surface in the window's key view loop and selects
    it, so WebKit focuses the page's first (last) element; as Tab leaves
    the page WebKit selects the next key view, which `MyGoWindow` turns
    into `WebViewTabOut`. The page's node lists the WKWebView, whose
    `accessibilityParent` is that node; the clip view lists none. With
    `ScrollToContainer`, `MyGoWebView`'s `scrollWheel:` gives the event to
    the surface's conversion (`scrollWheel`) instead of WebKit. WebKit
    sends a key the page did not handle again, and the WKWebView on up
    the responder chain: `MyGoClipView`'s `keyDown:` sends it to the
    surface as `WebViewKey` (`unhandledKey`), Tab aside. An Escape (or
    Cmd+.) comes as `cancelOperation:` first: WebKit sends a command its
    web process does not know up the chain and resends the key only if
    no responder took the command, and the `NSPanel` of a flyout takes
    it, so `MyGoClipView` takes `cancelOperation:` itself and sends
    `WebViewKey` with Escape (`unhandledCommand`).
  * Linux: the first web view puts the surface's area in a `GtkOverlay`,
    over a `GtkLayout` holding the WebKitWebViews (which, unlike a
    `GtkFixed`, asks for no size), as an overlay, which GTK realizes again
    with a new GL context (the GL renderer makes its objects again). The
    GtkGLArea has an alpha channel from then on, and frames drawn in
    memory paint over the web views (`CAIRO_OPERATOR_OVER`). An input
    shape on the overlay's window of the area
    (`gdk_window_input_shape_combine_region`) lets the pointer through to
    the pages, whose windows then set the cursor; a web view's own
    `button-press-event` tells the content. WebKitGTK focuses no element
    as a view takes the focus, so `TabInto` blurs the page's and passes the
    Tab being handled on to the view (`gtk_widget_event`); WebKit moves the
    focus out as Tab leaves the page through GTK's `focus` signal, which
    the view's handler turns into `WebViewTabOut`. The page's node lists
    the view's accessible, an `AtkSocket` the web process's tree is
    embedded in; the overlay is a subclass whose accessible lists the
    surface's alone. With `ScrollToContainer`, a handler of the view's
    `scroll-event`, which runs before WebKit's class handler, converts the
    event as the area's does (`scrollEvent`, moved by the view's
    allocation), sends it to the content and stops the signal. A scaled
    page's view is as large as it shows, and WebKit zooms it by the scale
    over the page's own zoom (`pageScale`), so that it lays out at the same
    width in CSS pixels. GTK runs each handler of `draw` with a clip of its
    own, and GDK draws WebKit's frames with OpenGL within a clip's
    rectangles alone: the view's handler of `draw` clips to the page's
    corners on whole pixels and calls WebKit's class handler itself
    (`GtkWidgetClass.draw`), and the region shaping the area keeps the
    pixels the corners cut off. WebKitGTK dispatches a key the page did not
    handle again once its web process says so, and its class handler of
    `key-press-event` then passes it on: a handler connected after it
    (`cbWebViewKey`) gets those keys alone and sends them as `WebViewKey`,
    but Tab, modifier keys on their own and the shortcuts of menu items with
    a role, which go on to the menu (`cbMenuKey`).
  * Windows: WebView2 in visual hosting, a composition controller
    (`ICoreWebView2Environment3`) whose visual is in a DirectComposition
    target of the surface's window that is not topmost (a window has one
    of each), on a device of its own without a rendering device
    (`DCompositionCreateDevice2`): the surface's frames, in the topmost
    target, are over it. The surface composes its frames from its first
    web view on, as in a window without a redirection bitmap: it sends
    `SurfaceRenew`, and the content makes its renderer again for a swap
    chain for composition, or shows frames drawn in memory through the
    compositor; GDI would draw under the web views. Each web view's
    visual is in one clipped to its clip, the page at its bounds in the
    surface's pixels, cut to its corners by a rectangle clip
    (`IDCompositionRectangleClip`, its setters taking floats through
    purego) and, scaled, at the page's size, which the visual's transform
    scales to its frame; the mouse goes to the page through the inverse.
    The surface gets the mouse everywhere and sends it on
    (`SendMouseInput`) where a web view takes the pointer, or to the one a
    press went to until the buttons are let go (with the capture), with a
    leave as the pointer goes; it sets the cursor the page asks for
    (`CursorChanged`), and a press moves the focus into the page.
    `TabInto` is `MoveFocus` (next or previous), and `MoveFocusRequested`
    becomes `WebViewTabOut`. The surface's drop target sends drags over a
    page to its composition controller (`ICoreWebView2CompositionController3`'s
    `DragEnter` and the others). With `ScrollToContainer`, `forwardMouse`
    keeps the wheel over that web view (`WM_MOUSEWHEEL`, `WM_MOUSEHWHEEL`)
    for the surface, which scrolls the content as over its own elements;
    a touchpad's pinch, the wheel by less than a notch with Ctrl held,
    still goes to the page, as pinches do on the other platforms.
    WebView2 tells of no key a page leaves unhandled: `keys.js`, built
    from `packages/bridge/src/keys-world.ts`, runs in an isolated world of
    each document of the web view, frames in its process included
    (`Page.addScriptToEvaluateOnNewDocument` with a `worldName`), decides
    after the page's handlers ran with the rules of `keys.ts`, and calls
    a binding of that world alone (`Runtime.addBinding` with an
    `executionContextName`, after `Runtime.enable`), which WebView2
    raises as `Runtime.bindingCalled` (`GetDevToolsProtocolEventReceiver`);
    `bindingCalled` sends `WebViewKey`. The page's scripts reach neither
    the world nor the binding, bridge or not, and their events are not
    trusted. For UI
    Automation the root also answers `IRawElementProviderHwndOverride`:
    for the window WebView2 shows a page with, it returns the page's node,
    which answers with WebView2's provider of the page
    (`get_AutomationProvider`), as WinUI 3 does. That provider has no
    children: the page's elements are under a top-level window of
    WebView2's (`Chrome_WidgetWin_1`), which
    `GetAutomationProviderForWindow` does not map to it, so UI Automation
    finds them there (seen with a runtime of October 2026).
* **Context menus** (`ui/menu.go`) open in two frames. A right-click or the
  menu key marks the element, from the states of the last frame, and the
  next frame runs its `ContextMenu` function to collect a `platform.Menu`;
  after the frame, package mygo shows it with `Menu.popup`, posted to the
  main loop, since native menus wait in a loop of their own. A choice
  comes back as the item's place and label, and its ID when the view gave
  it one (`MenuItem.ID`, `menuRun.keys`), which the next frame's run of
  the function matches to report `Chosen`, by the ID alone when there is
  one; text inputs' menus queue their editing commands instead. `PopoverMenu` opens the same way and draws
  the menu in the window instead (`ui/popovermenu.go`): the frame that
  would show it notes it (`menuState.drawn`, whose `menuShown` holds where
  it opened, from the element's corner, and the submenus open with their
  highlights), and while it shows, each frame runs the function to
  collect the `platform.Menu` and builds the menu from it with the parts
  of `MenuBase` (`menuParts`), which hold the keyboard and focus model of
  every drawn menu: themed, and headless for `MenuBase` and
  `ContextMenuBase`, whose `menuShown` is a local of their trigger and
  whose open state is the app's `*bool`. `Popup` builds an overlay of a
  point attached to the element where the menu opened, so that the menu
  flips about that point at the window's edges, and a panel (`RoleMenu`)
  for the menu and each submenu open, each attached to the item opening
  it (the submenus that `Submenu` registers, built after their menu's
  panel, as its siblings). A panel keeps the focus for its items, which
  the keys and the pointer highlight (`ActiveDescendant`), by their
  element IDs; the keys are read once the panel's items are built, which
  they move among, and Enter clicks the item highlighted for the next
  pass (`clickLater`), which reports it as `Clicked`; an item clicked
  closes the menu once its panel is built (`finish`), unless the view
  marked it `KeepOpen` after making it. A `Group`'s items are a range of
  its panel's, which the keys take as one stop (`menuStops`: the item
  checked, else the first), Left and Right moving within it. The menu
  closes for presses outside it but in the frame it opened, whose press
  opened it.
  An item chosen runs the function again at once, as the choice from a
  menu of the system's does in the next frame, or does its editing
  command; the overlay going gives the focus back to the element that
  had it. A menu whose element a pass does not build closes
  (`resolveMenu`). `PopoverMenuButton` draws a menu button's menu so
  (`menuShown.below`): opened below the button itself (`menuState.below`,
  which `openMenuButton` sets), its panel attaches to the button's
  bottom, flipping above it, and the button shows expanded; opened from a
  toolbar's overflow menu, it goes at the overflow button's corner as a
  context menu goes at its point. Opened by the keys or assistive
  technology (`menuState.key`), it starts on its first item, and a press
  on the button while it shows closes it (`buildMenu`, and `newMenu` for
  the bases).
  A window whose view sets `PopoverMenus` (`ui/menupresentation.go`,
  `engine.menuPresentation`) draws every menu so: `ContextMenu` and `Menu`
  take `PopoverMenu`'s and `PopoverMenuButton`'s path, and so do the
  widgets built on them. The drawn path is reached only through function
  values `SetMenuPresentation` sets (`menusInWindow`), so apps that never
  draw their menus do not link it.
  A text input's or selectable text's own editing menu has no function of
  the view's to build it. `resolveMenu` notes it as a drawn menu
  (`drawnMenu.edit`) and asks for another pass. After that pass's view,
  before the overlay layer joins the root, the frame finds the text's
  element in the content or the overlays (`node.find`) and draws the menu
  of its `EditItems` there, in the element's theme. One in a part that
  takes no input (`flagInert`), as a page going away, is not drawn, which
  closes it. The inspector's fields keep the system's: its panel is built
  after the overlays, over them.
  The `Tester` reads a drawn menu's items as last built (`drawnMenu.items`)
  and chooses one by its ID (`drawnMenu.choose`), which the next build
  takes as a click, so its menu helpers work on either.
  What a drawn item shows beyond its `platform.MenuItem` (`Danger`,
  `Trailing`, `Content`) stays on the `MenuItem` of the run collecting
  it (`menuRun.items`), which `drawnItem` reads, so that the system's
  menus and their backends never see it. An item with an ID keys its row
  (`menuItemKey`), whose highlight then follows it as items around it
  come and go. Once a pass built the menu, the items its levels highlight
  (`drawnMenu.highlighted`, by ID or else place and label) go to the
  next run of the function, whose `MenuItem.Highlighted` reports them;
  when they changed, the pass asks for another, so the function sees the
  highlight it built. `Menu.MaxWidth` (`menuRun.widths`, by
  `platform.Menu`) caps a panel's width, its rows' labels shrinking to an
  ellipsis.
* **Scenes** are flat lists of operations in device pixels: rounded
  rectangles with borders of a width per side, solid or dashed, filled
  with a color, a linear gradient mixed in sRGB or Oklab, a gradient of
  stops, linear, conic or radial (`Scene.Stops`, which ops point into, at
  most 32 each), or stripes, the border painted with the op's gradient where it
  says so (`BorderPaint`);
  shadows (blurred rounded rectangles, cut by the box casting them, as
  CSS's box-shadow is, or inner ones, inside the box where the hole they
  leave, blurred, does not cover it, as box-shadow: inset is); runs of
  glyphs, whose masks may take a gradient (paths drawn with one); images,
  in color or gray, blurred or not (an image's `Blur`: averaged over
  squares and blurred along rows and columns as a backdrop is, but
  transparent beyond its source rectangle, which `ui`'s `Element.Blur`
  draws its layer with); effects (`OpEffect`); holes (`OpHole`), rounded
  rectangles made transparent, what was painted there gone, for web
  views; and pushed and popped clips.
  Renderers draw the whole scene each frame and retain only textures.
  Wavy underlines are stroked paths.
* **Effects** (`scene.Effect`) are drawings that packages outside the
  renderers define, as the official plugins do (the glass plugin's Liquid
  Glass): a fragment shader for each GPU renderer, in Metal Shading
  Language, HLSL and GLSL, which the renderer puts between a head and a
  tail of its own (`effect.metal`, `effect.hlsl`, `effect.glsl`, after its
  shader's common part, with `EFFECT` defined: `EffectSource`), and a twin
  for the CPU renderer (`EffectPixels`), which must draw the same pixels.
  An effect paints its op's shape from five float4s of parameters
  (`EffectOp.Params`, which travel in the instance's slots fills use for
  colors and gradients), and from its backdrop when it reads one: what
  the operations before it painted, the area its blur reaches
  (`scene.BackdropOf`), averaged over squares of 1, 2, 4 or 8 pixels a
  side so that the blur stays a few texels wide, then blurred by a
  Gaussian along rows and along columns, each step kept in 8 bits a
  channel, as textures hold it, which the shaders sample bilinearly
  (`sampleBackdrop`, `BackdropImage.Sample`). The renderer multiplies an
  effect's color by its shape's coverage, the clip and the opacity.
  Effects carry the code compiled ahead of time from what their renderer
  makes of their shader, with its SHA-256: renderers compile the source
  when it no longer matches, as when their head or tail changed since,
  and an effect's tests fail then. Package `ui` gives packages a hook,
  `Element.Material` (a `ui.Material`, built with its element when it is
  a `MaterialBuilder`), and `Painter.Effect`, which only this module's
  packages can call, since effects are internal types. An effect's shape
  has continuous corners where its op does, which the renderer covers as
  such, while the effect gets positive radii and takes them as circular.
* **Shaders** (`ui/shader`) are effects an app writes, in Go's syntax:
  `internal/shader` (Ebitengine's Kage compiler, forked, with uint and
  loops that need no constant bounds) compiles one to the IR of
  `internal/shaderir`, whose backends write it as a function for the
  renderer's code to call (`Fragment` of `msl`, `hlsl` and `glsl`; only
  the platform's renderer's backend is linked), and whose interpreter
  (`interp`) is the CPU twin. A shader's effect (`Effect.Shader`) tells
  where the words of its uniforms go in the buffer its code reads: Metal's
  struct (buffer 2), HLSL's cbuffer (b2) or a std140 uniform block
  (binding point 0); the op carries the words and up to four images,
  bitmaps or canvases (`EffectOp.Uniforms`, `Images`), bound to textures 5
  to 8 (t6 to t9 in Direct3D). GLSL and HLSL read them as globals, so a
  shader goes between the effects' head and tail; Metal has no globals,
  so its shaders are whole libraries with a tail of their own
  (`ShaderSource`, `shader_ps`), which `ui/shader` builds, so that apps
  drawing none do not carry it. `ui` itself only has `Painter.ShaderEffect`
  and `Painter.ShaderFill`: the compiler, its package variables and
  go/parser stay out of apps that draw no shader. A shader filling text,
  paths and icons (`ShaderFill`) turns the glyph ops its function painted,
  with grayscale masks, into effect ops whose `EffectOp.Glyphs` point at
  their mask glyphs (glyphs of color stay an op of their own): the
  builder makes one instance per glyph, as `OpGlyphs` does, with 1 in
  `Params[1]` and the corner of the box the shader fills in `Grad`, and
  the shaders' tails cover it with the mask atlas and `textCoverage`
  (above `#ifndef EFFECT`, as effects share it), the shader's color in
  place of the paint; `raster.maskedEffect` is the CPU twin. An
  element's effect (`Element.Effect`, a `ui.Effect`) renders the
  element's subtree into a canvas kept in its state, at the window's
  scale, in the element's own space (`paintEffect`: positions shift, and
  transforms in the subtree lose the element's own, `unworld`), then
  paints the effect with the element's transform. The canvas is made in
  steps of 64 pixels (`effectLayerStep`), the content in its top left
  corner, and kept while the content fits and leaves less than two steps
  over, resized in place otherwise (`Image.Resize`): an element whose
  edges cross pixels as it moves, or whose text grows, keeps one canvas
  and one texture, rather than one a size. The effect gets the content's
  part (`Canvas.region`), so shaders read beyond it as transparent, as
  beyond a canvas of its size; what the subtree paints is clipped to that
  part, and backdrops end at its edge (`Scene.Drawn`, `Scene.BackdropOf`,
  which the painter, the builders and the CPU renderer use alike), as at a
  canvas's. The canvas is transient (`Image.Transient`), unless the
  element is kept (`Element.Cache`, `ui/cache.go`): then it paints the
  subtree into the other of two scenes and compares it with the last
  through a `scene.Differ` of its own (`layerCache`), and only a scene
  that differs, or is of another scale or part, bumps the canvas's
  version and goes in the frame's `Canvases`; one that does not stays
  the canvas's scene all the same, as the atlases hold its glyphs this
  frame. The window's `Differ` then finds the image op the same, so
  damage over the element redraws one image. A kept element alone (no
  effect, no blur) renders, rather than its box, what it paints around
  it (`keptLayer.area`: each one's box and shadows grown by 4, in its
  space, clipped by those that clip). Its code is reached only through
  the interface `Cache` stores (`layerKeeper`), so apps that never call
  it, nor fade a group (below), do not link it. `Opacity` below 1 (a transition's fade and a pose's
  `Fade` too) fades an element with children as one group, as CSS's
  group opacity (`ui/group.go`): the subtree renders into the same
  transient canvas, the area `keptLayer.area` gives within the clip,
  drawn as one image at the opacity (`paintGroup`), so every renderer
  draws it as it draws an effect's, and kept as `Cache` keeps its layer
  while what it holds is the same (`keptLayer.draw`). A layer costs a
  render pass, so a group paints flat first, its opacity multiplied into
  each op as before, and `checkFlat` looks at the ops it painted
  (`overlapping`: their bounds within the clips pairwise, at most 32 of
  them, so that what culling skips counts for nothing): when two
  overlap, it renders the layer, takes the flat ops back (`takeBack`:
  the scene's slices, its canvases and the parts drawn,
  `engine.drawn`) and paints the layer in their place. The state's
  `grouped` then has the next frames go to the layer at once, back to
  flat when it no longer overlaps, so the frames before change what a
  group costs, never what shows. Holes (web views) and effects reading
  their backdrop keep a group flat, as no layer shows what is behind
  it. The code is linked by `Opacity`, `Transition` and `AnimatePose`
  (`linkGroups`). A blurred or kept element fades its canvas at its
  opacity rather than each op in it, and paints nothing faded out.
  `ui/shader` gives an effect's entry point (`ColorEffect`,
  `DistortionEffect`, `LayerEffect`) a `Fragment` that calls it, and the bridge reads the content as image 3
  (`LayerImage`) from where the box's corner lies in it
  (`__layerInset`). A shader reading its backdrop (`backdropAt`,
  `backdropSample`) is an effect with `Backdrop`: `Painter.EffectBackdrop`
  computes the backdrop as the builder will (`scene.BackdropOf` of the
  op's bounds), the bridge maps positions to its texels
  (`__backdropRow0`, `__backdropRow1`, `__backdropArea`), and the
  renderers bind their backdrop texture as its image 2
  (`gpu.BackdropImage`); the CPU twin reads `scene.BackdropImage`. Direct3D's compiler takes from 0.1 s to more than 1 s
  for a shader's effect (the renderer's head and tail, with its coverage,
  are most of a small one's; optimization levels barely change it), so
  `ui/shader` starts it as it compiles one (`d3d11.PrecompileEffect`), on
  goroutines, as many at once as the CPUs but one. The renderers share
  the code (`compileEffectCode`), waiting for what is left, and it stays
  in `%LOCALAPPDATA%\MyGo\ShaderCache`, a file named by the SHA-256 of
  what it compiled from, one directory for the user as Windows' own
  D3DSCache is, the least recently used removed beyond 32 MB. Effects
  compiled ahead of time, and apps without shaders, do not link it. On
  macOS, `metal.PrecompileShader` does the same with the system's default
  device: Metal's library (about 85 ms the first time) and the pipeline
  for BGRA8 windows (about 60 ms), which renderers on that device retain
  (`sharedShader`) in place of making them; Metal's own disk cache keeps
  them for later launches, and wide-gamut windows make their pipeline
  from the shared library.
* **Corners.** On macOS, rounded corners are continuous, as AppKit's and
  SwiftUI's (`scene.Op.Continuous`), and drawn as Core Animation draws
  them on screen, with the function of its shaders (QuartzCore's
  `supercircle_sdf`), which differs from the Béziers of SwiftUI's paths
  by up to half a percent of the radius: a quarter circle around the
  diagonal that bends less and less toward the edges, which it meets
  1.528665 radii from the corner, a quartic of the ratio of the point's
  coordinates in the box of the curve. On sides too short for both
  corners' curves, the curves blend toward quarter circles by the side's
  clamp factor, from the side's length over its corners' mean radius, so a
  circle's corners are quarter circles; a shape is the intersection of its
  corners', so a curve may reach past the middle of a side whose other
  corner is smaller; and edges are antialiased as Core Animation does, by
  the value over the sum of its derivatives (`internal/raster/corner.go`).
  Against captures of layers on screen, every pixel is within 1/255 for
  corners that fit and for circles, and within 6/255 for pills and other
  short sides at the sizes of controls. The CPU's renderer finds where a
  curve crosses a row by regula falsi between the quarter circles of the
  radius and of the curve's extent, and keeps the rows' spans of a clip
  with continuous corners for the operations within it; a whole frame of
  `BenchmarkFrame` takes a fifth longer. Elsewhere corners are circular,
  as Windows and GTK draw them, and only the CPU's renderer and Metal's
  draw continuous ones.
* **Text.** `internal/text` lays out text with the system's own text stack,
  behind a small `engine` interface: DirectWrite on Windows
  (`IDWriteTextLayout`, with an `IDWriteTextRenderer` implemented in Go
  collecting its glyph runs), Core Text on macOS (`CTTypesetter`, with
  `NSFont` for the system font's weights) and Pango on Linux (with
  fontconfig and HarfBuzz underneath, as in GTK); in browsers, a canvas's
  2D context (`canvas_js.go`, see [Browsers](#browsers-internalweb)). They find the fonts, fall
  back to other fonts for what one lacks, shape, run the bidirectional
  algorithm and break lines; font files stay memory mapped and shared with
  every other process. A text wrapped again at another width, as in a window
  being resized, keeps its `CTTypesetter` while frames use it, and gives it up
  8 frames after the last, or as windows go idle. Core Text opens a break
  iterator for each line of text with a language attribute, so
  `languageShapes` leaves the attribute out where it changes nothing. A
  number, new in each frame on a dashboard, is put together from the glyphs
  and kerning of its characters, measured once for each font and checked
  against Core Text or DirectWrite from time to time (`numbers.go`). Latin
  text kept across widths is shaped into one line that its lines take their
  glyphs from, breaking at the spaces before plain words, checked in the same
  way (`wrap.go`): Core Text is asked for every other break, and DirectWrite,
  which shapes a whole text before breaking it, lays out a text with any other
  break, keeping the one line 8 frames after the last, or as windows go idle,
  and drawing the spaces ending a line as a run of their own, as DirectWrite
  does. Korean text
  breaks between words, as CSS's `word-break: keep-all` (`keepWordsWhole`
  takes the breaks between two letters or digits out of Unicode's): Core Text
  moves the break it suggests back to the last one left in the line; Pango
  is told not to break within the words (`pango_attr_allow_breaks_new`), and
  lays out again from a line a word longer than it overflows, without that
  word kept; DirectWrite's lines, when one ends within a word, are broken
  anew from its cluster metrics and shaped one by one; the canvas engine
  leaves those breaks out of its own. Every engine gives a line's glyphs in visual order,
  from the left, through right-to-left runs too (DirectWrite's runs, whose
  glyphs come in logical order, are reversed), so that what walks them,
  and `ui.Shape`'s callers, rely on one order. The package assembles their
  lines into layouts, with its own whitespace trimming, ellipsis,
  alignment, carets and selection, so those behave the same everywhere,
  and caches layouts by their parameters.
  A text that wraps none of its lines lays out alike at any width they
  fit in, but for where its alignment puts its lines: `LayoutFrom` lays
  it out at another width as the layout it is given (`ui` gives an
  element's last), or as the text's layout without a width, once made,
  sharing its lines, or copying those its alignment moves (`realign`), so
  that a text whose box grows or shrinks, as a transition or the window
  resizes it, is shaped once, and one measured, then laid out at the
  width it gets, too. The engines rasterize glyphs too (`IDWriteGlyphRunAnalysis`,
  `CTFontDrawGlyphs`, cairo) into a coverage atlas, color glyphs (emoji)
  into a color atlas, and subpixel glyphs, the coverage of each pixel's
  red, green and blue, into the color atlas as well. Text looks as each
  platform's own toolkit draws it, pixel for pixel, which tests against
  AppKit, Direct2D and GTK 3 labels showed:
  * *Placement.* `System.Glyph` takes a glyph's pen position and places
    it as the engine does: Core Graphics' subpixel quantization, which
    AppKit leaves on, at `min(5, ⌈100/(3·px)⌉)` positions a pixel for
    glyphs of `px` pixels an em, left of the pen; DirectWrite's six
    positions a pixel for ClearType, eight in natural, four in natural
    symmetric and two in downsampled rendering, whole pixels in GDI and
    aliased rendering, the nearest to the pen; GTK's whole pixels, as Pango rounds glyph
    positions. `System.Baseline` snaps baselines likewise: down to the
    next pixel on macOS (Core Graphics floors in its y-up space),
    to the nearest on Windows, up on Linux.
  * *macOS.* Core Text draws with font smoothing, as AppKit does unless
    the user turned it off (`AppleFontSmoothing`, read through
    `NSUserDefaults` as AppKit does: Core Graphics' bitmap contexts ignore
    it), which emboldens glyphs more the lighter their color is, in four
    steps of its luminance: its glyphs are rasterized for each
    `text.Shade` of the text's color. `text.Thick`, for text a
    `ui.Font` thickens (the terminal's `Font.Thicken`, as Ghostty's
    font-thicken), smooths at the strongest step whatever the color and
    the user's setting, and `text.Flat`, for text a `ui.Font` draws
    `Antialiased` (as browsers draw `-webkit-font-smoothing:
    antialiased`), does not smooth; other engines draw both as other
    text.
  * *Windows.* Glyphs take the rendering mode and grid fitting DirectWrite
    recommends for their font and size (`IDWriteFontFace3`'s, which from
    about 1.9 pixels a DIP downsamples natural symmetric rendering, as
    Direct2D draws), ClearType where the system smooths
    fonts with it (`SPI_GETFONTSMOOTHINGTYPE`, with the pixel geometry and
    ClearType level of the system's rendering parameters) and the glyph is
    on an opaque background (the root's, or that of an element around it
    holding all of it that shows, as a pane beside a sidebar over a
    material), and are aliased where the system does not
    smooth fonts. Renderers blend them as Direct2D does, with the gamma
    and enhanced contrasts of the system's rendering parameters
    (`scene.TextParams`, Windows Terminal's reproduction of Direct2D's
    shaders), and half again as much contrast for the families Direct2D
    finds too thin for antialiasing, such as Courier New.
  * *Linux.* Pango takes GTK's font options, which package ui reads from
    `gtk-xft-*` (`platform.Theme.FontRendering`, given to
    `System.SetFontRendering` with the interface font): the desktop's
    antialiasing, subpixel order and hint style, with metrics hinted to
    whole pixels and glyph positions rounded, as a GTK 3 label has them.
    Subpixel antialiasing draws subpixel glyphs.
  * *Decorations.* `System.Decorate` places underlines and strikethroughs
    as the platform does: Core Text's own geometry for AppKit, snapped in
    points, an underline as low and thick as the fonts under it want,
    skipping the ink of descenders (but a link's, on hover:
    `SolidUnderline`), a strikethrough through the middle of
    the x-height, from the text's start to its width rounded up to a
    point; Direct2D's, an underline at the font's offset rounded to whole
    pixels from the snapped baseline, a strikethrough from the baseline as
    laid out, with edges where its eight samples across and down a pixel
    put them; GTK's, at Pango's metrics in whole pixels, the underline
    along a run's ink and advances, the strikethrough along its ink.
    `LineStyle` overrides the font: a thickness (`DecorationThickness`)
    around the line's middle, and an underline's offset
    (`UnderlineOffset`, CSS's `text-underline-offset`), its top that many
    DIPs from the baseline the engine draws on, in whole pixels, for every
    engine, the browsers' canvas included; Core Text skips the ink where
    the offset puts the underline.
  * *Joined glyphs.* Renderers blend each glyph in turn, as Core Graphics
    and Direct2D do, but cairo adds the coverage of a run's glyphs before
    blending it, which differs where antialiased edges of neighbors share
    a pixel. There, on Linux, package ui has the text system join them
    (`System.GlyphRun`): their coverage added and clamped, cached as one
    bitmap.
  * *Strokes.* `TextStroke` draws each glyph's stroke as a mask of its
    own (`System.StrokeGlyph`), made in Go from the glyph's coverage for
    every engine: the coverage dilated by half the width less the
    coverage eroded by it, each edge pixel's coverage placing the edge
    within it, so the stroke is centered on the outline, round at its
    corners and as smooth as the glyph; color glyphs stroke their alpha.
    Cached with the glyphs, under a key with the width, and drawn by
    every renderer as any mask glyph, all of a text's before its glyphs
    (`paint-order: stroke fill`). `TextStroke` links it, so that apps that
    stroke no text do not.
  * *Shadows.* `TextShadow` and `Span.Shadow` draw each glyph's shadow
    as a mask of its own (`System.ShadowGlyph`), the glyph's coverage
    (the alpha of a color glyph) blurred in Go by a separable Gaussian
    of sigma half the blur, as CSS has it, padded by three sigmas and
    capped at 64 pixels. Cached with the glyphs, under a key with the
    sigma, and drawn as a mask glyph at the offset, all of a text's
    before its strokes and glyphs. `NewTextShadow`, which
    `Element.TextShadow` and a `Span`'s `Shadow` take, links it: a
    `TextShadow` has no fields to set otherwise, so a shadow that paints
    is one that linked it.
  * *Tabs.* `Style.TabSize` sets tab stops every that many spaces of the
    style's font, letter spacing included, from the start of each line,
    which each engine takes natively: Core Text's paragraph style (no
    tab stops but a `DefaultTabInterval`), DirectWrite's
    `SetIncrementalTabStop`, a Pango tab array of one stop, which it
    repeats, and the canvas engine's own lines, which otherwise measure a
    tab as the canvas does, as a space. The first `TabSize` links it
    (`System.UseTabSize`), as `Justify` does `UseJustify`.
    Paths drawn with
    `Painter` are masks in the coverage atlas, rasterized by `internal/vec`,
    cached by their shape relative to the pixel grid in quarters of a pixel,
    to which their points move first: a path looks the same whichever path
    of its key drew its mask first. A path too large for one mask, over
    4095 pixels a side, draws as tiles of it (`pathTiles`), each a mask of
    the whole path clipped to the tile: only the tiles that show and that
    its edges reach, and, inside a fill, tiles covered whole, which share
    one mask: those its edges wind around by its rule (`Path.FillRule`),
    which also picks the mask's (`vec.Rasterizer.MaskEvenOdd` for
    `EvenOdd`) and keys it, as it keys a path's clip. A path larger than
    a tile (511 pixels a side) draws as tiles too when the atlas has
    lately had no room for a path's mask (`pathCrowdedPaints`): such a mask takes a shelf of the atlas of its
    own, mostly empty for a long thin stroke, and a few of them, as wires
    redrawn every frame, leave no room for the frame's other paths, which
    would not show. A path whose mask finds no room draws as tiles at once,
    and the runtime's repaint (`System.MakeRoom`) draws the frame's large
    paths as tiles, which pack eight to a row of the largest atlas: the
    room made lets go of the masks of those the paint drew before
    (`System.Unkeep`), which it would keep as the frame drew them, and
    which would leave the tiles no room. On the
    pixel grid tiles show the pixels of one mask; under a transform off
    it, a faint line where they meet. `Path.Contains` counts the winding
    of the path flattened at four times its scale; an element's `HitTest`,
    kept in its state, is one more test of `engine.contains`, after its
    box and its own clip. A stroke's mask is the outline of
    its center line, each edge drawn once (`strokeInto`): one side,
    turning at corners and ends as the path's joins and caps say
    (`Path.Join`, `Path.Cap`), and back along the other. Its dashes (`Path.Dash`) are cut from the center line as the mask
    is drawn, from where each polyline starts in their pattern, so that a
    trimmed path's dashes stay where they are, and its key holds that place,
    in quarters of a pixel within one pattern, with the caps, joins and
    dashes. As in Skia, a dash through the start of a closed subpath is one
    dash, and the point between a dash and a gap is in the gap. Square caps
    reach past half the stroke's width, and miter joins as far as the points
    of its corners do within the miter limit (`flatPath.reach`, from the
    points the mask draws), and the mask and its tiles reach as far.
    Opaque `Painter.StrokePolyline` on a GPU is the exception: each segment
    is a rotated fill with round ends, drawn as other fills are, without a
    mask; translucent ones, and the CPU renderer, take the mask's way, so
    that overlapping segments do not show darker. A translucent line of one
    segment overlaps nothing, and is a rotated fill too: the stripes of a
    diff's fillers are hundreds of these, whose one mask would be as wide
    and as high as the filler in view is high, rasterized again as that
    changes, and drawn that large for each stripe.
    So are icons: `internal/svg` parses SVG documents (with `encoding/xml`
    and its own small CSS cascade) into nodes of paths, paints and layers,
    and draws them on the CPU with `internal/vec`, compositing gradients,
    group opacity, clip paths and masks in layers of premultiplied pixels;
    `ui.Icon` keeps the coverage of that drawing for each size, which the
    GPU tints like a glyph, and `ui.Image` the colored pixels, as images
    whose textures it updates in place when only the text color changes.
    An atlas logs the rectangles that change, so renderers upload only those.
    DirectWrite methods taking floats are called through purego, which sets
    the floating point registers that `syscall` leaves alone on ARM64.
    Letter spacing and OpenType features go to each engine's own, so lines
    break with them: `IDWriteTextLayout1`'s character spacing and an
    `IDWriteTypography`, Core Text's tracking and a font copied with feature
    settings, Pango's attributes. So do the spans of rich text, which style
    ranges of runes (`text.Span`): DirectWrite's setters over a range, the
    fonts of a Core Text attributed string's ranges, Pango's attributes
    between byte indices. `Params.Spans` holds them encoded as a string, so
    `Params` stays a key of the layout cache. A span's letter spacing of 0
    is the text's unless `SpacingSet` (ui's `Span.NoLetterSpacing`, or an
    inline element's `LetterSpacing(0)`) makes it its own, which each engine
    sets over the span's range as any other. Laying out reuses what shaping
    throws away: engines take the glyphs, runs and lines `shape` returns from
    a scratch each layout resets (`shapeScratch`), as the layout copies them
    into its lines, which share one allocation; Core Text keeps its buffers,
    the attributes of each font, and calls the functions of each layout
    through `SyscallN` rather than reflection. Colors, underlines and
    strikethroughs of spans only paint, by the rune each glyph starts.
    A span with an `ObjectWidth` makes its object replacement characters
    inline objects: boxes standing on the baseline, which lines break
    around and which draw no glyph (`Glyph.Object`), as a rich text's
    images, or a text's math with `Element.DrawObjects`, which paints them
    after the glyphs. The line takes their height, and their descent
    (`ObjectDescent`, encoded only for objects), in the shared layout;
    each engine only gives them their width: Core Text through run delegates, whose
    callbacks return floats Go cannot, so they are leaves in assembly
    (`rundelegate_darwin_*.s`); DirectWrite through `IDWriteInlineObject`s,
    their places found by hit testing, as its glyph runs' are; Pango through
    shape attributes; the canvas engine as clusters of their width.
    A span's `BaselineShift` moves its glyphs and objects off the baseline
    in the shared layout too, as the room the line takes for them and the
    baseline its decorations are drawn from (`decoRange.shift`).
    The engines break a paragraph at one width, which is all DirectWrite's
    layouts take, so what else paragraphs need is the shared layout's
    (`paragraph.go`), alike on every engine. A first line's indent
    (`Params.Indent`) breaks that line narrower, then the rest anew from
    where it ends. Justification (`Params.Justify`) widens the spaces and
    the room after Han characters and kana of the lines the width wrapped,
    but the last of each paragraph, moving each glyph by the room the
    clusters left of it gain, so that carets and selection follow; it is
    linked in once a `TextShape` asks for it (`System.UseJustify`), as
    apps that do not justify text need none of it. The engines all break
    lines at soft hyphens (U+00AD) and draw them as they please: the layout
    hides those within lines (a glyph of no font and no advance, which
    keeps the caret's place) and draws a hyphen, the engine's glyph for
    U+002D in the soft hyphen's style, at the end of a line broken at one.
    Only Pango leaves room for it as it breaks, so a line whose hyphen does
    not fit is broken again, narrower by the hyphen, where Unicode's line
    breaking allows (else the hyphen overflows, as a long word does), and
    the rest anew (`breakLines`). The padding of a span (`Span.PaddingX`),
    which engines know nothing of, is the shared layout's too: `padLine`
    moves the glyphs of each line's piece of the span in, and those after
    it on, by the padding at both ends of each piece, as CSS's
    `box-decoration-break: clone`, and widens the line; a line that does
    not fit with the padding of its pieces is broken again, narrower by it,
    and the rest anew, and an ellipsis leaves room for it. A paragraph
    without an indent, a soft hyphen or a padded span is shaped once.
    `Params.Balance` (`Element.Balance`) breaks a paragraph that wraps at
    narrower widths, bisecting to a quarter of a DIP, for the narrowest
    that keeps its count of lines (`System.balance`); `Params.Pretty`
    (`Element.Pretty`) breaks again only its last two lines, when the last
    is a word alone, bisecting for the widest width at which the line
    before gives it a word and they stay two, at a space
    (`System.prettyLines`), which `Element.Pretty` and a `TextShape` that
    asks for it link (`System.UsePretty`). The layout cache keys both with
    the other params, so a build lays it out once.
    Text elements built inside a text (`ui/inline.go`) are inline: the
    paragraph takes their text when its `Children` returns, and their
    styles as spans over its own when it lays out. At commit, each gets the
    boxes of its runes in the paragraph's layout (`Selection`), one hit
    each, so the pointer, the focus order, tooltips and menus work as for
    any element; they paint only their focus ring (their `Opacity`,
    `Invisible` and dimming fade the colors of their spans, `Span.faded`,
    and a color faded to nothing stays the span's own, `colorSet`, so the
    paragraph skips their glyphs but keeps their advance), and assistive
    technology sees those that are more than text, such as links, as nodes
    inside the paragraph's.
    Fontconfig knows no desktop's interface font, so on Linux `system-ui`
    stands for the family of GTK's `gtk-font-name` first
    (`platform.Theme.UIFont`, which package ui gives `SetUIFamily` with each
    change of the appearance).
* **Atlas lifetime.** A mask drawn for the first time goes to the
  transient zone at the bottom of the atlas, which the next frame frees,
  and moves to the lasting zone at the top once another frame draws it, so
  animated shapes never fill the atlas. When an atlas fills up during a
  frame anyway, the engine calls `MakeRoom`, which repacks what the frame
  drew, grows the atlas when that is much of it (what the frame left
  out counting once, however many times it draws it) and forgets the rest, and
  paints the frame again: no frame shows with glyphs missing. The mask
  atlas starts at 256×256, and the color atlas at one transparent texel
  until a color or subpixel glyph draws. Growth accounts for the width
  and height of missing bitmaps as well as their area, so long thin
  paths fit on the repaint too. The first glyph can grow an empty atlas
  immediately, without invalidating anything already painted.
* **Renderers.** `internal/gpu` turns a scene into instanced quads, in
  batches that share a scissor rectangle and an image, for a
  shader that computes the signed distance to rounded rectangles, Evan
  Wallace's blurred rounded box, gradients, stripes, the dashes of borders,
  atlas coverage and the innermost rounded clip; outer clips are scissor
  rectangles, and a clip reaching into an outer one's rounded corners cuts
  with that one's mask as well. The builder omits operations wholly hidden by the certainly
  opaque core of a later fill, keeping at most eight occluders and treating
  backdrop-reading effects as barriers. Its planner shares clipping rules
  with drawing, grows shadow support before transforming it, and skips
  scenes without potential opaque fills. Large shadows with a caster and
  border-only fills draw as scissored strips that leave out where their
  output is zero: inside the caster, between a border's edges, and outside
  a border's outer edge. With round corners they draw in bands of rows
  (`gpu/bands.go`), each drawing only the columns between where the outer
  edge may reach and where the inner one certainly covers, so a circle a
  pixel wide shades about its length rather than its box; the bands across
  the corners are as many as pay for their draw calls (`bandCost`). With
  continuous corners they draw around one rectangle. These scissors never
  change a clip mask's sampling coordinates. Both transformations are shared by all GPU backends.
  Large fills, shadows and images with continuous corners (negative radii,
  which only Metal gets) draw as nine-patches (`gpu/corners.go`): their
  corners' boxes as they are, and the cross between them as a twin with
  square corners, in batches whose pipeline lacks the curves' code. Away
  from the boxes the shader computes the same value either way: a fill's
  pixel area, and a blurred shadow whose samples miss the curved rows or
  whose blurred sides round to 0 and 1 (9 sigma from the curve). Each
  piece is a draw call of its own (its scissor rectangle), so a shape is
  cut only where the twin's pixels, within the shape's quad, save more than
  the pieces' calls cost (`pieceCost`): small shapes, near their corners
  everywhere, stay whole and join their neighbors' batches.
  Metal opts into three further builder capabilities: marking fills whose
  clip coverage is one, splitting opaque cores from blended edges, and
  batching by fragment class, the last of which Direct3D 11 takes too. OpenGL
  keeps the original instance flags and class-independent batching. Metal binds the instance buffer
  once a pass and draws each batch with its first instance as the base
  instance, which `[[instance_id]]` includes; a batch binds its pipeline,
  image, clip mask and scissor rectangle only when they changed, with
  selectors looked up once, and the scissor goes by pointer
  (`setScissorRects:count:`) rather than through a reflective purego
  function: messages from Go cost about half a microsecond each. An effect draws in a batch of its own, with a pipeline of
  its own, which the renderer makes the first time the effect draws; one
  reading its backdrop draws after a backdrop step (`Builder.Backdrops`):
  the renderer ends its pass, reads the backdrop's area of what it drew
  (Metal from the drawable, which is not `framebufferOnly`; Direct3D 11
  and OpenGL from a copy of the area, `CopySubresourceRegion` and
  `glCopyTexSubImage2D`, whose rows go up), averages and blurs it with two
  small pipelines (`down` and `blur`, scissored to the texels they
  compute, reading them with `Load`, `read` or `texelFetch`) into textures
  as large as the frame's largest backdrop, and goes on with the pass, the
  backdrop bound for the effect. An image drawn blurred goes through the
  same two pipelines before the frame's pass, which the builder asks for
  as it meets it (`Builder.BlurredImage`), from the image's texture into
  one of the frame's own, in BGRA8 whatever the frame's format, reading
  what lies beyond the image as transparent (`gpu.PassClear`); OpenGL
  reads canvases flipped and uploaded images not (`gpu.PassUnflipped`).
  The stops of gradients travel in a texture of 32-bit floats the
  builder fills each frame (`Builder.Stops`, two texels a stop: its
  color, then its place and its color in Oklab), bound to texture 9 (t10
  in Direct3D), from which the shaders' `stopsAt` mixes them as
  `internal/raster` does. Each renderer draws scenes offscreen for
  the tests of packages defining effects (`RenderOffscreen`,
  `NewOffscreen`).
* **Canvases** (`scene.NewCanvas`, `ui.Canvas`) are images drawn from a
  scene of their own. `Canvas.Draw` paints into its scene with a painter
  of scale 1 sharing the window's atlases, and lists it in the frame's
  `Scene.Canvases`, inner canvases first as they finish. Before a frame,
  each renderer draws the canvases it lists or shows whose version its
  texture does not hold (`Scene.EachCanvas`, those a canvas shows before
  it), each with a builder of its own, into a texture in the frame's
  format before effects: Metal into a BGRA8 render target in the frame's
  command buffer, Direct3D 11 into a BGRA render target view (the dynamic
  instance buffer, mapped with discard, serves all), OpenGL into a
  framebuffer object, whose rows go up, so that image instances showing
  it flip their texture coordinates (the samplers take source rectangles
  either way round). A canvas's texture lives as long as the canvas
  (`weak.Pointer`), not drawn again when shown; a transient canvas's,
  drawn anew in every frame that shows it, as an effect's, only while
  frames draw it: the renderers' sweep every 120 frames frees it, rather
  than wait for the canvas to be collected, which the little of Go's heap
  it takes may put off for minutes while its texture takes megabytes. The CPU renderer draws
  canvases into their `Pix` (`PixVersion`).
  Near square corners, coverage is exact, the area of a pixel
  inside the box, so lines thinner than a pixel cover as much as they
  should, as text decorations need. A fill's border widths travel in its
  texture rectangle, which fills do not use, and a glyph's gamma ratios
  and contrast in its radii. Each instance is thirteen float4s, including
  its two affine rows. The shader writes a second color, the source's alpha of each channel, and
  renderers blend with it (dual-source blending): it is the color's alpha
  but for subpixel glyphs, whose subpixels cover each channel by its own.
  OpenGL ES without `EXT_blend_func_extended` blends the mean of their
  subpixels instead. A hole is an opaque fill in a batch of its own
  (`Batch.Hole`), blended with a source factor of zero: the destination
  keeps one minus its coverage, as the CPU renderer's `erase` does. Every GPU renderer draws these instances:

  * `internal/gpu/d3d11` with a shader compiled to DXBC ahead of time
    (on Windows, with the system's `d3dcompiler_47.dll`), so apps carry no shader compiler. The
    generated file records the SHA-256 of the source it came from, line
    endings aside (`gpu.SourceSum`), as Metal's does: bytecode older than
    `shader.hlsl` falls back to compiling that with the same DLL, which
    Windows has, and its test fails. Both compilation paths enable IEEE
    strictness with optimization, avoiding a native compiler optimizer crash
    on transformed coverage sampling. Batches of a class (`gpu.Class`) draw
    with shaders of their own (`classes.hlsl`, after `shader.hlsl`, whose
    functions they share, which leaves the sources effects are compiled from
    as they are): instances of a class are not transformed, so they leave out
    the general shader's coordinates, pass on 6 to 10 values rather than 15,
    skip the clip where the vertex shader finds it holds the whole quad, and
    write one color, blended by its alpha, but for subpixel glyphs, which need
    dual-source blending. A plain fill takes 83 instruction slots rather than
    the general shader's 3,627. A set of classes draws with the first of
    `classShaders` holding them, made as first drawn: each class, the sets that
    small batches join most, and all of them, which still costs less than the
    general shader, which only transformed instances and effects need. The
    renderers of a process share one Direct3D 11 device and its immediate
    context (`shared.go`), with the shaders, input layout and states, which
    never change: a device costs the driver tens of megabytes, which a
    window each would multiply (#1517). Each keeps its swap chain and what
    its frames change, and the device goes with the last of them. They draw
    on the main thread, each frame binding all it draws with; the device is
    multithread protected (`ID3D10Multithread`) all the same, so that DXGI's
    calls on a swap chain from another thread are serialized with the
    context's. A renderer made after the device was removed makes a new
    one; those holding the old one fail their next frame (`Render`), and
    their windows make them again on the new one, as after any failed
    frame. A device made with WARP gives way the same way to one on the GPU
    once a renderer made can make one, as a window drawing in software
    tries from time to time. It draws
    into a flip-model swap
    chain on the surface's window, or, over a material, one for
    DirectComposition shown on it, with WARP when no hardware device
    works. At most one frame waits ahead of the screen, not DXGI's three,
    and `Present` does not block for
    it: the swap chain's frame latency object (`latency.go`) tells room
    for a frame, and a frame drawn before there is presents once there is,
    as a goroutine waiting on the object has the main thread present it
    (`SetPost`); frames paced by the display (`WM_PAINT`, but a resize's
    and `FrameNow`'s) are not built meanwhile (`Renderer.Ready`). Every
    present takes one of the object's signals, so its count stays the
    frames the screen can take. Frames that make the refresh without building
    ahead, as the last ones' cost tells (`frameCost`: the main thread's time and
    the GPU's timestamps, taken after the frame's clear, which waits for the
    window manager to give the buffer back; a frame no `Ready` started, as a
    resize's, counts none, its main thread's time not known), build once it composed the last
    (`DwmFlush`) and there is room, and present with sync interval 0, to show at
    its next composition. Heavier frames build ahead and present with sync
    interval 1, which keeps them at the display's pace a refresh later. A frame of a new size is
    presented at once (sync interval 0), not after the frame queued
    before it, and waits until DWM shows it (`DwmFlush`), so a live
    resize shows no stretched frames: the window takes its next size
    with the frame of that size. DWM may still show the window at its new
    size a refresh before that frame (#222), so the window's swap chain
    shows its frames unscaled (`DXGI_SCALING_NONE`) with the content's
    background beyond them (`SetBackgroundColor`, from
    `scene.Scene.Background`), and the window paints what it grew by
    around its surface with that background before fitting the surface
    to it (`platform.BackgroundSurface`, `fillUncovered`): what shows
    meanwhile is the background, not black. As the window shrinks, the
    surface takes the new size and presents its frame before DWM takes
    the window's, so DWM may show the window at its last size for a
    refresh, and around the surface the window's own pixels where the
    surface was, which the swap chain covered: the window paints them with
    the background too, under the surface, at each size (`fillUnder`),
    unless its frames are drawn in memory onto them. Until a frame of its
    content shows in it, the window is cloaked (`DWMWA_CLOAK`, from the
    surface's creation): shown, it would show white while the renderer
    starts and the first frame draws, a few hundred milliseconds (#905).
    Windows sends it `WM_PAINT` all the same, and uncloaks it after the
    one whose frame reached the surface (`platform.FirstFrameSurface`),
    or a second after it was shown without one (a timer, which only an
    idle main thread lets fire); a refresh of DWM between the present and
    its frame showing shows the background under the surface
    (`fillUnder`). A window whose frames show through DirectComposition
    (no redirection bitmap, as a flyout's, or web views over the frames)
    has no pixels of its own there, and DWM would show it black for a
    refresh or more: it stays cloaked until DWM composed the frame
    (`DwmFlush` on a goroutine, within four refreshes at 60 Hz), then
    uncloaks on the main thread (#1591). A window made hidden gets no `WM_PAINT`: its first frame is
    drawn while it is hidden (`drawHidden`), which makes it ready to
    show, and it uncloaks after its first `WM_PAINT` once shown; a
    present that DXGI reports occluded leaves the next frame to draw
    whole. Resizing the buffers takes DWM longer
    than a frame for a window about as large as a 4K screen, so while
    the window changes size the swap chain has three buffers a quarter
    larger than the window, until a frame a second after the last change,
    which a timer asks for, gives it two of the window's size again. The
    unscaled swap chain shows those buffers whole, from the top left
    corner, and the window clips them: showing only the window's size of
    them (`SetSourceSize`) would stretch that part over the buffers' size,
    magnifying the frame (#892), as it does for a swap chain for
    composition. A frame drawn whole fills what is beyond it in the
    buffers with the content's background (`clearWhole`), which shows
    where the window grows within them. A swap chain that stretches, where
    the unscaled one is refused, shows the window's size of the buffers.
    The swap chain flips in sequence (`FLIP_SEQUENTIAL`), so that a frame
    draws only what changed since the last, as Metal's (below): DXGI keeps
    what each buffer holds, and as a frame is presented with the
    rectangles it drew as its dirty rectangles (`Present1`), copies into
    it what the last frame changed outside them, so there is no buffer
    age to track. The frame clears the rectangles
    (`ID3D11DeviceContext1::ClearView`, which Direct3D 11.1 has, WARP too)
    and draws the batches scissored to each; a frame that changed nothing
    is not presented. With WARP, on a runner
    without a GPU, a caret blinking in a window of 1280×760 pixels took a
    tenth of the CPU's time it took drawn whole;
  * `internal/gpu/metal` with a shader in Metal Shading Language
    compiled into a Metal library ahead of time (on macOS, with
    Xcode's `metal` tools), which
    spares a first launch the 100 to 150 ms Metal takes to compile the
    source until it has cached it; a library older than `shader.metal`
    falls back to that, and its test fails. It draws into a CAMetalLayer
    it adds to the surface view's layer. The command queue, shaders,
    sampler and placeholder texture are made on demand. A frame that
    changes the layer (its size, scale or pixel format), or shows web
    views, which move in the window's transaction, presents with the Core
    Animation transaction (`presentsWithTransaction`), so a live resize
    shows no stretched frames; the others present as soon as the GPU has
    them (`presentDrawable:`), sparing a pass of AppKit's display cycle
    and a commit of the transaction each: an animation at 120 Hz takes
    about half the main thread's time it would. A resize's frame that
    AppKit asks for (`updateLayer`) after one presented with the
    transaction, outside a live resize, draws at the display link's next
    tick, as for a window resized from its view, or right after the frame
    that took back the drawables given back when idle: drawn in AppKit's
    display of the view, presented with the transaction too, it did not
    show, and the window kept the last frame stretched to its new size
    (#1044). So does one asked for after a pause, which would otherwise
    draw from the backend's queue (`drawSoon`) in a pass of its own, and
    not show either. The main thread never
    waits for the display: after each frame presented as soon as drawn, a
    goroutine on a thread of its own (`present.go`) takes the next frame's
    drawable, which `nextDrawable` holds back while the display holds the
    others, most of a refresh at times. A frame that comes while it does
    is built at once, its canvases and instances ready, and waits
    (`pendingFrame`); once the goroutine has the drawable, it has the
    main thread (`SetPost`, through `surface.Conn.Post`) draw the frame
    into it and present it. Frames of the display link's ticks
    (`platform.SurfaceEvent.Paced`) are not built while one waits
    (`Renderer.Ready`, `windowHost.waitDisplay`): the next draws once it
    was presented (`platform.PacedSurface.FrameNow`), at the time its tick
    asked for it, so that what moves keeps its pace; the link keeps
    ticking meanwhile. Other frames, as a resize's, draw the waiting one
    first. Frames presented with the transaction, which change the layer,
    take their drawable on the main thread, as the first after a pause
    does, after any being taken. Building a frame before its drawable
    comes, as blocking for it did, keeps the GPU as busy: building only
    once the drawable came drew a sixth fewer frames where the GPU took
    most of each refresh. Instances use two frame slots, for
    the main target and each canvas, and a slot waits only for the command
    buffer that last used it. Updating an atlas or image texture in place
    still waits for every frame in flight. Rendering a canvas into its
    texture stays ordered on the command queue. The layer keeps three
    drawables, as Core Animation makes while a window animates: with two,
    on a ProMotion display, frames waited for one most of each refresh,
    and a fifth of the frames went undrawn. The third costs a frame of memory while a window animates.
    Waiting for a drawable remains separate from waiting for an instance
    buffer, so offscreen encode timings do not establish presentation latency.
    Opaque fill cores use an unblended pipeline in BGRA8; float16 keeps
    blending to preserve its interpolation rounding, and GPUs outside the
    Mac2 family keep to the blended one: one such GPU, an Intel Haswell
    whose driver OpenCore Legacy Patcher backported, hung in the unblended
    pipeline (#1566), and blending them costs only that GPU's tile-based
    win of writing without blending. Fragment functions are
    specialized by batch class and continuous corners, with general shaders
    as an identical fallback. Runs of small batches of different classes
    (each covering at most 128×128 pixels, as a box's shadow then its
    fill) join into one batch whose function holds just their classes'
    paths (`Batch.Joined`): a draw call costs the CPU more than those
    pixels cost the joined function. A worker compiles and warms these pipelines,
    cached per device, outside the frame path. Renderer release stops and
    joins that worker before releasing its shader library. Float16 shadows
    stay general, and fills with fractional opacity avoid the plain class,
    because specialization otherwise changes rounding. GPUs outside
    Metal's Mac2 family (`supportsFamily:`), as Intel's Haswell, draw every
    batch with the general pipeline, compiling and warming none, and keep
    their batches together: one such GPU, on a driver backported by
    OpenCore Legacy Patcher, hung while specialized pipelines compiled
    (#1566). Function constant
    indices 0 through 7 belong to the renderer; effects start their own at 8.
    Two seconds after the last frame, as the
    driver frees its own memory of frames, a timer shrinks the drawables,
    which frees all but the one shown, until the next frame makes them
    again, and releases GPU instance buffers, atlas/image textures and
    backdrop textures: an idle window keeps one frame of memory. Its
    drawables are not `framebufferOnly`, as effects sample the drawable
    for their backdrops.
    A frame draws only what changed since its drawable was drawn. Core
    Animation hands the layer's drawables out in turn, and each holds the
    frame drawn into it last: the renderer keeps, by the drawable's
    texture (retained, so that no other takes its address), what changed
    in the frames since (`gpu.Ages`, as EGL's buffer age says), found by
    comparing each scene with the last (`scene.Differ`, as the CPU
    renderer does), grows it by the backdrops of the effects it meets,
    and, while that is less than half the frame, loads the drawable
    rather than clearing it, copies a texel cleared to the frame's color
    over the area (with the `down` pass, so that the GPU converts the
    color as it does clearing), and draws the batches scissored to it,
    leaving out those outside. The area is up to eight rectangles apart
    from each other (`gpu.Part`, from the Differ's, which `gpu.Ages`
    keeps for each drawable, those that meet or nearly do merged, and
    past eight the two whose union grows least): a spinner in one corner
    and a progress bar in the other redraw themselves, not all between,
    each batch drawing once in each rectangle it meets, so that none is
    blended twice. A backdrop an effect reads is within one rectangle,
    drawn before the effect reads it. Apple's tile-based GPUs then load and store
    only the tiles the pass draws in: a caret blinking in a window of
    3200×2000 pixels takes 0.4 ms of the GPU a frame rather than 2.4,
    and a spinner 0.4 rather than 2.9, on an M5. Copying the last frame
    forward instead (a blit) costs about what drawing it whole does, 0.34
    ms against 0.43 at 3456×2000. A frame whose scene is the last one's
    draws nothing and takes no drawable. Apple does not document that
    drawables keep what was drawn: a drawable not seen yet, the drawables
    of a new size or format, and those after the timer shrank them draw
    whole, and `MYGO_PARTIAL=0` draws every frame whole. The pixels are
    those of the frame drawn whole, byte for byte: an op that the builder
    puts under another pipeline than in the last frame (a batch
    specialized for other classes, a pipeline made meanwhile) draws a
    unit in the last place apart here and there, so its bounds count as
    changed (`pipelineDamage`), as do those of a clip that starts or stops
    holding an op drawn under a transform, which it then cuts with a mask
    (`scene.Differ`); `TestPartialFramesMatchWhole` draws random scenes
    changing frame after frame into three targets in turn and compares
    each frame with it drawn whole. Colors
    outside the sRGB gamut (`ui.Oklch`, as CSS's `oklch()`) are in a
    table of the scene (`scene.Scene.Wide`), which ops and glyphs point
    into with a 16-bit index (`Op.Wide`, in room the op's other fields
    leave); their `Color`, `Color2` and `BorderColor` hold the nearest
    sRGB colors, found as CSS Color 4 does (`internal/gamut`), which the
    CPU, OpenGL and Direct3D renderers draw, as `gpu.Builder` does unless
    `Wide`. The window host decides when a window draws them
    (`wideHold`): on a screen showing more than sRGB
    (`platform.WideGamutSurface`, `canRepresentDisplayGamut:` on macOS),
    from a frame with some until none came for two seconds, so that a
    blinking caret does not switch formats at every blink; those frames
    are the GPU's, and a window on an sRGB screen keeps drawing the
    nearest colors on the CPU. The Metal renderer (`SetWide`) then
    switches the layer to `RGBA16Float` in the extended sRGB color space,
    which keeps components outside 0 to 1 and which the system shows in
    the display's gamut, and draws with pipelines and backdrop textures
    of that format, made the first time. A uniform of the frame (the z of
    the vertex and fragment globals) tells the shaders: Oklab gradients
    then keep what their mix has outside sRGB, and effects read it as
    `e.wide`, as the glass does to take its tint in extended sRGB
    (`ui.Painter.EffectColor`);
  * `internal/gpu/gl` with the shader in GLSL 3.30 or GLSL ES 3.00, which
    the driver compiles when the renderer starts, since these versions
    have no compiled form every driver takes, and drivers keep what they
    compiled between launches, as Mesa and NVIDIA's do. It draws into
    the framebuffer of the GtkGLArea, which GTK shows. GL functions come
    from libepoxy, as GTK's do. Instances draw from per-instance
    attributes, pointed at each batch's first since OpenGL ES 3.0 has no
    base instance. The area's `create-context` asks GDK for OpenGL 3.3,
    else OpenGL ES 3.0, as GPUs with OpenGL ES alone have, and so does
    the probe below (`glContext`). In browsers the same renderer draws
    with WebGL 2, which is OpenGL ES 3.0 (see
    [Browsers](#browsers-internalweb)): only where its functions come from
    differs, `load_linux.go` or `load_js.go`. A frame draws only what
    changed since the last (`Renderer.Partial`, with `scene.Differ` and
    `gpu.Pipelines`, as Metal's), into a framebuffer that keeps what was
    drawn, so there is no buffer age to track: it clears the rectangles of
    the area with the scissor test on, which `glClear` keeps to, and
    draws the batches scissored to each. GTK keeps the GtkGLArea's framebuffer from render to
    render, but makes its buffers anew, holding nothing defined, whenever
    it allocates the area, at the same size too: a `SurfaceResize` has the
    next frame draw whole (`Invalidate`). Once the area has a context, GTK
    composites the whole window with OpenGL and tells EGL what each paint
    changed (`eglSwapBuffersWithDamageEXT`) in the window's coordinates
    unscaled, where EGL takes the buffer's pixels from the bottom left: at
    a scale of 2, Mesa told a compositor that a change at the top of the
    window was in its lower half, at half its size. A compositor that
    redraws only what it is told changed (Mesa's llvmpipe tells it whole
    frames changed, a GPU's buffers what GTK said) then showed title
    buttons the pointer hovered flickering or gone, and a shadow missing on
    some sides (#1071). At a scale of 2 or more on Wayland, the toplevel's
    `draw` signal adds what GTK repaints (cairo's clip) as
    `wl_surface.damage`, in the surface's coordinates, to the commit of the
    swap that follows (`damageGLPaint`); `TestGLDamageWayland` checks it
    under `weston --scale=2`. A canvas's WebGL 2 context keeps
    its drawing buffer (`preserveDrawingBuffer`), which browsers then copy
    as they composite each frame drawn; in Chrome on an M5 a caret blinking
    still took a quarter of the GPU's time it took drawn whole, and a frame
    that changed nothing leaves the canvas alone. On Mesa's llvmpipe a
    caret blink in a window of 1280×760 pixels took a sixth of the time.

  Linux draws with OpenGL only where it runs on a GPU. A GL context loads
  Mesa for good: some 50 MB of libraries (LLVM, which distributions' Mesa
  links, takes 19 MB as it loads), its threads and heap, as much as the
  rest of a small app; the first window of native UI loads it.
  Before a surface has one, the backend makes one context, on a window
  that never shows, and reads its renderer. A software
  renderer such as Mesa's llvmpipe (in virtual machines, in WSL without
  `GALLIUM_DRIVER=d3d12`) redraws every pixel of every frame on the CPU,
  ten times the CPU renderer's work on an animated page; and once a window
  has a GL context GTK composites it with OpenGL, so the choice is made
  before any surface has one; `MYGO_GPU=1` skips it and draws with OpenGL
  wherever GDK makes a context, from the first frame, as the GUI tests of
  CI do on llvmpipe. The devices answer first where they can: no GtkGLArea
  without NVIDIA's devices or a render node of a DRM driver with 3D
  (simpledrm, bochs, VirtualBox's or Hyper-V's only show what the CPU
  drew), nor on WSL's device without `GALLIUM_DRIVER=d3d12`. A GtkGLArea shows only
  what OpenGL draws into it: when its GL renderer fails all the same, the
  frames drawn in memory go through OpenGL too (`gl.Presenter` uploads
  them and blits them into the area's framebuffer).

  `internal/raster` draws the same scene with the same formulas on the CPU,
  solid spans inside shapes and only the edges of shadows computed, and
  blends ordinary opaque mask glyphs in integers, retaining the general
  path for gradients, corrected/subpixel text and rounded clip edges. It
  redraws only what differs from the last scene (`raster.Renderer`, with
  `scene.Differ`, which compares the operations of two scenes from both
  ends), with the effects reading their backdrops that meets and those
  backdrops, in rectangles apart from each other (`AddBackdrops`): it is
  the renderer of tests, of `MYGO_GPU=0` and of Linux where OpenGL would not
  run on a GPU, and the one a window falls back to when its GPU renderer
  fails.
  Frames that are not the surface's (a capture before the first frame) are
  kept, not drawn: OpenGL's context is current only in the surface's. An
  area drawn goes through the operations whose bounds (those the damage is
  found from) it meets; a large one is drawn on up to eight cores, in
  bands of 64 rows that each takes in turn, as rows differ in how much
  they draw, each pixel as drawing the area whole gives it. An effect is
  readied (`EffectPixels.Begin`) before its pixels, and one reading its
  backdrop reads pixels other bands draw, so an area is drawn up to each
  effect, its backdrop computed (`backdrop.read`, its rows and columns on
  several cores too), then from the effect to the next, in bands of 16
  rows, as effects are costly and often short. The glass plugin's
  `BenchmarkGlass`, a window of 1360×720 pixels with four panes, takes
  6.4 ms drawn whole on an M5, 22 ms on one core. A whole frame
  of `BenchmarkFrame`'s view at 1844×2044 pixels, built and drawn, takes
  0.7 ms rather than 3.2 on a Ryzen 7 8745HS: memory bandwidth and the
  lower clock of all cores keep it from scaling further.

  On Linux, `RequestFrame` of a surface drawing in memory adds a tick
  callback to the area, which GTK's frame clock runs in its update phase,
  before painting: the frame is drawn there, and `PresentDamage` keeps its
  pixels and asks GTK to repaint what changed (`gtk_widget_queue_draw_area`),
  which the `draw` signal paints from them in the same frame. GTK keeps
  the rest of its buffer, copying it from the last one into a new buffer
  when the compositor still holds the last, and tells the compositor
  only that changed: a digit of the counter copies 24 KB of pixels instead
  of 15 MB for half of a 4K display, in 0.01 ms instead of 1. A draw GTK
  asks for by itself, as a resize does, draws a frame in the `draw`
  signal, and repaints in the next frame what it changed outside GTK's
  clip. GTK neither paints a window that does not show nor runs its
  frame clock: until its first frame reached the surface
  (`platform.FirstFrameSurface`), `RequestFrame` of a window made hidden
  also adds an idle callback, which realizes the window, giving the area
  the size it will show at, and draws that frame in memory, showing it
  nowhere (`drawHidden`), which makes the window ready to show. A
  GtkGLArea has no context until it shows: the frame is followed by
  `SurfaceRenew`, so that the first in its `render` signal makes the GPU
  renderer, which the hidden one could not.

  GTK's frame clock waits, after each frame, the refresh interval of that
  frame's timings, and 1/60 s while none has one. GDK fills it in only
  from the compositor: on Wayland in the frame callback of a paint it
  commits itself, which it never asks for when it composites the window
  with OpenGL (`eglSwapBuffers` commits, with a swap interval of 0), and
  on X11 from a compositor sending `_NET_WM_FRAME_TIMINGS`. A GtkGLArea
  drew 60 frames a second on a 165 Hz display under Niri (#1219). The
  surface writes the interval of the monitor showing the window
  (`gdk_monitor_get_refresh_rate`, asked again each frame, so it follows
  the window to another monitor) into the timings of each frame it draws
  (`paceFrameClock`), unless they have one. `GdkFrameTimings` is private,
  and GTK 3.24.24 moved its `refresh_interval`: the offset is the one
  `gdk_frame_timings_get_refresh_interval` reads the write back from. A
  monitor of unknown rate, as Xvfb's, keeps 60 Hz, and a compositor's
  interval arriving later replaces the surface's. The clock still runs
  only while frames are asked for. On Wayland these frames follow a timer
  at the display's rate, not its refreshes.

  On Windows, `RequestFrame` invalidates the surface's window, whose
  `WM_PAINT` comes as soon as the message queue is empty, and frames drawn
  in memory show at once, through GDI or DirectComposition: nothing held
  them to the display, and a drawing asking for every frame
  (`Painter.AnimationFrame`) drew 5,000 a second on a 60 Hz display. After
  each, a goroutine waits for DWM's next composition (`DwmFlush`, through
  `platform.RefreshSurface`), for half a refresh at least, as it may
  return at once, and two at most, and paced frames (`WM_PAINT`, but a
  resize's and `FrameNow`'s) wait for it as they do for the swap chain's
  room (`refreshWaiter`, `windowHost.waitDisplay`): the next draws once it
  returns, through `FrameNow`, and the main thread handles input
  meanwhile.

  With a GPU renderer, every frame draws on the GPU, small changes too, so
  a gesture never switches renderers mid-way: on the CPU, a frame
  redrawing glass or a blur that content scrolls under takes 30 to 70 ms
  on a large window, where Metal takes 2 to 3. Every GPU renderer draws
  only what changed (above).

  Two seconds after the last frame (`frameIdle`), the host frees the frame
  drawn in memory, as large as the window, which the next frame draws whole,
  and tells the surface it is idle (`platform.IdleSurface`): Linux's calls
  glibc's `malloc_trim`. GTK paints a window it composites with OpenGL into
  an image as large as what it repaints, the whole window for a whole
  frame, and glibc, raising its
  threshold for giving large blocks back as they are freed, kept one or two
  of them, 15 to 30 MB for half of a 4K display. These timers run on the
  main thread through `surface.Conn.Post`.

  A GPU renderer that fails (a driver reset, a GPU unplugged, sleep) is
  released and another made in the same frame (`ui/window.go`): the GPU
  may be back already, and on Windows WARP stands in, presenting through a
  swap chain, as GDI cannot show frames once a flip-model swap chain has
  drawn into a window. Without one, frames are drawn in memory, and a
  frame tries again after a wait that doubles from one second to half a
  minute; a renderer drawing in software in place of a GPU the window had
  tries for it the same way. A window without a GPU at its first frame
  draws in memory for good.
* **Tests.** `ui.Tester` runs views against a host in memory
  (`ui/headless.go`) with the CPU renderer, at its own time
  (`engine.clock`), which stands still until `Tester.Advance` moves it.
  Its host runs no timer; it notes their deadlines, and `Advance` runs
  the frames due. `Tester.Access` and `AccessByRole`
  (`ui/tester_access.go`) build the last frame's accessibility tree on
  demand, as `accessTree` does for a window, and give its nodes as
  `AccessInfo`: the role an element was given (`node.role`), so that
  roles sharing a node's role stay apart, or the one following the
  node's in the order of `Role`; a role added to both needs nothing
  there, a state a field. The fake backend's surface lets the core's
  tests drive content windows through `package mygo`.
  `BenchmarkFrame` in `ui` measures a frame of a large window on the CPU,
  and `BenchmarkListScroll` the frames scrolling a list of a million rows;
  `BenchmarkDiff*` the frames of a window as godiff's, two lists of texts
  and rich texts, unchanged or scrolling, with their allocations
  (`TestDiffFrameAllocs` logs them).
  The GPU renderers' tests draw `gputest.Scene` and compare it with the
  CPU renderer's drawing: on Windows in a hidden window, on macOS into an
  offscreen texture, on Linux into a framebuffer of a context EGL makes
  without a window (Mesa's surfaceless platform, llvmpipe without a GPU),
  once with OpenGL 3.3 and once with OpenGL ES 3.0.

A new widget composes elements (`ui/widgets.go`), keeps what it needs from
frame to frame with `Local` or in `state`, declares its interaction with
element flags (`flagClickable`, `flagFocusable`, …), paints in `Draw`, and
gets a test with `Tester`. A new GPU renderer draws the instances of
`gpu.Builder` with a port of the shader, syncs atlases with
`Atlas.Changes`, is created in `ui/gpu_<os>.go` behind `gpuRenderer`, and
has a test that compares its drawing of `gputest.Scene` with the CPU
renderer's (`gputest.Compare`).

## Native modules (`native`, `internal/nativegen`)

A native module ([the guide](https://mygo.egoist.dev/docs/native-modules.md)) is a Go package whose
interfaces Swift, Rust or Zig implement, each in a directory named after
the language (`swift/`, `rust/`, `zig/`), all behind one C ABI. Three parts
make it work:

* **`internal/nativegen`** reads the package with `go/ast` alone (no type
  checking, so it is fast and needs no dependency built): the interfaces
  marked `//mygo:native` and everything they reach, structs, enums (a
  named string or integer type and its constants, read from literals and
  simple `iota` expressions) and the errors made with `native.NewError`.
  What crosses is a closed set of types (`Type.Kind`); anything else is a
  `Diag` at its line, with what to write instead. An interface the module
  returns is the platform's, one it only takes is Go's (`ByGo`). It writes
  `<package>_native.go` (constructors and proxies, `gogen.go`) and
  `<Module>.mygo.swift` (protocols, structs, enums, `<Module>Error`, the
  `@_cdecl` entry points and the glue in `support.go`), and on both sides
  the functions that encode the composite types the methods cross
  (`wire.go`: `_enc_<T>`/`_dec_<T>` in Go, `_mygoWrite_<T>`/`_mygoRead_<T>`
  in Swift, `<T>` named after the type, as `slice_map_int`, and a type of
  another module, whose struct fields name its types relative to it, as
  `<Module>_<T>`). For `rust/` and `zig/` it writes
  `src/mygo.rs` (`rustgen.go`: a trait per interface, `Send + Sync`,
  structs, enums, `<Module>Error`, `#[no_mangle] extern "C"` entry points,
  and the runtime of `rustsupport.go`: threads for calls with a context
  and for streams, `catch_unwind` at every entry) or `src/mygo.zig`
  (`ziggen.go`: a struct of a pointer and a vtable per interface, whose
  `of` checks at compile time that the implementation has each method,
  `export` entry points, an arena per call, and the runtime of
  `zigsupport.go`), the library's root, which imports the implementation
  as `impl`. Both refuse what only Swift implements (`portable`: views,
  textures, windows, other modules' interfaces, returned buffers). All
  carry `mygo:native <version> <hash>`, the hash of the
  package's type, const and error declarations with their comments, which
  `mygo build` compares (`Stale`). The generated Go names its own
  identifiers with a leading underscore (`_x`, `_ctx`, `_err`, `_r`, `_h`,
  `_fN`, `_gN`, and the packages it calls, imported as `_native`,
  `_runtime`, `_context`, `_fmt`, `_filepath`), and the parser rejects
  parameters named so, so that no parameter clashes with them; the
  signatures keep the interface's names. An argument that stands for
  memory or an object of the platform's (a buffer, a module's object, a
  view) is kept reachable until the platform is done with it: the call
  returns, or, for a stream, the stream ends. A stream's arguments are
  made as its loop starts, and the callbacks and values of Go's among
  them forgotten if it does not start (`native.Stream`'s `prepare`). The
  scaffolds of `mygo native new` and `add` are in `write.go`.
* **`native`** is the runtime the generated Go calls, imported only by
  modules, so apps without one link none of it. It loads
  `lib<Module>.dylib` as package `ffi` loads any library (`ffi.New(name,
  nil).From(dir)`: `MYGO_NATIVE_<NAME>`, the bundle's
  `Contents/Frameworks`, next to the executable, then `.mygo/native` of
  the module of the package's directory, which `runtime.Caller` of the
  generated file finds in builds without `-trimpath`, go test and go run,
  checked against the sources' times of the module's languages
  (`lib_ffi.go`); on Linux and Windows the same, Rust and Zig everywhere
  and Swift on Linux for go test only (`Module.supported`). `mygo_<m>_init`
  takes, beside the callback, the C runtime's `malloc` and `free` (libc's,
  ucrtbase's on Windows), with which every implementation allocates the
  blocks it gives Go and frees Go's, whatever its own allocator.
  Every entry point has one C signature, `(obj, args, len, call) ->
  block`: arguments go in the binary encoding (`codec.go`: integers as 8
  bytes little-endian, floats as float64, lengths before bytes and
  elements, a flag before a pointer's value, structs as their fields in
  order, an empty one as a zero byte so that every element takes one and
  a length is never more than the bytes left), from a pooled `Encoder`;
  results come back in a block `malloc`ed by the side that made it
  (status, length, bytes) and freed by the other, which Go's `Decoder`
  reads in place and frees on `Close`. Errors cross as a kind, code,
  domain, number and message, both ways. A method of numbers and bools
  that returns no error (`direct`) has a `_direct` entry point instead,
  `(obj, a0, a1 …) -> UInt64`, called with them as registers: integers as
  their bits, floats as a float64's, bools as 0 or 1. One purego callback, created once for all modules, carries
  everything the platform tells Go (`kind*` in `call.go`): results of
  asynchronous calls and values of streams, by call id; notifications and
  questions of callbacks, by the handle of a Go function; calls of methods
  of Go values, at once, or on a goroutine answered through
  `mygo_<m>_resume`, by a continuation that `status` carries, so that Go
  answers it, with an error, even where it has no method to call; and
  releases. Continuations' ids are unique in the process: their high bits
  are the module's index (`contBits`), which Go gives each module as it
  loads it (`mygo_<m>_init`). A stream is pulled: Go calls
  `mygo_<m>_next` for each value, so a lent `NativeBuffer` stays valid
  until the loop continues, and canceling the call cancels the Swift task.
  Objects are `Unmanaged` retains on the Swift side, released by `Close`
  or a `runtime.AddCleanup`; objects of the main thread are released
  there, posted through `App.WhenReady`, never waited for on the
  runtime's one goroutine of cleanups. Notifications run in order on one goroutine,
  through `mygo.RunOnMain` once the app runs. Main-thread methods run
  through `RunOnMain`, or directly on the main goroutine before `App.Run`,
  and in Swift under `MainActor.assumeIsolated`.
* **The CLI** (`cmd/mygo/native.go`) finds the app's modules among the
  packages it is built from (a package with a generated `_native.go`),
  listed once per build and target with the native libraries' packages
  (`Config.packageDirs`), so that apps without a module list nothing
  more, regenerates
  them in `generate` and `dev` or refuses stale ones in `build`, runs
  `swift build` (debug for the host, or release for the target's
  architectures, both at once for universal), copies the dylib and the
  frameworks its package brings into `Contents/Frameworks`, which
  `codesign --deep` signs, and merges the modules' `Info.plist` and
  `Entitlements.plist` (`mergePlist`) under the app's own keys, which
  settle the modules' conflicts. A module's language for a platform is
  `moduleLang` (`native_module.go`): Swift on macOS when it has `swift/`,
  else Rust, then Zig; Rust and Zig modules are libraries like those
  packages name, as resources (`nativesOf`, `Config.nativePackages` adding
  each module's library to its package's manifest, with no `build`, as
  `nativePackage.library` gives the language's per platform). `mygo dev`
  watches each language's directory and the plists, but not the
  generated files. `mygo native call` writes a small typed program
  into the module's directory that decodes the arguments into the
  method's parameters, and runs it.
* **Views.** An interface embedding `native.View` is a view of the
  platform (an `NSView` in `swift/`), its methods on the main thread; on
  platforms without an implementation its constructor returns
  `errors.ErrUnsupported`, and `ui.NativeView` of nil is a plain box.
  `native.View` has one method, `NativeView() uintptr`, the platform's
  view (0 once closed), which `ui.PlatformView` asks for, so the public
  API names no internal type. `ui.NativeView` is `ui.WebView`'s element
  around a `platformView` of the window's engine, which stands for the
  view as a `surface.WebView` and has the surface host it as it hosts an
  embedded web view, through `viewhost.Embed`, which package native sets
  as it initializes, so that only apps with a module link the hosting
  (`platform.ViewSurface`, `EmbedView`: a `window`
  whose `web` is the view, `foreign`), so placing, clipping to the
  hole's corners, stacking, hiding and the pointer's way through the
  surface are the web view's. A `platformView` holds the view by its
  handle, never its Go value, so a view the app lets go of is released;
  `native` tells the windows hosting a view as it closes or is released
  (`viewGone`, the function `Embed` was given), which drop it
  (`pruneViews`). Closing one also takes the `NSView` out of its
  superview, and a view another window took is put back as its window
  places it. Objects of the main thread close and release there.
* **Modules that use modules.** `nativegen` loads the native modules a
  module imports (`go list -find`), qualifies their types with their Swift
  modules, and makes generated declarations `public`. Generated packages
  register with `native.Register`, which loads a module's dependencies
  before it (dyld then finds their libraries loaded, by install name, when
  it links them) and wraps another module's objects by name (`Wrap`). The
  CLI builds dependencies first and passes `-I`, `-L` and `-l` to the
  dependent's `swift build`; `.mygo/native` is for editors only.
* **Textures.** `native.Texture` is `internal/texture.Texture`. `ui.Image`
  takes it through `imagesrc.Frames`, and `ui.ImageSource` is sealed by
  `imagesrc.Mark`, which `Bitmap`, `SVG` and textures embed, so that `ui`
  links no texture code. Swift presents an `IOSurface` through the
  callback (`kindPresent`, the surface retained); the texture holds the
  surface presented last, the one shown and those of frames in flight
  (`inFlight`), each in use so that pixel buffer pools never hand them
  back to be drawn on screen, and asks the windows that drew it for a
  frame, those that drew it within the last `staleAfter` presents: the
  others no longer show it, until they draw it again. A frame's `scene.Image` wraps the shown surface: GPU renderers
  ask its `GPU`, a `scene.GPUSource` the texture implements, for a
  texture of their API (`scene.Metal` on macOS, which wraps the surface
  with no copy), and draw its pixels, which `Restore` reads, where it
  gives none, as the CPU renderer does, into a texture of their own: the
  Metal renderer marks the textures a source gave (`texture.gpu`) and
  never uploads pixels into one.
* **Published implementations** (`native_swift.go`, `publishSwift` in
  `native_lib.go`): a module is a native library of its own, named as its
  Swift module and built per platform in that platform's language
  (`moduleTargets`, `moduleLibrary`), so `mygo native build` publishes its
  Rust and Zig builds as any library's, by `GOOS-GOARCH`, and its Swift as
  a universal release build packed as `.tar.gz` with its frameworks, named after its
  SHA-256, uploaded with `gh` to the module's release `native-<name>` of the
  checkout's repository unless `-release` or the library names another
  (`uploadNatives`, which never replaces a file: a name there already is
  the same bytes), recorded under `darwin-universal` of the module's
  `mygo-plugin.json` with the hash of its Swift package's sources, LF line
  endings, and those of the modules it uses (`moduleSourceHash`); it skips
  a module whose record matches, unless `-force`. `swiftBuild` takes it
  while the hash matches, in release builds and wherever Swift is missing,
  through the cache of native libraries (`fetchNative`), unpacked with no
  path or link that leads out of its directory (`untar`).

## CLI (`cmd/mygo`)

* Browsers (`web.go`): `build -platform web` (or `js/wasm`) compiles the
  app with `GOOS=js GOARCH=wasm` and the production flags into `<out>/web`,
  with a page of its own (`webPage`: a spinner while the WebAssembly loads)
  and the `wasm_exec.js` of the Go that compiled it, which must match.
  `dev -web` serves the page, the loader and the last build that compiled
  from memory (`webDev`), rebuilds on the watcher's changes as the desktop
  loop does, and tells pages through server-sent events (`/__mygo/events`):
  `reload` after a build, `build-error` with the compiler's output, which
  the page shows over the app until a build compiles.

* `init` renders `cmd/mygo/template`: a Go module and a TypeScript frontend
  built with Vite, side by side at the project root like the examples, draws
  a default icon at `resources/icon.png`, fetches modules, installs the
  JavaScript dependencies with Bun and generates the client. package.json
  runs the CLI from mygo-cli (`bun run dev`, `bun run build`), or with
  `go run github.com/egoist/mygo/cmd/mygo` for `-mygo <checkout>`, whose
  go.mod replaces the module with the checkout. mygo.config.ts imports
  `defineConfig` from mygo-cli, or from the checkout's `packages/cli` by a
  relative path between real locations, and sets `devUrl`, `devCommand` and
  `buildCommand` (the `dev:web` and `build:web` scripts, which run Vite and
  never mygo), `frontendDist` (Vite's `dist`) and `out` (`build`, so the two
  do not meet); `vite.config.ts` pins the dev server to the port of `devUrl`
  and does not watch the development app and builds. Names reach the
  templates escaped for their language (`json`, `printf "%q"`, `html`).
  `-template native` renders `cmd/mygo/template/native` instead (the
  frontend's is `template/web`): an app of native UI with a test of its
  view and a `mygo.json`, whose module has the CLI as a tool (`go get
  -tool`, or a `tool` line beside the `replace` of a checkout), for
  `go tool mygo dev` and `build`; no Bun. Without a frontend in the
  configuration, `bindings` stays empty and the CLI writes no client.

* Both templates install the agent skills embedded under
  `cmd/mygo/template/shared/.agents/skills`. `install-skills [dir]` refreshes
  the same bundled files in an existing directory, without reading project
  configuration or replacing unrelated skills and extra custom files.

* The configuration is `mygo.config.ts`, or `mygo.json` (`config.go`,
  `config_ts.go`). For the former, Bun, else Node.js 22.6 or later (with
  `--experimental-strip-types` before 22.18 and 23.6), runs a loader that
  imports it, awaits its default export or calls it with `{ command }`, and
  writes JSON to a temporary file; either way the JSON goes through the same
  checks. The loader goes to the runtime's standard input, never its
  command line: on Windows the runtime may be a batch file (npm's
  `bun.cmd`), and cmd.exe cuts the command line at a line break. Errors name the file in use. `defineConfig` and the types of the
  configuration come from `packages/cli/index.d.ts`; `TestConfigTypes`
  keeps its interfaces in step with the `Config` struct.

* `generate` builds the app for the host and runs it in generate mode
  (`MYGO_GENERATE`; `RequestSingleInstanceLock` then returns true at once).
  Before that, with `i18n` in the configuration, it checks the catalogs
  and writes their functions (see Catalogs of messages), as `dev` and
  `build` do; `i18n check` only checks them. `dev -lang` passes the
  language to the app as `MYGO_LOCALE` (in browsers, through `go.env`).

* `dev` (`dev.go`, `watch.go`) writes the client as `generate` does (the
  frontend imports it), runs `devCommand` in the project directory, waits
  for `devUrl` to answer and runs a development build, pointed at it
  with `MYGO_DEV_URL` (or at `frontendDist` on disk without `devUrl`). The
  build is packaged like a release: on macOS a bundle named
  "<name> Dev" with identifier "<id>.dev" in `.mygo/dev/<goos>-<goarch>`, so
  bundle-only features (notifications, URL schemes) work and its data stays
  apart from the production app's. Builds are assembled in a staging
  directory and renamed into place, so the running build keeps its files.
  * Builds run with `MYGO_DEV=1`, which the core takes out of its
    environment (`dev.go`): `App.Relaunch` then exits with code 75, which
    has `mygo dev` start the same build again, with the arguments
    `Relaunch` wrote in the file of `MYGO_DEV_RELAUNCH`. Production builds ignore it.
    `-background` adds `MYGO_DEV_BACKGROUND=1`, taken out the same way:
    the app does not come to the front as it launches
    (`AppOptions.Background`, macOS), and its windows show as
    `ShowInactive` would (`backgroundShow`) until a window takes the
    focus or the app becomes active.
    A build counts as started once its process is: one that crashes on
    start is reported as it exits.
  * *Reload.* A change (polling every 250 ms, debounced) rebuilds;
    when the executable, Info.plist and icon are unchanged nothing restarts.
    Otherwise the running build is sent SIGTERM (quit sequence), then
    SIGKILL after 3 s, and the new one starts once it has exited: builds
    never overlap, so the single-instance lock, the web view's profile and
    the app's files are free. Only the app gets the SIGTERM, which lets it
    end the processes it started; those left after it exits are killed. A
    build that fails to compile leaves the old one running; one that fails
    to start leaves none until the next change.
  * *Watching.* Exactly what the build reads, from `go list -deps` after
    every build: the directories of the compiled packages outside GOROOT and
    the module cache (so local `replace` modules too), embedded files,
    go.mod/go.sum, the configuration, the icon and the resources, but not
    the platform directories of other platforms. Frontend sources
    are the dev server's business and never rebuild the app. A build keeps
    the watcher's baseline unless it changed what is watched, so edits made
    during a build trigger another one. On Windows the watcher opens
    directories sharing them for deletion (`openDir`), which `os.Open`
    does not, so that deleting or renaming one it lists does not fail.
  * Quitting the app ends `mygo dev`; a crash waits for the next change.
    Ctrl+C stops the app as a change does; a second one kills it and the
    dev server at once. The watcher reports the paths that changed, which
    the rebuild names. Lines typed on the terminal are shortcuts (`r`
    restarts even an unchanged build, `c`, `q`, `h`); on Unix, mygo
    ignores SIGTTIN, so that reading them in the background fails rather
    than stopping it.

* *Output* (`console.go`), on standard error: a line per step of a
  command. On a terminal (Windows: a console that takes VT sequences once
  `enableVT` asks), the step in progress has a spinner, redrawn in place
  at 12 fps and cut to the width (`termWidth`, autowrap off besides), with
  its elapsed time and what it does: `goBuild` runs `go build -v` and
  shows the import paths it prints, and modules it downloads, keeping
  the other lines, the compiler's errors, for its error; downloads show
  their bytes. Steps nest (signing inside a build). What the programs the
  CLI runs print goes through `labeled` writers, which erase the spinner's
  line, write whole lines with a label (`web │`, `app │`) and draw it
  again; the app writes to an `os.Pipe`, not a writer of `exec.Cmd`,
  whose `Wait` would wait for the web view's processes holding it, and
  commands with writers get a `WaitDelay`. Without a terminal, each step
  has a start line and an end line, without colors unless `FORCE_COLOR`
  (`NO_COLOR` turns them off anyway). `dev` and `build` open with a
  banner whose five exclamation marks are those of MyGO!!!!!, in its
  members' colors, which light up one after the other on a terminal
  (redrawn two lines up with the cursor saved, until a line moves it).

* `build` generates the client, runs `buildCommand`, then compiles each
  target with `-trimpath -ldflags "-s -w -X …production=1"` (`-H=windowsgui`
  on Windows) and `-tags mygo_nodownload,mygo_noinspector`, which leave
  out package ffi's downloader and the inspector of native UI (unless
  `MYGO_INSPECTOR=1`), into a staging directory, so a
  failed build keeps the previous artifacts. `frontendDist` is embedded without touching the project
  (`embed.go`): `go build -overlay` adds a generated `mygo_frontend_gen.go`
  to the main package, with `//go:embed all:mygo_frontend` and a call to
  `SetFrontend`, and maps every `frontendDist` file into that virtual
  directory, so the frontend may live anywhere. macOS targets become `.app`
  bundles (Info.plist, `.icns` rendered in pure Go, and with `macos.icon`
  an `Assets.car`, as it is or compiled from an Icon Composer `.icon` by
  `xcrun actool`), signed with
  `macos.signingIdentity` (hardened runtime and timestamp for real
  identities, ad hoc by default); `darwin/universal` combines both
  architectures with a pure-Go fat-binary writer. Linux gets a `.desktop`
  entry and icon. The production flag makes `IsDev` false, which disables
  the web inspector by default.

* *Resources* (`resources.go`), as in quickgui: the contents of the
  project's `resources/` directory, plus the files and directories listed
  in `resources` in the configuration under their base names, are copied into
  `Contents/Resources` of macOS bundles and next to the executable on
  Linux and Windows, by `build` and `dev` alike; apps find them with
  `App.Path(PathResources)` (under `go run`, `./resources`). The platform
  directories of `resources/`, named `<goos>` or `<goos>-<goarch>`
  (`platformDir`; names other tools use, such as `darwin-x64`, are
  errors), ship with the apps of that target only, their entries merged
  with the shared ones: `merger` groups what goes to one path, ignoring
  case, and only descends into directories that several sources share, so
  a whole tree from one source stays one entry. For `darwin/universal`,
  `darwin-arm64` and `darwin-amd64` are walked as pairs whose names must
  match: identical files and links ship once, an arm64 and an x86_64
  Mach-O file become a universal binary (`writeUniversal`) when copied,
  anything else fails. A name starting with a dot is skipped when it is a
  directory or a file manager's dropping (`.DS_Store`, `Thumbs.db`,
  `desktop.ini`), and at the top level of `resources/` whatever it is; a
  dotfile inside a resource directory ships (`junkName`, `hiddenName`),
  since packages read such names. So is what `resourceFilter` excludes
  from `resources/` (but not from listed paths): Go source files, which
  only builds read, and the paths there that match `resourcesExclude`
  (`path.Match` segments, `**` for any number of them), with what a
  matching directory holds; the merger's
  listings and `resource.walk`, which copies and fingerprints, apply it,
  while `mygo dev`'s watcher still sees those files, which a package may
  embed. The entries of these directories and listed paths are followed
  when they are links, links inside them are copied as links,
  permissions are kept. Installed paths must be unique ignoring case
  (listed resources never merge), and top-level names must not replace
  the packaging's own files
  (`AppIcon.icns`, `Assets.car`, the executable, the `.desktop` entry). Code
  among them is signed before the app (`signNestedCode`), since
  `codesign --deep` only covers code directories and notarization rejects
  unsigned code: Mach-O files, then the bundles holding them, deepest
  first, as a bundle's signature seals what it holds (and signing its main
  executable signs the whole bundle). A real identity signs all of it,
  keeping the entitlements of each (`--preserve-metadata`) unless
  `macos.helperEntitlements` names others; ad hoc signing only signs code
  without an `LC_CODE_SIGNATURE`, and the bundles around it, so vendors'
  signatures stay. Windows builds sign the PE images among the resources
  that have no certificate table, with the app's certificate or command.
  The packages of the app may name native libraries in a
  `mygo-plugin.json` (`natives.go`, the format in `internal/nativelib`),
  with how to build each from its sources (`build`: a Rust crate for
  cargo, a Zig package for zig build) and its published files, one per
  platform with its URL and SHA-256, as the terminal plugin names
  libghostty-vt: `go list -deps` of the target finds them. A library with
  `build` in a package outside the module cache and `vendor` (the app's
  own, or a module replaced by a directory) whose sources are there is
  built for the target (`nativebuild.go`), unless its published file for
  the target was built from these sources (its `sourceHash`, the
  SHA-256 of the build directory's files but `nativelib.Skipped` ones,
  with LF line endings, its `args` and `macOS`) or the tool is missing, into `.mygo/native/<goos>-<goarch>` of its module,
  cargo with `CARGO_TARGET_DIR` and zig with `--prefix` and `--cache-dir`
  under `.mygo/native` too, so that builds write nothing into the sources
  but cargo's `Cargo.lock`. cargo-zigbuild, when installed with Zig, links
  Linux (against glibc 2.28, as Zig does) and other platforms' libraries
  but macOS's, which need Apple's SDK and so a Mac, and Windows' on
  Windows (MSVC). macOS libraries get the app's minimum version or the
  library's `macOS`, the later (`MACOSX_DEPLOYMENT_TARGET`, Zig's
  `-macos.<version>` target, without which Zig asks for the latest macOS).
  The CLI empties the debug sections of the Linux libraries it builds
  (`stripELF`, as `strip --strip-debug`), as Zig can keep them even when
  `build.zig` asks to strip (libghostty-vt's). cargo's JSON messages name the crate's
  cdylib; zig's prefix is searched for the one library it installed. Both
  build incrementally, so `mygo dev` builds on every rebuild, and watches
  the sources (but `target`, `zig-out` and hidden directories). Other
  libraries are downloaded once into
  `<user cache>/mygo/natives/<sha256>/`, checking their SHA-256. Each is
  installed at the top of the resources like a listed resource, both
  architectures of a universal app combined. `mygo native build`
  (`native.go`) builds the libraries of a package for every platform (or
  `-target`'s, adding to the files already named, skipping those whose
  file was built from the sources as they are unless `-force`, and
  listing the platforms that failed at the end) into `.mygo/native/release`, named
  `<name>-<goos>-<goarch>-<sha256[:12]><ext>` so that a release never
  replaces a file a published version of the package names, copies them
  into the cache, where apps on the machine find them before they are
  published, with `-upload` puts them on a GitHub release with `gh`, not
  as the repository's latest, and then writes their entries into
  `mygo-plugin.json`. Package `ffi` (below) finds them
  at run time. The CLI and the plugins
  download into that cache with `internal/download`: a 5xx, 408 or 429
  response, or a connection that fails or breaks off, is tried again
  after 1, 2 and 4 s (GitHub's release downloads answer 502 and 504 now
  and then), and a lock on `.lock` in the file's directory (`flock`,
  `LockFileEx`) has processes that need the file at once download it
  once: the others wait, then find it. Without it each renamed its own
  copy onto the file, which Windows refuses ("Access is denied") while
  another process has it open or loaded.
  `resources/icon.png` is the default icon. Each platform's output
  directory is assembled in a staging directory that replaces it whole, so
  removed resources do not linger; development builds on Linux and Windows
  remove what the previous build placed and this one lacks.

* Packages for the other platforms. Windows gets "<name> Setup
  <version>.exe", made with NSIS (`nsis.go`): a per-user install in
  `%LOCALAPPDATA%\Programs\<name>` (`windows.installDirName` names the
  folder otherwise), where the updater can write and where the installers
  of later versions install too (`InstallDirRegKey` reads the uninstall
  entry's `InstallLocation`), a Start menu shortcut, a desktop shortcut
  that the finish page's second check box (MUI's "show readme" one)
  creates, and an uninstaller registered
  under `HKCU\…\Uninstall\<identifier>`; `/S /D=<dir>` installs
  silently, without the desktop shortcut. The uninstaller runs from a
  copy of itself that nothing waits for, so it removes the app's folder
  last: the folder is gone once the uninstall is done. It tries deleting
  each shortcut again for up to 5 s, as Explorer opens a new shortcut a
  few seconds after it appears, not sharing it for deletion, and `Delete`
  fails meanwhile. `windows.installerInclude` names a script of the
  app's own that the generated one `!include`s after MUI2.nsh and the
  languages (`nsisHooks`); its `customInit`, `customInstall` and
  `customUnInstall` macros, each inserted only under `!ifmacrodef`, run
  in `.onInit`, at the end of the install section and in the uninstall
  section before `RMDir /r "$INSTDIR"`, as electron-builder's do; without
  it the script is unchanged.
  `makensis` comes from an installation of NSIS or, on Windows, where NSIS
  is rarely installed, from the official zip of the release that
  `Release` in `internal/nsis` pins, which the CLI downloads once, checks
  against its SHA-256 and unpacks into `<user cache>/mygo`, as Tauri
  does. It tries the copies of
  the zip in `Release.URLs` in order, until one answers with the right
  SHA-256: the asset of this repository's `nsis-<version>` release, then
  SourceForge, where NSIS publishes it. SourceForge's download host has
  been down for hours at a time, and its mirrors then redirect to it, so
  it is not the only source; a host that sends no response headers within
  30 s gives way to the next. Updating NSIS means publishing the copy (see
  [Releasing](https://github.com/egoist/mygo/blob/main/docs/architecture.md#releasing)). Other systems skip the
  installer without NSIS: its zip holds Windows programs only. A signed
  app gets a signed uninstaller too, as with Tauri: `!uninstfinalize`
  (NSIS 3.08 and later) makes makensis run `mygo sign-uninstaller` on the
  uninstaller it generates, before it puts it into the installer, and the
  CLI signs it as it signs the app. The executable and the Windows
  configuration reach it through the environment (`MYGO_SIGNER`,
  `MYGO_SIGN_SETTINGS`), since NSIS reads `$` in the script as its own
  syntax. Linux
  gets a Debian package written in pure Go (`deb.go`), whose maintainer
  is `linux.maintainer`, else the `author` of package.json, else the name
  of the app: the app in `/opt/<name>`, a `/usr/bin` link for each name
  of `linux.command`, the desktop entry (categories,
  comment, URL schemes; `Exec` is the app's path) and hicolor icons,
  depending on GTK 3 and WebKitGTK 4.1. It also gets an RPM package
  (`rpm.go`), built with `go.digitalxero.dev/rpm`, with the same files
  and metadata, and a `PKGBUILD`
  (`pkgbuild.go`), from which `makepkg -si` packages the archive for
  Arch Linux (`source` is its file name, with its SHA-256): its
  `package()` installs what the Debian package holds, with the same
  modes, the desktop entry written in it with `printf` as `deb.go`
  renders it, and the hicolor icons, which the build resizes as for the
  Debian package and writes next to it as more sources
  (`<name>-256x256.png`, `<name>-512x512.png`); pacman's hooks register
  them, the MIME package and the desktop entry, as the triggers of
  Debian do. `pkgver` is the version without the hyphen of a
  pre-release (`1.2.0beta.1`; vercmp sorts `1.2.0_beta.1` after
  `1.2.0`, as a remainder starting with a separator wins), `depends`
  takes per-format `deb`, `rpm` and `arch` lists, or maps a list of
  Debian dependencies through `archPackages` and `rpmPackages`, warning
  about those they lack, and `options` keeps the executable unstripped. Every
  value is quoted for the shell, and `-upload` leaves it out (`uploads`
  takes only known kinds). `linux.formats` chooses which of the three
  packages a build writes (`writeLinuxPackages`), all by default; the
  archive is always written. Packages hold the same files as
  the update archive; apps installed by a package manager do not update
  themselves (`Updater.Enabled` checks that the app can write where it is
  installed). Every Linux build also gets `install.sh`
  (`installscript.go`), a POSIX sh script, the same for every
  architecture, that installs the archive for the user in
  `~/.local/<name>.app` (which updates can replace), links
  `~/.local/bin/<command>` for each name of `linux.command` that no other
  program has (and removes a `~/.local/bin/<name>` link of its own, which
  earlier scripts made), and registers the app's `<name>.desktop`, with
  absolute `Exec` and `Icon` paths, and `<name>.xml`, the shared-mime-info
  package of the types it defines, under `$XDG_DATA_HOME`. It then warns
  when `ldconfig -p` lists no WebKitGTK (4.1 or 4.0, the libraries
  `internal/linux` loads), with the command that installs it on the
  distribution `/etc/os-release` names, and stays silent when it cannot
  tell (no `ldconfig`, or a cache without libc, as on NixOS or musl).
  `Update.Install` registers them again from the new version
  (`update.RefreshDesktopEntry`, the same rewrite in Go, which a test
  compares with the script's) when the user's entry runs the app it
  updated. It takes the archive it is given, else the one of its
  version next to it, else, with updates, the `url` of the target's
  manifest, read with sed from the indented JSON `mygo build` writes.
  `--uninstall` removes only what points into its install, including the
  URL handler entry the app registers.

* On a macOS host, macOS targets also get "<slug>-<version>-<arch>.dmg",
  or "<slug>-<version>.dmg" for darwin/universal
  (`dmg.go`): the CLI puts a copy of the app (`ditto --noclone`, since a
  clone of a sparse file takes fewer blocks than its copy on HFS+ will),
  the `/Applications` link, the volume icon and a `.DS_Store` written in
  pure Go (`dsstore.go`, byte-identical to dmgbuild's `ds_store` package)
  that lays out the Finder window in a folder, `hdiutil` creates a writable
  HFS+ image of it, as large as its files need (APFS where HFS+ fails, as
  on macOS 26.7.1), the CLI sets the volume's
  Finder flags, then `hdiutil convert` compresses it with LZMA.
  No AppleScript or Finder automation is involved, so it works headless and
  in CI. The image is signed with a real identity and, with `macos.notarize`,
  notarized with `notarytool` and stapled.

* `keygen` writes the update signing keys (see Updates above).

Configuration lives in an optional `mygo.config.ts` or `mygo.json`
(`cmd/mygo/config.go`): app
metadata (the icon defaults to `resources/icon.png`), extra `resources`,
the frontend (`devUrl`, `devCommand`, `buildCommand`, `frontendDist`,
`bindings`) and the `macos` section (minimum system version, signing
identity, entitlements of the app and of helpers, DMG title, notarization
profile).

## Platform differences

| feature                                                                          | macOS                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Linux                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Windows                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| watching files                                                                   | FSEvents, one stream per tree, no descriptor per file                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | inotify, per directory                                                                                                                                                                                                                                                                                                                                                                                                                                                     | `ReadDirectoryChangesW`, one for a recursive tree, and the parent to see the directory renamed                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| menu bar                                                                         | application menu bar, default menu installed                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | per-window GTK menu bar, none by default                                                                                                                                                                                                                                                                                                                                                                                                                                   | per-window Win32 menu bar, none by default                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| menu item icons                                                                  | `NSMenuItem` image, 16 pt, template images tinted                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | a `GtkBox` of a `GtkImage` (a cairo surface at the widget's scale) and the label; none on the bar's own items; tray menus' items get `icon-data` over DBusMenu (`dbusmenu_gtk_parse_get_cached_item`)                                                                                                                                                                                                                                                                      | Windows 11: drawn by MyGo in a column after the checks' (premultiplied BGRA, `internal/menuicon`); Windows 10: `hbmpItem`, a 32-bit premultiplied DIB section freed with its menu; none on the bar's own items                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| menu item subtitles                                                              | `NSMenuItem` `subtitle` from macOS 14; before, after the title (`Label — Subtitle`)                                                                                                                                                                                                                                                                                                                                                                                                                                   | after the label                                                                                                                                                                                                                                                                                                                                                                                                                                                            | after the label, with its ampersands escaped                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| auto-hide menu bar                                                               | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | the bar widget hides; `can-activate-accel` keeps its shortcuts; Alt alone or F10 show it and open its first menu until it deactivates                                                                                                                                                                                                                                                                                                                                      | the menu is attached only for the `SC_KEYMENU` menu loop that Alt alone or F10 start; shortcuts come from the webview                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| tray                                                                             | NSStatusItem, click events (a Control-click a right-click)                                                                                                                                                                                                                                                                                                                                                                                                                                                            | AppIndicator: a menu, and activation (a double click) for an icon with an `OnClick` listener                                                                                                                                                                                                                                                                                                                                                                               | notification area icon, click events                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| global shortcuts                                                                 | Carbon hot keys                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | X11: `XGrabKey` on the root window (with Caps/Num Lock variants), key presses from a GDK filter. Wayland: the XDG `GlobalShortcuts` portal (see [Linux](#linux-internallinux))                                                                                                                                                                                                                                                                                             | `RegisterHotKey`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| notifications                                                                    | UserNotifications, packaged apps only; `Group` is the `threadIdentifier`; `Image` a `UNNotificationAttachment` of a temporary file named for its format, which the system moves into its store; optional `Sender` uses communication notifications with the signed capability; the delegate is attached at launch, for the click that launched the app                                                                                                                                                                | org.freedesktop.Notifications over D-Bus; `Image` is the `image-data` hint, decoded by GdkPixbuf and fit to 256 pixels; ignores `Group` and `Sender`                                                                                                                                                                                                                                                                                                                       | notification-area balloons (toasts); `Image` is the balloon's large icon (`hBalloonIcon`, `NIIF_LARGE_ICON`), decoded by WIC, twice `SM_CXICON`; ignores `Group` and `Sender`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| notification removal                                                             | `removeDeliveredNotificationsWithIdentifiers:`; `ClearNotifications` removes all, earlier runs' too                                                                                                                                                                                                                                                                                                                                                                                                                   | `CloseNotification` on the bus, for those of this run                                                                                                                                                                                                                                                                                                                                                                                                                      | hides the balloon, which goes away by itself anyway                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| a web view scaled and rounded with native UI (`WebViewPlacement`)                | the pane's bounds scale it, its layer's corners cut it                                                                                                                                                                                                                                                                                                                                                                                                                                                                | WebKitGTK zooms the page to its view's size, which `resize`s it at the same width; `draw` clipped to the corners on whole pixels                                                                                                                                                                                                                                                                                                                                           | the visual's transform scales it, a rectangle clip cuts it                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| WebViewAvailable (any goroutine, before `Run` too)                               | `WKWebView` is there, which macOS always has                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | WebKitGTK 4.1 (or 4.0), JavaScriptCore and libsoup load, as `webKit` loads them for a window showing a page                                                                                                                                                                                                                                                                                                                                                                | `internal/webview2` finds a runtime, or a `WebView2Loader.dll` next to the executable exports what `createEnvironment` calls; once an environment was made, whether that worked. A runtime whose files are there but whose browser is not passes, and fails later, making the web view                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| secrets                                                                          | Security.framework generic passwords in the login keychain (`SecItem*`), service and account as keytar                                                                                                                                                                                                                                                                                                                                                                                                                | libsecret's `org.freedesktop.Secret.Generic` schema (attributes `service`, `account`), loaded on first use, libsecret 0.19 or later; no libsecret, no session bus (`g_bus_get_sync`) or no Secret Service on it (`G_DBUS_ERROR_SERVICE_UNKNOWN`, `NAME_HAS_NO_OWNER`, `NO_SERVER`) is `ErrUnsupported`                                                                                                                                                                     | Credential Manager generic credentials (`CredWriteW`), target `service/account`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| vibrancy                                                                         | all materials, behind pages and native UI; Liquid Glass (`NSGlassEffectView`) from macOS 26, the popover and HUD materials before, with a `tintColor` and the native UI's `Glass{Native}` placed over web views; frameless windows cut to `CornerRadius`; `SetActiveAppearance` through AppKit's private `_setForceMainAppearance:`                                                                                                                                                                                   | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Windows 11 22H2 Mica, Acrylic, Tabbed, behind pages and native UI, in windows created with a material, which have no menu bar; Liquid Glass as Acrylic; frameless windows given a `CornerRadius` rounded by DWM                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| active windows                                                                   | the core's state, from key windows; materials follow AppKit's (`NSVisualEffectStateFollowsWindowActiveState`), but panels', flyouts' and kept ones' (`NSVisualEffectStateActive`)                                                                                                                                                                                                                                                                                                                                     | the core's state, from GDK's focus; GTK's own title bar goes `:backdrop` as a focusable flyout takes the keyboard                                                                                                                                                                                                                                                                                                                                                          | the core's state, from `WM_ACTIVATE`; DWM's Mica and Acrylic follow the frame, kept active while the window's focusable flyout is (`WM_NCACTIVATE`)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| accent color and accessibility preferences                                       | `NSColor.controlAccentColor` (10.14+), `accessibilityDisplayShouldReduceMotion` (10.12+), `accessibilityDisplayShouldReduceTransparency` and `accessibilityDisplayShouldIncreaseContrast` (10.10+), with `NSSystemColorsDidChangeNotification` and `NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification`; no text scale                                                                                                                                                                                       | GTK's `gtk-enable-animations` and theme name, and the settings portal's accent, contrast and GNOME's `text-scaling-factor` (`ReadAll`, `SettingChanged`); no reduced transparency; the pointing devices from the default seat's, as they come and go                                                                                                                                                                                                                       | DWM's `AccentColor`, `SPI_GETCLIENTAREAANIMATION`, Personalize's `EnableTransparency`, `SPI_GETHIGHCONTRAST` and Accessibility's `TextScaleFactor`, with `WM_SETTINGCHANGE`; the pointing devices from `SM_MOUSEPRESENT`, `SM_DIGITIZER` and tablet mode, not followed as they are plugged in                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| preferred languages                                                              | the global `AppleLanguages` (`CFPreferencesCopyValue`), not the app's                                                                                                                                                                                                                                                                                                                                                                                                                                                 | `LANGUAGE`, then `LC_ALL`, `LC_MESSAGES`, `LANG`; read when asked, no changes reported                                                                                                                                                                                                                                                                                                                                                                                     | `GetUserPreferredUILanguages`, `WM_SETTINGCHANGE` "intl"                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| regional formats                                                                 | `autoupdatingCurrentLocale`, its calendar's first weekday, the hour of the skeleton "j"; `NSCurrentLocaleDidChangeNotification` and System Settings' distributed notifications                                                                                                                                                                                                                                                                                                                                        | glibc's `nl_langinfo_l` of `LC_TIME` (`_NL_TIME_FIRST_WEEKDAY`, `T_FMT`), else by region                                                                                                                                                                                                                                                                                                                                                                                   | `GetLocaleInfoEx` of the user's default: `LOCALE_IFIRSTDAYOFWEEK`, `LOCALE_STIMEFORMAT`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| the app's language kept                                                          | `AppleLanguages` of the app's defaults                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | the file `locale` in PathUserData                                                                                                                                                                                                                                                                                                                                                                                                                                          | the file `locale` in PathUserData, and the process's preferred UI languages                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| web views' language                                                              | from the app's `AppleLanguages`, next launch                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | `webkit_web_context_set_preferred_languages`, live                                                                                                                                                                                                                                                                                                                                                                                                                         | the environment's `Language`, as it is created                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `Theme.SetSource`                                                                | `NSApp`'s appearance (Aqua, DarkAqua, or none)                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | `gtk-application-prefer-dark-theme`; light also puts a theme named for its dark variant (Yaru-dark) in place of its light one (Yaru), which GTK and WebKitGTK otherwise take for dark, and the other sources reset the theme. Without a source, or with system, the setting follows the settings portal's `color-scheme` (GNOME's and KDE's dark style, which GTK 3 does not read) from `Init` on: dark where the portal prefers dark, else the desktop's own GTK settings | the title bars, menus and native UI, and pages through the DevTools protocol's emulated `prefers-color-scheme`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `Theme.SetGTKCSS`                                                                | nothing                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | a `GtkCssProvider` for the default screen at `GTK_STYLE_PROVIDER_PRIORITY_USER`, replaced by the next sheet that parses                                                                                                                                                                                                                                                                                                                                                    | nothing                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| a press the system cancels in native UI (`InputEvent.Canceled`, `PressCanceled`) | a context menu shown while a button is down, whose loop takes the release                                                                                                                                                                                                                                                                                                                                                                                                                                             | `GDK_GRAB_BROKEN` of the pointer, as a menu or another window takes the grab; a touch's `GDK_TOUCH_CANCEL` taps nothing                                                                                                                                                                                                                                                                                                                                                    | `WM_CAPTURECHANGED` (and so `WM_CANCELMODE`) while a button is down; `WM_POINTERUP` with `POINTER_MESSAGE_FLAG_CANCELED`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| pointer device and pressure of native UI (`InputEvent.Pointer`, `Pressure`)      | a mouse event's `subtype`: a tablet's pen (`NSEventSubtypeTabletPoint`, with `pressure`, or `TabletProximity`) or a touch; `tabletPoint:` events, a pen pressing harder or softer between moves, are moves where the pointer is                                                                                                                                                                                                                                                                                       | the event's source device (`gdk_event_get_source_device`): a pen or eraser, or a touchscreen, its pressure axis (`gdk_event_get_axis`); the area's own touches are fingers                                                                                                                                                                                                                                                                                                 | `WM_POINTER` messages, left to `DefWindowProc` to make mouse messages of, give the pressure (`GetPointerPenInfo`, `GetPointerTouchInfo`); the mouse messages' `GetMessageExtraInfo` (`MI_WP_SIGNATURE`) tells a pen's or a finger's                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| cursors of native UI without a system cursor                                     | `CursorWait`, `CursorHelp`, `CursorZoomIn`, `CursorZoomOut`, `CursorAllScroll` and `CursorCell` from AppKit's private class methods (`_waitCursor`, `_helpCursor`, …, looked up with `respondsToSelector:`), `CursorProgress` its `busyButClickableCursor`, else the nearest public cursor or the arrow                                                                                                                                                                                                               | the CSS names from the cursor theme, then GDK's X cursors, then the nearest (`cursorFallbacks`)                                                                                                                                                                                                                                                                                                                                                                            | `CursorZoomIn`, `CursorZoomOut` and `CursorCell` drawn (`CreateCursor`, `cursorMasks`), the others `IDC_APPSTARTING`, `IDC_WAIT`, `IDC_HELP`, `IDC_SIZEALL`, `IDC_NO`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| traffic lights, Dock                                                             | yes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| hidden title bar                                                                 | AppKit's traffic lights over a full-size content view                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | GTK's title buttons in header bars over the page, per `gtk-decoration-layout`; none where the Wayland compositor decorates windows                                                                                                                                                                                                                                                                                                                                         | caption buttons drawn in a layered child window, through DirectComposition over a material, light or dark per window (`SetWindowButtonsTheme`); snap layouts; a top edge that resizes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| progress bar                                                                     | Dock tile content view (NSBoxes: NSProgressIndicator does not draw there), app-wide                                                                                                                                                                                                                                                                                                                                                                                                                                   | Unity launcher API over D-Bus (`com.canonical.Unity.LauncherEntry`), app-wide                                                                                                                                                                                                                                                                                                                                                                                              | `ITaskbarList3`, per window                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| file icons                                                                       | `NSWorkspace iconForFile:` drawn into an sRGB `NSBitmapImageRep` at the size                                                                                                                                                                                                                                                                                                                                                                                                                                          | GIO's `standard::icon`, or a desktop entry's `GAppInfo` icon, through `gtk_icon_theme_lookup_by_gicon`                                                                                                                                                                                                                                                                                                                                                                     | `IShellItemImageFactory::GetImage` (`SIIGBF_ICONONLY`), a DIB with straight alpha                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| icons of file types (`TypeIcon`)                                                 | `UTType typeWithFilenameExtension:` → `NSWorkspace iconForContentType:` (`iconForFileType:` before macOS 11), drawn as file icons                                                                                                                                                                                                                                                                                                                                                                                     | `g_content_type_guess` of a name with the extension → `g_content_type_get_icon`, through the icon theme                                                                                                                                                                                                                                                                                                                                                                    | the image factory of a simple ID list (`SHSimpleIDListFromPath`), which needs no file, as file icons                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| installed apps                                                                   | `.app` bundles of the Applications folders, `NSFileManager displayNameAtPath:` and `NSBundle`, off the main thread; launched with `openURL:`                                                                                                                                                                                                                                                                                                                                                                          | `g_app_info_get_all` filtered by `g_app_info_should_show`; launched with `g_app_info_launch` and GDK's launch context                                                                                                                                                                                                                                                                                                                                                      | `FOLDERID_AppsFolder` enumerated in an STA of its own; launched with `ShellExecute` of `shell:AppsFolder\<ID>`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| badge count                                                                      | Dock tile label                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | Unity launcher API count                                                                                                                                                                                                                                                                                                                                                                                                                                                   | not shown                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| skip taskbar                                                                     | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | skip-taskbar hint                                                                                                                                                                                                                                                                                                                                                                                                                                                          | `ITaskbarList::DeleteTab` (the window style is untouched)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| FlashFrame                                                                       | informational Dock bounce                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | urgency hint                                                                                                                                                                                                                                                                                                                                                                                                                                                               | `FlashWindowEx` until focused                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| visible on all workspaces                                                        | `NSWindowCollectionBehaviorCanJoinAllSpaces`                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | `gtk_window_stick`                                                                                                                                                                                                                                                                                                                                                                                                                                                         | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| window icon                                                                      | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | `gtk_window_set_icon`                                                                                                                                                                                                                                                                                                                                                                                                                                                      | `WM_SETICON` at the window's DPI                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| URL schemes                                                                      | Info.plist (`urlSchemes`); `RegisterURLScheme` makes the app the default handler                                                                                                                                                                                                                                                                                                                                                                                                                                      | desktop entry + `mimeapps.list`                                                                                                                                                                                                                                                                                                                                                                                                                                            | `HKCU\Software\Classes`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| downloads                                                                        | `shouldPerformDownload`, non-displayable or attachment responses → `WKDownload` delegate                                                                                                                                                                                                                                                                                                                                                                                                                              | `download-started` / `decide-destination` on the web context; response policy for attachments                                                                                                                                                                                                                                                                                                                                                                              | `DownloadStarting` (`ICoreWebView2_4`), replacing WebView2's download UI                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| Cookies                                                                          | the session's `WKWebsiteDataStore`'s `WKHTTPCookieStore`, URLs matched in Go (`platform.CookieMatchesURL`), `Set` through `NSHTTPCookie`'s parser with a stand-in name and value; `Clear` with `removeDataOfTypes:`                                                                                                                                                                                                                                                                                                   | the session's web context's `WebKitCookieManager` (2.42+; `get_cookies` for a URL), kept in `cookies.sqlite` of the user data directory, or of a persistent session's directory (`set_persistent_storage`, as WebKitGTK keeps them in memory otherwise); libsoup 3 or 2.4 to match WebKitGTK 4.1 or 4.0; `Clear` with `webkit_website_data_manager_clear`                                                                                                                  | `ICoreWebView2CookieManager` (`ICoreWebView2_2`) of a web view of the session's profile showing a page, a window's or one in native UI, or while there is none of a hidden web view of the profile in the app window, closed once one shows a page, once an ephemeral session's store closes, or once no call needed it for 5 s and closing it loses no cookie (a `GetCookies` finds no session cookie, nor any of an InPrivate profile, which go with WebView2's processes); a window's first navigation waits for the calls under way; `ClearBrowsingData` goes the same way; changes are polled with `GetCookies` until they show, failing after 2 s; `GetCookies(uri)`, `DeleteAllCookies`; `put_Expires` called with `comCallFloat` |
| content rules                                                                    | the default `WKContentRuleListStore`, which keeps compiled lists under an identifier of the id and a hash of the rules (looked up first, the id's others removed), on each window's `WKUserContentController`; the store's reason for a failure is in `NSHelpAnchorErrorKey`                                                                                                                                                                                                                                          | a `WebKitUserContentFilterStore` in `content-rules` of the user data directory (2.24+), on each window's `WebKitUserContentManager`                                                                                                                                                                                                                                                                                                                                        | matched in Go (`internal/contentrules`, indexed by the domains of `url-filter`s and four bytes of their literals) from `WebResourceRequested` with a `*` filter, blocked pages answered with an empty 403 and other blocked requests with a redirect to `data:`, which Chromium fails as a network error; WebSocket handshakes never reach it; `css-display-none` rules as a style sheet a document-creation script adopts, kept when the page sets `adoptedStyleSheets`; parsed on a goroutine, nothing kept                                                                                                                                                                                                                            |
| `FitContent`                                                                     | the bridge, as elsewhere; WebKit's private `_setSizeToContentAutoSizeMaximumSize:` is not used; native UI measures itself (`ui/fit.go`)                                                                                                                                                                                                                                                                                                                                                                               | the bridge; native UI measures itself                                                                                                                                                                                                                                                                                                                                                                                                                                      | the bridge; native UI measures itself                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `Page.ThemeColor`                                                                | the bridge, as elsewhere; WKWebView's `themeColor` (macOS 12+) is not used                                                                                                                                                                                                                                                                                                                                                                                                                                            | the bridge                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | the bridge                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `Page.ProcessID`                                                                 | the web content process, `-[WKWebView _webProcessIdentifier]` (private, looked up with `respondsToSelector:`)                                                                                                                                                                                                                                                                                                                                                                                                         | 0: WebKitGTK has no API for it                                                                                                                                                                                                                                                                                                                                                                                                                                             | the browser process the app's web views share, `ICoreWebView2::get_BrowserProcessId`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `Page.GPUProcessID`                                                              | WebKit's GPU process, which plays the page's sound, `-[WKWebView _gpuProcessIdentifier]` (private, looked up with `respondsToSelector:`); 0 until WebKit starts it                                                                                                                                                                                                                                                                                                                                                    | 0: WebKitGTK has no API for it                                                                                                                                                                                                                                                                                                                                                                                                                                             | the GPU process of the environment, the `COREWEBVIEW2_PROCESS_KIND_GPU` entry of `ICoreWebView2Environment8`'s `GetProcessInfos`, queried for each call; 0 on runtimes without it                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| a page's sound (`IsAudible`, `SetAudioMuted`)                                    | private `-[WKWebView _isPlayingAudio]`, key-value observed, and `_mediaMutedState` / `_setPageMuted:` with the `_WKMediaAudioMuted` bit, the capture bits kept; looked up with `respondsToSelector:`, not audible and not muted where WebKit doesn't answer                                                                                                                                                                                                                                                           | `webkit_web_view_is_playing_audio` and `notify::is-playing-audio`; `webkit_web_view_set_is_muted` / `get_is_muted` (2.30+, bound when present)                                                                                                                                                                                                                                                                                                                             | `ICoreWebView2_8`'s `IsDocumentPlayingAudio`, `IsDocumentPlayingAudioChanged` and `IsMuted`, queried for each call; a mute set before the web view is made is put in `setUp`, before its first navigation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `BackgroundThrottling: ThrottlingOff`                                            | `inactiveSchedulingPolicy` `WKInactiveSchedulingPolicyNone` (macOS 14+) and the private `_hiddenPageDOMTimerThrottlingEnabled`, `_hiddenPageCSSAnimationSuspensionEnabled`, `_pageVisibilityBasedProcessSuppressionEnabled` off, on a copy of the preferences when `window.open()` handed over the opener's; the private `-[WKWebView _setWindowOcclusionDetectionEnabled:NO]`; all looked up with `respondsToSelector:`                                                                                              | the web view's settings' `HiddenPageDOMTimerThrottling` and `HiddenPageCSSAnimationSuspension` features off (`webkit_settings_set_feature_enabled`, 2.42+, bound on first use); hidden and minimized pages still stop drawing                                                                                                                                                                                                                                              | `--disable-background-timer-throttling --disable-renderer-backgrounding --disable-backgrounding-occluded-windows` in the environment options' `AdditionalBrowserArguments` when the page that starts the environment asks (later ones are logged); an embedded web view's controller still goes invisible with its host, which takes its page off the desktop                                                                                                                                                                                                                                                                                                                                                                            |
| a page's capture (`CaptureState`, `SetCaptureState`)                             | `WKWebView`'s `cameraCaptureState` and `microphoneCaptureState` (macOS 12+) and private `_displayCaptureState` (macOS 13+), key-value observed, and their setters `set…CaptureState:completionHandler:` (nil handler), looked up with `respondsToSelector:`; `SetAudioMuted`'s `_setPageMuted:` has one bit for the camera and the microphone, so with only one of them muted the other is unmuted again after it                                                                                                     | `webkit_web_view_get_camera_capture_state` and its microphone and display siblings with their `notify::` signals and setters (2.34+, bound when present); `webkit_web_view_set_is_muted` drops the capture mutes, which `SetAudioMuted` sets again                                                                                                                                                                                                                         | none: `CaptureNone`, setting does nothing                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `Autoplay: AutoplayAllow`                                                        | `WKWebViewConfiguration`'s `mediaTypesRequiringUserActionForPlayback` `WKAudiovisualMediaTypeNone`; a `window.open()` window that doesn't ask gets the default of a new configuration back on the opener's copy                                                                                                                                                                                                                                                                                                       | `webkit_policy_decision_use_with_policies` on every main-frame navigation, with `webkit_website_policies_new_with_policies` `autoplay` `WEBKIT_AUTOPLAY_ALLOW` (2.30+, bound when present; its variadic name/value pairs bound for one pair, as `g_object_set`): WebKitGTK decides autoplay from the navigation's policies, `WEBKIT_AUTOPLAY_ALLOW_WITHOUT_SOUND` by default, which `media-playback-requires-user-gesture` (off by default) does not lift                  | `--autoplay-policy=no-user-gesture-required` in the environment options' `AdditionalBrowserArguments` when the page that starts the environment asks (later ones are logged); then every page plays without a gesture                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| picture in picture (`PageOptions.PictureInPicture`)                              | private `-[WKPreferences _setAllowsPictureInPictureMediaPlayback:]`; `-[WKWebView _canTogglePictureInPicture]`, `_togglePictureInPicture` and `_isPictureInPictureActive`, looked up with `respondsToSelector:`; a main-frame navigation leaving with a video out turns `_setUsesPageCache:` off until one leaves without, as WebKit restores such a page believing its video still out                                                                                                                               | none: `TogglePictureInPicture` does nothing, `IsPictureInPictureActive` is false                                                                                                                                                                                                                                                                                                                                                                                           | Chromium's, on whatever the option; `TogglePictureInPicture` runs `requestPictureInPicture()` (or `exitPictureInPicture()`) through the DevTools protocol's `Runtime.evaluate` with `userGesture`, `IsPictureInPictureActive` evaluates `document.pictureInPictureElement`                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| a page's session state (`SessionState`)                                          | `WKWebView`'s `interactionState` (macOS 12+, looked up with `respondsToSelector:`), NSData of WebKit's `_sessionStateData`; restored when the back/forward list then has a current item; WebKit puts a page that scrolled before its window first showed on screen back at the top as the window does, so a page restored before then gets a script in the default client world, as it loads, that puts it back at the private `_scrollPosition` of the current item when it next scrolls to the top before any input | `webkit_web_view_get_session_state` / `_session_state_serialize`, `_session_state_new` / `restore_session_state`, then `go_to_back_forward_list_item` of the current item (2.12+, bound on first use)                                                                                                                                                                                                                                                                      | none: the core keeps the URL alone and loads it                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ClearBrowsingData, `Session.ClearData`                                           | the session's `WKWebsiteDataStore`, `allWebsiteDataTypes` or the `WKWebsiteDataType`s of the kinds the system's WebKit exports                                                                                                                                                                                                                                                                                                                                                                                        | the session's web context's website data manager, `WEBKIT_WEBSITE_DATA_ALL` or the kinds' types                                                                                                                                                                                                                                                                                                                                                                            | the WebView2 profile's `ClearBrowsingDataAll`, or `ClearBrowsingData` of the kinds' `COREWEBVIEW2_BROWSING_DATA_KINDS` (`ICoreWebView2Profile2`, through the web view cookie calls use)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| sessions (`PageOptions.Session`)                                                 | a `WKWebsiteDataStore` set on each web view's configuration: `dataStoreForIdentifier:` of a UUID made of the name (macOS 14+; before, `nonPersistentDataStore` kept until the app quits), `nonPersistentDataStore` for an ephemeral one, released when its last page closes; `window.open` hands the opener's configuration over                                                                                                                                                                                      | a `WebKitWebContext` per session, made with `webkit_web_context_new_with_website_data_manager` of a manager with base data and cache directories in `Sessions/<UUID>` of the user data and cache directories, or `webkit_website_data_manager_new_ephemeral`; web views made with `g_object_new` and `web-context`, which keeps a reference to it; custom schemes, languages and downloads set up on each context; unreferenced when an ephemeral one's last page closes   | a WebView2 profile per session (`ICoreWebView2Environment10`'s controller options: `put_ProfileName` `mygo-<UUID>`, or `mygo-private-<n>` with `put_IsInPrivateModeEnabled` for an ephemeral one, a new name for each of its stores); windows, web views in native UI and the cookie calls' hidden web views made with those options                                                                                                                                                                                                                                                                                                                                                                                                     |
| HTTP sign-in (`SetAuthHandler`)                                                  | `webView:didReceiveAuthenticationChallenge:completionHandler:`, `NSURLCredential` for the session; none: no prompt, the 401 page; empty answer: `RejectProtectionSpace`                                                                                                                                                                                                                                                                                                                                               | `WebKitWebView::authenticate`, `webkit_credential_new` for the session; none: WebKitGTK's dialog; empty answer: authenticates without credentials                                                                                                                                                                                                                                                                                                                          | `ICoreWebView2_10`'s `BasicAuthenticationRequested`, scheme and realm parsed from its challenge, no proxy flag; none: WebView2's dialog; empty answer: `Cancel`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| certificate errors (`SetCertificateErrorHandler`)                                | the server trust challenge of every connection, checked with `SecTrustEvaluateAsyncWithError` while a handler is set, allowed with `credentialForTrust:` for that connection                                                                                                                                                                                                                                                                                                                                          | `load-failed-with-tls-errors`, the main frame only; allowed with `webkit_web_context_allow_tls_certificate_for_host` (app-wide) and loaded again                                                                                                                                                                                                                                                                                                                           | `ICoreWebView2_14`'s `ServerCertificateErrorDetected`, every request, after `NavigationCompleted` failed; allowed with `ALWAYS_ALLOW` (app-wide)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| client certificates (`SetClientCertificateHandler`)                              | the client certificate challenge, identities of the keychain (`SecItemCopyMatching`, `kSecClassIdentity`), which the keychain asks the user for, answered with `credentialWithIdentity:certificates:persistence:`; none: WebKit never asks; empty answer: reject                                                                                                                                                                                                                                                      | scheme `CLIENT_CERTIFICATE_REQUESTED` on `WebKitWebView::authenticate`; WebKitGTK lists no certificates, so none are offered and a handler can only cancel (`webkit_authentication_request_cancel`), which ends the load as a cancellation `OnDidFailLoad` does not report; none: WebKitGTK's certificate chooser                                                                                                                                                          | `ICoreWebView2_5`'s `ClientCertificateRequested`, the mutually trusted certificates; none: WebView2's dialog; empty answer: the challenge is canceled, as a user's dismissal of the dialog is; a runtime without `_5` never asks                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| a page's context menu (`OnContextMenu`)                                          | `-[NSView willOpenMenu:withEvent:]` of `MyGoWebView`, on a menu with an item of `forwardContextMenuAction:` or a `WKMenuItemIdentifier*`: items named by their identifier, else WebKit's tag or AppKit's action, emptied and filled again in place; the target from the bridge alone, matched by the event's point; the app's items are `buildItem`'s, sent to `mygoContextItemClicked:` and the menu's window                                                                                                        | `WebKitWebView::context-menu`: items named by their stock action, labels from their `GtkAction`, state from their `GAction`; the hit test tells all but the selection; renamed stock items are new ones of the same action; the app's items wrap a `GSimpleAction` (`webkit_context_menu_item_new_from_gaction`)                                                                                                                                                           | `ICoreWebView2_11`'s `ContextMenuRequested`, with the whole target (`Complete`); a changed menu is `Handled`, built by `buildMenu` and tracked after a deferral, and a WebView2 item chosen is its `SelectedCommandId`; a runtime without `_11` never asks                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| permissions                                                                      | `WKUIDelegate` media capture (camera, microphone)                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | `permission-request` (camera, microphone, geolocation, notifications)                                                                                                                                                                                                                                                                                                                                                                                                      | `PermissionRequested` (the same four; WebView2 asks about others)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| user agent                                                                       | `customUserAgent`; `UserAgentSuffix` is the configuration's `applicationNameForUserAgent`, which a `window.open()` window does not inherit                                                                                                                                                                                                                                                                                                                                                                            | `WebKitSettings:user-agent`; `UserAgentSuffix` appends application details, split at the first "/"                                                                                                                                                                                                                                                                                                                                                                         | `ICoreWebView2Settings2`'s user agent, and a suffix appended to the settings' own user agent; a runtime without `Settings2` ignores both                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| swipes and pinches (`SwipeNavigation`, `PinchZoom`)                              | `allowsBackForwardNavigationGestures` and `allowsMagnification` of the `WKWebView`, both off unless asked for                                                                                                                                                                                                                                                                                                                                                                                                         | `WebKitSettings:enable-back-forward-navigation-gestures`; WebKitGTK has no setting for pinches, so the web view's `GtkGestureZoom`, which it keeps in its data as `wk-view-zoom-gesture` (2.38+), is given `GTK_PHASE_NONE` unless `PinchZoom`: it then sees neither a touchpad's pinch nor a touchscreen's                                                                                                                                                                | `ICoreWebView2Settings6`'s `IsSwipeNavigationEnabled` and `ICoreWebView2Settings5`'s `IsPinchZoomEnabled`, both on in WebView2 and put to the options' values in `setUp`, before the first navigation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| the browser's keys (reload, print, find, zoom)                                   | none                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | none                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | WebView2's (F5, Ctrl+R, Ctrl+P, Ctrl+F, Ctrl+Plus, ...) only with the inspector (`ICoreWebView2Settings3`'s `AreBrowserAcceleratorKeysEnabled`); `AcceleratorKeyPressed` still gives the menus every key                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| file associations                                                                | `CFBundleDocumentTypes`; files arrive with `application:openURLs:`                                                                                                                                                                                                                                                                                                                                                                                                                                                    | desktop entry `MimeType` (`%U`), a shared-mime-info package in the .deb and .rpm for types the app defines (`x-`)                                                                                                                                                                                                                                                                                                                                                          | ProgIDs and `OpenWithProgids` written by the installer                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| document windows                                                                 | `representedURL` (proxy icon, Command-click folder menu) and `setDocumentEdited:` (the dot), then the traffic lights are laid out again                                                                                                                                                                                                                                                                                                                                                                               | the core puts `*` before the title                                                                                                                                                                                                                                                                                                                                                                                                                                         | the core puts `*` before the title                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| replacing a document's file                                                      | `-[NSFileManager replaceItemAtURL:withItemAtURL:…]` (permissions, dates, extended attributes, ACLs, identity)                                                                                                                                                                                                                                                                                                                                                                                                         | rename after `chmod` and `lchown` to the target's                                                                                                                                                                                                                                                                                                                                                                                                                          | `ReplaceFileW`, retried on sharing violations; when it stops halfway, having removed the target, the replacement is renamed into place                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| recent documents                                                                 | `noteNewRecentDocumentURL:` / `clearRecentDocuments:` of the shared `NSDocumentController` (the Dock menu)                                                                                                                                                                                                                                                                                                                                                                                                            | `gtk_recent_manager_add_item`, removing the items of `g_get_application_name()`                                                                                                                                                                                                                                                                                                                                                                                            | `SHAddToRecentDocs` (`SHARD_PATHW`), `IApplicationDestinations::RemoveAllDestinations`; the process keeps the AppUserModelID the shell derives from its path, which the installer's shortcuts have too                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| jump list                                                                        | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | `ICustomDestinationList`, committed whole from what `App.JumpList` keeps: the Recent category, `AddUserTasks` with an `IShellLinkW` per task (`PKEY_Title`, description, working directory, arguments quoted with `syscall.EscapeArg`), `CommitList`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| Dock menu                                                                        | `applicationDockMenu:`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| PrintToPDF                                                                       | `printOperationWithPrintInfo:` save job (`NSJobSavingURL`), fit to width; the core rewrites the radicals the text names to the ideographs the fonts draw (`pdf_text.go`)                                                                                                                                                                                                                                                                                                                                              | `WebKitPrintOperation` to GTK's "Print to File"                                                                                                                                                                                                                                                                                                                                                                                                                            | DevTools `Page.printToPDF`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| power events                                                                     | NSWorkspace sleep/wake, `com.apple.screenIsLocked` distributed notifications                                                                                                                                                                                                                                                                                                                                                                                                                                          | logind `PrepareForSleep` (system bus), screen saver `ActiveChanged` (GNOME, freedesktop)                                                                                                                                                                                                                                                                                                                                                                                   | `WM_POWERBROADCAST`, `WM_WTSSESSION_CHANGE`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| Now Playing and media keys                                                       | `MPNowPlayingInfoCenter` (its `nowPlayingInfo` and `playbackState`; artwork as an `MPMediaItemArtwork` decoding the bytes it holds when asked) and the targets of `MPRemoteCommandCenter`'s commands, enabled as the info offers them; MediaPlayer.framework loads with the first `Set`                                                                                                                                                                                                                               | an MPRIS player (`org.mpris.MediaPlayer2` and `.Player` at `/org/mpris/MediaPlayer2`, exported with `g_dbus_connection_register_object`), whose bus name `org.mpris.MediaPlayer2.<app>.instance<pid>` is owned only while it shows something; `PropertiesChanged` on each change, `Seeked` when the position jumps; the artwork goes to a file in `$XDG_RUNTIME_DIR` for `mpris:artUrl`                                                                                    | the `SystemMediaTransportControls` of the application window (`ISystemMediaTransportControlsInterop::GetForWindow`), with agile event handlers, a `RandomAccessStreamReference` over a memory stream for the thumbnail, and the timeline properties for position and seeking                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| KeepAwake                                                                        | `NSProcessInfo` activity (shows in `pmset -g assertions`)                                                                                                                                                                                                                                                                                                                                                                                                                                                             | XDG portal `Inhibit`, else `org.freedesktop.ScreenSaver.Inhibit`                                                                                                                                                                                                                                                                                                                                                                                                           | `PowerCreateRequest`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| KeepRunning                                                                      | `NSProcessInfo` activity `NSActivityUserInitiatedAllowingIdleSystemSleep`: no App Nap, idle sleep allowed (not in `pmset -g assertions`)                                                                                                                                                                                                                                                                                                                                                                              | nothing: desktops don't slow apps out of sight                                                                                                                                                                                                                                                                                                                                                                                                                             | nothing yet (power throttling, EcoQoS, would be `SetProcessInformation`'s `ProcessPowerThrottling`)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| IsOnBattery, IdleTime                                                            | IOKit power sources, `CGEventSourceSecondsSinceLastEventType`                                                                                                                                                                                                                                                                                                                                                                                                                                                         | `/sys/class/power_supply`; Mutter idle monitor or `GetSessionIdleTime`                                                                                                                                                                                                                                                                                                                                                                                                     | `GetSystemPowerStatus`, `GetLastInputInfo`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| network status                                                                   | `nw_path_monitor` on a queue of its own, the first `Status` waiting (up to a second) for its first path; online when the path is satisfied, metered when it is expensive or constrained                                                                                                                                                                                                                                                                                                                               | `GNetworkMonitor`, `network-available` (a default route) and `network-metered`                                                                                                                                                                                                                                                                                                                                                                                             | `GetNetworkConnectivityHint`, `NotifyNetworkConnectivityHintChange`; online from local access up (not none or hidden), metered for a fixed or variable cost, roaming, over or near the data limit                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| window position                                                                  | honored                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | ignored by Wayland compositors                                                                                                                                                                                                                                                                                                                                                                                                                                             | honored                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| resize borders without a title bar                                               | the window's own                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | the outer 5 px of the page                                                                                                                                                                                                                                                                                                                                                                                                                                                 | invisible, outside the window; along the top of a frameless window or a hidden title bar, a child window                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| content protection                                                               | yes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | ignored                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | yes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| click-through (`SetIgnoreMouseEvents`)                                           | `ignoresMouseEvents`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | an empty input shape                                                                                                                                                                                                                                                                                                                                                                                                                                                       | layered, `WS_EX_TRANSPARENT`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| input region (`SetInputRegion`)                                                  | `ignoresMouseEvents` switched as the pointer comes into the region or leaves it, from a global and a local monitor of its moves and releases, while a window has one, and a tracking area active always (`input_region.go`)                                                                                                                                                                                                                                                                                           | the input shape, after GTK's own, on size-allocate (`gdk_window_input_shape_combine_region`)                                                                                                                                                                                                                                                                                                                                                                               | layered, `WS_EX_TRANSPARENT` switched as a timer at each tick of the system's clock (15.6 ms) finds the cursor in the region or out of it (`input_region.go`)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| panels                                                                           | `NSPanel` with the nonactivating style, floating, on all Spaces as a full-screen auxiliary                                                                                                                                                                                                                                                                                                                                                                                                                            | sticky utility window, kept above, out of the taskbar and the pager; a gtk-layer-shell overlay surface on Wayland where it can be                                                                                                                                                                                                                                                                                                                                          | topmost `WS_EX_TOOLWINDOW` owned by the hidden application window, rounded                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| flyouts                                                                          | borderless nonactivating `NSPanel` child window, or an `NSPopover`; placed in the visible frame                                                                                                                                                                                                                                                                                                                                                                                                                       | `GTK_WINDOW_POPUP` (override-redirect, placed in the work area, on X11; `xdg_popup` with `gdk_window_move_to_rect` on Wayland); focusable ones grab the seat                                                                                                                                                                                                                                                                                                               | owned `WS_POPUP` + `WS_EX_TOOLWINDOW`, `WS_EX_NOACTIVATE` unless focusable, `CS_DROPSHADOW` for a shadow, with corners rounded by DWM on Windows 11                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| custom scheme origin                                                             | `<scheme>://<host>`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | `<scheme>://<host>`                                                                                                                                                                                                                                                                                                                                                                                                                                                        | `http://<scheme>.localhost`, or `http://<host>.<scheme>.localhost` for another host (the page's `location`)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `LoadHTML` documents                                                             | a reload loads the base URL (`about:blank` without one), so the core cancels it (`Navigation.Reload`) and loads the HTML again; not in the history                                                                                                                                                                                                                                                                                                                                                                    | as macOS                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | as macOS, but in the history: going back to one with a base URL loads that URL                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| window\.open                                                                     | keeps the opener                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | independent window                                                                                                                                                                                                                                                                                                                                                                                                                                                         | keeps the opener: the new window's web view, set up, becomes the popup (`put_NewWindow`, under a deferral)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| keys held (`Context.KeyDown`)                                                    | `keyDown:` and `keyUp:`; a local monitor of key ups hands the surface those let go of while Command is held, which `sendEvent:` keeps from the key window; resigning first responder or key window lets go of all                                                                                                                                                                                                                                                                                                     | key presses and releases, and a release the input method filters (`HeldKeys.Lift`): IBus and Fcitx hand back those they leave, which `HeldKeys` keeps from the content                                                                                                                                                                                                                                                                                                     | `WM_KEYUP` and `WM_SYSKEYUP`; a `VK_PROCESSKEY` release lets go of the key at its scancode; `WM_ENTERMENULOOP` lets go of all (`HeldKeys.LiftAll`), whose releases the menu's loop takes; `WM_KILLFOCUS` all                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| native UI surface                                                                | layer-backed NSView, frames from `CADisplayLink` (a timer at the display's rate before macOS 14), input methods through NSTextInputClient                                                                                                                                                                                                                                                                                                                                                                             | GtkGLArea (GtkDrawingArea without a GPU), GtkIMMulticontext                                                                                                                                                                                                                                                                                                                                                                                                                | `MyGoSurface` child window, IMM32                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| native UI data drags                                                             | NSDraggingSession, NSPasteboardItemDataProvider, NSDraggingDestination                                                                                                                                                                                                                                                                                                                                                                                                                                                | GTK drag contexts, MIME selections, text/uri-list                                                                                                                                                                                                                                                                                                                                                                                                                          | OLE IDataObject, IDropSource, IDropTarget, Shell drag images                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| concealed clipboard writes (`ClipboardOptions.Concealed`)                        | `org.nspasteboard.ConcealedType` on every item, `prepareForNewContentsWithOptions:` with `NSPasteboardContentsCurrentHostOnly`                                                                                                                                                                                                                                                                                                                                                                                        | the `x-kde-passwordManagerHint` target, `secret`                                                                                                                                                                                                                                                                                                                                                                                                                           | the `ExcludeClipboardContentFromMonitorProcessing` format                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| native UI accessibility                                                          | `NSAccessibilityElement` subclasses                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | ATK objects (GObject types registered through purego), bridged to AT-SPI by GTK                                                                                                                                                                                                                                                                                                                                                                                            | UI Automation fragments (COM objects; assembly thunks for the methods taking doubles)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| native UI rendering                                                              | Metal, into a CAMetalLayer presenting as soon as drawn, or with the Core Animation transaction for frames that resize it or show web views                                                                                                                                                                                                                                                                                                                                                                            | OpenGL 3.3 or ES 3.0 in the GtkGLArea's render signal; on the CPU, painted with cairo, where OpenGL runs on the CPU                                                                                                                                                                                                                                                                                                                                                        | Direct3D 11 (WARP without a GPU), flip-model swap chain presenting dirty rectangles                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| web views in native UI                                                           | WKWebView in a clip view under the surface; `hitTest:` lets the pointer through                                                                                                                                                                                                                                                                                                                                                                                                                                       | WebKitWebView in a `GtkLayout` under the area in a `GtkOverlay`; an input shape lets the pointer through                                                                                                                                                                                                                                                                                                                                                                   | WebView2 composition controller in a DirectComposition target under the frames'; the surface sends it the mouse                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| audio output                                                                     | Audio Queue on the default output                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | PulseAudio simple API (PipeWire too), else ALSA `default`                                                                                                                                                                                                                                                                                                                                                                                                                  | WASAPI shared mode, reopened when the default output changes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| gamepads                                                                         | GameController.framework, extended gamepad profile                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | evdev, the kernel's gamepad layout, Xbox's X and Y swapped back                                                                                                                                                                                                                                                                                                                                                                                                            | XInput, four slots, Guide by `XInputGetStateEx`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
