@typecad/ui 1.0.0-alpha.13 → 1.0.0-alpha.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +1457 -1469
  2. package/dist/cli.js +22 -19
  3. package/dist/preview/host-ui-runtime.js +0 -1
  4. package/dist/ui-engine/model.js +7 -1
  5. package/dist/ui-engine/runtime-header/canvas-scrollbar.js +115 -115
  6. package/dist/ui-engine/runtime-header/dirty-scroll-mutators.js +182 -182
  7. package/dist/ui-engine/runtime-header/forward-decls.js +227 -216
  8. package/dist/ui-engine/runtime-header/init-press-input.js +138 -138
  9. package/dist/ui-engine/runtime-header/keyboard.js +676 -676
  10. package/dist/ui-engine/runtime-header/node-draw-body.js +1658 -1656
  11. package/dist/ui-engine/runtime-header/paint-order-coords.js +259 -259
  12. package/dist/ui-engine/runtime-header/paint-rects-repair.js +736 -736
  13. package/dist/ui-engine/runtime-header/scroll-physics.js +4 -4
  14. package/dist/ui-engine/runtime-header/structs.js +228 -228
  15. package/dist/ui-engine/runtime-header/text-rendering.js +888 -888
  16. package/dist/ui-engine/runtime-header/tick/bindings-phase.js +118 -118
  17. package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +896 -896
  18. package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.js +24 -24
  19. package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +11 -11
  20. package/dist/ui-engine/runtime-header/types-defines.js +110 -110
  21. package/dist/ui-engine/shadcn-kit.d.ts +1 -1
  22. package/dist/ui-engine/shadcn-kit.js +4 -0
  23. package/dist/ui-engine/ui-lowering.d.ts +1 -1
  24. package/dist/ui-engine/ui-lowering.js +14 -5
  25. package/dist/ui-engine/ui-registry.js +9 -1
  26. package/dist/wizard/display-catalog.d.ts +0 -3
  27. package/dist/wizard/display-catalog.js +3 -12
  28. package/dist/wizard/index.d.ts +2 -0
  29. package/dist/wizard/index.js +1 -0
  30. package/dist/wizard/integration-wizard.d.ts +3 -0
  31. package/dist/wizard/integration-wizard.js +69 -20
  32. package/dist/wizard/package-writer.d.ts +20 -0
  33. package/dist/wizard/package-writer.js +79 -0
  34. package/package.json +4 -4
  35. package/src/cli.ts +90 -87
  36. package/src/preview/host-ui-runtime.ts +0 -1
  37. package/src/ui-engine/model.ts +6 -1
  38. package/src/ui-engine/runtime-header/canvas-scrollbar.ts +121 -121
  39. package/src/ui-engine/runtime-header/dirty-scroll-mutators.ts +188 -188
  40. package/src/ui-engine/runtime-header/forward-decls.ts +238 -227
  41. package/src/ui-engine/runtime-header/init-press-input.ts +144 -144
  42. package/src/ui-engine/runtime-header/keyboard.ts +689 -689
  43. package/src/ui-engine/runtime-header/node-draw-body.ts +1683 -1681
  44. package/src/ui-engine/runtime-header/paint-order-coords.ts +265 -265
  45. package/src/ui-engine/runtime-header/paint-rects-repair.ts +742 -742
  46. package/src/ui-engine/runtime-header/scroll-physics.ts +4 -4
  47. package/src/ui-engine/runtime-header/structs.ts +234 -234
  48. package/src/ui-engine/runtime-header/text-rendering.ts +894 -894
  49. package/src/ui-engine/runtime-header/tick/bindings-phase.ts +124 -124
  50. package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +902 -902
  51. package/src/ui-engine/runtime-header/tick/scroll-canvas-phase.ts +30 -30
  52. package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +11 -11
  53. package/src/ui-engine/runtime-header/types-defines.ts +116 -116
  54. package/src/ui-engine/shadcn-kit.ts +4 -0
  55. package/src/ui-engine/ui-lowering.ts +12 -4
  56. package/src/ui-engine/ui-registry.ts +9 -1
  57. package/src/wizard/display-catalog.ts +261 -273
  58. package/src/wizard/index.ts +46 -38
  59. package/src/wizard/integration-wizard.ts +679 -619
  60. package/src/wizard/package-writer.ts +98 -0
