@typecad/ui 0.1.0-alpha.1
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.
- package/LICENSE +21 -0
- package/README.md +1443 -0
- package/dist/engine-index.d.ts +7 -0
- package/dist/engine-index.js +41 -0
- package/dist/index.d.ts +165 -0
- package/dist/index.js +42 -0
- package/dist/preview/build-program.d.ts +7 -0
- package/dist/preview/build-program.js +665 -0
- package/dist/preview/host-gfx.d.ts +90 -0
- package/dist/preview/host-gfx.js +552 -0
- package/dist/preview/host-ui-runtime.d.ts +241 -0
- package/dist/preview/host-ui-runtime.js +3236 -0
- package/dist/preview/types.d.ts +83 -0
- package/dist/preview/types.js +1 -0
- package/dist/types.d.ts +108 -0
- package/dist/types.js +10 -0
- package/dist/ui-engine/block-layout.d.ts +8 -0
- package/dist/ui-engine/block-layout.js +95 -0
- package/dist/ui-engine/color.d.ts +49 -0
- package/dist/ui-engine/color.js +273 -0
- package/dist/ui-engine/css-parser.d.ts +155 -0
- package/dist/ui-engine/css-parser.js +1058 -0
- package/dist/ui-engine/default-keyboards.d.ts +3 -0
- package/dist/ui-engine/default-keyboards.js +53 -0
- package/dist/ui-engine/easing.d.ts +12 -0
- package/dist/ui-engine/easing.js +76 -0
- package/dist/ui-engine/font-assets.d.ts +50 -0
- package/dist/ui-engine/font-assets.js +431 -0
- package/dist/ui-engine/html-parser.d.ts +116 -0
- package/dist/ui-engine/html-parser.js +284 -0
- package/dist/ui-engine/image-assets.d.ts +21 -0
- package/dist/ui-engine/image-assets.js +125 -0
- package/dist/ui-engine/inline-parser.d.ts +30 -0
- package/dist/ui-engine/inline-parser.js +66 -0
- package/dist/ui-engine/keyframes.d.ts +3 -0
- package/dist/ui-engine/keyframes.js +39 -0
- package/dist/ui-engine/layout-engine.d.ts +35 -0
- package/dist/ui-engine/layout-engine.js +203 -0
- package/dist/ui-engine/model.d.ts +239 -0
- package/dist/ui-engine/model.js +987 -0
- package/dist/ui-engine/rich-layout.d.ts +51 -0
- package/dist/ui-engine/rich-layout.js +220 -0
- package/dist/ui-engine/run-types.d.ts +13 -0
- package/dist/ui-engine/run-types.js +1 -0
- package/dist/ui-engine/runtime-header/antialiasing.d.ts +1 -0
- package/dist/ui-engine/runtime-header/antialiasing.js +141 -0
- package/dist/ui-engine/runtime-header/blend-bodies.d.ts +1 -0
- package/dist/ui-engine/runtime-header/blend-bodies.js +39 -0
- package/dist/ui-engine/runtime-header/canvas-helpers.d.ts +1 -0
- package/dist/ui-engine/runtime-header/canvas-helpers.js +155 -0
- package/dist/ui-engine/runtime-header/canvas-scrollbar.d.ts +1 -0
- package/dist/ui-engine/runtime-header/canvas-scrollbar.js +105 -0
- package/dist/ui-engine/runtime-header/color-mono-refresh.d.ts +1 -0
- package/dist/ui-engine/runtime-header/color-mono-refresh.js +154 -0
- package/dist/ui-engine/runtime-header/dirty-scroll-mutators.d.ts +1 -0
- package/dist/ui-engine/runtime-header/dirty-scroll-mutators.js +169 -0
- package/dist/ui-engine/runtime-header/display-shim.d.ts +1 -0
- package/dist/ui-engine/runtime-header/display-shim.js +104 -0
- package/dist/ui-engine/runtime-header/forward-decls.d.ts +1 -0
- package/dist/ui-engine/runtime-header/forward-decls.js +137 -0
- package/dist/ui-engine/runtime-header/guard-close.d.ts +1 -0
- package/dist/ui-engine/runtime-header/guard-close.js +8 -0
- package/dist/ui-engine/runtime-header/image-drawing.d.ts +1 -0
- package/dist/ui-engine/runtime-header/image-drawing.js +300 -0
- package/dist/ui-engine/runtime-header/init-press-input.d.ts +1 -0
- package/dist/ui-engine/runtime-header/init-press-input.js +126 -0
- package/dist/ui-engine/runtime-header/keyboard.d.ts +1 -0
- package/dist/ui-engine/runtime-header/keyboard.js +342 -0
- package/dist/ui-engine/runtime-header/node-decoration.d.ts +1 -0
- package/dist/ui-engine/runtime-header/node-decoration.js +212 -0
- package/dist/ui-engine/runtime-header/paint-order-coords.d.ts +1 -0
- package/dist/ui-engine/runtime-header/paint-order-coords.js +190 -0
- package/dist/ui-engine/runtime-header/paint-rects-repair.d.ts +1 -0
- package/dist/ui-engine/runtime-header/paint-rects-repair.js +553 -0
- package/dist/ui-engine/runtime-header/scroll-physics.d.ts +1 -0
- package/dist/ui-engine/runtime-header/scroll-physics.js +161 -0
- package/dist/ui-engine/runtime-header/state-bindings-nav.d.ts +1 -0
- package/dist/ui-engine/runtime-header/state-bindings-nav.js +176 -0
- package/dist/ui-engine/runtime-header/structs.d.ts +1 -0
- package/dist/ui-engine/runtime-header/structs.js +220 -0
- package/dist/ui-engine/runtime-header/text-rendering.d.ts +1 -0
- package/dist/ui-engine/runtime-header/text-rendering.js +715 -0
- package/dist/ui-engine/runtime-header/tick/bindings-phase.d.ts +1 -0
- package/dist/ui-engine/runtime-header/tick/bindings-phase.js +103 -0
- package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.d.ts +1 -0
- package/dist/ui-engine/runtime-header/tick/dirty-draw-phase.js +1051 -0
- package/dist/ui-engine/runtime-header/tick/flush-phase.d.ts +1 -0
- package/dist/ui-engine/runtime-header/tick/flush-phase.js +17 -0
- package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.d.ts +1 -0
- package/dist/ui-engine/runtime-header/tick/scroll-canvas-phase.js +15 -0
- package/dist/ui-engine/runtime-header/tick/transitions-phase.d.ts +1 -0
- package/dist/ui-engine/runtime-header/tick/transitions-phase.js +213 -0
- package/dist/ui-engine/runtime-header/tick-motion-helpers.d.ts +1 -0
- package/dist/ui-engine/runtime-header/tick-motion-helpers.js +26 -0
- package/dist/ui-engine/runtime-header/tick.d.ts +1 -0
- package/dist/ui-engine/runtime-header/tick.js +17 -0
- package/dist/ui-engine/runtime-header/touch-keyboard-fwd.d.ts +1 -0
- package/dist/ui-engine/runtime-header/touch-keyboard-fwd.js +406 -0
- package/dist/ui-engine/runtime-header/types-defines.d.ts +1 -0
- package/dist/ui-engine/runtime-header/types-defines.js +79 -0
- package/dist/ui-engine/runtime-header.d.ts +1 -0
- package/dist/ui-engine/runtime-header.js +69 -0
- package/dist/ui-engine/scroll-memory-diagnostics.d.ts +16 -0
- package/dist/ui-engine/scroll-memory-diagnostics.js +58 -0
- package/dist/ui-engine/select-engine.d.ts +4 -0
- package/dist/ui-engine/select-engine.js +19 -0
- package/dist/ui-engine/style-resolver.d.ts +77 -0
- package/dist/ui-engine/style-resolver.js +341 -0
- package/dist/ui-engine/text-layout.d.ts +19 -0
- package/dist/ui-engine/text-layout.js +92 -0
- package/dist/ui-engine/transpile-ui.d.ts +11 -0
- package/dist/ui-engine/transpile-ui.js +33 -0
- package/dist/ui-engine/ua-stylesheet.d.ts +3 -0
- package/dist/ui-engine/ua-stylesheet.js +56 -0
- package/dist/ui-engine/ui-file-splitter.d.ts +14 -0
- package/dist/ui-engine/ui-file-splitter.js +47 -0
- package/dist/ui-engine/ui-lowering.d.ts +33 -0
- package/dist/ui-engine/ui-lowering.js +390 -0
- package/dist/ui-engine/ui-registry.d.ts +81 -0
- package/dist/ui-engine/ui-registry.js +429 -0
- package/dist/ui-engine/yoga-layout.d.ts +12 -0
- package/dist/ui-engine/yoga-layout.js +314 -0
- package/package.json +86 -0
- package/src/engine-index.ts +51 -0
- package/src/index.ts +232 -0
- package/src/preview/build-program.ts +734 -0
- package/src/preview/host-gfx.ts +580 -0
- package/src/preview/host-ui-runtime.ts +3245 -0
- package/src/preview/types.ts +96 -0
- package/src/types.ts +127 -0
- package/src/ui-engine/block-layout.ts +104 -0
- package/src/ui-engine/color.ts +263 -0
- package/src/ui-engine/css-parser.ts +1003 -0
- package/src/ui-engine/default-keyboards.ts +58 -0
- package/src/ui-engine/easing.ts +53 -0
- package/src/ui-engine/font-assets.ts +512 -0
- package/src/ui-engine/html-parser.ts +397 -0
- package/src/ui-engine/image-assets.ts +170 -0
- package/src/ui-engine/inline-parser.ts +78 -0
- package/src/ui-engine/keyframes.ts +47 -0
- package/src/ui-engine/layout-engine.ts +228 -0
- package/src/ui-engine/model.ts +1225 -0
- package/src/ui-engine/rich-layout.ts +257 -0
- package/src/ui-engine/run-types.ts +14 -0
- package/src/ui-engine/runtime-header/antialiasing.ts +141 -0
- package/src/ui-engine/runtime-header/blend-bodies.ts +39 -0
- package/src/ui-engine/runtime-header/canvas-helpers.ts +155 -0
- package/src/ui-engine/runtime-header/canvas-scrollbar.ts +105 -0
- package/src/ui-engine/runtime-header/color-mono-refresh.ts +154 -0
- package/src/ui-engine/runtime-header/dirty-scroll-mutators.ts +169 -0
- package/src/ui-engine/runtime-header/display-shim.ts +104 -0
- package/src/ui-engine/runtime-header/forward-decls.ts +137 -0
- package/src/ui-engine/runtime-header/guard-close.ts +8 -0
- package/src/ui-engine/runtime-header/image-drawing.ts +300 -0
- package/src/ui-engine/runtime-header/init-press-input.ts +126 -0
- package/src/ui-engine/runtime-header/keyboard.ts +342 -0
- package/src/ui-engine/runtime-header/node-decoration.ts +212 -0
- package/src/ui-engine/runtime-header/paint-order-coords.ts +190 -0
- package/src/ui-engine/runtime-header/paint-rects-repair.ts +553 -0
- package/src/ui-engine/runtime-header/scroll-physics.ts +161 -0
- package/src/ui-engine/runtime-header/state-bindings-nav.ts +176 -0
- package/src/ui-engine/runtime-header/structs.ts +220 -0
- package/src/ui-engine/runtime-header/text-rendering.ts +715 -0
- package/src/ui-engine/runtime-header/tick/bindings-phase.ts +103 -0
- package/src/ui-engine/runtime-header/tick/dirty-draw-phase.ts +1051 -0
- package/src/ui-engine/runtime-header/tick/flush-phase.ts +17 -0
- package/src/ui-engine/runtime-header/tick/scroll-canvas-phase.ts +15 -0
- package/src/ui-engine/runtime-header/tick/transitions-phase.ts +213 -0
- package/src/ui-engine/runtime-header/tick-motion-helpers.ts +26 -0
- package/src/ui-engine/runtime-header/tick.ts +18 -0
- package/src/ui-engine/runtime-header/touch-keyboard-fwd.ts +406 -0
- package/src/ui-engine/runtime-header/types-defines.ts +79 -0
- package/src/ui-engine/runtime-header.ts +71 -0
- package/src/ui-engine/scroll-memory-diagnostics.ts +79 -0
- package/src/ui-engine/select-engine.ts +21 -0
- package/src/ui-engine/style-resolver.ts +416 -0
- package/src/ui-engine/text-layout.ts +114 -0
- package/src/ui-engine/transpile-ui.ts +45 -0
- package/src/ui-engine/ua-stylesheet.ts +60 -0
- package/src/ui-engine/ui-file-splitter.ts +59 -0
- package/src/ui-engine/ui-lowering.ts +459 -0
- package/src/ui-engine/ui-registry.ts +530 -0
- package/src/ui-engine/yoga-layout.ts +309 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Slice of the C++ runtime header (original source lines 5288-5298).
|
|
2
|
+
// Phase 4/5: fb bulk push + refresh flush + closing brace of ui_tick.
|
|
3
|
+
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
+
export function emitTickFlushPhase(): string {
|
|
5
|
+
return `
|
|
6
|
+
}
|
|
7
|
+
// ── Framebuffer bulk push ────────────────────────────────────────────────
|
|
8
|
+
// When a framebuffer was used this frame, flush it to the display in a single
|
|
9
|
+
// SPI transaction and restore the direct-draw target. No-op without one.
|
|
10
|
+
if (__ui_fb) {
|
|
11
|
+
ui_push_framebuffer();
|
|
12
|
+
}
|
|
13
|
+
ui_display_use_default_target();
|
|
14
|
+
// ③ Flush — ILI9341 is immediate, no separate flush needed. On deferred-
|
|
15
|
+
// refresh panels (e-ink), flush the union of this frame's dirty paint rects
|
|
16
|
+
// as one partial refresh. No-op on TFT.`;
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Slice of the C++ runtime header (original source lines 5279-5287).
|
|
2
|
+
// scrollbar + buffered scroll canvas push.
|
|
3
|
+
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
+
export function emitTickScrollCanvasPhase(): string {
|
|
5
|
+
return `
|
|
6
|
+
}
|
|
7
|
+
// ②b Draw scrollbar + push canvas for the buffered scroll container.
|
|
8
|
+
if (bufferedScrollNode >= 0 && bufferedScrollCanvas) {
|
|
9
|
+
ui_push_buffered_scroll_canvas(bufferedScrollCanvas, bufferedScrollRepaintCanvas,
|
|
10
|
+
bufferedScrollNode, bufferedScrollVX, bufferedScrollVY,
|
|
11
|
+
bufferedScrollRepaintY, bufferedScrollRepaintH, __ui_draw_target);
|
|
12
|
+
} else if (bufferedScrollNode >= 0 && bufferedScrollDirectStrip) {
|
|
13
|
+
ui_draw_scrollbar_direct(bufferedScrollNode, bufferedScrollVX, bufferedScrollVY);
|
|
14
|
+
__ui_nodes[bufferedScrollNode].lastPaintedScrollY = __ui_nodes[bufferedScrollNode].scrollY;`;
|
|
15
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// Slice of the C++ runtime header (original source lines 4027-4233).
|
|
2
|
+
// transitions + keyframes.
|
|
3
|
+
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
+
export function emitTickTransitionsPhase(): string {
|
|
5
|
+
return `
|
|
6
|
+
}
|
|
7
|
+
// ① Advance transitions.
|
|
8
|
+
for (uint16_t i = 0; i < __ui_trans_count; i++) {
|
|
9
|
+
if (!__ui_trans[i].active) continue;
|
|
10
|
+
__ui_trans[i].elapsed += deltaMs;
|
|
11
|
+
uint16_t k = __ui_trans[i].durationMs == 0
|
|
12
|
+
? 100
|
|
13
|
+
: (uint16_t)((uint32_t)__ui_trans[i].elapsed * 100 / __ui_trans[i].durationMs);
|
|
14
|
+
if (__ui_trans[i].durationMs > 0 && __ui_trans[i].durationMs <= UI_TRANSITION_SNAP_MS) k = 100;
|
|
15
|
+
uint32_t v = UI_LERP_COLOR(__ui_trans[i].prevValue, __ui_trans[i].targetValue, (uint8_t)k);
|
|
16
|
+
if (__ui_trans[i].prop == PROP_FG) {
|
|
17
|
+
__ui_nodes[__ui_trans[i].node].fg = v;
|
|
18
|
+
} else {
|
|
19
|
+
__ui_nodes[__ui_trans[i].node].bg = v;
|
|
20
|
+
}
|
|
21
|
+
ui_mark_dirty(__ui_trans[i].node);
|
|
22
|
+
if (k >= 100) __ui_trans[i].active = 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ①b Advance @keyframes animations.
|
|
26
|
+
uint8_t scrollMotionActive = ui_scroll_motion_active(settlingOnActiveScreen);
|
|
27
|
+
for (uint16_t i = 0; i < __ui_anim_count; i++) {
|
|
28
|
+
if (!__ui_anims[i].active) continue;
|
|
29
|
+
// Skip animations on non-visible screens OR hidden subtrees — their nodes
|
|
30
|
+
// are not drawn, so advancing them would paint stray fragments ("blotches")
|
|
31
|
+
// on the active screen. The screenId check handles multi-screen nav; the
|
|
32
|
+
// effective-visibility check handles master-detail panes (all on screen 0,
|
|
33
|
+
// but only one pane is visible at a time — the rest have visible=0 set by
|
|
34
|
+
// a ui.bind(..., 'visible', ...) binding). Without this, infinite animations
|
|
35
|
+
// on a hidden pane (e.g. the transforms dots) keep ticking, marking their
|
|
36
|
+
// nodes dirty, and repainting on top of the visible pane's content.
|
|
37
|
+
{
|
|
38
|
+
uint16_t animNode = __ui_anims[i].node;
|
|
39
|
+
if (animNode >= __ui_node_count) continue;
|
|
40
|
+
if (__ui_nodes[animNode].screenId != __ui_active_screen) continue;
|
|
41
|
+
if (!ui_is_effectively_visible(animNode)) continue;
|
|
42
|
+
}
|
|
43
|
+
if (scrollMotionActive &&
|
|
44
|
+
ui_keyframe_set_has_scroll_sensitive_geometry(__ui_anims[i].keyframeSet)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
__ui_anims[i].elapsed += (uint32_t)deltaMs;
|
|
48
|
+
uint32_t elapsedNoDelay = __ui_anims[i].elapsed;
|
|
49
|
+
if (elapsedNoDelay < __ui_anims[i].delayMs) continue;
|
|
50
|
+
elapsedNoDelay -= __ui_anims[i].delayMs;
|
|
51
|
+
// Check iteration limit (finite).
|
|
52
|
+
uint8_t completing = 0;
|
|
53
|
+
if (__ui_anims[i].iterations > 0) {
|
|
54
|
+
uint32_t totalDuration = (uint32_t)__ui_anims[i].iterations * (uint32_t)__ui_anims[i].durationMs;
|
|
55
|
+
if (elapsedNoDelay >= totalDuration) {
|
|
56
|
+
elapsedNoDelay = totalDuration;
|
|
57
|
+
completing = 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Compute cycle position: 0.0 - 1.0 within one loop.
|
|
61
|
+
uint8_t pct = 100;
|
|
62
|
+
if (!completing && __ui_anims[i].durationMs > 0) {
|
|
63
|
+
uint32_t cycleMs = elapsedNoDelay % __ui_anims[i].durationMs;
|
|
64
|
+
pct = (uint8_t)((uint32_t)cycleMs * 100 / __ui_anims[i].durationMs);
|
|
65
|
+
}
|
|
66
|
+
// Find surrounding keyframe stops.
|
|
67
|
+
if (__ui_anims[i].keyframeSet >= __ui_keyframe_set_count) continue;
|
|
68
|
+
const UIKeyframeSet* ks = &__ui_keyframe_sets[__ui_anims[i].keyframeSet];
|
|
69
|
+
if (ks->stopCount == 0) continue;
|
|
70
|
+
// Find the two stops that bracket pct.
|
|
71
|
+
uint8_t lo = 0, hi = ks->stopCount - 1;
|
|
72
|
+
for (uint8_t s = 0; s < ks->stopCount; s++) {
|
|
73
|
+
if (ks->stops[s].percent <= pct) lo = s;
|
|
74
|
+
if (ks->stops[s].percent >= pct) { hi = s; break; }
|
|
75
|
+
}
|
|
76
|
+
const UIKeyframeStop* sLo = &ks->stops[lo];
|
|
77
|
+
const UIKeyframeStop* sHi = &ks->stops[hi];
|
|
78
|
+
// Lerp factor between lo and hi.
|
|
79
|
+
uint8_t range = sHi->percent - sLo->percent;
|
|
80
|
+
uint8_t lerpK = range > 0 ? (uint8_t)((uint16_t)(pct - sLo->percent) * 100 / range) : 0;
|
|
81
|
+
// Shape the lerp by the animation's timing function (ease-in-out, etc.).
|
|
82
|
+
// CSS attaches it to the animation and applies it between stops.
|
|
83
|
+
lerpK = ui_ease_lerp_k(__ui_anims[i].timingFunction, lerpK);
|
|
84
|
+
// Apply to node — only mark dirty if a value actually changed.
|
|
85
|
+
uint16_t n = __ui_anims[i].node;
|
|
86
|
+
if (n >= __ui_node_count) continue;
|
|
87
|
+
uint8_t changed = 0;
|
|
88
|
+
if ((sLo->props & UI_KF_BG) && (sHi->props & UI_KF_BG)) {
|
|
89
|
+
uint32_t newBg = range > 0 ? UI_LERP_COLOR(sLo->bg, sHi->bg, lerpK) : sLo->bg;
|
|
90
|
+
if (newBg != __ui_nodes[n].bg) { __ui_nodes[n].bg = newBg; __ui_nodes[n].hasBg = 1; changed = 1; }
|
|
91
|
+
}
|
|
92
|
+
if ((sLo->props & UI_KF_FG) && (sHi->props & UI_KF_FG)) {
|
|
93
|
+
uint32_t newFg = range > 0 ? UI_LERP_COLOR(sLo->fg, sHi->fg, lerpK) : sLo->fg;
|
|
94
|
+
if (newFg != __ui_nodes[n].fg) { __ui_nodes[n].fg = newFg; changed = 1; }
|
|
95
|
+
}
|
|
96
|
+
if ((sLo->props & UI_KF_OPACITY) && (sHi->props & UI_KF_OPACITY)) {
|
|
97
|
+
uint8_t newOp = range > 0
|
|
98
|
+
? (uint8_t)((int16_t)sLo->opacity + ((int16_t)sHi->opacity - (int16_t)sLo->opacity) * lerpK / 100)
|
|
99
|
+
: sLo->opacity;
|
|
100
|
+
if (newOp != __ui_nodes[n].opacity) { __ui_nodes[n].opacity = newOp; changed = 1; }
|
|
101
|
+
}
|
|
102
|
+
int16_t nextTransformX = __ui_nodes[n].transformOffsetX;
|
|
103
|
+
int16_t nextTransformY = __ui_nodes[n].transformOffsetY;
|
|
104
|
+
int16_t nextRotateDeg = __ui_nodes[n].rotateDeg;
|
|
105
|
+
int16_t nextWidth = __ui_nodes[n].box.w;
|
|
106
|
+
int16_t nextHeight = __ui_nodes[n].box.h;
|
|
107
|
+
uint8_t geometryChanged = 0;
|
|
108
|
+
uint8_t hasSizeFrame = (sLo->props & UI_KF_SIZE) && (sHi->props & UI_KF_SIZE);
|
|
109
|
+
if (hasSizeFrame) {
|
|
110
|
+
nextWidth = range > 0
|
|
111
|
+
? (int16_t)((int32_t)sLo->width + ((int32_t)sHi->width - (int32_t)sLo->width) * lerpK / 100)
|
|
112
|
+
: sLo->width;
|
|
113
|
+
nextHeight = range > 0
|
|
114
|
+
? (int16_t)((int32_t)sLo->height + ((int32_t)sHi->height - (int32_t)sLo->height) * lerpK / 100)
|
|
115
|
+
: sLo->height;
|
|
116
|
+
if (nextWidth < 0) nextWidth = 0;
|
|
117
|
+
if (nextHeight < 0) nextHeight = 0;
|
|
118
|
+
if (nextWidth != __ui_nodes[n].box.w || nextHeight != __ui_nodes[n].box.h) {
|
|
119
|
+
changed = 1;
|
|
120
|
+
geometryChanged = 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if ((sLo->props & UI_KF_TRANSFORM) && (sHi->props & UI_KF_TRANSFORM)) {
|
|
124
|
+
int16_t pxX = range > 0
|
|
125
|
+
? (int16_t)((int32_t)sLo->transformOffsetX + ((int32_t)sHi->transformOffsetX - (int32_t)sLo->transformOffsetX) * lerpK / 100)
|
|
126
|
+
: sLo->transformOffsetX;
|
|
127
|
+
int16_t pxY = range > 0
|
|
128
|
+
? (int16_t)((int32_t)sLo->transformOffsetY + ((int32_t)sHi->transformOffsetY - (int32_t)sLo->transformOffsetY) * lerpK / 100)
|
|
129
|
+
: sLo->transformOffsetY;
|
|
130
|
+
int16_t pctX = range > 0
|
|
131
|
+
? (int16_t)((int32_t)sLo->translatePctX + ((int32_t)sHi->translatePctX - (int32_t)sLo->translatePctX) * lerpK / 100)
|
|
132
|
+
: sLo->translatePctX;
|
|
133
|
+
int16_t pctY = range > 0
|
|
134
|
+
? (int16_t)((int32_t)sLo->translatePctY + ((int32_t)sHi->translatePctY - (int32_t)sLo->translatePctY) * lerpK / 100)
|
|
135
|
+
: sLo->translatePctY;
|
|
136
|
+
int16_t scaleX = range > 0
|
|
137
|
+
? (int16_t)((int32_t)sLo->scaleX + ((int32_t)sHi->scaleX - (int32_t)sLo->scaleX) * lerpK / 100)
|
|
138
|
+
: sLo->scaleX;
|
|
139
|
+
int16_t scaleY = range > 0
|
|
140
|
+
? (int16_t)((int32_t)sLo->scaleY + ((int32_t)sHi->scaleY - (int32_t)sLo->scaleY) * lerpK / 100)
|
|
141
|
+
: sLo->scaleY;
|
|
142
|
+
nextRotateDeg = range > 0
|
|
143
|
+
? (int16_t)((int32_t)sLo->rotateDeg + ((int32_t)sHi->rotateDeg - (int32_t)sLo->rotateDeg) * lerpK / 100)
|
|
144
|
+
: sLo->rotateDeg;
|
|
145
|
+
if (scaleX < 0) scaleX = 0;
|
|
146
|
+
if (scaleY < 0) scaleY = 0;
|
|
147
|
+
int16_t refW = hasSizeFrame ? nextWidth : __ui_anims[i].baseWidth;
|
|
148
|
+
int16_t refH = hasSizeFrame ? nextHeight : __ui_anims[i].baseHeight;
|
|
149
|
+
if (refW <= 0) refW = __ui_nodes[n].box.w;
|
|
150
|
+
if (refH <= 0) refH = __ui_nodes[n].box.h;
|
|
151
|
+
int16_t originPxX = (int16_t)((int32_t)refW * __ui_anims[i].originX / 100);
|
|
152
|
+
int16_t originPxY = (int16_t)((int32_t)refH * __ui_anims[i].originY / 100);
|
|
153
|
+
int16_t scaledW = (int16_t)((int32_t)refW * scaleX / 100);
|
|
154
|
+
int16_t scaledH = (int16_t)((int32_t)refH * scaleY / 100);
|
|
155
|
+
int16_t scaleOffsetX = originPxX - (int16_t)((int32_t)originPxX * scaleX / 100);
|
|
156
|
+
int16_t scaleOffsetY = originPxY - (int16_t)((int32_t)originPxY * scaleY / 100);
|
|
157
|
+
nextTransformX = pxX + (int16_t)((int32_t)refW * pctX / 100) + scaleOffsetX;
|
|
158
|
+
nextTransformY = pxY + (int16_t)((int32_t)refH * pctY / 100) + scaleOffsetY;
|
|
159
|
+
nextWidth = scaledW < 0 ? 0 : scaledW;
|
|
160
|
+
nextHeight = scaledH < 0 ? 0 : scaledH;
|
|
161
|
+
if (nextTransformX != __ui_nodes[n].transformOffsetX ||
|
|
162
|
+
nextTransformY != __ui_nodes[n].transformOffsetY ||
|
|
163
|
+
nextRotateDeg != __ui_nodes[n].rotateDeg ||
|
|
164
|
+
nextWidth != __ui_nodes[n].box.w ||
|
|
165
|
+
nextHeight != __ui_nodes[n].box.h) {
|
|
166
|
+
changed = 1;
|
|
167
|
+
geometryChanged = 1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (changed) {
|
|
171
|
+
// Throttle color/opacity-only redraws to ~10fps to avoid ILI9341 tearing
|
|
172
|
+
// from rapid SPI writes (ada49b4). Spatial transforms (translate/scale/
|
|
173
|
+
// rotate/size) are exempt: at 10fps a small dot moving a few px reads as
|
|
174
|
+
// a jump, and the redraw is only the node's own tiny footprint, so the
|
|
175
|
+
// tearing risk that motivated the gate doesn't apply. Geometry redraws
|
|
176
|
+
// every frame a value actually changes (the 'changed' guard above still
|
|
177
|
+
// suppresses no-op repaints).
|
|
178
|
+
uint8_t throttleRedraw = !geometryChanged &&
|
|
179
|
+
!(completing || __ui_anims[i].elapsed - __ui_anims[i].lastUpdateMs >= 100);
|
|
180
|
+
if (!throttleRedraw) {
|
|
181
|
+
UIRect oldGeometryRect = {0, 0, 0, 0};
|
|
182
|
+
uint8_t hasOldGeometryRect = 0;
|
|
183
|
+
if (geometryChanged) {
|
|
184
|
+
ui_node_current_paint_rect(n, &oldGeometryRect);
|
|
185
|
+
hasOldGeometryRect = oldGeometryRect.w > 0 && oldGeometryRect.h > 0;
|
|
186
|
+
__ui_nodes[n].transformOffsetX = nextTransformX;
|
|
187
|
+
__ui_nodes[n].transformOffsetY = nextTransformY;
|
|
188
|
+
__ui_nodes[n].rotateDeg = nextRotateDeg;
|
|
189
|
+
__ui_nodes[n].box.w = nextWidth;
|
|
190
|
+
__ui_nodes[n].box.h = nextHeight;
|
|
191
|
+
ui_invalidate_text_layout_cache(n);
|
|
192
|
+
}
|
|
193
|
+
uint8_t repairedGeometry = 0;
|
|
194
|
+
if (geometryChanged && hasOldGeometryRect) {
|
|
195
|
+
// Small moving solid fills can be repaired as one old+new union
|
|
196
|
+
// bitmap. This avoids the visible erase-then-redraw blink that shows
|
|
197
|
+
// up when transform animations run at full frame rate on SPI TFTs.
|
|
198
|
+
repairedGeometry = ui_try_repair_geometry_fill(n, &oldGeometryRect);
|
|
199
|
+
}
|
|
200
|
+
if (geometryChanged && !repairedGeometry) {
|
|
201
|
+
// Fallback: preserve the old behavior, but clear the captured OLD
|
|
202
|
+
// footprint after the node fields have been updated.
|
|
203
|
+
if (hasOldGeometryRect) ui_clear_node_paint_rect(n, &oldGeometryRect);
|
|
204
|
+
else ui_clear_current_node_paint(n);
|
|
205
|
+
ui_invalidate_scroll_canvas_for_node(n);
|
|
206
|
+
}
|
|
207
|
+
if (!repairedGeometry) ui_mark_dirty(n);
|
|
208
|
+
__ui_anims[i].lastUpdateMs = __ui_anims[i].elapsed;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (completing) __ui_anims[i].active = 0;
|
|
212
|
+
}`;
|
|
213
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Slice of the C++ runtime header (original source lines 3910-3929).
|
|
2
|
+
// scroll_motion_active, keyframe_set_has_scroll_sensitive_geometry.
|
|
3
|
+
// See docs/superpowers/specs/2026-07-12-split-runtime-header-design.md.
|
|
4
|
+
export function emitTickMotionHelpers(): string {
|
|
5
|
+
return `
|
|
6
|
+
static inline uint8_t ui_scroll_motion_active(uint8_t settlingOnActiveScreen) {
|
|
7
|
+
if (__ui_scroll_node >= 0 && __ui_is_dragging) return 1;
|
|
8
|
+
return settlingOnActiveScreen;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
static inline uint8_t ui_keyframe_set_has_scroll_sensitive_geometry(uint8_t setIdx) {
|
|
12
|
+
if (setIdx >= __ui_keyframe_set_count) return 0;
|
|
13
|
+
const UIKeyframeSet* ks = &__ui_keyframe_sets[setIdx];
|
|
14
|
+
for (uint8_t s = 0; s < ks->stopCount; s++) {
|
|
15
|
+
if (ks->stops[s].props & (UI_KF_TRANSFORM | UI_KF_SIZE)) return 1;
|
|
16
|
+
}
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Per-frame driver. The host async/loop pump calls this each tick (~16ms).
|
|
21
|
+
// Phase -2: poll touch (if configured). Phase -1: poll input pins.
|
|
22
|
+
// Phase 0: evaluate bindings. Phase 1: transitions. Phase 2: draw.
|
|
23
|
+
// Forward decl: the keyboard overlay is defined below but drawn at the end.
|
|
24
|
+
// (ui_kb_draw and ui_kb_handle_tap forward declarations are near the touch
|
|
25
|
+
// state machine, above.)`;
|
|
26
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// ui_tick (original source lines 3930-5298) split into 5 contiguous phase slices.
|
|
2
|
+
// The phases tile 3930-5298 with no gaps; concatenation reproduces the original
|
|
3
|
+
// byte-for-byte. No wrapper logic — just ordered concatenation.
|
|
4
|
+
import { emitTickBindingsPhase } from "./tick/bindings-phase.js";
|
|
5
|
+
import { emitTickTransitionsPhase } from "./tick/transitions-phase.js";
|
|
6
|
+
import { emitTickDirtyDrawPhase } from "./tick/dirty-draw-phase.js";
|
|
7
|
+
import { emitTickScrollCanvasPhase } from "./tick/scroll-canvas-phase.js";
|
|
8
|
+
import { emitTickFlushPhase } from "./tick/flush-phase.js";
|
|
9
|
+
|
|
10
|
+
export function emitTick(): string {
|
|
11
|
+
return [
|
|
12
|
+
emitTickBindingsPhase(),
|
|
13
|
+
emitTickTransitionsPhase(),
|
|
14
|
+
emitTickDirtyDrawPhase(),
|
|
15
|
+
emitTickScrollCanvasPhase(),
|
|
16
|
+
emitTickFlushPhase(),
|
|
17
|
+
].join("");
|
|
18
|
+
}
|