operad 6.1.0

A cross-platform GUI library for Rust.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# Operad 6.0 Module Organization

Operad v5 shipped with a deliberately broad API surface, but the source layout
still mostly reflects incremental growth: most modules sit directly under
`src/`, and `src/lib.rs` owns core document types, text measurement, widget
helpers, tests, module declarations, and public re-exports. That made sense
while stabilizing v5, but it is not a good long-term shape.

V6 should reorganize the crate around ownership boundaries, not around whatever
was added first.

## Goals

- Make source layout communicate the architecture.
- Keep backend-neutral contracts separate from backend adapters.
- Keep reusable widgets separate from core document/runtime contracts.
- Keep diagnostics/testing/devtool utilities separate from production contracts.
- Keep `lib.rs` small enough to act as a crate entry point instead of a second
  implementation module.
- Preserve public paths intentionally, or break them intentionally as part of
  the v6 migration guide. Avoid accidental churn.

## V5 Shape

V5 shipped with these high-friction areas:

- `src/lib.rs` is over 11k lines and contains foundational types, widget helper
  implementations, public re-exports, and tests.
- Most conceptual subsystems are top-level siblings: `actions`, `commands`,
  `input`, `input_devices`, `transactions`, `navigation`, `overlays`,
  `renderer`, `paint`, `compositor`, `wgpu_renderer`, `host`, `runtime`,
  `windows`, and many more all live in the same directory.
- Optional backend integrations (`egui_host`, `wgpu_renderer`,
  `accesskit_winit_adapter`) sit next to backend-neutral contracts.
- `widget_ext` is the only real subtree, but core widgets still live in
  `lib.rs`, so widget implementation ownership is split.
- Tests are split between module-local tests and integration tests, but there is
  no obvious source-level separation between test support and runtime support.

## Proposed Source Tree

The source tree should move toward this shape:

```text
src/
  lib.rs
  prelude.rs

  core/
    mod.rs
    document.rs
    geometry.rs
    layout.rs
    text.rs
    animation.rs
    localization.rs
    versioning.rs

  interaction/
    mod.rs
    input.rs
    devices.rs
    actions.rs
    commands.rs
    drag_drop.rs
    navigation.rs
    overlays.rs
    transactions.rs
    focus.rs

  render/
    mod.rs
    paint.rs
    renderer.rs
    compositor.rs
    display.rs
    effective_geometry.rs
    resources.rs
    assets.rs
    fonts.rs

  runtime/
    mod.rs
    host.rs
    platform.rs
    windows.rs
    scheduler.rs

  adapters/
    mod.rs
    egui.rs
    accesskit_winit.rs
    wgpu.rs

  accessibility/
    mod.rs
    tree.rs
    adapter.rs
    help.rs

  widgets/
    mod.rs
    core.rs
    text_input.rs
    menu.rs
    data.rs
    pickers.rs
    surfaces.rs

  shell/
    mod.rs
    workspace.rs
    bars.rs
    panels.rs

  domain/
    mod.rs
    charts.rs
    editor.rs

  theme/
    mod.rs
    tokens.rs
    stability.rs

  diagnostics/
    mod.rs
    debug.rs
    errors.rs
    limits.rs
    testing.rs
```

This does not mean all of those files must exist immediately. It is the intended
ownership map.

## Initial V6 Restructure

The first v6 pass moved the existing modules into ownership folders while
preserving the flat v5 public module paths:

```text
src/
  accessibility/        # accessibility contracts and tooltip/help policy
  adapters/             # egui, wgpu, and accesskit-winit integrations
  core/                 # layout, localization, state, versioning
  diagnostics/          # debug, diagnostics reports, errors, limits, testing
  domain/               # charts and editor primitives
  interaction/          # input, devices, actions, commands, drag/drop, forms
  render/               # paint, renderer, compositor, assets, fonts, caches
  runtime/              # host, platform, frame runtime, windows
  shell/
  theme/
  widgets/ext/
```

`src/lib.rs` now uses path-based compatibility declarations for common v5
imports such as `operad::layout`, `operad::renderer`, and `operad::input`.
Grouped facades were added for `operad::core`, `operad::interaction`,
`operad::render`, `operad::runtime`, `operad::adapters`,
`operad::diagnostics`, and `operad::domain` so new code can start using the v6
shape without forcing every downstream consumer to migrate at once.

## GPU Canvas Rendering

V6 makes WGPU canvases first-class render targets. A canvas can declare a
texture-backed GPU context with `CanvasContent::gpu_context()` or
`UiNode::gpu_canvas(...)`; native-window apps can register app-owned rendering
with `NativeWgpuCanvasRenderRegistry`.

The registered renderer receives a `WgpuCanvasContext`, so it can create command
encoders, begin render passes, use its own pipelines, and submit any number of
WGPU passes into the canvas texture. The normal UI render pass samples that same
texture when it paints the canvas item.

## Public API Shape

The physical layout and public API do not have to be identical.

V6 should expose a clearer high-level API:

```rust
operad::core
operad::interaction
operad::render
operad::runtime
operad::adapters
operad::accessibility
operad::widgets
operad::theme
operad::diagnostics
operad::prelude
```

For common v5 paths, choose one of two strategies per module:

- Keep stable aliases when churn is not worth it, for example
  `operad::layout` re-exporting `operad::core::layout`.
- Break intentionally where the old path was actively misleading, with a
  migration guide entry and deprecation window if possible.

Do not keep every old flat module forever. That would preserve the current
problem under a layer of aliases.

## What Belongs Where

### Core

Core is the retained document model and data types needed before a host,
renderer, or widget exists:

- `UiDocument`, `UiNode`, `UiNodeId`
- geometry primitives such as `UiPoint`, `UiSize`, `UiRect`
- layout facade and layout snapshots
- text content, text style, measurement traits
- animation metadata
- localization and versioning metadata

Core should not know about WGPU, egui, AccessKit, widget extension controls, or
native windows.

### Interaction

Interaction owns user intent before product semantics:

- raw and normalized input
- pointer, wheel, keyboard, touch, stylus, and gamepad records
- actions, commands, shortcuts, drag/drop
- focus, navigation, overlays, transactions, selection

Interaction should be renderer-neutral and host-neutral. It may emit platform
requests as contracts, but it should not execute platform behavior.

### Render

Render owns backend-neutral drawing intent and resource contracts:

- paint records and display lists
- renderer adapter traits and render frame requests
- compositor feature requirements and fallback plans
- effective geometry used by paint, hit testing, and accessibility
- resources, assets, fonts, cache lifecycle

WGPU does not belong here as a backend-neutral contract; it belongs in
`adapters/wgpu.rs` or `adapters/wgpu/`.

### Runtime

Runtime owns host loop contracts:

- host frame request/output records
- scheduler, repaint, timer, idle, lifecycle contracts
- platform service request/response records
- multi-window/document/surface routing

Runtime should not include a concrete winit event loop implementation except
through an adapter module.

### Adapters

Adapters are optional backend integrations:

- `egui`
- `wgpu`
- `accesskit_winit`
- future native host bridges

Feature gates should live at this boundary whenever possible. Backend-specific
types should not leak back into core modules.

### Accessibility

Accessibility deserves its own subsystem because it cuts across document,
interaction, host, and widgets:

- accessibility tree and metadata records
- adapter request/response contracts
- focus traps, live regions, navigable targets
- help, tooltip, validation help, context menu policy where it affects
  accessible behavior

The AccessKit winit bridge still belongs under `adapters`.

### Widgets

Widgets should own reusable controls only:

- buttons, checkboxes, sliders, scrollbars
- text input and selectable text
- menus, popups, command palette, select/search controls
- data widgets, pickers, surfaces

Widget helpers can depend on core, interaction, render, accessibility, and
theme contracts. Core must not depend on widgets.

### Domain

Charts and editor primitives are reusable, but they are not the same layer as
buttons and menus. They should live under a domain-oriented subtree until they
are either split into a separate crate or promoted into a clearer subsystem.

### Diagnostics

Diagnostics, debug views, limits, errors, and testing helpers are related but
should not be mixed into the runtime path. They should be easy to find and easy
to feature-gate later if package size or compile time becomes a concern.

## Migration Plan

### Phase 1: Create Facades Without Moving Behavior

- Add group modules such as `core`, `interaction`, `render`, and `runtime` that
  re-export existing flat modules.
- Keep existing public paths working.
- Update docs and examples to prefer the grouped paths.

This phase is partly complete. `prelude.rs` is still intentionally deferred
until the main document/widget split makes the common import set clearer.

### Phase 2: Split `lib.rs`

Move implementation out of `lib.rs` in small pieces:

1. geometry primitives
2. visual/style/text primitives
3. document/node tree
4. layout, hit testing, focus, scrolling integration
5. core widget helpers
6. module-local tests

`lib.rs` should end this phase as module declarations, public re-exports, and
crate-level docs only.

### Phase 3: Move Backend-Neutral Modules Into Subtrees

Move files mechanically into their target folders while preserving public module
aliases:

- render contracts into `render/`
- interaction contracts into `interaction/`
- runtime contracts into `runtime/`
- accessibility contracts into `accessibility/`
- diagnostics/testing support into `diagnostics/`

Use small commits and run the full feature matrix after each group.

This phase is complete for the existing backend-neutral modules. The remaining
work is to reduce `src/lib.rs` by moving the large inline document and widget
implementations into the new folders.

### Phase 4: Move Optional Backends

Move optional integrations under `adapters/`:

- `egui_host` -> `adapters/egui`
- `wgpu_renderer` -> `adapters/wgpu`
- `accesskit_winit_adapter` -> `adapters/accesskit_winit`

At this point feature gates should read as adapter choices, not as random
top-level modules.

This phase is complete for the current optional integrations. The old public
paths remain as compatibility aliases for now.

### Phase 5: Decide Public Compatibility

For v6, decide which v5 paths remain as aliases and which paths become
intentional breaking changes. Document every break in `docs/v6_0_migration_guide.md`.

The default should be:

- preserve extremely common paths for one major cycle when cheap;
- break misleading backend-specific paths;
- avoid preserving obscure aliases that make the new structure harder to learn.

## Non-Goals

- Do not split into multiple crates until the module boundaries have survived
  inside one crate.
- Do not reorganize by file size alone.
- Do not use `core` as a dumping ground.
- Do not move optional backend code into backend-neutral modules.
- Do not make examples import private implementation modules.

## Success Criteria

- `src/lib.rs` is below 1,000 lines and mostly declarative.
- A new contributor can predict where a module belongs from the ownership map.
- Feature-gated adapters are physically isolated.
- Widgets are not implemented partly in `lib.rs` and partly in `widget_ext`.
- Docs and examples use the v6 grouped paths.
- Existing public compatibility is intentional and documented.
- The release matrix still passes:

```bash
cargo fmt --all -- --check
cargo check --locked --no-default-features --all-targets
cargo test --locked --no-default-features
cargo check --locked --all-features --all-targets
cargo test --locked --all-features -- --list
cargo check --locked --all-features --examples
cargo doc --locked --all-features --no-deps
```