@flyingrobots/bijou-tui 4.4.1 → 7.0.0

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 (203) hide show
  1. package/README.md +244 -21
  2. package/dist/animate.d.ts +4 -0
  3. package/dist/animate.d.ts.map +1 -1
  4. package/dist/animate.js +47 -20
  5. package/dist/animate.js.map +1 -1
  6. package/dist/app-frame-actions.d.ts.map +1 -1
  7. package/dist/app-frame-actions.js +55 -0
  8. package/dist/app-frame-actions.js.map +1 -1
  9. package/dist/app-frame-i18n.d.ts.map +1 -1
  10. package/dist/app-frame-i18n.js +51 -0
  11. package/dist/app-frame-i18n.js.map +1 -1
  12. package/dist/app-frame-layers.d.ts +11 -1
  13. package/dist/app-frame-layers.d.ts.map +1 -1
  14. package/dist/app-frame-layers.js +19 -0
  15. package/dist/app-frame-layers.js.map +1 -1
  16. package/dist/app-frame-overlays.d.ts +82 -0
  17. package/dist/app-frame-overlays.d.ts.map +1 -0
  18. package/dist/app-frame-overlays.js +480 -0
  19. package/dist/app-frame-overlays.js.map +1 -0
  20. package/dist/app-frame-palette.d.ts.map +1 -1
  21. package/dist/app-frame-palette.js +36 -16
  22. package/dist/app-frame-palette.js.map +1 -1
  23. package/dist/app-frame-render.d.ts.map +1 -1
  24. package/dist/app-frame-render.js +16 -7
  25. package/dist/app-frame-render.js.map +1 -1
  26. package/dist/app-frame-types.d.ts +141 -5
  27. package/dist/app-frame-types.d.ts.map +1 -1
  28. package/dist/app-frame-types.js +17 -1
  29. package/dist/app-frame-types.js.map +1 -1
  30. package/dist/app-frame-utils.d.ts +3 -1
  31. package/dist/app-frame-utils.d.ts.map +1 -1
  32. package/dist/app-frame-utils.js +11 -5
  33. package/dist/app-frame-utils.js.map +1 -1
  34. package/dist/app-frame.d.ts +22 -86
  35. package/dist/app-frame.d.ts.map +1 -1
  36. package/dist/app-frame.js +475 -629
  37. package/dist/app-frame.js.map +1 -1
  38. package/dist/browsable-list.d.ts +12 -0
  39. package/dist/browsable-list.d.ts.map +1 -1
  40. package/dist/browsable-list.js +17 -6
  41. package/dist/browsable-list.js.map +1 -1
  42. package/dist/canvas.d.ts +11 -3
  43. package/dist/canvas.d.ts.map +1 -1
  44. package/dist/canvas.js +146 -13
  45. package/dist/canvas.js.map +1 -1
  46. package/dist/cell-glyph-fit.d.ts +20 -0
  47. package/dist/cell-glyph-fit.d.ts.map +1 -0
  48. package/dist/cell-glyph-fit.js +82 -0
  49. package/dist/cell-glyph-fit.js.map +1 -0
  50. package/dist/collection-surface.d.ts +8 -0
  51. package/dist/collection-surface.d.ts.map +1 -1
  52. package/dist/collection-surface.js +72 -8
  53. package/dist/collection-surface.js.map +1 -1
  54. package/dist/command-palette.d.ts +2 -0
  55. package/dist/command-palette.d.ts.map +1 -1
  56. package/dist/command-palette.js +36 -19
  57. package/dist/command-palette.js.map +1 -1
  58. package/dist/css/text-style.d.ts +2 -0
  59. package/dist/css/text-style.d.ts.map +1 -1
  60. package/dist/css/text-style.js +18 -8
  61. package/dist/css/text-style.js.map +1 -1
  62. package/dist/debug-overlay.d.ts +19 -0
  63. package/dist/debug-overlay.d.ts.map +1 -0
  64. package/dist/debug-overlay.js +25 -0
  65. package/dist/debug-overlay.js.map +1 -0
  66. package/dist/design-language.d.ts.map +1 -1
  67. package/dist/design-language.js +4 -5
  68. package/dist/design-language.js.map +1 -1
  69. package/dist/driver.d.ts +102 -0
  70. package/dist/driver.d.ts.map +1 -1
  71. package/dist/driver.js +259 -19
  72. package/dist/driver.js.map +1 -1
  73. package/dist/eventbus.d.ts +20 -0
  74. package/dist/eventbus.d.ts.map +1 -1
  75. package/dist/eventbus.js +47 -0
  76. package/dist/eventbus.js.map +1 -1
  77. package/dist/file-picker.d.ts.map +1 -1
  78. package/dist/file-picker.js +2 -2
  79. package/dist/file-picker.js.map +1 -1
  80. package/dist/flex.d.ts.map +1 -1
  81. package/dist/flex.js +6 -6
  82. package/dist/flex.js.map +1 -1
  83. package/dist/focus-area.d.ts +13 -4
  84. package/dist/focus-area.d.ts.map +1 -1
  85. package/dist/focus-area.js +56 -14
  86. package/dist/focus-area.js.map +1 -1
  87. package/dist/focus-map.d.ts +40 -0
  88. package/dist/focus-map.d.ts.map +1 -0
  89. package/dist/focus-map.js +133 -0
  90. package/dist/focus-map.js.map +1 -0
  91. package/dist/grid.d.ts +2 -2
  92. package/dist/grid.d.ts.map +1 -1
  93. package/dist/grid.js +11 -148
  94. package/dist/grid.js.map +1 -1
  95. package/dist/help.d.ts +2 -0
  96. package/dist/help.d.ts.map +1 -1
  97. package/dist/help.js +6 -4
  98. package/dist/help.js.map +1 -1
  99. package/dist/icon-presentation.d.ts +10 -0
  100. package/dist/icon-presentation.d.ts.map +1 -0
  101. package/dist/icon-presentation.js +12 -0
  102. package/dist/icon-presentation.js.map +1 -0
  103. package/dist/index.d.ts +32 -9
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +17 -5
  106. package/dist/index.js.map +1 -1
  107. package/dist/input-map.d.ts +68 -0
  108. package/dist/input-map.d.ts.map +1 -0
  109. package/dist/input-map.js +162 -0
  110. package/dist/input-map.js.map +1 -0
  111. package/dist/input-routing-inspector.d.ts +24 -0
  112. package/dist/input-routing-inspector.d.ts.map +1 -0
  113. package/dist/input-routing-inspector.js +76 -0
  114. package/dist/input-routing-inspector.js.map +1 -0
  115. package/dist/keybindings.d.ts.map +1 -1
  116. package/dist/keybindings.js +3 -0
  117. package/dist/keybindings.js.map +1 -1
  118. package/dist/layout-inspector.d.ts +31 -0
  119. package/dist/layout-inspector.d.ts.map +1 -0
  120. package/dist/layout-inspector.js +133 -0
  121. package/dist/layout-inspector.js.map +1 -0
  122. package/dist/layout-preset.d.ts +1 -1
  123. package/dist/layout-preset.d.ts.map +1 -1
  124. package/dist/motion/reconciler.d.ts +6 -2
  125. package/dist/motion/reconciler.d.ts.map +1 -1
  126. package/dist/motion/reconciler.js +40 -10
  127. package/dist/motion/reconciler.js.map +1 -1
  128. package/dist/motion/types.d.ts +3 -1
  129. package/dist/motion/types.d.ts.map +1 -1
  130. package/dist/navigable-table.d.ts +9 -10
  131. package/dist/navigable-table.d.ts.map +1 -1
  132. package/dist/navigable-table.js +33 -14
  133. package/dist/navigable-table.js.map +1 -1
  134. package/dist/notification.d.ts +15 -0
  135. package/dist/notification.d.ts.map +1 -1
  136. package/dist/notification.js +136 -34
  137. package/dist/notification.js.map +1 -1
  138. package/dist/overlay.d.ts.map +1 -1
  139. package/dist/overlay.js +40 -14
  140. package/dist/overlay.js.map +1 -1
  141. package/dist/pager.d.ts +3 -1
  142. package/dist/pager.d.ts.map +1 -1
  143. package/dist/pager.js +4 -0
  144. package/dist/pager.js.map +1 -1
  145. package/dist/pipeline/middleware/grayscale.d.ts.map +1 -1
  146. package/dist/pipeline/middleware/grayscale.js +5 -5
  147. package/dist/pipeline/middleware/grayscale.js.map +1 -1
  148. package/dist/pipeline/middleware/motion.d.ts.map +1 -1
  149. package/dist/pipeline/middleware/motion.js +4 -3
  150. package/dist/pipeline/middleware/motion.js.map +1 -1
  151. package/dist/pipeline/middleware/paint.d.ts.map +1 -1
  152. package/dist/pipeline/middleware/paint.js +2 -1
  153. package/dist/pipeline/middleware/paint.js.map +1 -1
  154. package/dist/pipeline/middleware/surface-shaders.d.ts +37 -0
  155. package/dist/pipeline/middleware/surface-shaders.d.ts.map +1 -0
  156. package/dist/pipeline/middleware/surface-shaders.js +164 -0
  157. package/dist/pipeline/middleware/surface-shaders.js.map +1 -0
  158. package/dist/pipeline/pipeline.d.ts +37 -2
  159. package/dist/pipeline/pipeline.d.ts.map +1 -1
  160. package/dist/pipeline/pipeline.js +121 -22
  161. package/dist/pipeline/pipeline.js.map +1 -1
  162. package/dist/raytrace.d.ts +59 -0
  163. package/dist/raytrace.d.ts.map +1 -0
  164. package/dist/raytrace.js +121 -0
  165. package/dist/raytrace.js.map +1 -0
  166. package/dist/runtime-binding.d.ts +59 -0
  167. package/dist/runtime-binding.d.ts.map +1 -0
  168. package/dist/runtime-binding.js +271 -0
  169. package/dist/runtime-binding.js.map +1 -0
  170. package/dist/runtime.d.ts +19 -0
  171. package/dist/runtime.d.ts.map +1 -1
  172. package/dist/runtime.js +222 -31
  173. package/dist/runtime.js.map +1 -1
  174. package/dist/split-pane.d.ts +2 -2
  175. package/dist/split-pane.d.ts.map +1 -1
  176. package/dist/split-pane.js +28 -49
  177. package/dist/split-pane.js.map +1 -1
  178. package/dist/subapp/mount.d.ts +17 -0
  179. package/dist/subapp/mount.d.ts.map +1 -1
  180. package/dist/subapp/mount.js +13 -0
  181. package/dist/subapp/mount.js.map +1 -1
  182. package/dist/surface-budget.d.ts +27 -0
  183. package/dist/surface-budget.d.ts.map +1 -0
  184. package/dist/surface-budget.js +61 -0
  185. package/dist/surface-budget.js.map +1 -0
  186. package/dist/surface-diff.d.ts +36 -0
  187. package/dist/surface-diff.d.ts.map +1 -0
  188. package/dist/surface-diff.js +202 -0
  189. package/dist/surface-diff.js.map +1 -0
  190. package/dist/surface-layout.d.ts +19 -3
  191. package/dist/surface-layout.d.ts.map +1 -1
  192. package/dist/surface-layout.js +42 -12
  193. package/dist/surface-layout.js.map +1 -1
  194. package/dist/types.d.ts +8 -0
  195. package/dist/types.d.ts.map +1 -1
  196. package/dist/types.js.map +1 -1
  197. package/dist/view-output.js +2 -2
  198. package/dist/view-output.js.map +1 -1
  199. package/dist/viewport.d.ts +13 -1
  200. package/dist/viewport.d.ts.map +1 -1
  201. package/dist/viewport.js +33 -11
  202. package/dist/viewport.js.map +1 -1
  203. package/package.json +4 -4
