Skip to main content

pathland_core/
constants.rs

1//! Protocol constants: categories, commands, component types, value types, flags.
2//!
3//! These constants are part of the wire protocol (see `spec/OPCODE.md`) and MUST
4//! NOT be renumbered once released. Component types were renumbered pre-release
5//! to the grouped ranges in `spec/PRIMITIVES.md` (wire version stays 1).
6
7/// Opcode categories (`Category` field, u8).
8pub mod category {
9    /// Tree mutations (guest → host): node create/delete/insert/remove/move.
10    pub const TREE: u8 = 0x01;
11    /// Parameters and design tokens (guest → host): the constraint properties
12    /// (spacing, padding, alignment, …) and content that native renderers use
13    /// to lay out and style native elements. The engine does NOT emit rects.
14    pub const PARAMETER: u8 = 0x02;
15    /// Raw input events (host → guest): pointer down/move/up, key down/up.
16    pub const EVENT: u8 = 0x03;
17    /// Control (both directions): reset, environment, custom data.
18    pub const META: u8 = 0x04;
19}
20
21/// Commands within the `TREE` category.
22pub mod tree {
23    /// `A=nodeId, B=componentType (u16, low)`
24    pub const CREATE_NODE: u8 = 0x01;
25    /// `A=nodeId`
26    pub const DELETE_NODE: u8 = 0x02;
27    /// `A=parentId, B=childId, C=index` (append is `C = u32::MAX`, see [`crate::APPEND`])
28    pub const INSERT_CHILD: u8 = 0x03;
29    /// `A=parentId, B=childId`
30    pub const REMOVE_CHILD: u8 = 0x04;
31    /// `A=parentId, B=childId, C=newIndex` (append is `C = u32::MAX`, see [`crate::APPEND`])
32    pub const MOVE_CHILD: u8 = 0x05;
33}
34
35/// Commands within the `PARAMETER` category.
36pub mod parameter {
37    /// `A=nodeId, B=(valueType << 16) | propertyId, C=value`
38    pub const SET_PROPERTY: u8 = 0x01;
39    /// `A=arenaRef (path), B=valueType (u8), C=value`
40    pub const SET_DESIGN_TOKEN: u8 = 0x02;
41    /// `A=nodeId, B=arenaRef (utf8)`
42    pub const SET_TEXT: u8 = 0x03;
43    /// **Draft.** `A=nodeId, B=days since epoch (I32), C=millis of day (U32)` —
44    /// set a node's date value (e.g. a `DATE_PICKER`); see
45    /// `spec/PRIMITIVES.md` / `spec/OPCODE.md`.
46    pub const SET_DATE: u8 = 0x04;
47}
48
49/// Commands within the `EVENT` category.
50///
51/// Events are **raw inputs** (host → guest), each carrying a host-resolved
52/// `targetId`. High-level interpretations (tap, drag, long-press) are built by
53/// the guest/app from these raw inputs and are NOT part of the protocol.
54pub mod event {
55    /// `A=targetId, B=x (f32), C=y (f32)` (Flags `POINTER_SECONDARY`)
56    pub const POINTER_DOWN: u8 = 0x01;
57    /// `A=targetId, B=x (f32), C=y (f32)` (Flags `HOVER_ENTER` / `HOVER_LEAVE`)
58    pub const POINTER_MOVE: u8 = 0x02;
59    /// `A=targetId, B=x (f32), C=y (f32)` (Flags `POINTER_SECONDARY`)
60    pub const POINTER_UP: u8 = 0x03;
61    /// `A=targetId, B=keyCode (u16, low), C=modifiers (u8, low)` (Flags `KEY_REPEAT`)
62    pub const KEY_DOWN: u8 = 0x04;
63    /// `A=targetId, B=keyCode (u16, low), C=modifiers (u8, low)`
64    pub const KEY_UP: u8 = 0x05;
65    /// `A=targetId, B=value (f32)` — a control's value changed (host → guest).
66    /// The renderer resolves the control's semantic value (e.g. a slider thumb
67    /// dragged to a point on its track); the guest/app writes it into its state.
68    pub const VALUE_CHANGED: u8 = 0x06;
69    /// `A=targetId, B=string offset` — a text field's value changed (host →
70    /// guest). The new text lives in the batch's string section, referenced by
71    /// the *relative* offset in `B` (the same convention as `PARAMETER::SET_TEXT`).
72    pub const TEXT_CHANGED: u8 = 0x07;
73    /// **Draft.** `A=targetId, B=focused (0/1)` — a node gained/lost focus.
74    pub const FOCUS_CHANGED: u8 = 0x08;
75    /// **Draft.** `A=targetId, B=editing (0/1)` — an editing session began/ended.
76    pub const EDITING_CHANGED: u8 = 0x09;
77    /// **Draft.** `A=targetId, B=0` — the user committed a field (onSubmit).
78    pub const SUBMIT: u8 = 0x0A;
79    /// **Draft.** `A=targetId, B=offsetX (f32), C=offsetY (f32)` — scroll offset.
80    pub const SCROLL: u8 = 0x0B;
81    /// **Draft.** `A=targetId, B=deltaX (f32), C=deltaY (f32)` — wheel/trackpad.
82    pub const WHEEL: u8 = 0x0C;
83    /// **Draft.** `A=targetId, B=days since epoch (I32), C=millis of day (U32)`
84    /// — a `DATE_PICKER`'s value changed (matches `PARAMETER::SET_DATE`).
85    pub const DATE_CHANGED: u8 = 0x0D;
86    /// **Draft.** Global navigation request (host → guest), never node-keyed.
87    /// With the `NAVIGATE_URL` flag, `B` is a string offset (event arena /
88    /// batch string section) to the destination URL; without it, the event means
89    /// "back one step" (native back affordance) and `B`/`C` are ignored.
90    pub const NAVIGATE: u8 = 0x0E;
91    /// **Draft.** A bound `AUDIO`/`VIDEO` node's playback state changed
92    /// (host → guest); `B` = 0/1. Reported only when `PLAYBACK_STATE` is bound.
93    pub const MEDIA_PLAY_STATE_CHANGED: u8 = 0x0F;
94    /// **Draft.** A bound media node's current position (host → guest); `B` =
95    /// seconds (f32). Reported while playing; an app-initiated seek is not echoed.
96    pub const MEDIA_TIME_UPDATED: u8 = 0x10;
97    /// **Draft.** A bound media node reached the end of its media (host → guest).
98    pub const MEDIA_ENDED: u8 = 0x11;
99    /// **Draft.** A bound media node's volume changed (host → guest); `B` =
100    /// volume (f32, 0..1).
101    pub const MEDIA_VOLUME_CHANGED: u8 = 0x12;
102    /// **Draft.** A `SIZE_THAT_FITS` slot's selected candidate index changed
103    /// (host → guest); `B` = index (f32). Reported once after the first measure,
104    /// then only when the derived fit index changes.
105    pub const FIT_CHANGED: u8 = 0x13;
106}
107
108/// Commands within the `META` category.
109pub mod meta {
110    /// Host must clear all rendered output.
111    pub const RESET: u8 = 0x01;
112    /// `A=fieldId (u16, low), B=field value` — a platform environment field
113    /// (host → guest); see [`crate::environment`]. An extensible field family:
114    /// each opcode sets one field (viewport, initial route, …).
115    pub const ENVIRONMENT: u8 = 0x02;
116    /// The host (renderer) requests a full snapshot of the current tree
117    /// (host → guest). `A/B/C = 0`. Used for reconnect/gap recovery.
118    pub const RESYNC: u8 = 0x03;
119    /// A transport-liveness heartbeat probe (guest → host). `A/B/C = 0`, no
120    /// payload. **Network batch transport only** (spec/OPCODE.md §Transport —
121    /// heartbeat): the shared-memory ring MUST NOT emit, expect, or relay it.
122    pub const PING: u8 = 0x04;
123    /// The reply to `META::PING` (host → guest). `A/B/C = 0`, no payload.
124    /// Network batch transport only (see [`PING`]).
125    pub const PONG: u8 = 0x05;
126}
127
128/// Environment field ids for `META::ENVIRONMENT` (host → guest).
129///
130/// Each opcode sets one platform environment field; new fields are new ids, never
131/// new commands (spec/OPCODE.md §Environment fields).
132pub mod environment {
133    /// Viewport width in logical points (f32 in `B`).
134    pub const VIEWPORT_WIDTH: u16 = 0x0001;
135    /// Viewport height in logical points (f32 in `B`).
136    pub const VIEWPORT_HEIGHT: u16 = 0x0002;
137    /// The initial route/deep-link path (STRING: `B` is a string-section/event-arena
138    /// offset — the `TEXT_CHANGED`/`NAVIGATE` dual convention).
139    pub const ROUTE: u16 = 0x0003;
140}
141
142/// Flag bits used across categories.
143pub mod flag {
144    /// `POINTER_DOWN` / `POINTER_UP`: secondary button (bit 0).
145    pub const POINTER_SECONDARY: u16 = 0x0001;
146    /// `POINTER_MOVE`: pointer is entering/hovering (bit 0).
147    pub const HOVER_ENTER: u16 = 0x0001;
148    /// `POINTER_MOVE`: pointer is leaving (bit 1).
149    pub const HOVER_LEAVE: u16 = 0x0002;
150    /// `KEY_DOWN`: key repeat (bit 1).
151    pub const KEY_REPEAT: u16 = 0x0002;
152    /// `NAVIGATE`: `B` is a URL string offset (bit 0). Without this flag the
153    /// event is a back request.
154    pub const NAVIGATE_URL: u16 = 0x0001;
155}
156
157/// Bits for the `EVENT_LISTENERS` semantic property (a u32 bitmask).
158///
159/// Each bit requests that a renderer attach native input recognition for the
160/// matching raw-input event and report it for that node — so any element (not
161/// just a button) can emit raw events. Bits are independent of the `EVENT`
162/// command ids; more event kinds can be added later.
163pub mod listener {
164    /// `POINTER_DOWN` events (bit 0).
165    pub const POINTER_DOWN: u32 = 1 << 0;
166    /// `POINTER_MOVE` events (bit 1).
167    pub const POINTER_MOVE: u32 = 1 << 1;
168    /// `POINTER_UP` events (bit 2).
169    pub const POINTER_UP: u32 = 1 << 2;
170    /// `KEY_DOWN` events (bit 3).
171    pub const KEY_DOWN: u32 = 1 << 3;
172    /// `KEY_UP` events (bit 4).
173    pub const KEY_UP: u32 = 1 << 4;
174    /// **Draft.** `FOCUS_CHANGED` events (bit 5).
175    pub const FOCUS: u32 = 1 << 5;
176    /// **Draft.** `EDITING_CHANGED` events (bit 6).
177    pub const EDITING: u32 = 1 << 6;
178    /// **Draft.** `SUBMIT` events (bit 7).
179    pub const SUBMIT: u32 = 1 << 7;
180    /// **Draft.** `SCROLL` events (bit 8).
181    pub const SCROLL: u32 = 1 << 8;
182    /// **Draft.** `WHEEL` events (bit 9).
183    pub const WHEEL: u32 = 1 << 9;
184
185    /// All pointer events (down + move + up).
186    pub const POINTER: u32 = POINTER_DOWN | POINTER_MOVE | POINTER_UP;
187}
188
189/// Bits for the `BORDER_EDGES` style property (a u32 bitmask).
190///
191/// Each bit selects one edge of a node's border. `LEADING`/`TRAILING` are
192/// direction-aware; a renderer resolves them to physical `left`/`right`
193/// according to its layout direction (LTR by default).
194pub mod border_edges {
195    /// Top edge (bit 0).
196    pub const TOP: u32 = 1 << 0;
197    /// Leading edge (bit 1) — physical left in LTR.
198    pub const LEADING: u32 = 1 << 1;
199    /// Bottom edge (bit 2).
200    pub const BOTTOM: u32 = 1 << 2;
201    /// Trailing edge (bit 3) — physical right in LTR.
202    pub const TRAILING: u32 = 1 << 3;
203
204    /// All four edges.
205    pub const ALL: u32 = TOP | LEADING | BOTTOM | TRAILING;
206}
207
208/// Value types for `PARAMETER` properties (u8, encoded in the high byte of `B`).
209pub mod value_type {
210    pub const U8: u8 = 0x01;
211    pub const U32: u8 = 0x02;
212    pub const I32: u8 = 0x03;
213    pub const F32: u8 = 0x04;
214    pub const STRING: u8 = 0x05;
215    pub const ENUM: u8 = 0x06;
216    pub const COLOR: u8 = 0x07;
217    pub const DESIGN_TOKEN: u8 = 0x08;
218    /// **Draft.** Arena-backed length-prefixed array: `[u32 count][element × count]`
219    /// in the string arena (each element holds the value-type's bit pattern —
220    /// today `F32`s, e.g. the `FIT_QUERY` threshold table).
221    pub const LIST: u8 = 0x09;
222}
223
224/// Component types (u16, encoded in the low half of `B` of `TREE::CREATE_NODE`).
225///
226/// IDs are grouped into three definitive ranges (see `spec/PRIMITIVES.md`):
227/// Primitive Drawing `0x01`–`0x0F`, Layout & Container `0x10`–`0x1F`, Semantic
228/// Control `0x20`–`0x2F`, plus the utility `COMMENT` at `0x7F`. Renumbered
229/// pre-release (wire version stays 1).
230pub mod component_type {
231    // ── Primitive Drawing & Visual Nodes (0x01–0x0F) ────────────────────────
232    /// Standard styled text display.
233    pub const TEXT: u16 = 0x01;
234    /// Raster, vector, or system icon asset.
235    pub const IMAGE: u16 = 0x02;
236    /// **Draft.** Solid color / layout-filling background view.
237    pub const COLOR: u16 = 0x03;
238    /// **Draft.** Vector geometry (`SHAPE_KIND` selects the shape).
239    pub const SHAPE: u16 = 0x04;
240    /// **Draft.** Axis-aligned separator line.
241    pub const DIVIDER: u16 = 0x05;
242    /// Flexible expanding layout filler.
243    pub const SPACER: u16 = 0x06;
244    /// **Draft.** Determinate progress or activity indicator.
245    pub const PROGRESS_VIEW: u16 = 0x07;
246    /// **Draft.** Range meter against a scale (read-only).
247    pub const GAUGE: u16 = 0x08;
248    /// **Draft.** Audio playback node (`AUDIO_SOURCE` references the media;
249    /// playback interaction is renderer-native).
250    pub const AUDIO: u16 = 0x09;
251    /// **Draft.** Video playback node (`VIDEO_SOURCE` references the media;
252    /// playback interaction is renderer-native).
253    pub const VIDEO: u16 = 0x0A;
254    /// **Draft.** Semantic icon (`ICON_NAME` selects a renderer-native symbol —
255    /// Adwaita on GTK, Lucide on the web; spec/ICONS.md).
256    pub const ICON: u16 = 0x0B;
257    // 0x0C–0x0F reserved (future drawing nodes).
258
259    // ── Layout & Container Primitives (0x10–0x1F) ───────────────────────────
260    /// Vertical flex stack.
261    pub const VSTACK: u16 = 0x10;
262    /// Horizontal flex stack.
263    pub const HSTACK: u16 = 0x11;
264    /// **Draft.** Depth-overlapping layer stack.
265    pub const ZSTACK: u16 = 0x12;
266    /// Static 2D matrix grid (eagerly rendered).
267    pub const GRID: u16 = 0x13;
268    /// Scrollable content container.
269    pub const SCROLLVIEW: u16 = 0x14;
270    /// **Draft.** Virtualized vertical grid.
271    pub const LAZY_VGRID: u16 = 0x15;
272    /// **Draft.** Virtualized horizontal grid.
273    pub const LAZY_HGRID: u16 = 0x16;
274    /// **Draft.** Fit slot (`SizeThatFits`): shows its single selected child —
275    /// only the selected candidate is ever transmitted. The renderer measures
276    /// its own allocated width against `FIT_QUERY` and reports `FIT_CHANGED`.
277    pub const SIZE_THAT_FITS: u16 = 0x17;
278    // 0x18–0x1A reserved (formerly composite views, removed).
279    /// **Draft.** Virtualized vertical stack.
280    pub const LAZY_VSTACK: u16 = 0x1B;
281    /// **Draft.** Virtualized horizontal stack.
282    pub const LAZY_HSTACK: u16 = 0x1C;
283    /// **Draft.** Explicit row grouping for a `GRID`: a grid child whose children
284    /// are one row's cells (the SwiftUI `GridRow` surface). Renders nothing
285    /// outside a `GRID`.
286    pub const GRID_ROW: u16 = 0x1D;
287    // 0x1E–0x1F reserved (future layout nodes).
288
289    // ── Semantic Control Nodes (0x20–0x2F) ──────────────────────────────────
290    /// Action trigger control.
291    pub const BUTTON: u16 = 0x20;
292    /// Single-line text input (secure variant via `IS_SECURE`).
293    pub const TEXT_FIELD: u16 = 0x21;
294    /// **Draft.** Multi-line text editing area.
295    pub const TEXT_EDITOR: u16 = 0x22;
296    // 0x23 reserved.
297    /// Boolean control; the visual variant is `TOGGLE_STYLE`
298    /// (`Switch`/`Checkbox`/`Button`).
299    pub const TOGGLE: u16 = 0x24;
300    /// Continuous or stepped numeric range control.
301    pub const SLIDER: u16 = 0x25;
302    /// **Draft.** Discrete increment/decrement control.
303    pub const STEPPER: u16 = 0x26;
304    /// **Draft.** Date & time selection control (`PARAMETER::SET_DATE` value).
305    pub const DATE_PICKER: u16 = 0x27;
306    /// **Draft.** Selection control (options are child nodes).
307    pub const PICKER: u16 = 0x28;
308    /// **Draft.** Contextual action trigger + popover container.
309    pub const MENU: u16 = 0x29;
310    /// **Draft.** Native system color picker control.
311    pub const COLOR_PICKER: u16 = 0x2A;
312    // 0x2B–0x2F reserved (future semantic controls).
313
314    /// Opaque/debug node; renderers ignore it (no native element).
315    pub const COMMENT: u16 = 0x7F;
316}
317
318/// Property IDs (u16, encoded in the low half of `B` of `PARAMETER::SET_PROPERTY`).
319///
320/// IDs are specified in `spec/OPCODE.md` (carried forward from the historical protocol).
321pub mod property_id {
322    // Stack
323    pub const SPACING: u16 = 0x0001;
324    pub const ALIGNMENT: u16 = 0x0002;
325    // 0x0003 reserved (formerly JUSTIFICATION; main-axis distribution is
326    // expressed via a spacer element instead).
327    // 0x0004 reserved (formerly PADDING; now a styling modifier at 0x1011).
328    pub const CONTENT_MARGINS: u16 = 0x0005;
329    // Text
330    pub const TEXT: u16 = 0x000A;
331    pub const LINE_LIMIT: u16 = 0x000B;
332    pub const TEXT_ALIGNMENT: u16 = 0x000C;
333    pub const TRUNCATION_MODE: u16 = 0x000D;
334    /// **Draft.** `SHAPE` geometry kind (F32 enum): `Circle`=0, `Rectangle`=1,
335    /// `RoundedRectangle`=2, `Capsule`=3, `Ellipse`=4, `Path`=5.
336    pub const SHAPE_KIND: u16 = 0x0006;
337    // Layout modifiers (draft, 0x000E–0x001D)
338    /// **Draft.** Post-layout translation, x (F32). `.offset(x:y:)`.
339    pub const OFFSET_X: u16 = 0x000E;
340    /// **Draft.** Post-layout translation, y (F32).
341    pub const OFFSET_Y: u16 = 0x000F;
342    /// **Draft.** Absolute position within the parent, x (F32). `.position(x:y:)`.
343    pub const POSITION_X: u16 = 0x0010;
344    /// **Draft.** Absolute position within the parent, y (F32).
345    pub const POSITION_Y: u16 = 0x0011;
346    /// **Draft.** Minimum width (F32). `.frame(minWidth:...)`.
347    pub const MIN_WIDTH: u16 = 0x0012;
348    /// **Draft.** Ideal width (F32).
349    pub const IDEAL_WIDTH: u16 = 0x0013;
350    /// **Draft.** Maximum width (F32).
351    pub const MAX_WIDTH: u16 = 0x0014;
352    /// **Draft.** Minimum height (F32).
353    pub const MIN_HEIGHT: u16 = 0x0015;
354    /// **Draft.** Ideal height (F32).
355    pub const IDEAL_HEIGHT: u16 = 0x0016;
356    /// **Draft.** Maximum height (F32).
357    pub const MAX_HEIGHT: u16 = 0x0017;
358    /// **Draft.** Fixed-size hint, horizontal (U8 0/1). `.fixedSize()`.
359    pub const FIXED_SIZE_HORIZONTAL: u16 = 0x0018;
360    /// **Draft.** Fixed-size hint, vertical (U8 0/1).
361    pub const FIXED_SIZE_VERTICAL: u16 = 0x0019;
362    /// **Draft.** Layout priority (F32). `.layoutPriority(_:)`.
363    pub const LAYOUT_PRIORITY: u16 = 0x001A;
364    /// **Draft.** Aspect ratio (F32). `.aspectRatio(_:)`.
365    pub const ASPECT_RATIO: u16 = 0x001B;
366    /// **Draft.** Content mode (F32 enum): `Fit`=0, `Fill`=1.
367    pub const CONTENT_MODE: u16 = 0x001C;
368    /// **Draft.** Minimum scale factor (F32). `.minimumScaleFactor(_:)`.
369    pub const MINIMUM_SCALE_FACTOR: u16 = 0x001D;
370    /// **Draft.** Grid column count (F32, constructor property): a positive value
371    /// pins the count (equal `1fr` tracks); `FILL`/absent = auto-fit. Never a
372    /// pixel width — the grid's box comes from `WIDTH`/`HEIGHT`.
373    pub const GRID_COLUMNS: u16 = 0x001E;
374    /// **Draft.** Grid row count (F32, constructor property): the `LAZY_HGRID`
375    /// fixed track; positive = count, `FILL`/absent = auto-fit.
376    pub const GRID_ROWS: u16 = 0x001F;
377    /// **Draft.** Grid track spec (STRING, constructor property): a comma-
378    /// separated list of per-track sizes — `flex` | `fixed:<points>` |
379    /// `adaptive:<points>` — taking precedence over `GRID_COLUMNS`/`GRID_ROWS`
380    /// (the equal-`1fr` count is `N`×`flex` sugar). CSS-grid-native: renderers
381    /// without a native equivalent (GTK `GtkGrid`) fall back to natural sizing.
382    pub const GRID_TRACKS: u16 = 0x0020;
383    // Style (0x1000 range)
384    pub const BACKGROUND_COLOR: u16 = 0x1001;
385    /// **Draft.** Image source (STRING: a resource name, file path, or URL —
386    /// an **asset reference**, resolved and loaded by the renderer/host; never
387    /// embedded in the opcode stream).
388    pub const IMAGE_SOURCE: u16 = 0x1002;
389    /// **Draft.** Audio source (STRING asset reference, see `IMAGE_SOURCE`).
390    pub const AUDIO_SOURCE: u16 = 0x1033;
391    /// **Draft.** Video source (STRING asset reference, see `IMAGE_SOURCE`).
392    pub const VIDEO_SOURCE: u16 = 0x1034;
393    /// **Draft.** Media playback state (U32 0=pause, 1=play) on an `AUDIO`/`VIDEO`
394    /// node. When bound, the renderer reports `MEDIA_PLAY_STATE_CHANGED`.
395    pub const PLAYBACK_STATE: u16 = 0x1035;
396    /// **Draft.** Media position in seconds (F32) on an `AUDIO`/`VIDEO` node; a
397    /// change seeks. When bound, the renderer reports `MEDIA_TIME_UPDATED`.
398    pub const MEDIA_POSITION: u16 = 0x1036;
399    /// **Draft.** Media volume (F32 0..1) on an `AUDIO`/`VIDEO` node. When bound,
400    /// the renderer reports `MEDIA_VOLUME_CHANGED`.
401    pub const MEDIA_VOLUME: u16 = 0x1037;
402    /// **Draft.** Semantic icon name (STRING, canonical; spec/ICONS.md) on an
403    /// `ICON` node. The renderer maps it to its native icon set and falls back
404    /// to a renderer-default visual for unknown names.
405    pub const ICON_NAME: u16 = 0x1038;
406    pub const BORDER_WIDTH: u16 = 0x1003;
407    pub const BORDER_COLOR: u16 = 0x1004;
408    pub const BORDER_RADIUS: u16 = 0x1005;
409    pub const PADDING_STYLE: u16 = 0x1006;
410    pub const FONT_SIZE: u16 = 0x1007;
411    pub const FONT_WEIGHT: u16 = 0x1008;
412    pub const FONT_FAMILY: u16 = 0x1009;
413    pub const COLOR: u16 = 0x100A;
414    pub const WIDTH: u16 = 0x100B;
415    pub const HEIGHT: u16 = 0x100C;
416    pub const OPACITY: u16 = 0x100D;
417    pub const VISIBLE: u16 = 0x100E;
418    pub const Z_INDEX: u16 = 0x100F;
419    pub const CLIPS_TO_BOUNDS: u16 = 0x1010;
420    pub const PADDING: u16 = 0x1011;
421    pub const PADDING_TOP: u16 = 0x1012;
422    pub const PADDING_RIGHT: u16 = 0x1013;
423    pub const PADDING_BOTTOM: u16 = 0x1014;
424    pub const PADDING_LEFT: u16 = 0x1015;
425    /// `BORDER_EDGES` — a u32 bitmask (see [`crate::border_edges`]) selecting
426    /// which edges of a node's border are drawn.
427    pub const BORDER_EDGES: u16 = 0x1016;
428    // Text-format modifiers (draft, 0x1017–0x1020)
429    /// **Draft.** Font style (F32 enum): `Normal`=0, `Italic`=1.
430    pub const FONT_STYLE: u16 = 0x1017;
431    /// **Draft.** Font design (F32 enum): `Default`=0, `Serif`=1, `Rounded`=2,
432    /// `Monospaced`=3.
433    pub const FONT_DESIGN: u16 = 0x1018;
434    /// **Draft.** Font width (F32, 0.5–1.5, 1.0 default).
435    pub const FONT_WIDTH: u16 = 0x1019;
436    /// **Draft.** Kerning (F32 points). `.kerning(_:)`.
437    pub const KERNING: u16 = 0x101A;
438    /// **Draft.** Tracking (F32 points). `.tracking(_:)`.
439    pub const TRACKING: u16 = 0x101B;
440    /// **Draft.** Baseline offset (F32 points). `.baselineOffset(_:)`.
441    pub const BASELINE_OFFSET: u16 = 0x101C;
442    /// **Draft.** Line spacing (F32 points). `.lineSpacing(_:)`.
443    pub const LINE_SPACING: u16 = 0x101D;
444    /// **Draft.** Text case (F32 enum): `None`=0, `Uppercase`=1, `Lowercase`=2.
445    pub const TEXT_CASE: u16 = 0x101E;
446    /// **Draft.** Underline (U8 0/1). `.underline()`.
447    pub const UNDERLINE: u16 = 0x101F;
448    /// **Draft.** Strikethrough (U8 0/1). `.strikethrough()`.
449    pub const STRIKETHROUGH: u16 = 0x1020;
450    // Effect modifiers (draft, 0x1021–0x102C)
451    /// **Draft.** Shadow color (COLOR). `.shadow(color:...)`.
452    pub const SHADOW_COLOR: u16 = 0x1021;
453    /// **Draft.** Shadow radius (F32).
454    pub const SHADOW_RADIUS: u16 = 0x1022;
455    /// **Draft.** Shadow x offset (F32).
456    pub const SHADOW_X: u16 = 0x1023;
457    /// **Draft.** Shadow y offset (F32).
458    pub const SHADOW_Y: u16 = 0x1024;
459    /// **Draft.** Blur radius (F32). `.blur(radius:)`.
460    pub const BLUR_RADIUS: u16 = 0x1025;
461    /// **Draft.** Saturation (F32 0–1). `.saturation(_:)`.
462    pub const SATURATION: u16 = 0x1026;
463    /// **Draft.** Contrast (F32 0–1). `.contrast(_:)`.
464    pub const CONTRAST: u16 = 0x1027;
465    /// **Draft.** Brightness (F32 −1–1). `.brightness(_:)`.
466    pub const BRIGHTNESS: u16 = 0x1028;
467    /// **Draft.** Grayscale (F32 0–1). `.grayscale(_:)`.
468    pub const GRAYSCALE: u16 = 0x1029;
469    /// **Draft.** Hue rotation (F32 degrees). `.hueRotation(_:)`.
470    pub const HUE_ROTATION: u16 = 0x102A;
471    /// **Draft.** Color multiply (COLOR). `.colorMultiply(_:)`.
472    pub const COLOR_MULTIPLY: u16 = 0x102B;
473    /// **Draft.** Color invert (U8 0/1). `.colorInvert()`.
474    pub const COLOR_INVERT: u16 = 0x102C;
475    // Transform (draft)
476    /// **Draft.** Rotation (F32 degrees, counter-clockwise). `.rotationEffect(_:)`.
477    pub const ROTATION_DEGREES: u16 = 0x102D;
478    /// **Draft.** Uniform scale (F32). `.scaleEffect(_:)`.
479    pub const SCALE: u16 = 0x102E;
480    /// **Draft.** Whether the element participates in hit testing (U8 0/1).
481    /// `.allowsHitTesting(_:)`.
482    pub const ALLOWS_HIT_TESTING: u16 = 0x102F;
483    /// **Draft.** Accent/tint color (COLOR). `.tint(_:)`.
484    pub const TINT: u16 = 0x1030;
485    /// **Draft.** Presentation hint for structural swaps (F32 enum code):
486    /// `None`=0, `PlatformDefault`=1, `Fade`=2, `Slide`=3, `Scale`=4 — emitted
487    /// by a `NavigationContainer`/`Conditional.when` slot; the renderer may
488    /// animate the swap and must render normally when it ignores the hint.
489    pub const TRANSITION: u16 = 0x1031;
490    /// **Draft.** A `SIZE_THAT_FITS` slot's candidate fit-query (LIST): the
491    /// candidates' `minWidth` thresholds, ascending. The renderer measures its
492    /// allocated width and reports the derived fit index (`FIT_CHANGED`).
493    pub const FIT_QUERY: u16 = 0x1039;
494    /// **Draft.** Predefined typography (ENUM code, see [`crate::text_style`]):
495    /// `.font(.title2)` picks a whole design-system typography; the heading
496    /// styles (LargeTitle…Headline) imply a heading element on a `TEXT`.
497    /// Raw font modifiers (`FONT_SIZE`/`FONT_WEIGHT`/`FONT_FAMILY`/…) override
498    /// the visual on top and never imply a heading.
499    pub const TEXT_STYLE: u16 = 0x1032;
500    // Semantic (0x2000 range)
501    pub const ROLE: u16 = 0x2001;
502    pub const STATE: u16 = 0x2002;
503    pub const ENABLED: u16 = 0x2003;
504    pub const SELECTED: u16 = 0x2004;
505    /// `EVENT_LISTENERS` — a u32 bitmask (see [`crate::listener`]) declaring
506    /// which raw-input events a node wants the renderer to report. This is the
507    /// declarative signal the application sets so a renderer attaches native
508    /// input recognition to any element — not just buttons.
509    pub const EVENT_LISTENERS: u16 = 0x2005;
510    /// The current value of a value-bearing control (e.g. a `SLIDER`).
511    pub const VALUE: u16 = 0x2006;
512    /// The inclusive minimum of a value-bearing control's range (e.g. a `SLIDER`).
513    pub const MIN_VALUE: u16 = 0x2007;
514    /// The inclusive maximum of a value-bearing control's range (e.g. a `SLIDER`).
515    pub const MAX_VALUE: u16 = 0x2008;
516    /// The caption label of a `TEXT_FIELD` (a `STRING` property).
517    pub const LABEL: u16 = 0x200A;
518    /// The placeholder text of a `TEXT_FIELD` (a `STRING` property).
519    pub const PROMPT: u16 = 0x200B;
520    /// **Draft.** Stepper increment per press (F32).
521    pub const STEP_VALUE: u16 = 0x2009;
522    /// **Draft.** Control size (F32 enum): `Small`=0, `Regular`=1, `Large`=2.
523    pub const CONTROL_SIZE: u16 = 0x200C;
524    /// **Draft.** Masked-input token for a `TEXT_FIELD` (U8 0/1).
525    pub const IS_SECURE: u16 = 0x200D;
526    /// **Draft.** Determinate progress fraction of a `PROGRESS_VIEW` (F32).
527    pub const PROGRESS: u16 = 0x200E;
528    /// **Draft.** Indeterminate (activity) token of a `PROGRESS_VIEW` (U8 0/1).
529    pub const IS_INDETERMINATE: u16 = 0x200F;
530    /// **Draft.** Selected child index of a `PICKER`/`MENU` (U32).
531    pub const SELECTION: u16 = 0x2010;
532    /// **Draft.** Current color of a `COLOR_PICKER` (COLOR).
533    pub const COLOR_VALUE: u16 = 0x2012;
534    /// **Draft.** `DATE_PICKER` presentation (F32 enum): `Date`=0, `Time`=1,
535    /// `DateAndTime`=2.
536    pub const DATE_PICKER_MODE: u16 = 0x2013;
537    /// **Draft.** `PICKER` presentation (F32 enum): `Menu`=0, `Segmented`=1,
538    /// `Wheel`=2, `RadioGroup`=3.
539    pub const PICKER_STYLE: u16 = 0x2014;
540    /// **Draft.** Bound callback id; gates event delivery for this node.
541    pub const ACTION_ID: u16 = 0x2016;
542    /// **Draft.** Two-way binding id (control value ↔ app state).
543    pub const BINDING_ID: u16 = 0x2017;
544    /// **Draft.** Visual style token for a `TOGGLE` (F32 enum code):
545    /// `Switch`=0, `Checkbox`=1, `Button`=2.
546    pub const TOGGLE_STYLE: u16 = 0x2018;
547    /// **Draft.** Current navigation path (STRING, arenaRef), emitted by a
548    /// `NavigationContainer` slot; drives web URL sync.
549    pub const ROUTE: u16 = 0x2019;
550    /// **Draft.** Navigation back-stack depth (U32: number of destinations in
551    /// the app's path, including the current one — `push` increments, `pop`
552    /// decrements, `replace` leaves it unchanged). Emitted by a
553    /// `NavigationContainer` slot so native navigation adapters can reconcile
554    /// their page stack by depth (push/pop/replace/reset) instead of route
555    /// tags alone. See `spec/DSL.md §4.5` and `spec/MODIFIERS.md §6`.
556    pub const NAV_DEPTH: u16 = 0x201A;
557    /// **Draft.** Navigation chrome mode (F32 enum code) on a
558    /// `NavigationContainer` slot: `PlatformDefault`=0 (the renderer supplies
559    /// the navigation chrome — the native container where one exists, a
560    /// renderer-drawn back affordance on DOM), `Custom`=1 (the developer owns
561    /// all navigation UI and the renderer adds none). A container emits this
562    /// once at mount (it never varies per destination). See `spec/DSL.md §4.5`
563    /// and `spec/MODIFIERS.md §6`.
564    pub const NAV_CHROME: u16 = 0x201B;
565}
566
567/// The protocol value type for a property id.
568///
569/// Color-valued properties (COLOR, BACKGROUND_COLOR, BORDER_COLOR) are emitted
570/// with the `COLOR` value type; `EVENT_LISTENERS` and `BORDER_EDGES` are raw
571/// `U32` bitmasks; `LABEL`/`PROMPT`/`FONT_FAMILY` are `STRING`; `LINE_LIMIT`,
572/// `ACTION_ID`, and `BINDING_ID` are `U32`; all other constraint/style
573/// properties are `F32` (enum-valued properties like `ALIGNMENT`/`TOGGLE_STYLE`
574/// carry their numeric code as an `F32`). See `spec/MODIFIERS.md` for the
575/// canonical mapping.
576pub fn value_type_for(prop: u16) -> u8 {
577    match prop {
578        property_id::COLOR
579        | property_id::BACKGROUND_COLOR
580        | property_id::BORDER_COLOR
581        | property_id::COLOR_VALUE
582        | property_id::COLOR_MULTIPLY
583        | property_id::SHADOW_COLOR
584        | property_id::TINT => value_type::COLOR,
585        property_id::EVENT_LISTENERS | property_id::BORDER_EDGES => value_type::U32,
586        property_id::SELECTED
587        | property_id::IS_SECURE
588        | property_id::IS_INDETERMINATE
589        | property_id::VISIBLE
590        | property_id::ENABLED
591        | property_id::CLIPS_TO_BOUNDS
592        | property_id::UNDERLINE
593        | property_id::STRIKETHROUGH
594        | property_id::COLOR_INVERT
595        | property_id::ALLOWS_HIT_TESTING
596        | property_id::FIXED_SIZE_HORIZONTAL
597        | property_id::FIXED_SIZE_VERTICAL => value_type::U8,
598        property_id::LABEL
599        | property_id::PROMPT
600        | property_id::FONT_FAMILY
601        | property_id::IMAGE_SOURCE
602        | property_id::AUDIO_SOURCE
603        | property_id::VIDEO_SOURCE
604        | property_id::ICON_NAME
605        | property_id::ROUTE => value_type::STRING,
606        property_id::LINE_LIMIT
607        | property_id::SELECTION
608        | property_id::ACTION_ID
609        | property_id::BINDING_ID
610        | property_id::NAV_DEPTH => value_type::U32,
611        _ => value_type::F32,
612    }
613}
614
615/// Special size constants for `WIDTH` / `HEIGHT`.
616pub mod size {
617    /// Fill the available space (parent main-axis remainder).
618    pub const FILL: f32 = -1.0;
619    /// Hug content (size to the intrinsic content).
620    pub const HUG_CONTENT: f32 = -2.0;
621}
622
623/// Semantic-role codes for the `ROLE` semantic property (`0x2001`).
624///
625/// Roles are protocol-semantic (carried as an `F32` enum code; see
626/// `spec/OPCODE.md` §semantic properties). The catalog is **semantic structure
627/// only** — interactive/control roles (button, link, checkbox, …) are NOT roles:
628/// they are intrinsic to the control components (a `BUTTON` renders as
629/// `<button>`, a `TOGGLE` as `<input type="checkbox">`, a `MENU` as
630/// `role="menu"`), and a custom-looking button is expressed with `Button` +
631/// `ButtonStyle`. The web renderer maps each semantic role onto its native
632/// element. Values MUST NOT be renumbered once released (wire version stays 1).
633pub mod role {
634    /// No semantic role (the default).
635    pub const NONE: u8 = 0;
636    /// A heading (ARIA `heading`; the HTML renderer uses `<hN>`, the level
637    /// driven by a `TEXT_STYLE` typography when present, default `<h2>`).
638    pub const HEADER: u8 = 1;
639    /// A paragraph (HTML `<p>`).
640    pub const PARAGRAPH: u8 = 2;
641    /// A list container (the HTML renderer uses `<ul>`).
642    pub const LIST: u8 = 3;
643    /// An item within a list (HTML `<li>`).
644    pub const LIST_ITEM: u8 = 4;
645    /// A summarising/complementary region (HTML `<section>`).
646    pub const SUMMARY: u8 = 5;
647    /// Site banner (HTML `<header>`).
648    pub const BANNER: u8 = 6;
649    /// Site navigation (HTML `<nav>`).
650    pub const NAVIGATION: u8 = 7;
651    /// The page's main content (HTML `<main>`).
652    pub const MAIN: u8 = 8;
653    /// Site footer / content info (HTML `<footer>`).
654    pub const CONTENT_INFO: u8 = 9;
655    /// Complementary/aside content (HTML `<aside>`).
656    pub const COMPLEMENTARY: u8 = 10;
657    /// A self-contained article (HTML `<article>`).
658    pub const ARTICLE: u8 = 11;
659    /// A thematically grouped section (HTML `<section>`).
660    pub const SECTION: u8 = 12;
661    /// A search region (HTML `<search>`).
662    pub const SEARCH: u8 = 13;
663}
664
665/// Predefined typography codes for the `TEXT_STYLE` property (see
666/// `spec/MODIFIERS.md`). Each value selects a whole typography from the design
667/// system (font size/weight/design). The **heading** styles (LargeTitle through
668/// Headline) imply a heading element when applied to a `TEXT`: the renderer
669/// emits `<h1>`–`<h5>` (the level comes from the style — no `ROLE` needed). The
670/// non-heading styles render as plain `<span>` text. A raw font modifier
671/// (`FONT_SIZE`, `FONT_WEIGHT`, `FONT_FAMILY`, …) never implies a heading — it
672/// only overrides the typography's visual.
673pub mod text_style {
674    /// The largest title style (heading level 1).
675    pub const LARGE_TITLE: u8 = 0;
676    /// A primary title (heading level 2).
677    pub const TITLE: u8 = 1;
678    /// A secondary title (heading level 3).
679    pub const TITLE2: u8 = 2;
680    /// A tertiary title (heading level 4).
681    pub const TITLE3: u8 = 3;
682    /// A headline (heading level 5).
683    pub const HEADLINE: u8 = 4;
684    /// A sub-headline (NOT a heading — plain `<span>` text).
685    pub const SUBHEADLINE: u8 = 5;
686    /// Body text (the default).
687    pub const BODY: u8 = 6;
688    /// A callout (slightly larger than body).
689    pub const CALLOUT: u8 = 7;
690    /// Footnote text.
691    pub const FOOTNOTE: u8 = 8;
692    /// Caption text.
693    pub const CAPTION: u8 = 9;
694    /// A second, smaller caption.
695    pub const CAPTION2: u8 = 10;
696}
697
698/// Canonical icon names (`ICON_NAME` values; spec/ICONS.md).
699///
700/// The spec is the **vocabulary contract only**: these names are the protocol
701/// `ICON_NAME` surface every renderer understands. The canonical-name →
702/// native-glyph mapping is **renderer-owned** (Adwaita on GTK, Remix filled on
703/// the web, SF Symbols on Apple) and lives in each renderer — never here, never
704/// in the spec.
705pub mod icon {
706    pub const HOME: &str = "home";
707    pub const SETTINGS: &str = "settings";
708    pub const SEARCH: &str = "search";
709    pub const MENU: &str = "menu";
710    pub const CLOSE: &str = "close";
711    pub const CLOUD: &str = "cloud";
712    pub const CHEVRON_LEFT: &str = "chevron-left";
713    pub const CHEVRON_RIGHT: &str = "chevron-right";
714    pub const CHEVRON_UP: &str = "chevron-up";
715    pub const CHEVRON_DOWN: &str = "chevron-down";
716    pub const ARROW_LEFT: &str = "arrow-left";
717    pub const ARROW_RIGHT: &str = "arrow-right";
718    pub const ADD: &str = "add";
719    pub const REMOVE: &str = "remove";
720    pub const CHECK: &str = "check";
721    pub const EDIT: &str = "edit";
722    pub const DELETE: &str = "delete";
723    pub const SAVE: &str = "save";
724    pub const SHARE: &str = "share";
725    pub const DOWNLOAD: &str = "download";
726    pub const UPLOAD: &str = "upload";
727    pub const REFRESH: &str = "refresh";
728    pub const PLAY: &str = "play";
729    pub const PAUSE: &str = "pause";
730    pub const STOP: &str = "stop";
731    pub const SKIP_BACK: &str = "skip-back";
732    pub const SKIP_FORWARD: &str = "skip-forward";
733    pub const VOLUME: &str = "volume";
734    pub const VOLUME_MUTE: &str = "volume-mute";
735    pub const SHUFFLE: &str = "shuffle";
736    pub const REPEAT: &str = "repeat";
737    pub const INFO: &str = "info";
738    pub const WARNING: &str = "warning";
739    pub const ERROR: &str = "error";
740    pub const SUCCESS: &str = "success";
741    pub const HEART: &str = "heart";
742    pub const STAR: &str = "star";
743    pub const USER: &str = "user";
744    pub const USERS: &str = "users";
745    pub const LOCK: &str = "lock";
746    pub const LOGOUT: &str = "logout";
747    pub const BELL: &str = "bell";
748    pub const FOLDER: &str = "folder";
749    pub const FILE: &str = "file";
750    pub const IMAGE: &str = "image";
751    pub const MUSIC: &str = "music";
752    pub const GRID: &str = "grid";
753    pub const LIST: &str = "list";
754    pub const FILTER: &str = "filter";
755
756    /// Every canonical name, in deterministic (spec, spec/ICONS.md) order.
757    pub const NAMES: &[&str] = &[
758        HOME, SETTINGS, SEARCH, MENU, CLOSE, CLOUD, CHEVRON_LEFT, CHEVRON_RIGHT,
759        CHEVRON_UP, CHEVRON_DOWN, ARROW_LEFT, ARROW_RIGHT, ADD, REMOVE, CHECK,
760        EDIT, DELETE, SAVE, SHARE, DOWNLOAD, UPLOAD, REFRESH, PLAY, PAUSE, STOP,
761        SKIP_BACK, SKIP_FORWARD, VOLUME, VOLUME_MUTE, SHUFFLE, REPEAT, INFO,
762        WARNING, ERROR, SUCCESS, HEART, STAR, USER, USERS, LOCK, LOGOUT, BELL,
763        FOLDER, FILE, IMAGE, MUSIC, GRID, LIST, FILTER,
764    ];
765
766    /// Whether `name` is a canonical `ICON_NAME` in the spec vocabulary.
767    pub fn is_canonical(name: &str) -> bool {
768        NAMES.contains(&name)
769    }
770}
771
772/// Sentinel for append positions (`index = u32::MAX`).
773pub const APPEND: u32 = u32::MAX;