Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ADR 0006: Rust-native reference editor on Masonry, Vello and AccessKit; toolchain policy

Document status: accepted. Canonical source.

Decision delegated to research on 2026-08-29. Evidence: nuif:research:masonry-editor-stack-decision, nuif:research:rust-toolchain-and-msrv-policy, nuif:research:masonry-xilem-and-linebender-test-harness, nuif:research:egui-and-egui-kittest, nuif:research:iced-slint-gpui-makepad-floem, nuif:research:accesskit-semantic-ui-testing, nuif:research:vello-testing-and-cpu-reference, nuif:research:wasm-headless-execution.

Context

docs/whitepaper/06-language-and-runtime-choice.md and apps/editor/ARCHITECTURE.md proposed a Svelte 5 and TypeScript shell over a Rust/WASM core. The editor’s role (apps/editor/README.md, RFC 0004) is a test instrument: headless execution, deterministic snapshots through a CPU reference path, an accessibility tree that carries entity identifiers, and the same harness as the CLI.

Decision

Stack

  1. The reference editor is a Rust binary crate (apps/editor) built directly on Masonry (retained widget tree) with Vello rendering and AccessKit. Xilem is not used: its view layer lags the widget set (xilem issue 1710) and entity-to-widget identity must be explicit in the editor.
  2. Masonry is pinned by full SHA to the reviewed refpath/xilem fork at 1b96eb8; its parent eabfe0a carries the wgpu 29 migration, and it descends from the evaluated upstream main revision b81d8d7 (2026-08-28). The 0.4.0 release of 2025-10-29 lacks the Canvas widget, paints into a Vello 0.6 Scene, and screenshots only through wgpu. The pinned line provides Widget::paint over an imaging::Painter, Canvas::update_scene recording an imaging::record::Scene, and masonry_testing rasterization through imaging_vello_cpu without a GPU.
  3. The editor canvas is a lowering from NUIF RenderScene to imaging commands. NUIF’s own CPU reference renderer remains the conformance oracle; Masonry’s vello_cpu path rasterizes shell chrome for headless screenshot tests only.
  4. For every type that crosses the widget boundary (Vello, Parley, AccessKit, wgpu), the editor crate follows Masonry’s pinned versions. A cargo metadata probe of Masonry main with independently chosen Vello 0.10, Parley 0.11 and AccessKit 0.25 produced duplicate Vello (0.8/0.10), wgpu (28/29), Parley (0.8/0.11.1), AccessKit (0.24.1/0.25) and four accesskit_consumer versions; the editor build therefore disables NUIF’s standalone Vello backend and exchanges pixel buffers with the reference path as bytes.
  5. The Svelte shell becomes a later browser demonstration of the WASM bindings. Engine parity in browsers is tested through wasm-bindgen-test and Playwright layout oracles; in-browser WebGPU pixel oracles are not used.

Toolchain and MSRV

  1. rust-toolchain.toml pins the current stable, 1.99.0 (released 2026-10-01; official release). The pin is raised in one dedicated commit within each release cycle.
  2. rust-version is 1.97: max(toolchain − 2, highest dependency MSRV). The current 1.99 toolchain raises the policy floor to 1.97; the pinned Masonry source requires 1.96. The separately pinned MSRV job checks the workspace and every target at 1.97.0.
  3. The workspace uses resolver = "3" so that dependency resolution is MSRV-aware.
  4. CI runs the main job on the pinned toolchain and an msrv job that checks the workspace on 1.97.0.

Licensing

  1. Masonry is licensed Apache-2.0 only; Vello, Parley and imaging are Apache-2.0 OR MIT; AccessKit is MIT OR Apache-2.0; accesskit_winit, winit, tree_arena, insta and ciborium are Apache-2.0 only. Depending on Apache-2.0-only crates does not constrain NUIF’s Apache-2.0 OR MIT (Apache-2.0 §4 obliges notice retention on redistribution and permits different terms for one’s own work); the only downstream effect is on GPLv2-only consumers.
  2. deny.toml allows exactly: MIT, Apache-2.0, Apache-2.0 WITH LLVM-exception, BSD-2-Clause, BSD-2-Clause-Patent, BSD-3-Clause, ISC, Zlib, Unicode-3.0, BSL-1.0, CC0-1.0, 0BSD, Unlicense. BlueOak-1.0.0 is not allowed; minicbor is therefore excluded (RFC 0005 selects dcbor, BSD-2-Clause-Patent).

Rationale

  • Masonry main is the only candidate whose harness returns the frame’s visual layer plan and AccessKit TreeUpdate from one redraw(), accepts ActionRequests directly, controls time, hosts a custom-painted canvas, and rasterizes without a GPU.
  • egui remains a migration candidate. A custom renderer can prepare an intermediate texture before the egui render pass and sample it during painting. Its published 0.36.1 snapshot harness uses wgpu; it does not supply the current CPU shell-rendering path. A local egui 0.34 CPU/semantic probe passes through supported APIs. Full editor parity and integration with the current egui version remain unverified. Evidence and migration criteria: nuif:research:editor-fork-exit-review.
  • Floem: no AccessKit (issues 8 and 973 open). Blitz: custom paint sources exist but the harness is unpublished. GPUI: builds an AccessKit tree per frame but exposes no query in test contexts and requires latest stable. iced: no accessibility tree. Slint: licence and DSL-owned element tree.

Widget inventory

Masonry main ships 37 widgets including Split (draggable), CollapsePanel, Selector, StepInput, TextInput, VirtualScroll, Canvas and a tooltip layer. Missing for apps/editor/UI-SPEC.md and composed in the app crate: tree view (layers panel), drag-and-drop reparenting (emits protocol Move from canvas pointer events), menus and tab strip, colour picker, keyboard-shortcut table, multi-line text input (newlines unsupported in TextInput), text undo/redo (xilem issue 1417).

Risks and mitigations

  • API churn: paint signature, layout system and renderer changed between 0.4.0 and main without a changelog; 304 days without a release. Mitigation: git pin, single bump commits, harness behind NUIF’s session-driver trait, no Masonry types in crates/.
  • Split pointer defect (xilem issue 1581). The pinned harness also contains an unsafe NodeId conversion in access_node. NUIF automation and tests avoid that helper by traversing the public consumer tree and resolving local IDs with locate_node; the dependency still contains the unused helper. unsafe_code = "forbid" stays in crates/. Evidence: nuif:research:editor-fork-exit-review.
  • vello_cpu regressions affect shell screenshots only (tier 2 tolerance); the render suite uses NUIF’s CPU reference.

Consequences

  • rust-toolchain.toml, Cargo.toml (rust-version, resolver), .github/workflows/ci.yml and deny.toml are updated with this ADR.
  • apps/editor/ARCHITECTURE.md, apps/editor/UI-SPEC.md and docs/whitepaper/06-language-and-runtime-choice.md reference this ADR.
  • The editor exposes entity identifiers through AccessKit author_id; the harness queries by role, label and identifier and dispatches actions without pointer synthesis.

Unverified

Linebender Zulip release announcements were not retrieved; the anyrender CustomPaintSource trait was not located.