@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
@@ -2,123 +2,123 @@
2
2
  // ui_tick signature + opening, caret blink re-mark, bindings/list-bindings/input-bindings. Contains ui_tick opening.
3
3
  // See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
4
4
  export function emitTickBindingsPhase() {
5
- return `
6
- static inline void ui_tick(uint16_t deltaMs) {
7
- // Touch poll — runs if touch is configured (defined by the emit layer)
8
- ui_poll_touch();
9
- // <drawer> slide animation (device parity with the preview's applyDrawers).
10
- ui_drawer_tick(deltaMs);
11
- // Allocate the retained framebuffer before transitions run. Geometry repair
12
- // must clear old animation footprints into RAM, not directly onto the panel.
13
- (void)ui_get_framebuffer();
14
- // ⓪' Poll GPIO inputs
15
- ui_poll_inputs();
16
- #if defined(UI_HIDE_OSK)
17
- // Advance the caret blink phase for the active input (desktop target).
18
- __ui_kb_blink++;
19
- // Re-mark the edited input dirty every ~16 ticks so the blink repainting
20
- // keeps cycling even when no other state changes (otherwise the caret
21
- // freezes once the typed-text dirty clears).
22
- if (__ui_kb_visible && __ui_kb_target >= 0 && (__ui_kb_blink & 0x10)) {
23
- ui_mark_dirty(static_cast<uint16_t>(__ui_kb_target));
24
- }
25
- #endif
26
- // ⓪ Evaluate bindings: call each binding's fn, compare to the node's
27
- // current property value, mark dirty if changed.
28
- for (uint16_t i = 0; i < __ui_binding_count; i++) {
29
- if (__ui_bindings[i].prop == PROP_TEXT && __ui_bindings[i].textFn) {
30
- // Text callbacks are necessarily evaluated to detect changes (the callback
31
- // may format a signal or read external state), but avoid a stack-sized old
32
- // copy: compare the generated value against the node buffer after writing.
33
- // The callback contract is fill-style and must be deterministic for the same
34
- // inputs; the temporary buffer keeps a change from destroying the old text.
35
- uint16_t n = __ui_bindings[i].node;
36
- if (n >= __ui_node_count) continue;
37
- char nextBuf[UI_TEXT_BUF + 1];
38
- nextBuf[0] = '\\0';
39
- __ui_bindings[i].textFn(nextBuf, UI_TEXT_BUF + 1);
40
- nextBuf[UI_TEXT_BUF] = '\\0';
41
- if (strcmp(nextBuf, __ui_nodes[n].textBuffer) != 0) {
42
- strncpy(__ui_nodes[n].textBuffer, nextBuf, UI_TEXT_BUF);
43
- __ui_nodes[n].textBuffer[UI_TEXT_BUF] = '\\0';
44
- ui_invalidate_text_layout_cache(n);
45
- ui_mark_dirty(n);
46
- }
47
- } else if (__ui_bindings[i].fn) {
48
- // Color/numeric binding
49
- uint32_t newVal = __ui_bindings[i].fn();
50
- if (__ui_bindings[i].prop == PROP_VISIBLE) {
51
- uint8_t nextVisible = newVal ? 1 : 0;
52
- if (nextVisible != __ui_nodes[__ui_bindings[i].node].visible) {
53
- ui_set_visible(__ui_bindings[i].node, nextVisible);
54
- }
55
- continue;
56
- }
57
- if (__ui_bindings[i].prop == PROP_VALUE) {
58
- // Numeric value binding: drive a progress/range node's value live.
59
- uint16_t n = __ui_bindings[i].node;
60
- int16_t v = static_cast<int16_t>(__ui_bindings[i].fn());
61
- if (v != __ui_nodes[n].value) {
62
- __ui_nodes[n].value = v;
63
- ui_mark_dirty(n);
64
- }
65
- continue;
66
- }
67
- // Cache numeric binding results. The first sample establishes the baseline;
68
- // subsequent identical values return immediately without touching node state.
69
- if (__ui_bindings[i].initialized && newVal == __ui_bindings[i].lastValue) continue;
70
- __ui_bindings[i].lastValue = newVal;
71
- __ui_bindings[i].initialized = 1;
72
- uint32_t* target = (__ui_bindings[i].prop == PROP_BG) ? &__ui_nodes[__ui_bindings[i].node].bg
73
- : (__ui_bindings[i].prop == PROP_FG) ? &__ui_nodes[__ui_bindings[i].node].fg
74
- : (__ui_bindings[i].prop == PROP_BORDER_COLOR) ? &__ui_nodes[__ui_bindings[i].node].borderColor
75
- : &__ui_nodes[__ui_bindings[i].node].bg;
76
- if (newVal != *target) {
77
- *target = newVal;
78
- // When a background binding writes a new color, ensure hasBg is set
79
- // so the draw dispatch actually fills (the node may have started
80
- // transparent but now has a runtime-assigned background).
81
- if (__ui_bindings[i].prop == PROP_BG) __ui_nodes[__ui_bindings[i].node].hasBg = 1;
82
- ui_mark_dirty(__ui_bindings[i].node);
83
- }
84
- }
85
- }
86
- // ⓪b Evaluate list bindings (on-node): refresh item count, recompute content
87
- // height, and advance any in-flight settle animation (bounce-back / edge-snap).
88
- // Also note whether any active-screen node is settling (feeds scroll-motion
89
- // gating below without a second full-node scan).
90
- uint8_t settlingOnActiveScreen = 0;
91
- for (uint16_t i = 0; i < __ui_node_count; i++) {
92
- if (__ui_nodes[i].virtualized && __ui_nodes[i].listCountFn) {
93
- uint16_t ih = __ui_nodes[i].listItemHeight > 0 ? __ui_nodes[i].listItemHeight : 24;
94
- // Keep the callback result as the list's invalidation token. The callback
95
- // is still evaluated because it is the public list-count source, but an
96
- // unchanged token avoids layout/dirty work and preserves the retained
97
- // viewport canvas.
98
- uint16_t newCount = __ui_nodes[i].listCountFn();
99
- if (newCount != __ui_nodes[i].listCount) {
100
- __ui_nodes[i].listCount = newCount;
101
- __ui_nodes[i].contentHeight = static_cast<int16_t>(static_cast<uint32_t>(newCount) * ih);
102
- __ui_nodes[i].lastPaintedScrollY = __ui_nodes[i].scrollY - (__ui_nodes[i].box.h > 0 ? __ui_nodes[i].box.h : 1);
103
- ui_mark_dirty(i);
104
- }
105
- }
106
- if (__ui_nodes[i].settling) {
107
- if (__ui_nodes[i].screenId == __ui_active_screen) settlingOnActiveScreen = 1;
108
- ui_scroll_advance_settle(i, deltaMs);
109
- }
110
- }
111
- // ⓪c Evaluate input bindings (two-way): if a bound <input>'s textBuffer
112
- // changed since last tick (e.g. the user typed via the on-screen keyboard),
113
- // fire the author's callback with the new text.
114
- for (uint16_t i = 0; i < __ui_input_binding_count; i++) {
115
- if (!__ui_input_bindings[i].cb) continue;
116
- uint16_t n = __ui_input_bindings[i].node;
117
- if (n >= __ui_node_count) continue;
118
- const char* cur = __ui_nodes[n].textBuffer;
119
- if (strcmp(cur, __ui_input_bindings[i].lastSeen) != 0) {
120
- strncpy(__ui_input_bindings[i].lastSeen, cur, UI_TEXT_BUF);
121
- __ui_input_bindings[i].lastSeen[UI_TEXT_BUF] = '\\0';
122
- __ui_input_bindings[i].cb(cur);
5
+ return `
6
+ static inline void ui_tick(uint16_t deltaMs) {
7
+ // Touch poll — runs if touch is configured (defined by the emit layer)
8
+ ui_poll_touch();
9
+ // <drawer> slide animation (device parity with the preview's applyDrawers).
10
+ ui_drawer_tick(deltaMs);
11
+ // Allocate the retained framebuffer before transitions run. Geometry repair
12
+ // must clear old animation footprints into RAM, not directly onto the panel.
13
+ (void)ui_get_framebuffer();
14
+ // ⓪' Poll GPIO inputs
15
+ ui_poll_inputs();
16
+ #if defined(UI_HIDE_OSK)
17
+ // Advance the caret blink phase for the active input (desktop target).
18
+ __ui_kb_blink++;
19
+ // Re-mark the edited input dirty every ~16 ticks so the blink repainting
20
+ // keeps cycling even when no other state changes (otherwise the caret
21
+ // freezes once the typed-text dirty clears).
22
+ if (__ui_kb_visible && __ui_kb_target >= 0 && (__ui_kb_blink & 0x10)) {
23
+ ui_mark_dirty(static_cast<uint16_t>(__ui_kb_target));
24
+ }
25
+ #endif
26
+ // ⓪ Evaluate bindings: call each binding's fn, compare to the node's
27
+ // current property value, mark dirty if changed.
28
+ for (uint16_t i = 0; i < __ui_binding_count; i++) {
29
+ if (__ui_bindings[i].prop == PROP_TEXT && __ui_bindings[i].textFn) {
30
+ // Text callbacks are necessarily evaluated to detect changes (the callback
31
+ // may format a signal or read external state), but avoid a stack-sized old
32
+ // copy: compare the generated value against the node buffer after writing.
33
+ // The callback contract is fill-style and must be deterministic for the same
34
+ // inputs; the temporary buffer keeps a change from destroying the old text.
35
+ uint16_t n = __ui_bindings[i].node;
36
+ if (n >= __ui_node_count) continue;
37
+ char nextBuf[UI_TEXT_BUF + 1];
38
+ nextBuf[0] = '\\0';
39
+ __ui_bindings[i].textFn(nextBuf, UI_TEXT_BUF + 1);
40
+ nextBuf[UI_TEXT_BUF] = '\\0';
41
+ if (strcmp(nextBuf, __ui_nodes[n].textBuffer) != 0) {
42
+ strncpy(__ui_nodes[n].textBuffer, nextBuf, UI_TEXT_BUF);
43
+ __ui_nodes[n].textBuffer[UI_TEXT_BUF] = '\\0';
44
+ ui_invalidate_text_layout_cache(n);
45
+ ui_mark_dirty(n);
46
+ }
47
+ } else if (__ui_bindings[i].fn) {
48
+ // Color/numeric binding
49
+ uint32_t newVal = __ui_bindings[i].fn();
50
+ if (__ui_bindings[i].prop == PROP_VISIBLE) {
51
+ uint8_t nextVisible = newVal ? 1 : 0;
52
+ if (nextVisible != __ui_nodes[__ui_bindings[i].node].visible) {
53
+ ui_set_visible(__ui_bindings[i].node, nextVisible);
54
+ }
55
+ continue;
56
+ }
57
+ if (__ui_bindings[i].prop == PROP_VALUE) {
58
+ // Numeric value binding: drive a progress/range node's value live.
59
+ uint16_t n = __ui_bindings[i].node;
60
+ int16_t v = static_cast<int16_t>(__ui_bindings[i].fn());
61
+ if (v != __ui_nodes[n].value) {
62
+ __ui_nodes[n].value = v;
63
+ ui_mark_dirty(n);
64
+ }
65
+ continue;
66
+ }
67
+ // Cache numeric binding results. The first sample establishes the baseline;
68
+ // subsequent identical values return immediately without touching node state.
69
+ if (__ui_bindings[i].initialized && newVal == __ui_bindings[i].lastValue) continue;
70
+ __ui_bindings[i].lastValue = newVal;
71
+ __ui_bindings[i].initialized = 1;
72
+ uint32_t* target = (__ui_bindings[i].prop == PROP_BG) ? &__ui_nodes[__ui_bindings[i].node].bg
73
+ : (__ui_bindings[i].prop == PROP_FG) ? &__ui_nodes[__ui_bindings[i].node].fg
74
+ : (__ui_bindings[i].prop == PROP_BORDER_COLOR) ? &__ui_nodes[__ui_bindings[i].node].borderColor
75
+ : &__ui_nodes[__ui_bindings[i].node].bg;
76
+ if (newVal != *target) {
77
+ *target = newVal;
78
+ // When a background binding writes a new color, ensure hasBg is set
79
+ // so the draw dispatch actually fills (the node may have started
80
+ // transparent but now has a runtime-assigned background).
81
+ if (__ui_bindings[i].prop == PROP_BG) __ui_nodes[__ui_bindings[i].node].hasBg = 1;
82
+ ui_mark_dirty(__ui_bindings[i].node);
83
+ }
84
+ }
85
+ }
86
+ // ⓪b Evaluate list bindings (on-node): refresh item count, recompute content
87
+ // height, and advance any in-flight settle animation (bounce-back / edge-snap).
88
+ // Also note whether any active-screen node is settling (feeds scroll-motion
89
+ // gating below without a second full-node scan).
90
+ uint8_t settlingOnActiveScreen = 0;
91
+ for (uint16_t i = 0; i < __ui_node_count; i++) {
92
+ if (__ui_nodes[i].virtualized && __ui_nodes[i].listCountFn) {
93
+ uint16_t ih = __ui_nodes[i].listItemHeight > 0 ? __ui_nodes[i].listItemHeight : 24;
94
+ // Keep the callback result as the list's invalidation token. The callback
95
+ // is still evaluated because it is the public list-count source, but an
96
+ // unchanged token avoids layout/dirty work and preserves the retained
97
+ // viewport canvas.
98
+ uint16_t newCount = __ui_nodes[i].listCountFn();
99
+ if (newCount != __ui_nodes[i].listCount) {
100
+ __ui_nodes[i].listCount = newCount;
101
+ __ui_nodes[i].contentHeight = static_cast<int16_t>(static_cast<uint32_t>(newCount) * ih);
102
+ __ui_nodes[i].lastPaintedScrollY = __ui_nodes[i].scrollY - (__ui_nodes[i].box.h > 0 ? __ui_nodes[i].box.h : 1);
103
+ ui_mark_dirty(i);
104
+ }
105
+ }
106
+ if (__ui_nodes[i].settling) {
107
+ if (__ui_nodes[i].screenId == __ui_active_screen) settlingOnActiveScreen = 1;
108
+ ui_scroll_advance_settle(i, deltaMs);
109
+ }
110
+ }
111
+ // ⓪c Evaluate input bindings (two-way): if a bound <input>'s textBuffer
112
+ // changed since last tick (e.g. the user typed via the on-screen keyboard),
113
+ // fire the author's callback with the new text.
114
+ for (uint16_t i = 0; i < __ui_input_binding_count; i++) {
115
+ if (!__ui_input_bindings[i].cb) continue;
116
+ uint16_t n = __ui_input_bindings[i].node;
117
+ if (n >= __ui_node_count) continue;
118
+ const char* cur = __ui_nodes[n].textBuffer;
119
+ if (strcmp(cur, __ui_input_bindings[i].lastSeen) != 0) {
120
+ strncpy(__ui_input_bindings[i].lastSeen, cur, UI_TEXT_BUF);
121
+ __ui_input_bindings[i].lastSeen[UI_TEXT_BUF] = '\\0';
122
+ __ui_input_bindings[i].cb(cur);
123
123
  }`;
124
124
  }