@@ -0,0 +1,164 @@
1
+ import { isPackedSurface } from '@flyingrobots/bijou';
2
+ import { CELL_STRIDE, FLAG_BG_SET, FLAG_FG_SET, OFF_ALPHA, OFF_BG_R, OFF_FG_R, } from '@flyingrobots/bijou/perf';
3
+ export function surfaceShaderFilter(...shaders) {
4
+ let frame = 0;
5
+ return (state, next) => {
6
+ if (shaders.length === 0) {
7
+ next();
8
+ return;
9
+ }
10
+ frame += 1;
11
+ const context = {
12
+ frame,
13
+ dt: state.dt,
14
+ width: state.targetSurface.width,
15
+ height: state.targetSurface.height,
16
+ };
17
+ for (const shader of shaders) {
18
+ shader(state.targetSurface, context);
19
+ }
20
+ next();
21
+ };
22
+ }
23
+ export function scanlines(options = {}) {
24
+ const dimFactor = clampFactor(options.dimFactor ?? 0.78);
25
+ const startBright = options.startBright ?? true;
26
+ return (surface, context) => {
27
+ shadeSurface(surface, context, (_x, y) => {
28
+ const dimmedRow = startBright ? (y % 2 === 1) : (y % 2 === 0);
29
+ return dimmedRow ? dimFactor : 1;
30
+ });
31
+ };
32
+ }
33
+ export function flicker(options = {}) {
34
+ const minFactor = clampFactor(options.minFactor ?? 0.94);
35
+ const maxFactor = clampFactor(options.maxFactor ?? 1.04);
36
+ return (surface, context) => {
37
+ const t = normalizedNoise(0, 0, context.frame);
38
+ const factor = lerp(minFactor, maxFactor, t);
39
+ shadeSurface(surface, context, () => factor);
40
+ };
41
+ }
42
+ export function noise(options = {}) {
43
+ const intensity = Math.max(0, Math.min(options.intensity ?? 0.12, 1));
44
+ return (surface, context) => {
45
+ shadeSurface(surface, context, (x, y) => {
46
+ const centered = (normalizedNoise(x, y, context.frame) - 0.5) * 2;
47
+ return clampFactor(1 + centered * intensity);
48
+ });
49
+ };
50
+ }
51
+ export function vignette(options = {}) {
52
+ const edgeFactor = clampFactor(options.edgeFactor ?? 0.72);
53
+ const exponent = Math.max(0.1, options.exponent ?? 1.6);
54
+ return (surface, context) => {
55
+ const cx = (context.width - 1) / 2;
56
+ const cy = (context.height - 1) / 2;
57
+ const maxDistance = Math.max(1, Math.hypot(cx, cy));
58
+ shadeSurface(surface, context, (x, y) => {
59
+ const distance = Math.hypot(x - cx, y - cy) / maxDistance;
60
+ const edgeBias = Math.pow(Math.min(1, distance), exponent);
61
+ return lerp(1, edgeFactor, edgeBias);
62
+ });
63
+ };
64
+ }
65
+ function shadeSurface(surface, context, factorForCell) {
66
+ if (surface.width === 0 || surface.height === 0)
67
+ return;
68
+ if (isPackedSurface(surface)) {
69
+ shadePackedSurface(surface, context, factorForCell);
70
+ return;
71
+ }
72
+ shadeCellSurface(surface, context, factorForCell);
73
+ }
74
+ function shadePackedSurface(surface, context, factorForCell) {
75
+ const buf = surface.buffer;
76
+ const width = surface.width;
77
+ const height = surface.height;
78
+ for (let y = 0; y < height; y++) {
79
+ for (let x = 0; x < width; x++) {
80
+ const factor = factorForCell(x, y, context);
81
+ if (factor === 1)
82
+ continue;
83
+ const index = y * width + x;
84
+ const off = index * CELL_STRIDE;
85
+ const alpha = buf[off + OFF_ALPHA];
86
+ const cell = surface.cells[index];
87
+ if (alpha & FLAG_FG_SET) {
88
+ const nextFg = shadePackedRgb(buf, off + OFF_FG_R, factor);
89
+ cell.fg = rgbToHex(nextFg[0], nextFg[1], nextFg[2]);
90
+ }
91
+ if (alpha & FLAG_BG_SET) {
92
+ const nextBg = shadePackedRgb(buf, off + OFF_BG_R, factor);
93
+ cell.bg = rgbToHex(nextBg[0], nextBg[1], nextBg[2]);
94
+ }
95
+ }
96
+ }
97
+ surface.markAllDirty();
98
+ }
99
+ function shadePackedRgb(buf, start, factor) {
100
+ const r = shadeChannel(buf[start], factor);
101
+ const g = shadeChannel(buf[start + 1], factor);
102
+ const b = shadeChannel(buf[start + 2], factor);
103
+ buf[start] = r;
104
+ buf[start + 1] = g;
105
+ buf[start + 2] = b;
106
+ return [r, g, b];
107
+ }
108
+ function shadeCellSurface(surface, context, factorForCell) {
109
+ for (let y = 0; y < surface.height; y++) {
110
+ for (let x = 0; x < surface.width; x++) {
111
+ const factor = factorForCell(x, y, context);
112
+ if (factor === 1)
113
+ continue;
114
+ const cell = surface.get(x, y);
115
+ const fgHex = typeof cell.fg === 'string' ? cell.fg : cell.fg?.hex;
116
+ const bgHex = typeof cell.bg === 'string' ? cell.bg : cell.bg?.hex;
117
+ const nextFg = fgHex ? shadeHex(fgHex, factor) : undefined;
118
+ const nextBg = bgHex ? shadeHex(bgHex, factor) : undefined;
119
+ if (nextFg !== cell.fg || nextBg !== cell.bg) {
120
+ surface.set(x, y, { ...cell, fg: nextFg, bg: nextBg });
121
+ }
122
+ }
123
+ }
124
+ }
125
+ function shadeHex(hex, factor) {
126
+ if (hex.length !== 7 || hex[0] !== '#')
127
+ return hex;
128
+ const digits = hex.slice(1);
129
+ if (!/^[0-9A-Fa-f]{6}$/.test(digits))
130
+ return hex;
131
+ const r = parseInt(digits.slice(0, 2), 16);
132
+ const g = parseInt(digits.slice(2, 4), 16);
133
+ const b = parseInt(digits.slice(4, 6), 16);
134
+ if (isNaN(r) || isNaN(g) || isNaN(b))
135
+ return hex;
136
+ return rgbToHex(shadeChannel(r, factor), shadeChannel(g, factor), shadeChannel(b, factor));
137
+ }
138
+ function shadeChannel(value, factor) {
139
+ return Math.max(0, Math.min(255, Math.round(value * factor)));
140
+ }
141
+ function rgbToHex(r, g, b) {
142
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
143
+ }
144
+ function toHex(value) {
145
+ return value.toString(16).padStart(2, '0');
146
+ }
147
+ function clampFactor(value) {
148
+ if (!Number.isFinite(value))
149
+ return 1;
150
+ return Math.max(0, Math.min(value, 2));
151
+ }
152
+ function lerp(start, end, t) {
153
+ return start + (end - start) * t;
154
+ }
155
+ function normalizedNoise(x, y, frame) {
156
+ let value = Math.imul(x + 1, 374761393);
157
+ value = (value + Math.imul(y + 1, 668265263)) >>> 0;
158
+ value = (value + Math.imul(frame + 1, 982451653)) >>> 0;
159
+ value ^= value >>> 13;
160
+ value = Math.imul(value, 1274126177) >>> 0;
161
+ value ^= value >>> 16;
162
+ return value / 0xffffffff;
163
+ }
164
+ //# sourceMappingURL=surface-shaders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface-shaders.js","sourceRoot":"","sources":["../../../src/pipeline/middleware/surface-shaders.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { Surface, BijouContext } from '@flyingrobots/bijou';
1
+ import type { Surface, BijouContext, LayoutNode } from '@flyingrobots/bijou';
2
2
  /**
3
3
  * The state passed through the rendering pipeline.
4
4
  */