@@ -116,7 +116,7 @@ static inline uint8_t ui_scroll_release(int16_t node) {
116
116
  __ui_nodes[node].settling = 1;
117
117
  __ui_settle_from_overscroll = __ui_nodes[node].overscrollPx;
118
118
  __ui_settle_from_scrollY = 0;
119
- __ui_settle_start_ms = millis();
119
+ __ui_settle_start_ms = __tc_now_ms();
120
120
  changed = 1;
121
121
  } else {
122
122
  int16_t sy = __ui_nodes[node].scrollY;
@@ -126,13 +126,13 @@ static inline uint8_t ui_scroll_release(int16_t node) {
126
126
  __ui_nodes[node].settling = 1;
127
127
  __ui_settle_from_scrollY = sy; // positive → snap toward 0
128
128
  __ui_settle_from_overscroll = 0;
129
- __ui_settle_start_ms = millis();
129
+ __ui_settle_start_ms = __tc_now_ms();
130
130
  changed = 1;
131
131
  } else if (maxS > 0 && sy < maxS && sy >= maxS - snap) {
132
132
  __ui_nodes[node].settling = 1;
133
133
  __ui_settle_from_scrollY = sy - maxS; // negative → snap toward max
134
134
  __ui_settle_from_overscroll = 0;
135
- __ui_settle_start_ms = millis();
135
+ __ui_settle_start_ms = __tc_now_ms();
136
136
  changed = 1;
137
137
  }
138
138
  }
@@ -151,7 +151,7 @@ static inline void ui_scroll_advance_settle(uint16_t node, uint16_t deltaMs) {
151
151
  __ui_nodes[node].settling = 0;
152
152
  return;
153
153
  }
154
- uint32_t elapsed = millis() - __ui_settle_start_ms;
154
+ uint32_t elapsed = __tc_now_ms() - __ui_settle_start_ms;
155
155
  uint16_t dur = static_cast<uint16_t>(UI_SCROLL_SETTLE_MS);
156
156
  // ease-out: k = 1 - (1 - t)^2, t in [0,1]
157
157
  uint32_t t = elapsed >= dur ? 100 : (elapsed * 100) / dur;
