operad 5.0.0

Renderer-neutral UI toolkit contracts and rendering primitives.
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
404
405
406
407
408
409
410
411
412
413
# Codex Notes on Operad

These notes describe what I would want from Operad as a shared UI foundation for
Fabricad, the DAW, and the game. I intentionally wrote this from the current
code shape and our product needs, without reading any other design note in this
directory.

## Short Version

Operad should be a native Rust UI model and rendering boundary, not a wrapper
around any one UI toolkit. Its most useful role is to give our apps a retained,
testable, renderer-agnostic UI document that can eventually be painted by egui,
wgpu, or another backend.

The core crate should stay small and boring:

- Document tree
- Layout inputs and computed layout
- Hit testing
- Focus and input routing
- Scroll state
- Basic animation state
- Neutral style types
- Renderer-independent paint/display lists
- Testing and screenshot-audit hooks

Everything backend-specific should sit outside the core: egui, wgpu, glyphon,
cosmic-text, platform windows, app command systems, and product-specific widgets.

## Why Operad Is Worth Having

The common problem across the three apps is not just that egui looks rough. It is
that immediate-mode UI makes it easy to accidentally create layouts that are hard
to audit, hard to virtualize, hard to render outside egui, and hard to make feel
like a serious native application.

Fabricad especially needs UI that can be inspected and verified. We need to know
that every view fits at multiple aspect ratios, that no text falls off a panel,
that scroll regions are real, that tables paginate or virtualize correctly, and
that viewport overlays do not fight application chrome. A retained document model
is the right foundation for that.

For the DAW, Operad could give us predictable native app controls and a better
foundation for piano-roll and timeline overlays. For the game, Operad can keep
menus and HUDs independent from egui while still allowing an egui adapter during
the migration.

## Core Abstraction Boundaries

### `operad-core`

This should be the minimal, renderer-independent layer.

It should own:

- `UiDocument`, `UiNode`, stable node ids, tree mutation
- Geometry types: point, size, rect, insets
- Neutral style types: color, stroke, radius, opacity, text style, layout style
- Layout execution through a backend abstraction, probably Taffy internally
- Computed layout cache and invalidation
- Hit testing and z ordering
- Focus traversal and focus scopes
- Pointer capture, keyboard focus, and event routing
- Scroll containers and scroll state
- Basic transition/animation state
- Accessibility metadata as data, even if backends ignore it initially
- A renderer-neutral paint list or display list

It should not depend on:

- egui
- glyphon
- wgpu
- winit
- eframe
- product crates
- app-specific command enums

Taffy is acceptable in core for now because layout is a central job of the core.
If we want to be stricter, we can wrap Taffy behind our own layout style types so
consumers do not build directly against Taffy APIs.

### `operad-egui`

This adapter should let us embed Operad documents inside existing egui apps.

It should own:

- Conversion from egui input into Operad input events
- Painting an Operad display list through egui
- Temporary bridging for egui fonts and text rendering
- Debug overlays for layout boxes, focus, clipping, and hit regions

It should not define core UI behavior. If button behavior, scroll behavior, text
editing, or table virtualization lives only in the egui adapter, then Operad has
not actually solved the portability problem.

### `operad-text`

Text should be optional and carefully separated.

The core should define neutral text concepts:

- Font family preference
- Size and line height
- Weight
- Italic/style
- Wrap mode
- Alignment
- Color

The core should expose a `TextMeasurer` trait and include a cheap approximate
measurer for tests and simple tools.

A separate text crate or feature can provide real shaping and measurement. I
would prefer `cosmic-text` for this layer. I would not put `glyphon` in core,
because glyphon is primarily a wgpu text renderer and brings graphics
dependencies into places that only need measurement.

### `operad-wgpu`

This should be the eventual native renderer.

It should own:

- Rect, stroke, image, and mesh rendering
- Text rendering, likely through glyphon or another wgpu text path
- Texture atlas/image resource management
- Clipping/scissor management
- GPU batching
- Render-target integration

The wgpu renderer should consume the same display list that the egui adapter
consumes. That keeps core behavior testable without a GPU.

### Widget Layer

I would keep widgets separate from the document core.

Possible shape:

- `operad-widgets` for reusable controls
- Product crates compose those widgets into domain views
- Apps can still build nodes directly when needed

Widgets should emit semantic actions rather than owning application state. For
example, a command palette widget should emit `CommandSelected(id)`, not know
about Fabricad's command enum directly.

## What I Need Before Using It Seriously

### Real Scroll Containers

This is the first hard requirement for Fabricad.

Needed behavior:

- Vertical and horizontal scroll offsets
- Wheel and trackpad input
- Scrollbar thumb geometry
- Dragging scrollbar thumbs
- Programmatic scroll-to-node
- Nested scroll region behavior
- Clipping that matches hit testing and painting

Without this, Operad cannot replace the egui panels that currently fail when
content is taller than the window.

### Text Input

Text editing has to be a core interaction, not a page-specific hack.

Needed behavior:

- Single-line and multiline editing
- Caret movement
- Selection
- Backspace/delete
- Home/end and word movement
- Clipboard copy/paste/cut through platform adapters
- IME composition hooks
- Mouse selection
- Focus loss/commit behavior

Fabricad uses filters, name fields, markdown editing, property editors, and
command palette input. The DAW also needs project names, numeric entry, search,
and possibly lyrics/notes later.

### Virtual Lists and Tables

Fabricad has many tables and lists where "render every row" is the wrong model.

Needed behavior:

- Fixed-height virtual list
- Variable-height virtual list eventually
- Sticky headers
- Column sizing
- Sort/filter state hooks
- Row selection
- Keyboard navigation
- Pagination helpers for small datasets
- Displaying "showing N-M of K" as a standard pattern

This is where Operad can become more useful than egui for us. It should make the
correct path easy for large data views.

### Command Palette and Menu Model

The command palette should be a reusable system:

- Command registry
- Search/filter
- Keyboard navigation
- Recent/frequent ranking later
- Shortcut display
- Action dispatch through app-provided callbacks

Menus should also be data-driven enough that Fabricad, the DAW, and the game can
share the same behavior while rendering different command sets.

### Docking, Splitters, and Panels

Fabricad wants professional application chrome:

- Pinned navigation rail
- Optional panels
- Docked side panels
- Floating panels
- Split panes
- Resizable panels
- Responsive collapse rules

This does not all need to be in v1, but the core layout model should not make it
hard to add.

### Canvas and Viewport Overlays

Operad should not try to own every high-performance canvas immediately.

For Fabricad layout/3D and the DAW piano roll, I want a clear escape hatch:

- App owns the domain renderer/canvas
- Operad owns chrome and overlays
- Hit testing can decide whether UI or canvas receives input
- Viewport fullscreen can be modeled as layout state, not an egui special case

This lets us migrate app chrome without blocking on rewriting every custom
renderer.

## Display List Boundary

The right renderer boundary is probably a display list.

Core produces something like:

- Rect fill
- Rect stroke
- Text run
- Image
- Custom mesh or custom paint callback
- Clip push/pop or clip rect per item
- Z order
- Transform/opacity

Backends consume this list:

- `operad-egui` paints it through egui
- `operad-wgpu` batches and renders it natively
- A test backend can inspect it without a window

This is also useful for audit tooling. We can assert that nodes are inside their
clips, that text has finite measured bounds, and that no interactive node is
unreachable.

## Testing and Audit Hooks

This is where Operad can be especially useful to me.

I want a standard harness that can:

- Build each product view at named viewport sizes
- Compute layout without opening a window
- Export a layout tree as JSON
- Render screenshots through a deterministic backend
- Check for text overflow
- Check for clipped interactive controls
- Check for missing scroll containers
- Check for unreachable focusable elements
- Compare screenshots to baselines where useful

Fabricad needs this badly. The recent UI issues were often not logic bugs; they
were layout/audit failures.

## Suggested Crate Layout

A practical structure:

```text
operad/
  crates/
    operad-core/
    operad-egui/
    operad-text-cosmic/
    operad-wgpu/
    operad-widgets/
    operad-audit/
  examples/
    egui_shell.rs
    scroll_table.rs
    command_palette.rs
    daw_transport.rs
    fabricad_panel.rs
```

If we keep a single crate for now, use features with strict boundaries:

```text
default = ["egui"]
egui = ["dep:egui"]
text-cosmic = ["dep:cosmic-text"]
wgpu = ["dep:wgpu", "dep:glyphon"]
widgets = []
audit = ["serde"]
```

The important rule is that disabling default features should not pull wgpu.

## API Shape I Would Prefer

The core should make app code read like it is building a document, not like it is
manually pushing rectangles.

Example direction:

```rust
let root = document.root();
let panel = document.panel(root, Panel::new().layout(fill()).scroll_y());
let search = document.text_input(panel, TextInput::new("Search").placeholder("recipe, lot, rule"));
let table = document.virtual_table(panel, Table::new(columns).row_count(rows.len()));
```

But it should still allow low-level node construction for custom views.

Actions should be typed outside the core:

```rust
enum AppAction {
    RunCommand(CommandId),
    SelectRow(RowId),
    EditLayerName(LayerId, String),
}
```

Widgets can return neutral event payloads or user-supplied action ids. Core
should not know product-specific action enums.

## Adoption Strategy

I would not rewrite Fabricad first.

Better order:

1. Make Operad core dependency-light and split egui/text boundaries.
2. Port the game menu to consume Operad through the new package cleanly.
3. Port one DAW surface, probably transport plus side panels.
4. Add real scroll containers and text input.
5. Port a Fabricad small panel with known pain, such as Sidebar Modules or
   command palette.
6. Add virtual tables.
7. Port Fabricad Notebook or Layout Diff controls.
8. Only then consider replacing broad Fabricad chrome.

This order keeps risk down and gives the library real consumers quickly.

## Non-Goals

Operad should not become:

- A Tauri/webview abstraction
- A thin wrapper around egui
- A game HUD-only library
- A Fabricad-only design system
- A renderer that requires wgpu just to compute layout
- A place for application domain state

## Current Concerns

The current extracted crate is useful, but these should be addressed early:

- `glyphon` is in the core dependency list, which pulls wgpu even without egui.
- `TextStyle` exposes backend-specific text types.
- Input events are too small for serious app UI.
- Scroll containers are not core behavior yet.
- There is no widget layer yet.
- There is no display-list boundary yet.
- The egui renderer is inside the same source file as core behavior.
- The public API exposes `taffy::Style` directly, which may make future layout
  abstraction harder.

None of these are blockers for the first extraction, but they are the next set of
decisions that will determine whether Operad becomes a reusable foundation or
just a shared copy of the game UI experiment.

## Bottom Line

I want Operad to be the place where layout, input routing, scroll behavior,
focus, and view auditability become reliable across our native Rust apps.

The best version of Operad is not "our own egui" and not "a wgpu renderer." It is
the stable UI document and interaction model that can survive multiple renderers.
That boundary would make it useful immediately through an egui adapter and much
more valuable later through a native wgpu backend.