@@ -47,17 +47,52 @@ export type RenderMiddleware = (state: RenderState, next: () => void) => void |
47
47
  * A stage in the rendering pipeline.
48
48
  */
49
49
  export type RenderStage = 'Layout' | 'Paint' | 'PostProcess' | 'Diff' | 'Output';
50
+ /** Per-stage timing sample captured during a single pipeline execution. */
51
+ export interface RenderStageTiming {
52
+ /** Stage that completed. */
53
+ readonly stage: RenderStage;
54
+ /** Wall-clock duration for this stage in milliseconds. */
55
+ readonly durationMs: number;
56
+ }
57
+ /** Observer notified whenever a render stage completes. */
58
+ export type RenderStageCompleteHandler = (stage: RenderStage, durationMs: number, state: RenderState) => void;
59
+ /** Disposable observer registration handle. */
60
+ export interface RenderStageObserver {
61
+ dispose(): void;
62
+ }
63
+ /** Key used to store per-frame stage timings in `RenderState.data`. */
64
+ export declare const RENDER_STAGE_TIMINGS_KEY = "__pipelineStageTimings";
65
+ /** Key used to pass the resolved layout root between middleware stages. */
66
+ export declare const RENDER_LAYOUT_ROOT_KEY = "__bijou:layoutRoot";
67
+ /**
68
+ * Read the resolved layout root from a render-state data bag.
69
+ * Built-in layout middleware writes this value in `Layout`.
70
+ */
71
+ export declare function getRenderLayoutRoot(state: Pick<RenderState, 'data'>): LayoutNode | undefined;
72
+ /**
73
+ * Read per-stage timings captured during the current pipeline execution.
74
+ *
75
+ * The returned array is replaced on each `pipeline.execute(state)` call.
76
+ */
77
+ export declare function getRenderStageTimings(state: Pick<RenderState, 'data'>): readonly RenderStageTiming[];
50
78
  /**
51
79
  * The rendering pipeline registry.
52
80
  */