@@ -1,234 +1,234 @@
1
- // Slice of the C++ runtime header (original source lines 90-303).
2
- // Enums (UINodeKind, UIProperty) and all struct definitions + extern table decls.
3
- // See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
4
- export function emitStructs(): string {
5
- return `
6
- enum UINodeKind { NODE_FILL, NODE_TEXT, NODE_BUTTON, NODE_CHECK, NODE_RADIO, NODE_PROGRESS, NODE_RANGE, NODE_INPUT, NODE_IMG, NODE_LIST, NODE_CANVAS, NODE_SELECT };
7
- enum UIProperty { PROP_BG, PROP_FG, PROP_TEXT, PROP_VISIBLE, PROP_BORDER_COLOR, PROP_VALUE };
8
-
9
- struct UIRect { int16_t x, y, w, h; };
10
- struct UIFontGlyph {
11
- uint16_t codepoint;
12
- int8_t xOffset;
13
- int8_t yOffset;
14
- uint8_t width;
15
- uint8_t height;
16
- uint8_t advance;
17
- uint16_t dataOffset; // 4-bit alpha pixel offset
18
- };
19
- struct UIFontFace {
20
- uint8_t id;
21
- uint8_t glyphCount;
22
- uint8_t lineHeight;
23
- uint8_t baseline;
24
- const UIFontGlyph* glyphs;
25
- const uint8_t* alpha;
26
- };
27
- struct UINode {
28
- UIRect box;
29
- uint32_t bg;
30
- uint32_t fg;
31
- UINodeKind kind;
32
- const char* text;
33
- char textBuffer[UI_TEXT_BUF + 1]; // dynamic text — read only when hasTextBinding == 1
34
- uint8_t hasTextBinding; // set by ui_init when a PROP_TEXT binding targets this node
35
- const uint8_t* font;
36
- uint8_t hasBg;
37
- uint8_t textAlign; // 0=left, 1=center, 2=right
38
- uint8_t textSize; // GFX text size: 1-4
39
- uint8_t lineHeight; // px per text line (0 = font default)
40
- int8_t letterSpacing; // px between chars (0 = default advance)
41
- uint8_t fontAntialias; // 1 = smooth text edges when UI_AA is available
42
- uint8_t fontFace; // 0 = classic GFX bitmap font; otherwise UIFontFace id
43
- uint32_t borderColor; // resolved color for the border (0 = use fg)
44
- uint8_t borderStyle; // 0=none, 1=solid, 2=dashed
45
- uint8_t borderWidth; // px, 0=none (uniform fallback)
46
- uint8_t borderTopWidth; // per-side; equals borderWidth when uniform
47
- uint8_t borderRightWidth;
48
- uint8_t borderBottomWidth;
49
- uint8_t borderLeftWidth;
50
- uint8_t hasPerSideBorder; // 1 when any per-side width differs from borderWidth
51
- uint8_t borderRadius; // px, 0=square
52
- uint8_t paddingTop;
53
- uint8_t paddingRight;
54
- uint8_t paddingBottom;
55
- uint8_t paddingLeft;
56
- uint8_t gradientEnabled; // 0=none, 1=vertical, 2=horizontal
57
- uint32_t gradientColor1;
58
- uint32_t gradientColor2;
59
- uint32_t outlineColor;
60
- uint8_t outlineStyle; // 0=none, 1=solid, 2=dashed
61
- uint8_t outlineWidth;
62
- int16_t zIndex; // effective draw layer; higher layers draw later
63
- int16_t transformOffsetX; // draw-only transform: translate(...)
64
- int16_t transformOffsetY;
65
- int16_t rotateDeg;
66
- int8_t pressedOffsetX; // draw-only :pressed offset, no Yoga relayout
67
- int8_t pressedOffsetY;
68
- uint8_t shadowCount; // 0-4 active shadows
69
- int8_t shadowOffsetX[4];
70
- int8_t shadowOffsetY[4];
71
- uint8_t shadowBlur[4];
72
- uint32_t shadowColor[4];
73
- uint8_t shadowAlpha[4];
74
- uint8_t shadowInset[4]; // 0=outset, 1=inset
75
- uint8_t textShadowCount;
76
- int8_t textShadowOffsetX;
77
- int8_t textShadowOffsetY;
78
- uint8_t textShadowBlur;
79
- uint32_t textShadowColor;
80
- uint8_t textShadowAlpha;
81
- uint8_t underline; // text-decoration: 0=none,1=underline,2=line-through,3=both
82
- uint8_t textOverflow; // text-overflow: 0=clip, 1=ellipsis (truncate + ...)
83
- uint8_t nowrap; // 1 = no text wrapping (white-space: nowrap/pre)
84
- uint8_t whiteSpaceMode; // 0=normal, 1=nowrap, 2=pre, 3=pre-line
85
- uint8_t visible; // 0=hidden, 1=visible
86
- uint8_t opacity; // 0-100
87
- uint32_t clearColor; // ancestor's background — used to wipe transparent text before redraw
88
- int16_t lastTextWidth;
89
- int16_t lastTextHeight;
90
- uint32_t layoutCacheKey; // 0 = invalid; non-zero hashes layout inputs
91
- uint16_t layoutMetricsW; // cached ui_text_layout_metrics width
92
- uint16_t layoutMetricsH; // cached ui_text_layout_metrics height
93
- // scroll (unified: containers and virtualized lists share these)
94
- uint8_t scrollable; // 1 = children offset by scrollY, clipped to this box
95
- uint8_t virtualized; // 1 = children produced by list*Fn callbacks (<list>)
96
- int16_t scrollY; // committed offset (always in [0, maxScroll]); draw subtracts it
97
- int16_t contentHeight; // total child height (clamp bound + scrollbar ratio)
98
- int16_t overscrollPx; // elastic excursion past a boundary (0 in-bounds; +top, -bottom)
99
- uint8_t settling; // 1 while a bounce-back/snap animation runs
100
- int16_t lastPaintedScrollY; // scrollY at last container repaint (Mode B shift delta)
101
- uint16_t listCount; // virtualized: current item count (refreshed each frame)
102
- uint16_t (*listCountFn)(void);
103
- void (*listItemFn)(uint16_t idx, char* buf, uint8_t size);
104
- void (*listTapFn)(uint16_t idx); // nullptr if no tap handler
105
- uint16_t parent; // 0xFFFF = root/no parent (UI_NO_PARENT)
106
- uint16_t subtreeEnd; // exclusive pre-order end index
107
- uint8_t screenId; // which <screen> this node belongs to (for navigation)
108
- uint8_t imgDataId; // index into __ui_images[] (255 = no image)
109
- uint8_t objectFit; // 0=none, 1=fill, 2=contain, 3=cover, 4=scale-down
110
- uint16_t listItemHeight; // px per item for <list> (0 = not a list)
111
- int16_t rangeMin; // for <range>: minimum value
112
- int16_t rangeMax; // for <range>: maximum value
113
- int16_t maxlen; // for <input>: max character length (0 = UI_TEXT_BUF)
114
- uint16_t canvasW; // canvas buffer width (for <canvas>)
115
- uint16_t canvasH; // canvas buffer height (for <canvas>)
116
- // Rich-text runs (runCount > 0 for text nodes with mixed inline content).
117
- // The node references a contiguous slice of the global run / segment / line
118
- // arrays; geometry is precomputed at transpile time (runs are static-only).
119
- uint8_t runCount; // number of runs in this node (0 = plain single-string text)
120
- uint8_t richLineCount; // number of wrapped lines
121
- uint16_t runStart; // first index into __ui_runs[]
122
- uint16_t richSegStart; // first index into __ui_rich_segs[]
123
- uint16_t richSegCount; // total segments across all lines
124
- uint16_t richLineStart; // first index into __ui_rich_lines[]
125
- // runtime slot
126
- uint8_t dirty;
127
- int16_t value; // unified element
128
- uint8_t disabled; // HTML disabled attr: no taps/keyboard, dimmed draw state
129
- uint8_t optionCount; // <select>: number of options
130
- void (*optionTextFn)(uint8_t idx, char* buf, uint8_t size); // option text by index
131
- int8_t drawerSide; // <drawer>/<toast>: 0=bottom 1=top 2=left 3=right; 4=<dialog> center; -1 = none
132
- uint16_t toastDuration; // <toast duration>: ms before auto-close (0 = manual)
133
- uint32_t checkedBg; // :checked background (RGB565) — switch track / checkbox face / radio dot / select selected row
134
- uint32_t checkedFg; // :checked color (RGB565) — knob / checkmark / selected-row text
135
- uint8_t hasCheckedBg; // 1 when checkedBg was authored (0 = swap not wired)
136
- uint8_t hasCheckedFg; // 1 when checkedFg was authored
137
- int8_t flowAxis; // visibility reflow: 0 none, 1 column, 2 row (ui_reflow_visibility)
138
- uint8_t flowGap; // visibility reflow: main-axis gap between in-flow children
139
- uint8_t flowFlags; // bit0 auto height, bit1 auto width, bit2 out-of-flow
140
- };
141
- // Rich-text run: one piece of styled inline text within a node's run list.
142
- struct UIRichRun {
143
- const char* text;
144
- uint32_t fg;
145
- uint8_t textSize;
146
- uint8_t fontFace;
147
- uint8_t underline; // 0=none,1=underline,2=line-through,3=both
148
- int8_t letterSpacing;
149
- int8_t linkTarget; // resolved screen index, -1 = not a link
150
- };
151
- // One laid-out segment of a run on one line (precomputed geometry).
152
- struct UIRichSeg {
153
- uint8_t runIndex; // index into the node's runs (0..runCount-1)
154
- const char* text;
155
- int16_t x; // offset from the line's left edge (pre-alignment)
156
- uint16_t w; // measured width
157
- uint8_t line; // which line (0..richLineCount-1) this segment is on
158
- };
159
- // One wrapped line of rich text (precomputed).
160
- struct UIRichLine {
161
- int16_t y; // top y relative to the node's text top
162
- uint16_t h; // line height (tallest run on this line)
163
- int16_t baseline; // baseline y (for mixed-size baseline alignment)
164
- uint16_t w; // total line width (for alignment)
165
- };
166
- struct UITransition {
167
- uint16_t node;
168
- UIProperty prop;
169
- uint16_t durationMs;
170
- // The :pressed and base-state target colors. ui_on_press arms toward
171
- // pressedTarget; ui_on_release arms toward baseTarget.
172
- uint32_t pressedTarget;
173
- uint32_t baseTarget;
174
- // runtime
175
- uint32_t elapsed;
176
- uint32_t prevValue;
177
- uint32_t targetValue;
178
- uint8_t active;
179
- };
180
- struct UIBinding {
181
- uint16_t node;
182
- UIProperty prop;
183
- uint32_t (*fn)(void); // for color/numeric bindings
184
- void (*textFn)(char* buf, uint8_t size); // for text bindings (PROP_TEXT): fills buf
185
- uint32_t lastValue; // numeric binding cache; avoids redundant dirty work
186
- uint8_t initialized; // first evaluation establishes the baseline
187
- };
188
-
189
- // Color lerp for transitions (rgb565). For mono, this collapses to a snap.
190
- static inline uint16_t lerp_color(uint16_t a, uint16_t b, uint8_t k100) {
191
- if (k100 >= 100) return b;
192
- // Lerp in 888 internally for smoother color transitions (keyframe animation,
193
- // :pressed transitions). Unpack 565→888, lerp at 8-bit, re-quantize to 565.
194
- uint8_t ar5 = (a >> 11) & 0x1f, ag6 = (a >> 5) & 0x3f, ab5 = a & 0x1f;
195
- uint8_t br5 = (b >> 11) & 0x1f, bg6 = (b >> 5) & 0x3f, bb5 = b & 0x1f;
196
- uint16_t ar8 = (ar5 << 3) | (ar5 >> 2), ag8 = (ag6 << 2) | (ag6 >> 4), ab8 = (ab5 << 3) | (ab5 >> 2);
197
- uint16_t br8 = (br5 << 3) | (br5 >> 2), bg8 = (bg6 << 2) | (bg6 >> 4), bb8 = (bb5 << 3) | (bb5 >> 2);
198
- int16_t r = static_cast<int16_t>(ar8 + static_cast<int16_t>((br8 - ar8) * k100 / 100));
199
- int16_t g = static_cast<int16_t>(ag8 + static_cast<int16_t>((bg8 - ag8) * k100 / 100));
200
- int16_t bl = static_cast<int16_t>(ab8 + static_cast<int16_t>((bb8 - ab8) * k100 / 100));
201
- return (static_cast<uint16_t>((r >> 3) & 0x1f) << 11) | (static_cast<uint16_t>((g >> 2) & 0x3f) << 5) | static_cast<uint16_t>((bl >> 3) & 0x1f);
202
- }
203
-
204
- // RGB888 lerp — for transitions on RGB888/RGB666 targets (Phase 2+). Unused in
205
- // Phase 1; the 565 lerp_color above remains the active path for TFT targets,
206
- // whose node colors are still emitted as 565 values stored in uint32_t fields.
207
- static inline uint32_t lerp_color_888(uint32_t a, uint32_t b, uint8_t k100) {
208
- if (k100 >= 100) return b;
209
- uint8_t ar = (a >> 16) & 0xff, ag = (a >> 8) & 0xff, ab = a & 0xff;
210
- uint8_t br = (b >> 16) & 0xff, bg = (b >> 8) & 0xff, bb = b & 0xff;
211
- int16_t r = ar + static_cast<int16_t>((static_cast<int16_t>(br) - static_cast<int16_t>(ar)) * k100 / 100);
212
- int16_t g = ag + static_cast<int16_t>((static_cast<int16_t>(bg) - static_cast<int16_t>(ag)) * k100 / 100);
213
- int16_t bl = ab + static_cast<int16_t>((static_cast<int16_t>(bb) - static_cast<int16_t>(ab)) * k100 / 100);
214
- return (static_cast<uint32_t>(r & 0xff) << 16) | (static_cast<uint32_t>(g & 0xff) << 8) | static_cast<uint32_t>(bl & 0xff);
215
- }
216
-
217
- // Declared by the lowering output (the tables). Matches the mutable (non-const)
218
- // definitions: ui_tick updates node bg/dirty and transition elapsed/active.
219
- extern UINode __ui_nodes[];
220
- extern UITransition __ui_trans[];
221
- extern UIBinding __ui_bindings[];
222
- extern const UIFontFace __ui_font_faces[];
223
- // Rich-text run / segment / line tables (parallel arrays; nodes reference
224
- // contiguous slices via runStart/richSegStart/richLineStart + counts).
225
- extern UIRichRun __ui_runs[];
226
- extern UIRichSeg __ui_rich_segs[];
227
- extern UIRichLine __ui_rich_lines[];
228
- extern const uint16_t __ui_node_count;
229
- extern const uint16_t __ui_trans_count;
230
- extern const uint16_t __ui_binding_count;
231
- extern const uint16_t __ui_run_count;
232
- extern const uint16_t __ui_rich_seg_count;
233
- extern const uint16_t __ui_rich_line_count;`;
234
- }
1
+ // Slice of the C++ runtime header (original source lines 90-303).
2
+ // Enums (UINodeKind, UIProperty) and all struct definitions + extern table decls.
3
+ // See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
4
+ export function emitStructs(): string {
5
+ return `
6
+ enum UINodeKind { NODE_FILL, NODE_TEXT, NODE_BUTTON, NODE_CHECK, NODE_RADIO, NODE_PROGRESS, NODE_RANGE, NODE_INPUT, NODE_IMG, NODE_LIST, NODE_CANVAS, NODE_SELECT };
7
+ enum UIProperty { PROP_BG, PROP_FG, PROP_TEXT, PROP_VISIBLE, PROP_BORDER_COLOR, PROP_VALUE };
8
+
9
+ struct UIRect { int16_t x, y, w, h; };
10
+ struct UIFontGlyph {
11
+ uint16_t codepoint;
12
+ int8_t xOffset;
13
+ int8_t yOffset;
14
+ uint8_t width;
15
+ uint8_t height;
16
+ uint8_t advance;
17
+ uint16_t dataOffset; // 4-bit alpha pixel offset
18
+ };
19
+ struct UIFontFace {
20
+ uint8_t id;
21
+ uint8_t glyphCount;
22
+ uint8_t lineHeight;
23
+ uint8_t baseline;
24
+ const UIFontGlyph* glyphs;
25
+ const uint8_t* alpha;
26
+ };
27
+ struct UINode {
28
+ UIRect box;
29
+ uint32_t bg;
30
+ uint32_t fg;
31
+ UINodeKind kind;
32
+ const char* text;
33
+ char textBuffer[UI_TEXT_BUF + 1]; // dynamic text — read only when hasTextBinding == 1
34
+ uint8_t hasTextBinding; // set by ui_init when a PROP_TEXT binding targets this node
35
+ const uint8_t* font;
36
+ uint8_t hasBg;
37
+ uint8_t textAlign; // 0=left, 1=center, 2=right
38
+ uint8_t textSize; // GFX text size: 1-4
39
+ uint8_t lineHeight; // px per text line (0 = font default)
40
+ int8_t letterSpacing; // px between chars (0 = default advance)
41
+ uint8_t fontAntialias; // 1 = smooth text edges when UI_AA is available
42
+ uint8_t fontFace; // 0 = classic GFX bitmap font; otherwise UIFontFace id
43
+ uint32_t borderColor; // resolved color for the border (0 = use fg)
44
+ uint8_t borderStyle; // 0=none, 1=solid, 2=dashed
45
+ uint8_t borderWidth; // px, 0=none (uniform fallback)
46
+ uint8_t borderTopWidth; // per-side; equals borderWidth when uniform
47
+ uint8_t borderRightWidth;
48
+ uint8_t borderBottomWidth;
49
+ uint8_t borderLeftWidth;
50
+ uint8_t hasPerSideBorder; // 1 when any per-side width differs from borderWidth
51
+ uint8_t borderRadius; // px, 0=square
52
+ uint8_t paddingTop;
53
+ uint8_t paddingRight;
54
+ uint8_t paddingBottom;
55
+ uint8_t paddingLeft;
56
+ uint8_t gradientEnabled; // 0=none, 1=vertical, 2=horizontal
57
+ uint32_t gradientColor1;
58
+ uint32_t gradientColor2;
59
+ uint32_t outlineColor;
60
+ uint8_t outlineStyle; // 0=none, 1=solid, 2=dashed
61
+ uint8_t outlineWidth;
62
+ int16_t zIndex; // effective draw layer; higher layers draw later
63
+ int16_t transformOffsetX; // draw-only transform: translate(...)
64
+ int16_t transformOffsetY;
65
+ int16_t rotateDeg;
66
+ int8_t pressedOffsetX; // draw-only :pressed offset, no Yoga relayout
67
+ int8_t pressedOffsetY;
68
+ uint8_t shadowCount; // 0-4 active shadows
69
+ int8_t shadowOffsetX[4];
70
+ int8_t shadowOffsetY[4];
71
+ uint8_t shadowBlur[4];
72
+ uint32_t shadowColor[4];
73
+ uint8_t shadowAlpha[4];
74
+ uint8_t shadowInset[4]; // 0=outset, 1=inset
75
+ uint8_t textShadowCount;
76
+ int8_t textShadowOffsetX;
77
+ int8_t textShadowOffsetY;
78
+ uint8_t textShadowBlur;
79
+ uint32_t textShadowColor;
80
+ uint8_t textShadowAlpha;
81
+ uint8_t underline; // text-decoration: 0=none,1=underline,2=line-through,3=both
82
+ uint8_t textOverflow; // text-overflow: 0=clip, 1=ellipsis (truncate + ...)
83
+ uint8_t nowrap; // 1 = no text wrapping (white-space: nowrap/pre)
84
+ uint8_t whiteSpaceMode; // 0=normal, 1=nowrap, 2=pre, 3=pre-line
85
+ uint8_t visible; // 0=hidden, 1=visible
86
+ uint8_t opacity; // 0-100
87
+ uint32_t clearColor; // ancestor's background — used to wipe transparent text before redraw
88
+ int16_t lastTextWidth;
89
+ int16_t lastTextHeight;
90
+ uint32_t layoutCacheKey; // 0 = invalid; non-zero hashes layout inputs
91
+ uint16_t layoutMetricsW; // cached ui_text_layout_metrics width
92
+ uint16_t layoutMetricsH; // cached ui_text_layout_metrics height
93
+ // scroll (unified: containers and virtualized lists share these)
94
+ uint8_t scrollable; // 1 = children offset by scrollY, clipped to this box
95
+ uint8_t virtualized; // 1 = children produced by list*Fn callbacks (<list>)
96
+ int16_t scrollY; // committed offset (always in [0, maxScroll]); draw subtracts it
97
+ int16_t contentHeight; // total child height (clamp bound + scrollbar ratio)
98
+ int16_t overscrollPx; // elastic excursion past a boundary (0 in-bounds; +top, -bottom)
99
+ uint8_t settling; // 1 while a bounce-back/snap animation runs
100
+ int16_t lastPaintedScrollY; // scrollY at last container repaint (Mode B shift delta)
101
+ uint16_t listCount; // virtualized: current item count (refreshed each frame)
102
+ uint16_t (*listCountFn)(void);
103
+ void (*listItemFn)(uint16_t idx, char* buf, uint8_t size);
104
+ void (*listTapFn)(uint16_t idx); // nullptr if no tap handler
105
+ uint16_t parent; // 0xFFFF = root/no parent (UI_NO_PARENT)
106
+ uint16_t subtreeEnd; // exclusive pre-order end index
107
+ uint8_t screenId; // which <screen> this node belongs to (for navigation)
108
+ uint8_t imgDataId; // index into __ui_images[] (255 = no image)
109
+ uint8_t objectFit; // 0=none, 1=fill, 2=contain, 3=cover, 4=scale-down
110
+ uint16_t listItemHeight; // px per item for <list> (0 = not a list)
111
+ int16_t rangeMin; // for <range>: minimum value
112
+ int16_t rangeMax; // for <range>: maximum value
113
+ int16_t maxlen; // for <input>: max character length (0 = UI_TEXT_BUF)
114
+ uint16_t canvasW; // canvas buffer width (for <canvas>)
115
+ uint16_t canvasH; // canvas buffer height (for <canvas>)
116
+ // Rich-text runs (runCount > 0 for text nodes with mixed inline content).
117
+ // The node references a contiguous slice of the global run / segment / line
118
+ // arrays; geometry is precomputed at transpile time (runs are static-only).
119
+ uint8_t runCount; // number of runs in this node (0 = plain single-string text)
120
+ uint8_t richLineCount; // number of wrapped lines
121
+ uint16_t runStart; // first index into __ui_runs[]
122
+ uint16_t richSegStart; // first index into __ui_rich_segs[]
123
+ uint16_t richSegCount; // total segments across all lines
124
+ uint16_t richLineStart; // first index into __ui_rich_lines[]
125
+ // runtime slot
126
+ uint8_t dirty;
127
+ int16_t value; // unified element
128
+ uint8_t disabled; // HTML disabled attr: no taps/keyboard, dimmed draw state
129
+ uint8_t optionCount; // <select>: number of options
130
+ void (*optionTextFn)(uint8_t idx, char* buf, uint8_t size); // option text by index
131
+ int8_t drawerSide; // <drawer>/<toast>: 0=bottom 1=top 2=left 3=right; 4=<dialog> center; -1 = none
132
+ uint16_t toastDuration; // <toast duration>: ms before auto-close (0 = manual)
133
+ uint32_t checkedBg; // :checked background (RGB565) — switch track / checkbox face / radio dot / select selected row
134
+ uint32_t checkedFg; // :checked color (RGB565) — knob / checkmark / selected-row text
135
+ uint8_t hasCheckedBg; // 1 when checkedBg was authored (0 = swap not wired)
136
+ uint8_t hasCheckedFg; // 1 when checkedFg was authored
137
+ int8_t flowAxis; // visibility reflow: 0 none, 1 column, 2 row (ui_reflow_visibility)
138
+ uint8_t flowGap; // visibility reflow: main-axis gap between in-flow children
139
+ uint8_t flowFlags; // bit0 auto height, bit1 auto width, bit2 out-of-flow
140
+ };
141
+ // Rich-text run: one piece of styled inline text within a node's run list.
142
+ struct UIRichRun {
143
+ const char* text;
144
+ uint32_t fg;
145
+ uint8_t textSize;
146
+ uint8_t fontFace;
147
+ uint8_t underline; // 0=none,1=underline,2=line-through,3=both
148
+ int8_t letterSpacing;
149
+ int8_t linkTarget; // resolved screen index, -1 = not a link
150
+ };
151
+ // One laid-out segment of a run on one line (precomputed geometry).
152
+ struct UIRichSeg {
153
+ uint8_t runIndex; // index into the node's runs (0..runCount-1)
154
+ const char* text;
155
+ int16_t x; // offset from the line's left edge (pre-alignment)
156
+ uint16_t w; // measured width
157
+ uint8_t line; // which line (0..richLineCount-1) this segment is on
158
+ };
159
+ // One wrapped line of rich text (precomputed).
160
+ struct UIRichLine {
161
+ int16_t y; // top y relative to the node's text top
162
+ uint16_t h; // line height (tallest run on this line)
163
+ int16_t baseline; // baseline y (for mixed-size baseline alignment)
164
+ uint16_t w; // total line width (for alignment)
165
+ };
166
+ struct UITransition {
167
+ uint16_t node;
168
+ UIProperty prop;
169
+ uint16_t durationMs;
170
+ // The :pressed and base-state target colors. ui_on_press arms toward
171
+ // pressedTarget; ui_on_release arms toward baseTarget.
172
+ uint32_t pressedTarget;
173
+ uint32_t baseTarget;
174
+ // runtime
175
+ uint32_t elapsed;
176
+ uint32_t prevValue;
177
+ uint32_t targetValue;
178
+ uint8_t active;
179
+ };
180
+ struct UIBinding {
181
+ uint16_t node;
182
+ UIProperty prop;
183
+ uint32_t (*fn)(void); // for color/numeric bindings
184
+ void (*textFn)(char* buf, uint8_t size); // for text bindings (PROP_TEXT): fills buf
185
+ uint32_t lastValue; // numeric binding cache; avoids redundant dirty work
186
+ uint8_t initialized; // first evaluation establishes the baseline
187
+ };
188
+
189
+ // Color lerp for transitions (rgb565). For mono, this collapses to a snap.
190
+ static inline uint16_t lerp_color(uint16_t a, uint16_t b, uint8_t k100) {
191
+ if (k100 >= 100) return b;
192
+ // Lerp in 888 internally for smoother color transitions (keyframe animation,
193
+ // :pressed transitions). Unpack 565→888, lerp at 8-bit, re-quantize to 565.
194
+ uint8_t ar5 = (a >> 11) & 0x1f, ag6 = (a >> 5) & 0x3f, ab5 = a & 0x1f;
195
+ uint8_t br5 = (b >> 11) & 0x1f, bg6 = (b >> 5) & 0x3f, bb5 = b & 0x1f;
196
+ uint16_t ar8 = (ar5 << 3) | (ar5 >> 2), ag8 = (ag6 << 2) | (ag6 >> 4), ab8 = (ab5 << 3) | (ab5 >> 2);
197
+ uint16_t br8 = (br5 << 3) | (br5 >> 2), bg8 = (bg6 << 2) | (bg6 >> 4), bb8 = (bb5 << 3) | (bb5 >> 2);
198
+ int16_t r = static_cast<int16_t>(ar8 + static_cast<int16_t>((br8 - ar8) * k100 / 100));
199
+ int16_t g = static_cast<int16_t>(ag8 + static_cast<int16_t>((bg8 - ag8) * k100 / 100));
200
+ int16_t bl = static_cast<int16_t>(ab8 + static_cast<int16_t>((bb8 - ab8) * k100 / 100));
201
+ return (static_cast<uint16_t>((r >> 3) & 0x1f) << 11) | (static_cast<uint16_t>((g >> 2) & 0x3f) << 5) | static_cast<uint16_t>((bl >> 3) & 0x1f);
202
+ }
203
+
204
+ // RGB888 lerp — for transitions on RGB888/RGB666 targets (Phase 2+). Unused in
205
+ // Phase 1; the 565 lerp_color above remains the active path for TFT targets,
206
+ // whose node colors are still emitted as 565 values stored in uint32_t fields.
207
+ static inline uint32_t lerp_color_888(uint32_t a, uint32_t b, uint8_t k100) {
208
+ if (k100 >= 100) return b;
209
+ uint8_t ar = (a >> 16) & 0xff, ag = (a >> 8) & 0xff, ab = a & 0xff;
210
+ uint8_t br = (b >> 16) & 0xff, bg = (b >> 8) & 0xff, bb = b & 0xff;
211
+ int16_t r = ar + static_cast<int16_t>((static_cast<int16_t>(br) - static_cast<int16_t>(ar)) * k100 / 100);
212
+ int16_t g = ag + static_cast<int16_t>((static_cast<int16_t>(bg) - static_cast<int16_t>(ag)) * k100 / 100);
213
+ int16_t bl = ab + static_cast<int16_t>((static_cast<int16_t>(bb) - static_cast<int16_t>(ab)) * k100 / 100);
214
+ return (static_cast<uint32_t>(r & 0xff) << 16) | (static_cast<uint32_t>(g & 0xff) << 8) | static_cast<uint32_t>(bl & 0xff);
215
+ }
216
+
217
+ // Declared by the lowering output (the tables). Matches the mutable (non-const)
218
+ // definitions: ui_tick updates node bg/dirty and transition elapsed/active.
219
+ extern UINode __ui_nodes[];
220
+ extern UITransition __ui_trans[];
221
+ extern UIBinding __ui_bindings[];
222
+ extern const UIFontFace __ui_font_faces[];
223
+ // Rich-text run / segment / line tables (parallel arrays; nodes reference
224
+ // contiguous slices via runStart/richSegStart/richLineStart + counts).
225
+ extern UIRichRun __ui_runs[];
226
+ extern UIRichSeg __ui_rich_segs[];
227
+ extern UIRichLine __ui_rich_lines[];
228
+ extern const uint16_t __ui_node_count;
229
+ extern const uint16_t __ui_trans_count;
230
+ extern const uint16_t __ui_binding_count;
231
+ extern const uint16_t __ui_run_count;
232
+ extern const uint16_t __ui_rich_seg_count;
233
+ extern const uint16_t __ui_rich_line_count;`;
234
+ }