53
81
  export interface RenderPipeline {
54
82
  /** Register middleware for a specific stage. */
55
83
  use(stage: RenderStage, middleware: RenderMiddleware): void;
84
+ /** Observe per-stage completion timings for each pipeline execution. */
85
+ onStageComplete(handler: RenderStageCompleteHandler): RenderStageObserver;
56
86
  /** Execute the entire pipeline for a given state. */
57
87
  execute(state: RenderState): void;
58
88
  }
89
+ /** Options for creating a programmable render pipeline. */
90
+ export interface CreatePipelineOptions {
91
+ /** Optional timing source override, primarily for deterministic tests. */
92
+ now?: () => number;
93
+ }
59
94
  /**
60
95
  * Create a new programmable rendering pipeline.
61
96
  */
62
- export declare function createPipeline(): RenderPipeline;
97
+ export declare function createPipeline(options?: CreatePipelineOptions): RenderPipeline;
63
98
  //# sourceMappingURL=pipeline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/pipeline/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,KAAK,EAAE,GAAG,CAAC;IACX,8CAA8C;IAC9C,GAAG,EAAE,YAAY,CAAC;IAClB,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;OAGG;IACH,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9F;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,aAAa,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC5D,qDAAqD;IACrD,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,cAAc,CA8C/C"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/pipeline/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,KAAK,EAAE,GAAG,CAAC;IACX,8CAA8C;IAC9C,GAAG,EAAE,YAAY,CAAC;IAClB,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;OAGG;IACH,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9F;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,aAAa,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEjF,2EAA2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,2DAA2D;AAC3D,MAAM,MAAM,0BAA0B,GAAG,CACvC,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,WAAW,KACf,IAAI,CAAC;AAEV,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,uEAAuE;AACvE,eAAO,MAAM,wBAAwB,2BAA2B,CAAC;AAEjE,2EAA2E;AAC3E,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,UAAU,GAAG,SAAS,CAE5F;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,SAAS,iBAAiB,EAAE,CAGpG;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC5D,wEAAwE;IACxE,eAAe,CAAC,OAAO,EAAE,0BAA0B,GAAG,mBAAmB,CAAC;IAC1E,qDAAqD;IACrD,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CACnC;AAED,2DAA2D;AAC3D,MAAM,WAAW,qBAAqB;IACpC,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AASD;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,cAAc,CA+IlF"}
@@ -1,7 +1,33 @@
1
+ /** Key used to store per-frame stage timings in `RenderState.data`. */
2
+ export const RENDER_STAGE_TIMINGS_KEY = '__pipelineStageTimings';
3
+ /** Key used to pass the resolved layout root between middleware stages. */
4
+ export const RENDER_LAYOUT_ROOT_KEY = '__bijou:layoutRoot';
5
+ /**
6
+ * Read the resolved layout root from a render-state data bag.
7
+ * Built-in layout middleware writes this value in `Layout`.
8
+ */
9
+ export function getRenderLayoutRoot(state) {
10
+ return state.data[RENDER_LAYOUT_ROOT_KEY];
11
+ }
12
+ /**
13
+ * Read per-stage timings captured during the current pipeline execution.
14
+ *
15
+ * The returned array is replaced on each `pipeline.execute(state)` call.
16
+ */
17
+ export function getRenderStageTimings(state) {
18
+ const timings = state.data[RENDER_STAGE_TIMINGS_KEY];
19
+ return Array.isArray(timings) ? timings : [];
20
+ }
21
+ function isPromiseLike(value) {
22
+ return typeof value === 'object'
23
+ && value !== null
24
+ && 'then' in value
25
+ && typeof value.then === 'function';
26
+ }
1
27
  /**
2
28
  * Create a new programmable rendering pipeline.
3
29
  */
4
- export function createPipeline() {
30
+ export function createPipeline(options = {}) {
5
31
  const stages = {
6
32
  Layout: [],
7
33
  Paint: [],
@@ -9,37 +35,110 @@ export function createPipeline() {
9
35
  Diff: [],
10
36
  Output: [],
11
37
  };
38
+ const stageCompleteHandlers = new Set();
39
+ const warnedAsyncMiddleware = new WeakSet();
12
40
  const STAGE_ORDER = ['Layout', 'Paint', 'PostProcess', 'Diff', 'Output'];
41
+ let cachedPlan = [];
42
+ let chainDirty = true;
43
+ const readNow = options.now ?? (() => globalThis.performance?.now?.() ?? Date.now());
13
44
  function use(stage, middleware) {
14
45
  stages[stage].push(middleware);
46
+ chainDirty = true;
15
47
  }
16
- function execute(state) {
17
- // Flatten all middleware into a single execution chain based on stage order
18
- const chain = [];
19
- for (const stage of STAGE_ORDER) {
20
- chain.push(...stages[stage]);
48
+ function onStageComplete(handler) {
49
+ stageCompleteHandlers.add(handler);
50
+ return {
51
+ dispose() {
52
+ stageCompleteHandlers.delete(handler);
53
+ },
54
+ };
55
+ }
56
+ function getExecutionPlan() {
57
+ if (chainDirty) {
58
+ cachedPlan = STAGE_ORDER.map((stage) => ({
59
+ stage,
60
+ middlewares: stages[stage],
61
+ }));
62
+ chainDirty = false;
21
63
  }
22
- let index = 0;
23
- const next = () => {
24
- if (index < chain.length) {
25
- const mw = chain[index++];
26
- try {
27
- // Note: The pipeline is currently synchronous. If a middleware returns a Promise,
28
- // it won't block the TEA update loop, but it might resolve out-of-order.
29
- // For now, we expect render middleware to be entirely synchronous.
30
- void mw(state, next);
64
+ return cachedPlan;
65
+ }
66
+ function recordStageTiming(state, timings, stage, durationMs) {
67
+ const timing = { stage, durationMs };
68
+ timings.push(timing);
69
+ for (const handler of stageCompleteHandlers) {
70
+ try {
71
+ handler(stage, durationMs, state);
72
+ }
73
+ catch (err) {
74
+ if (state.ctx.io.writeError) {
75
+ state.ctx.io.writeError(`[Pipeline Observer Error] ${err instanceof Error ? err.stack : err}\n`);
31
76
  }
32
- catch (err) {
33
- // Log and continue if a specific middleware fails, preventing full crash
34
- if (state.ctx.io.writeError) {
35
- state.ctx.io.writeError(`[Pipeline Error] ${err instanceof Error ? err.stack : err}\n`);
77
+ }
78
+ }
79
+ }
80
+ function writePipelineError(state, message, detail) {
81
+ if (!state.ctx.io.writeError)
82
+ return;
83
+ const suffix = detail == null
84
+ ? ''
85
+ : detail instanceof Error
86
+ ? ` ${detail.stack ?? detail.message}`
87
+ : ` ${String(detail)}`;
88
+ state.ctx.io.writeError(`${message}${suffix}\n`);
89
+ }
90
+ function execute(state) {
91
+ const plan = getExecutionPlan();
92
+ const timings = [];
93
+ state.data[RENDER_STAGE_TIMINGS_KEY] = timings;
94
+ const runStage = (stageIndex, middlewareIndex, stageStartMs) => {
95
+ if (stageIndex >= plan.length)
96
+ return;
97
+ const entry = plan[stageIndex];
98
+ if (middlewareIndex >= entry.middlewares.length) {
99
+ recordStageTiming(state, timings, entry.stage, readNow() - stageStartMs);
100
+ runStage(stageIndex + 1, 0, readNow());
101
+ return;
102
+ }
103
+ const middleware = entry.middlewares[middlewareIndex];
104
+ let advanced = false;
105
+ const next = () => {
106
+ if (advanced)
107
+ return;
108
+ advanced = true;
109
+ runStage(stageIndex, middlewareIndex + 1, stageStartMs);
110
+ };
111
+ try {
112
+ const result = middleware(state, next);
113
+ if (isPromiseLike(result)) {
114
+ if (!warnedAsyncMiddleware.has(middleware)) {
115
+ warnedAsyncMiddleware.add(middleware);
116
+ writePipelineError(state, `[Pipeline Error] Async render middleware returned a Promise in ${entry.stage}; render middleware must be synchronous. Move async work into Cmd/Msg round trips.`);
117
+ }
118
+ Promise.resolve(result).catch((err) => {
119
+ writePipelineError(state, `[Pipeline Error] Async render middleware rejected in ${entry.stage}:`, err);
120
+ });
121
+ // Async middleware is unsupported because it can resume out of frame
122
+ // order. Keep the current frame moving and let the guarded `next`
123
+ // ignore any late continuation.
124
+ if (!advanced) {
125
+ next();
36
126
  }
37
- next();
38
127
  }
39
128
  }
129
+ catch (err) {
130
+ // Log and continue if a specific middleware fails, preventing full crash
131
+ writePipelineError(state, '[Pipeline Error]', err);
132
+ next();
133
+ }
134
+ // A middleware that does not call next() halts the pipeline. Record the
135
+ // current stage timing so callers can still observe partial execution.
136
+ if (!advanced) {
137
+ recordStageTiming(state, timings, entry.stage, readNow() - stageStartMs);
138
+ }
40
139
  };
41
- next();
140
+ runStage(0, 0, readNow());
42
141
  }
43
- return { use, execute };
142
+ return { use, onStageComplete, execute };
44
143
  }
45
144
  //# sourceMappingURL=pipeline.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/pipeline/pipeline.ts"],"names":[],"mappings":"AA+DA;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAA4C;QACtD,MAAM,EAAE,EAAE;QACV,KAAK,EAAE,EAAE;QACT,WAAW,EAAE,EAAE;QACf,IAAI,EAAE,EAAE;QACR,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,MAAM,WAAW,GAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAExF,SAAS,GAAG,CAAC,KAAkB,EAAE,UAA4B;QAC3D,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;IAED,SAAS,OAAO,CAAC,KAAkB;QACjC,4EAA4E;QAC5E,MAAM,KAAK,GAAuB,EAAE,CAAC;QACrC,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,CAAC;QAED,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBACzB,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;gBAC1B,IAAI,CAAC;oBACH,kFAAkF;oBAClF,yEAAyE;oBACzE,mEAAmE;oBACnE,KAAK,EAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;gBACxB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,yEAAyE;oBACzE,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;wBAC5B,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,oBAAoB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;oBAC1F,CAAC;oBACD,IAAI,EAAE,CAAC;gBACT,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,IAAI,EAAE,CAAC;IACT,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/pipeline/pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Small raytrace geometry helpers for shader-authored terminal scenes.
3
+ *
4
+ * This module owns camera rays, vector math, and primitive intersections.
5
+ * Apps keep material, lighting, palette, and sampling policy.
6
+ */
7
+ export type RaytraceVector3 = readonly [number, number, number];
8
+ export type RaytraceScreenPoint = readonly [number, number];
9
+ export interface RaytraceRay {
10
+ readonly origin: RaytraceVector3;
11
+ readonly direction: RaytraceVector3;
12
+ }
13
+ export interface RaytraceSphere {
14
+ readonly kind: 'sphere';
15
+ readonly center: RaytraceVector3;
16
+ readonly radius: number;
17
+ }
18
+ export interface RaytracePlane {
19
+ readonly kind: 'plane';
20
+ readonly point: RaytraceVector3;
21
+ readonly normal: RaytraceVector3;
22
+ }
23
+ export type RaytraceShape = RaytraceSphere | RaytracePlane;
24
+ export interface RaytraceHit<Shape extends RaytraceShape = RaytraceShape> {
25
+ readonly shape: Shape;
26
+ readonly distance: number;
27
+ readonly point: RaytraceVector3;
28
+ readonly normal: RaytraceVector3;
29
+ }
30
+ export interface RaytraceLookAtRayOptions {
31
+ readonly origin: RaytraceVector3;
32
+ readonly target: RaytraceVector3;
33
+ readonly screen: RaytraceScreenPoint;
34
+ readonly focalLength?: number;
35
+ readonly up?: RaytraceVector3;
36
+ }
37
+ export interface RaytraceOrbitCameraRayOptions {
38
+ readonly angleRadians: number;
39
+ readonly radius: number;
40
+ readonly height: number;
41
+ readonly target: RaytraceVector3;
42
+ readonly screen: RaytraceScreenPoint;
43
+ readonly focalLength?: number;
44
+ readonly up?: RaytraceVector3;
45
+ }
46
+ export declare function raytraceLookAtRay(options: RaytraceLookAtRayOptions): RaytraceRay;
47
+ export declare function raytraceOrbitCameraRay(options: RaytraceOrbitCameraRayOptions): RaytraceRay;
48
+ export declare function raytraceNearestHit(ray: RaytraceRay, shapes: readonly RaytraceShape[]): RaytraceHit | undefined;
49
+ export declare function raytraceSphereHit(ray: RaytraceRay, sphere: RaytraceSphere): RaytraceHit<RaytraceSphere> | undefined;
50
+ export declare function raytracePlaneHit(ray: RaytraceRay, plane: RaytracePlane): RaytraceHit<RaytracePlane> | undefined;
51
+ export declare function raytraceReflect(ray: RaytraceVector3, normal: RaytraceVector3): RaytraceVector3;
52
+ export declare function raytraceNormalize(vector: RaytraceVector3): RaytraceVector3;
53
+ export declare function raytraceLength(vector: RaytraceVector3): number;
54
+ export declare function raytraceDot(a: RaytraceVector3, b: RaytraceVector3): number;
55
+ export declare function raytraceCross(a: RaytraceVector3, b: RaytraceVector3): RaytraceVector3;
56
+ export declare function raytraceAdd(a: RaytraceVector3, b: RaytraceVector3): RaytraceVector3;
57
+ export declare function raytraceSub(a: RaytraceVector3, b: RaytraceVector3): RaytraceVector3;
58
+ export declare function raytraceScale(vector: RaytraceVector3, scalar: number): RaytraceVector3;
59
+ //# sourceMappingURL=raytrace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raytrace.d.ts","sourceRoot":"","sources":["../src/raytrace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Small raytrace geometry helpers for shader-authored terminal scenes.
3
+ *
4
+ * This module owns camera rays, vector math, and primitive intersections.
5
+ * Apps keep material, lighting, palette, and sampling policy.
6
+ */
7
+ const DEFAULT_FOCAL_LENGTH = 1;
8
+ const MIN_HIT_DISTANCE = 0.000001;
9
+ const WORLD_UP = [0, 1, 0];
10
+ const FALLBACK_RIGHT = [1, 0, 0];
11
+ export function raytraceLookAtRay(options) {
12
+ const focalLength = options.focalLength ?? DEFAULT_FOCAL_LENGTH;
13
+ const up = options.up ?? WORLD_UP;
14
+ const forward = raytraceNormalize(raytraceSub(options.target, options.origin));
15
+ const rightCandidate = raytraceNormalize(raytraceCross(forward, up));
16
+ const right = raytraceLength(rightCandidate) === 0 ? FALLBACK_RIGHT : rightCandidate;
17
+ const cameraUp = raytraceNormalize(raytraceCross(right, forward));
18
+ const direction = raytraceNormalize(raytraceAdd(raytraceAdd(raytraceScale(right, options.screen[0]), raytraceScale(cameraUp, options.screen[1])), raytraceScale(forward, focalLength)));
19
+ return {
20
+ origin: options.origin,
21
+ direction,
22
+ };
23
+ }
24
+ export function raytraceOrbitCameraRay(options) {
25
+ const origin = [
26
+ options.target[0] + (Math.sin(options.angleRadians) * options.radius),
27
+ options.target[1] + options.height,
28
+ options.target[2] + (Math.cos(options.angleRadians) * options.radius),
29
+ ];
30
+ return raytraceLookAtRay({
31
+ origin,
32
+ target: options.target,
33
+ screen: options.screen,
34
+ focalLength: options.focalLength,
35
+ up: options.up,
36
+ });
37
+ }
38
+ export function raytraceNearestHit(ray, shapes) {
39
+ let nearest;
40
+ for (const shape of shapes) {
41
+ const hit = shape.kind === 'sphere'
42
+ ? raytraceSphereHit(ray, shape)
43
+ : raytracePlaneHit(ray, shape);
44
+ if (hit !== undefined && (nearest === undefined || hit.distance < nearest.distance)) {
45
+ nearest = hit;
46
+ }
47
+ }
48
+ return nearest;
49
+ }
50
+ export function raytraceSphereHit(ray, sphere) {
51
+ const offset = raytraceSub(ray.origin, sphere.center);
52
+ const halfB = raytraceDot(offset, ray.direction);
53
+ const c = raytraceDot(offset, offset) - (sphere.radius * sphere.radius);
54
+ const discriminant = (halfB * halfB) - c;
55
+ if (discriminant < 0)
56
+ return undefined;
57
+ const root = Math.sqrt(discriminant);
58
+ const near = -halfB - root;
59
+ const far = -halfB + root;
60
+ const distance = near > MIN_HIT_DISTANCE
61
+ ? near
62
+ : far > MIN_HIT_DISTANCE
63
+ ? far
64
+ : undefined;
65
+ if (distance === undefined)
66
+ return undefined;
67
+ const point = raytraceAdd(ray.origin, raytraceScale(ray.direction, distance));
68
+ return {
69
+ shape: sphere,
70
+ distance,
71
+ point,
72
+ normal: raytraceNormalize(raytraceSub(point, sphere.center)),
73
+ };
74
+ }
75
+ export function raytracePlaneHit(ray, plane) {
76
+ const normal = raytraceNormalize(plane.normal);
77
+ const denominator = raytraceDot(normal, ray.direction);
78
+ if (Math.abs(denominator) <= MIN_HIT_DISTANCE)
79
+ return undefined;
80
+ const distance = raytraceDot(raytraceSub(plane.point, ray.origin), normal) / denominator;
81
+ if (distance <= MIN_HIT_DISTANCE)
82
+ return undefined;
83
+ return {
84
+ shape: plane,
85
+ distance,
86
+ point: raytraceAdd(ray.origin, raytraceScale(ray.direction, distance)),
87
+ normal,
88
+ };
89
+ }
90
+ export function raytraceReflect(ray, normal) {
91
+ return raytraceSub(ray, raytraceScale(normal, 2 * raytraceDot(ray, normal)));
92
+ }
93
+ export function raytraceNormalize(vector) {
94
+ const length = raytraceLength(vector);
95
+ return length === 0
96
+ ? [0, 0, 0]
97
+ : [vector[0] / length, vector[1] / length, vector[2] / length];
98
+ }
99
+ export function raytraceLength(vector) {
100
+ return Math.hypot(vector[0], vector[1], vector[2]);
101
+ }
102
+ export function raytraceDot(a, b) {
103
+ return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
104
+ }
105
+ export function raytraceCross(a, b) {
106
+ return [
107
+ (a[1] * b[2]) - (a[2] * b[1]),
108
+ (a[2] * b[0]) - (a[0] * b[2]),
109
+ (a[0] * b[1]) - (a[1] * b[0]),
110
+ ];
111
+ }
112
+ export function raytraceAdd(a, b) {
113
+ return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
114
+ }
115
+ export function raytraceSub(a, b) {
116
+ return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
117
+ }
118
+ export function raytraceScale(vector, scalar) {
119
+ return [vector[0] * scalar, vector[1] * scalar, vector[2] * scalar];
120
+ }
121
+ //# sourceMappingURL=raytrace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raytrace.js","sourceRoot":"","sources":["../src/raytrace.ts"],"names":[],"mappings":"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"}