@nodetool-ai/game-renderer 0.8.1 → 0.8.3

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 (277) hide show
  1. package/README.md +46 -0
  2. package/dist/.nodetool-build-stamp +1 -1
  3. package/dist/audio/mixer.d.ts +75 -0
  4. package/dist/audio/mixer.d.ts.map +1 -0
  5. package/dist/audio/mixer.js +345 -0
  6. package/dist/audio/mixer.js.map +1 -0
  7. package/dist/audio/player.d.ts +67 -0
  8. package/dist/audio/player.d.ts.map +1 -0
  9. package/dist/audio/player.js +337 -0
  10. package/dist/audio/player.js.map +1 -0
  11. package/dist/audio/spatial.d.ts +50 -0
  12. package/dist/audio/spatial.d.ts.map +1 -0
  13. package/dist/audio/spatial.js +166 -0
  14. package/dist/audio/spatial.js.map +1 -0
  15. package/dist/audio/voices.d.ts +11 -0
  16. package/dist/audio/voices.d.ts.map +1 -0
  17. package/dist/audio/voices.js +22 -0
  18. package/dist/audio/voices.js.map +1 -0
  19. package/dist/audio.d.ts +6 -38
  20. package/dist/audio.d.ts.map +1 -1
  21. package/dist/audio.js +3 -226
  22. package/dist/audio.js.map +1 -1
  23. package/dist/browser.d.ts +2 -1
  24. package/dist/browser.d.ts.map +1 -1
  25. package/dist/browser.js +5 -5
  26. package/dist/browser.js.map +1 -1
  27. package/dist/browser3d.d.ts +2 -0
  28. package/dist/browser3d.d.ts.map +1 -0
  29. package/dist/browser3d.js +2 -0
  30. package/dist/browser3d.js.map +1 -0
  31. package/dist/build-tauri.d.ts +69 -0
  32. package/dist/build-tauri.d.ts.map +1 -0
  33. package/dist/build-tauri.js +406 -0
  34. package/dist/build-tauri.js.map +1 -0
  35. package/dist/build.d.ts.map +1 -1
  36. package/dist/build.js +29 -19
  37. package/dist/build.js.map +1 -1
  38. package/dist/build3d.d.ts +11 -0
  39. package/dist/build3d.d.ts.map +1 -0
  40. package/dist/build3d.js +126 -0
  41. package/dist/build3d.js.map +1 -0
  42. package/dist/canvas2d.d.ts +12 -3
  43. package/dist/canvas2d.d.ts.map +1 -1
  44. package/dist/canvas2d.js +59 -12
  45. package/dist/canvas2d.js.map +1 -1
  46. package/dist/fixed-tick-host.d.ts +10 -0
  47. package/dist/fixed-tick-host.d.ts.map +1 -0
  48. package/dist/fixed-tick-host.js +29 -0
  49. package/dist/fixed-tick-host.js.map +1 -0
  50. package/dist/frame-budget.d.ts +34 -0
  51. package/dist/frame-budget.d.ts.map +1 -0
  52. package/dist/frame-budget.js +52 -0
  53. package/dist/frame-budget.js.map +1 -0
  54. package/dist/frame.d.ts +20 -1
  55. package/dist/frame.d.ts.map +1 -1
  56. package/dist/frame.js +69 -1
  57. package/dist/frame.js.map +1 -1
  58. package/dist/game3d-capture-page.js +5834 -0
  59. package/dist/game3d-player.js +6001 -0
  60. package/dist/imageDiff.d.ts +9 -0
  61. package/dist/imageDiff.d.ts.map +1 -0
  62. package/dist/imageDiff.js +30 -0
  63. package/dist/imageDiff.js.map +1 -0
  64. package/dist/index.d.ts +12 -1
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +9 -0
  67. package/dist/index.js.map +1 -1
  68. package/dist/input-bindings.d.ts +76 -0
  69. package/dist/input-bindings.d.ts.map +1 -0
  70. package/dist/input-bindings.js +377 -0
  71. package/dist/input-bindings.js.map +1 -0
  72. package/dist/input.d.ts +1 -1
  73. package/dist/input.d.ts.map +1 -1
  74. package/dist/input.js +1 -14
  75. package/dist/input.js.map +1 -1
  76. package/dist/input3d.d.ts +3 -0
  77. package/dist/input3d.d.ts.map +1 -0
  78. package/dist/input3d.js +3 -0
  79. package/dist/input3d.js.map +1 -0
  80. package/dist/node.d.ts +5 -0
  81. package/dist/node.d.ts.map +1 -1
  82. package/dist/node.js +28 -11
  83. package/dist/node.js.map +1 -1
  84. package/dist/node3d.d.ts +29 -0
  85. package/dist/node3d.d.ts.map +1 -0
  86. package/dist/node3d.js +160 -0
  87. package/dist/node3d.js.map +1 -0
  88. package/dist/particles/curves.d.ts +16 -0
  89. package/dist/particles/curves.d.ts.map +1 -0
  90. package/dist/particles/curves.js +49 -0
  91. package/dist/particles/curves.js.map +1 -0
  92. package/dist/particles/index.d.ts +6 -0
  93. package/dist/particles/index.d.ts.map +1 -0
  94. package/dist/particles/index.js +6 -0
  95. package/dist/particles/index.js.map +1 -0
  96. package/dist/particles/random.d.ts +10 -0
  97. package/dist/particles/random.d.ts.map +1 -0
  98. package/dist/particles/random.js +26 -0
  99. package/dist/particles/random.js.map +1 -0
  100. package/dist/particles/render2d.d.ts +40 -0
  101. package/dist/particles/render2d.d.ts.map +1 -0
  102. package/dist/particles/render2d.js +70 -0
  103. package/dist/particles/render2d.js.map +1 -0
  104. package/dist/particles/shapes.d.ts +18 -0
  105. package/dist/particles/shapes.d.ts.map +1 -0
  106. package/dist/particles/shapes.js +92 -0
  107. package/dist/particles/shapes.js.map +1 -0
  108. package/dist/particles/simulator.d.ts +88 -0
  109. package/dist/particles/simulator.d.ts.map +1 -0
  110. package/dist/particles/simulator.js +371 -0
  111. package/dist/particles/simulator.js.map +1 -0
  112. package/dist/player-v1.js +2502 -0
  113. package/dist/preparation3d.d.ts +3 -0
  114. package/dist/preparation3d.d.ts.map +1 -0
  115. package/dist/preparation3d.js +3 -0
  116. package/dist/preparation3d.js.map +1 -0
  117. package/dist/renderPipeline.d.ts +12 -0
  118. package/dist/renderPipeline.d.ts.map +1 -0
  119. package/dist/renderPipeline.js +17 -0
  120. package/dist/renderPipeline.js.map +1 -0
  121. package/dist/renderer3d/animation/index.d.ts +11 -0
  122. package/dist/renderer3d/animation/index.d.ts.map +1 -0
  123. package/dist/renderer3d/animation/index.js +212 -0
  124. package/dist/renderer3d/animation/index.js.map +1 -0
  125. package/dist/renderer3d/assets/cache.d.ts +14 -0
  126. package/dist/renderer3d/assets/cache.d.ts.map +1 -0
  127. package/dist/renderer3d/assets/cache.js +74 -0
  128. package/dist/renderer3d/assets/cache.js.map +1 -0
  129. package/dist/renderer3d/assets/dispose.d.ts +4 -0
  130. package/dist/renderer3d/assets/dispose.d.ts.map +1 -0
  131. package/dist/renderer3d/assets/dispose.js +41 -0
  132. package/dist/renderer3d/assets/dispose.js.map +1 -0
  133. package/dist/renderer3d/assets/hdri-contract.d.ts +23 -0
  134. package/dist/renderer3d/assets/hdri-contract.d.ts.map +1 -0
  135. package/dist/renderer3d/assets/hdri-contract.js +2 -0
  136. package/dist/renderer3d/assets/hdri-contract.js.map +1 -0
  137. package/dist/renderer3d/assets/instances.d.ts +5 -0
  138. package/dist/renderer3d/assets/instances.d.ts.map +1 -0
  139. package/dist/renderer3d/assets/instances.js +86 -0
  140. package/dist/renderer3d/assets/instances.js.map +1 -0
  141. package/dist/renderer3d/capture-driver-types.d.ts +42 -0
  142. package/dist/renderer3d/capture-driver-types.d.ts.map +1 -0
  143. package/dist/renderer3d/capture-driver-types.js +2 -0
  144. package/dist/renderer3d/capture-driver-types.js.map +1 -0
  145. package/dist/renderer3d/capture-page.d.ts +36 -0
  146. package/dist/renderer3d/capture-page.d.ts.map +1 -0
  147. package/dist/renderer3d/capture-page.js +68 -0
  148. package/dist/renderer3d/capture-page.js.map +1 -0
  149. package/dist/renderer3d/culling.d.ts +10 -0
  150. package/dist/renderer3d/culling.d.ts.map +1 -0
  151. package/dist/renderer3d/culling.js +27 -0
  152. package/dist/renderer3d/culling.js.map +1 -0
  153. package/dist/renderer3d/environment/index.d.ts +4 -0
  154. package/dist/renderer3d/environment/index.d.ts.map +1 -0
  155. package/dist/renderer3d/environment/index.js +9 -0
  156. package/dist/renderer3d/environment/index.js.map +1 -0
  157. package/dist/renderer3d/environment/sky.d.ts +45 -0
  158. package/dist/renderer3d/environment/sky.d.ts.map +1 -0
  159. package/dist/renderer3d/environment/sky.js +221 -0
  160. package/dist/renderer3d/environment/sky.js.map +1 -0
  161. package/dist/renderer3d/hud/fonts.d.ts +13 -0
  162. package/dist/renderer3d/hud/fonts.d.ts.map +1 -0
  163. package/dist/renderer3d/hud/fonts.js +69 -0
  164. package/dist/renderer3d/hud/fonts.js.map +1 -0
  165. package/dist/renderer3d/hud/paint.d.ts +4 -0
  166. package/dist/renderer3d/hud/paint.d.ts.map +1 -0
  167. package/dist/renderer3d/hud/paint.js +22 -0
  168. package/dist/renderer3d/hud/paint.js.map +1 -0
  169. package/dist/renderer3d/import.d.ts +34 -0
  170. package/dist/renderer3d/import.d.ts.map +1 -0
  171. package/dist/renderer3d/import.js +408 -0
  172. package/dist/renderer3d/import.js.map +1 -0
  173. package/dist/renderer3d/index.d.ts +74 -0
  174. package/dist/renderer3d/index.d.ts.map +1 -0
  175. package/dist/renderer3d/index.js +338 -0
  176. package/dist/renderer3d/index.js.map +1 -0
  177. package/dist/renderer3d/lights/index.d.ts +7 -0
  178. package/dist/renderer3d/lights/index.d.ts.map +1 -0
  179. package/dist/renderer3d/lights/index.js +67 -0
  180. package/dist/renderer3d/lights/index.js.map +1 -0
  181. package/dist/renderer3d/materials/index.d.ts +4 -0
  182. package/dist/renderer3d/materials/index.d.ts.map +1 -0
  183. package/dist/renderer3d/materials/index.js +8 -0
  184. package/dist/renderer3d/materials/index.js.map +1 -0
  185. package/dist/renderer3d/passes/post-processing.d.ts +44 -0
  186. package/dist/renderer3d/passes/post-processing.d.ts.map +1 -0
  187. package/dist/renderer3d/passes/post-processing.js +213 -0
  188. package/dist/renderer3d/passes/post-processing.js.map +1 -0
  189. package/dist/renderer3d/pipeline.d.ts +15 -0
  190. package/dist/renderer3d/pipeline.d.ts.map +1 -0
  191. package/dist/renderer3d/pipeline.js +10 -0
  192. package/dist/renderer3d/pipeline.js.map +1 -0
  193. package/dist/renderer3d/playwright-contract.d.ts +3 -0
  194. package/dist/renderer3d/playwright-contract.d.ts.map +1 -0
  195. package/dist/renderer3d/playwright-contract.js +4 -0
  196. package/dist/renderer3d/playwright-contract.js.map +1 -0
  197. package/dist/renderer3d/preparation.d.ts +79 -0
  198. package/dist/renderer3d/preparation.d.ts.map +1 -0
  199. package/dist/renderer3d/preparation.js +458 -0
  200. package/dist/renderer3d/preparation.js.map +1 -0
  201. package/dist/renderer3d/scene-sync.d.ts +8 -0
  202. package/dist/renderer3d/scene-sync.d.ts.map +1 -0
  203. package/dist/renderer3d/scene-sync.js +96 -0
  204. package/dist/renderer3d/scene-sync.js.map +1 -0
  205. package/dist/renderer3d/shadows/cascades.d.ts +40 -0
  206. package/dist/renderer3d/shadows/cascades.d.ts.map +1 -0
  207. package/dist/renderer3d/shadows/cascades.js +244 -0
  208. package/dist/renderer3d/shadows/cascades.js.map +1 -0
  209. package/dist/renderer3d/shadows/index.d.ts +44 -0
  210. package/dist/renderer3d/shadows/index.d.ts.map +1 -0
  211. package/dist/renderer3d/shadows/index.js +129 -0
  212. package/dist/renderer3d/shadows/index.js.map +1 -0
  213. package/dist/renderer3d/types.d.ts +18 -0
  214. package/dist/renderer3d/types.d.ts.map +1 -0
  215. package/dist/renderer3d/types.js +2 -0
  216. package/dist/renderer3d/types.js.map +1 -0
  217. package/dist/smoke.d.ts +15 -0
  218. package/dist/smoke.d.ts.map +1 -0
  219. package/dist/smoke.js +138 -0
  220. package/dist/smoke.js.map +1 -0
  221. package/dist/standalone-player.d.ts +11 -1
  222. package/dist/standalone-player.d.ts.map +1 -1
  223. package/dist/standalone-player.js +67 -41
  224. package/dist/standalone-player.js.map +1 -1
  225. package/dist/standalone-player3d.d.ts +14 -0
  226. package/dist/standalone-player3d.d.ts.map +1 -0
  227. package/dist/standalone-player3d.js +255 -0
  228. package/dist/standalone-player3d.js.map +1 -0
  229. package/dist/touch-controls.d.ts +22 -8
  230. package/dist/touch-controls.d.ts.map +1 -1
  231. package/dist/touch-controls.js +88 -21
  232. package/dist/touch-controls.js.map +1 -1
  233. package/dist/ui/controller.d.ts +59 -0
  234. package/dist/ui/controller.d.ts.map +1 -0
  235. package/dist/ui/controller.js +201 -0
  236. package/dist/ui/controller.js.map +1 -0
  237. package/dist/ui/hud2d.d.ts +11 -0
  238. package/dist/ui/hud2d.d.ts.map +1 -0
  239. package/dist/ui/hud2d.js +25 -0
  240. package/dist/ui/hud2d.js.map +1 -0
  241. package/dist/ui/layout.d.ts +42 -0
  242. package/dist/ui/layout.d.ts.map +1 -0
  243. package/dist/ui/layout.js +182 -0
  244. package/dist/ui/layout.js.map +1 -0
  245. package/dist/ui/paint.d.ts +45 -0
  246. package/dist/ui/paint.d.ts.map +1 -0
  247. package/dist/ui/paint.js +121 -0
  248. package/dist/ui/paint.js.map +1 -0
  249. package/dist/webgpu/effects.d.ts +22 -0
  250. package/dist/webgpu/effects.d.ts.map +1 -0
  251. package/dist/webgpu/effects.js +69 -0
  252. package/dist/webgpu/effects.js.map +1 -0
  253. package/dist/webgpu/hud.d.ts +4 -0
  254. package/dist/webgpu/hud.d.ts.map +1 -0
  255. package/dist/webgpu/hud.js +27 -0
  256. package/dist/webgpu/hud.js.map +1 -0
  257. package/dist/webgpu/lighting.d.ts +4 -0
  258. package/dist/webgpu/lighting.d.ts.map +1 -0
  259. package/dist/webgpu/lighting.js +47 -0
  260. package/dist/webgpu/lighting.js.map +1 -0
  261. package/dist/webgpu/pipeline.d.ts +11 -0
  262. package/dist/webgpu/pipeline.d.ts.map +1 -0
  263. package/dist/webgpu/pipeline.js +11 -0
  264. package/dist/webgpu/pipeline.js.map +1 -0
  265. package/dist/webgpu/sprites.d.ts +6 -0
  266. package/dist/webgpu/sprites.d.ts.map +1 -0
  267. package/dist/webgpu/sprites.js +74 -0
  268. package/dist/webgpu/sprites.js.map +1 -0
  269. package/dist/webgpu/types.d.ts +14 -0
  270. package/dist/webgpu/types.d.ts.map +1 -0
  271. package/dist/webgpu/types.js +2 -0
  272. package/dist/webgpu/types.js.map +1 -0
  273. package/dist/webgpu.d.ts +4 -3
  274. package/dist/webgpu.d.ts.map +1 -1
  275. package/dist/webgpu.js +119 -279
  276. package/dist/webgpu.js.map +1 -1
  277. package/package.json +52 -10
@@ -0,0 +1,201 @@
1
+ import { gameUiFont } from "./paint.js";
2
+ import { hitGameUiButton, layoutGameUi, nextGameUiFocus } from "./layout.js";
3
+ // Standard gamepad mapping: button 0 confirms, 12 to 15 are the D-pad.
4
+ const CONFIRM = 0;
5
+ const DPAD = new Map([[12, "up"], [13, "down"], [14, "left"], [15, "right"]]);
6
+ const FOCUS_KEY = "gamepad";
7
+ /**
8
+ * Turns pointer, touch and gamepad input on the HUD into presses of the buttons' input actions.
9
+ * A pressed button holds its action until the pointer lifts or the confirm button is released, so a button
10
+ * reaches the simulation as ordinary input and replays exactly. Focus is presentation and never enters a snapshot.
11
+ */
12
+ export class GameUiController {
13
+ sink;
14
+ measure;
15
+ boxes = [];
16
+ ui;
17
+ focusId;
18
+ held = new Map();
19
+ padButtons = new Set();
20
+ insets;
21
+ constructor(sink, measure) {
22
+ this.sink = sink;
23
+ this.measure = measure;
24
+ }
25
+ /** Lays out the frame's HUD tree in the HUD rectangle, for hit tests and focus moves until the next frame. */
26
+ update(ui, viewport, insets) {
27
+ this.ui = ui;
28
+ this.insets = insets;
29
+ this.boxes = ui ? layoutGameUi(ui, viewport, this.measure, insets) : [];
30
+ if (this.focusId !== undefined && !this.boxes.some((box) => box.node.kind === "button" && box.node.id === this.focusId)) {
31
+ this.focusId = undefined;
32
+ }
33
+ }
34
+ /** The frame's HUD tree with the focused button and safe-area insets, for the renderer. */
35
+ annotate(frame) {
36
+ if (!frame.ui || (this.focusId === undefined && this.insets === undefined)) {
37
+ return frame;
38
+ }
39
+ const ui = { ...frame.ui };
40
+ if (this.focusId !== undefined) {
41
+ ui.focusId = this.focusId;
42
+ }
43
+ if (this.insets !== undefined) {
44
+ ui.insets = this.insets;
45
+ }
46
+ return { ...frame, ui };
47
+ }
48
+ get focusedId() { return this.focusId; }
49
+ /** A pointer went down at a HUD point. Returns true when it landed on a button, which then holds its action. */
50
+ pointerDown(pointerId, x, y) {
51
+ const box = hitGameUiButton(this.boxes, x, y);
52
+ if (!box || box.node.kind !== "button") {
53
+ return false;
54
+ }
55
+ this.hold(pointerId, box.node.action);
56
+ return true;
57
+ }
58
+ pointerUp(pointerId) {
59
+ this.releaseKey(pointerId);
60
+ }
61
+ /** Whether the D-pad and confirm button drive the HUD this frame. */
62
+ get navigating() {
63
+ return this.ui?.focusNavigation === true && this.boxes.some((box) => box.node.kind === "button");
64
+ }
65
+ /**
66
+ * Moves focus with the D-pad and presses the focused button with the confirm button, then returns the pads
67
+ * with those buttons released, so the game's own bindings do not also see them. Without focus navigation the
68
+ * pads pass through unchanged.
69
+ */
70
+ pollGamepads(pads) {
71
+ const list = pads ?? [];
72
+ if (!this.navigating) {
73
+ this.padButtons.clear();
74
+ this.releaseKey(FOCUS_KEY);
75
+ return list;
76
+ }
77
+ const down = new Set();
78
+ for (const pad of list) {
79
+ if (!pad || pad.connected === false) {
80
+ continue;
81
+ }
82
+ for (const index of [CONFIRM, ...DPAD.keys()]) {
83
+ if (pad.buttons[index]?.pressed) {
84
+ down.add(index);
85
+ }
86
+ }
87
+ }
88
+ for (const [index, direction] of DPAD) {
89
+ if (down.has(index) && !this.padButtons.has(index)) {
90
+ this.focusId = nextGameUiFocus(this.boxes, this.focusId, direction);
91
+ }
92
+ }
93
+ if (down.has(CONFIRM) && !this.padButtons.has(CONFIRM)) {
94
+ this.focusId ??= nextGameUiFocus(this.boxes, undefined, "down");
95
+ const focused = this.boxes.find((box) => box.node.id === this.focusId);
96
+ if (focused?.node.kind === "button") {
97
+ this.hold(FOCUS_KEY, focused.node.action);
98
+ }
99
+ }
100
+ else if (!down.has(CONFIRM)) {
101
+ this.releaseKey(FOCUS_KEY);
102
+ }
103
+ this.padButtons.clear();
104
+ for (const index of down) {
105
+ this.padButtons.add(index);
106
+ }
107
+ return list.map((pad) => pad && {
108
+ ...pad,
109
+ buttons: pad.buttons.map((button, index) => index === CONFIRM || DPAD.has(index) ? { pressed: false, value: 0 } : button)
110
+ });
111
+ }
112
+ /** Releases everything the HUD holds, as when play pauses or stops. */
113
+ release() {
114
+ for (const key of [...this.held.keys()]) {
115
+ this.releaseKey(key);
116
+ }
117
+ this.padButtons.clear();
118
+ }
119
+ hold(key, action) {
120
+ this.releaseKey(key);
121
+ this.held.set(key, action);
122
+ this.sink.pressUiAction(action);
123
+ }
124
+ releaseKey(key) {
125
+ const action = this.held.get(key);
126
+ if (action === undefined) {
127
+ return;
128
+ }
129
+ this.held.delete(key);
130
+ this.sink.releaseUiAction(action);
131
+ }
132
+ }
133
+ /**
134
+ * Forwards pointer events on `element` that land on HUD buttons to the controller, in HUD pixels.
135
+ * Events that hit a button stop there, so they do not also reach touch look or canvas focus handlers.
136
+ */
137
+ export function attachGameUiPointer(element, controller, viewport, active = () => true) {
138
+ const down = (event) => {
139
+ const size = viewport();
140
+ if (!active()) {
141
+ return;
142
+ }
143
+ const rect = element.getBoundingClientRect();
144
+ if (!size || rect.width <= 0 || rect.height <= 0) {
145
+ return;
146
+ }
147
+ const x = (event.clientX - rect.left) * size.width / rect.width;
148
+ const y = (event.clientY - rect.top) * size.height / rect.height;
149
+ if (controller.pointerDown(event.pointerId, x, y)) {
150
+ event.preventDefault();
151
+ event.stopPropagation();
152
+ }
153
+ };
154
+ const up = (event) => { controller.pointerUp(event.pointerId); };
155
+ element.addEventListener("pointerdown", down);
156
+ window.addEventListener("pointerup", up);
157
+ window.addEventListener("pointercancel", up);
158
+ return () => {
159
+ element.removeEventListener("pointerdown", down);
160
+ window.removeEventListener("pointerup", up);
161
+ window.removeEventListener("pointercancel", up);
162
+ };
163
+ }
164
+ /**
165
+ * The device safe area where it overlaps `element`, in HUD pixels. Reads the CSS `env(safe-area-inset-*)`
166
+ * values through a probe element, so it is zero on devices without a notch or rounded corners.
167
+ */
168
+ export function browserGameUiInsets(element, viewport) {
169
+ const probe = document.createElement("div");
170
+ probe.style.cssText = "position:fixed;visibility:hidden;pointer-events:none;" +
171
+ "padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)";
172
+ document.body.appendChild(probe);
173
+ const style = getComputedStyle(probe);
174
+ const safe = { top: parseFloat(style.paddingTop) || 0, right: parseFloat(style.paddingRight) || 0,
175
+ bottom: parseFloat(style.paddingBottom) || 0, left: parseFloat(style.paddingLeft) || 0 };
176
+ probe.remove();
177
+ const rect = element.getBoundingClientRect();
178
+ if (rect.width <= 0 || rect.height <= 0) {
179
+ return { top: 0, right: 0, bottom: 0, left: 0 };
180
+ }
181
+ const sx = viewport.width / rect.width;
182
+ const sy = viewport.height / rect.height;
183
+ return {
184
+ top: Math.max(0, safe.top - rect.top) * sy,
185
+ right: Math.max(0, rect.right - (window.innerWidth - safe.right)) * sx,
186
+ bottom: Math.max(0, rect.bottom - (window.innerHeight - safe.bottom)) * sy,
187
+ left: Math.max(0, safe.left - rect.left) * sx
188
+ };
189
+ }
190
+ /** Measures HUD text with an offscreen browser canvas. Without a 2D context, text measures zero wide. */
191
+ export function browserGameUiMeasure(gameId) {
192
+ const context = document.createElement("canvas").getContext("2d");
193
+ if (!context) {
194
+ return () => 0;
195
+ }
196
+ return (text, size, fontId) => {
197
+ context.font = gameUiFont(size, fontId, gameId);
198
+ return context.measureText(text).width;
199
+ };
200
+ }
201
+ //# sourceMappingURL=controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../src/ui/controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { GameRenderFrame } from "@nodetool-ai/protocol";
2
+ import { type HudContext } from "../frame.js";
3
+ import { type GameUiPaintContext } from "./paint.js";
4
+ import type { GameUiViewport } from "./layout.js";
5
+ /** The 2D HUD rectangle: the frame's view at one HUD pixel per canvas pixel. */
6
+ export declare function gameUiViewport2D(frame: Pick<GameRenderFrame, "width" | "height" | "pixelsPerUnit">): GameUiViewport;
7
+ /** Loads the images a frame's HUD tree draws through a renderer's asset loader. */
8
+ export declare function loadGameUiImages<I>(frame: Pick<GameRenderFrame, "ui">, load: (assetId: string) => Promise<I | null>): Promise<Map<string, I>>;
9
+ /** Paints the 2D HUD: the widget tree, then the `hud` labels above it. `scale` is output pixels per HUD pixel. */
10
+ export declare function paintGameHud2D(context: HudContext & GameUiPaintContext, frame: GameRenderFrame, scale?: number, images?: ReadonlyMap<string, unknown>): void;
11
+ //# sourceMappingURL=hud2d.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hud2d.d.ts","sourceRoot":"","sources":["../../src/ui/hud2d.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAA+B,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,QAAQ,GAAG,eAAe,CAAC,GAAG,cAAc,CAEnH;AAED,mFAAmF;AACnF,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAOnJ;AAED,kHAAkH;AAClH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,kBAAkB,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,SAAI,EACxG,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAG7C"}
@@ -0,0 +1,25 @@
1
+ import { paintHud } from "../frame.js";
2
+ import { gameUiImageIds, paintGameUi } from "./paint.js";
3
+ /** The 2D HUD rectangle: the frame's view at one HUD pixel per canvas pixel. */
4
+ export function gameUiViewport2D(frame) {
5
+ return { width: frame.width * frame.pixelsPerUnit, height: frame.height * frame.pixelsPerUnit };
6
+ }
7
+ /** Loads the images a frame's HUD tree draws through a renderer's asset loader. */
8
+ export async function loadGameUiImages(frame, load) {
9
+ const images = new Map();
10
+ await Promise.all(gameUiImageIds(frame.ui).map(async (assetId) => {
11
+ const image = await load(assetId);
12
+ if (image) {
13
+ images.set(assetId, image);
14
+ }
15
+ }));
16
+ return images;
17
+ }
18
+ /** Paints the 2D HUD: the widget tree, then the `hud` labels above it. `scale` is output pixels per HUD pixel. */
19
+ export function paintGameHud2D(context, frame, scale = 1, images) {
20
+ if (frame.ui) {
21
+ paintGameUi(context, frame.ui, gameUiViewport2D(frame), { scale, gameId: frame.gameId, images });
22
+ }
23
+ paintHud(context, frame.hud, scale, frame.gameId);
24
+ }
25
+ //# sourceMappingURL=hud2d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hud2d.js","sourceRoot":"","sources":["../../src/ui/hud2d.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAmB,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,WAAW,EAA2B,MAAM,YAAY,CAAC;AAGlF,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,KAAkE;IACjG,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;AAClG,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAI,KAAkC,EAAE,IAA4C;IACxH,MAAM,MAAM,GAAG,IAAI,GAAG,EAAa,CAAC;IACpC,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QAC/D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,KAAK,EAAE,CAAC;YAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAAC,CAAC;IAC5C,CAAC,CAAC,CAAC,CAAC;IACJ,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kHAAkH;AAClH,MAAM,UAAU,cAAc,CAAC,OAAwC,EAAE,KAAsB,EAAE,KAAK,GAAG,CAAC,EACxG,MAAqC;IACrC,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;QAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAAC,CAAC;IACnH,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { GameUiFrame, GameUiNode } from "@nodetool-ai/protocol";
2
+ /** The HUD rectangle in HUD pixels: the 2D canvas at one pixel per pixel, or the 3D presentation's hudWidth by hudHeight. */
3
+ export interface GameUiViewport {
4
+ readonly width: number;
5
+ readonly height: number;
6
+ }
7
+ /** Device safe-area insets in HUD pixels. */
8
+ export interface GameUiInsets {
9
+ readonly top: number;
10
+ readonly right: number;
11
+ readonly bottom: number;
12
+ readonly left: number;
13
+ }
14
+ /** A node placed on the HUD, with the opacity it inherits from its ancestors. */
15
+ export interface GameUiBox {
16
+ readonly node: GameUiNode;
17
+ readonly x: number;
18
+ readonly y: number;
19
+ readonly width: number;
20
+ readonly height: number;
21
+ readonly opacity: number;
22
+ }
23
+ /** Advance width of `text` in HUD pixels at font `size`, in the HUD font for `fontId`. */
24
+ export type GameUiMeasureText = (text: string, size: number, fontId: string | undefined) => number;
25
+ export declare const GAME_UI_TEXT_SIZE = 16;
26
+ /** Line height of a text node as a multiple of its font size. */
27
+ export declare const GAME_UI_LINE_HEIGHT = 1.25;
28
+ /**
29
+ * Places every visible node of a HUD tree. The result is in paint order: each node before its children,
30
+ * and siblings in tree order. Hidden nodes and their subtrees are left out.
31
+ * This is the one layout both the 2D HUD pass and the 3D HUD module draw from.
32
+ */
33
+ export declare function layoutGameUi(ui: GameUiFrame, viewport: GameUiViewport, measure: GameUiMeasureText, insets?: GameUiInsets): GameUiBox[];
34
+ /** The topmost visible button under a HUD point, or undefined. */
35
+ export declare function hitGameUiButton(boxes: readonly GameUiBox[], x: number, y: number): GameUiBox | undefined;
36
+ export type GameUiDirection = "up" | "down" | "left" | "right";
37
+ /**
38
+ * The button focus moves to from `currentId` in `direction`: the nearest button whose centre lies that way,
39
+ * with sideways distance counted double. Without a current focus it is the first button in paint order.
40
+ */
41
+ export declare function nextGameUiFocus(boxes: readonly GameUiBox[], currentId: string | undefined, direction: GameUiDirection): string | undefined;
42
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/ui/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAErE,6HAA6H;AAC7H,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,0FAA0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,CAAC;AAEnG,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAMxC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,iBAAiB,EAChG,MAAM,GAAE,YAAwB,GAAG,SAAS,EAAE,CAyE/C;AAwCD,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAMxG;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAkB1I"}
@@ -0,0 +1,182 @@
1
+ export const GAME_UI_TEXT_SIZE = 16;
2
+ /** Line height of a text node as a multiple of its font size. */
3
+ export const GAME_UI_LINE_HEIGHT = 1.25;
4
+ const NO_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };
5
+ /**
6
+ * Places every visible node of a HUD tree. The result is in paint order: each node before its children,
7
+ * and siblings in tree order. Hidden nodes and their subtrees are left out.
8
+ * This is the one layout both the 2D HUD pass and the 3D HUD module draw from.
9
+ */
10
+ export function layoutGameUi(ui, viewport, measure, insets = NO_INSETS) {
11
+ const children = new Map();
12
+ for (const node of ui.nodes) {
13
+ if (node.visible === false) {
14
+ continue;
15
+ }
16
+ const list = children.get(node.parent) ?? [];
17
+ list.push(node);
18
+ children.set(node.parent, list);
19
+ }
20
+ // The document and scene trees merge into one frame, so a container id can repeat. Sizing and placing
21
+ // each id once keeps a repeated id from making a node its own descendant.
22
+ const sizes = new Map();
23
+ const sizing = new Set();
24
+ const placed = new Set();
25
+ const sizeOf = (node) => {
26
+ const known = sizes.get(node.id);
27
+ if (known) {
28
+ return known;
29
+ }
30
+ if (sizing.has(node.id)) {
31
+ return { width: 0, height: 0 };
32
+ }
33
+ sizing.add(node.id);
34
+ const content = contentSize(node, children.get(node.id) ?? [], sizeOf, measure);
35
+ const size = { width: node.width ?? content.width, height: node.height ?? content.height };
36
+ sizes.set(node.id, size);
37
+ return size;
38
+ };
39
+ const safe = ui.safeArea ? insets : NO_INSETS;
40
+ const root = { x: safe.left, y: safe.top,
41
+ width: Math.max(0, viewport.width - safe.left - safe.right), height: Math.max(0, viewport.height - safe.top - safe.bottom) };
42
+ const boxes = [];
43
+ const place = (node, x, y, inherited) => {
44
+ if (placed.has(node.id)) {
45
+ return;
46
+ }
47
+ placed.add(node.id);
48
+ const size = sizeOf(node);
49
+ const box = { node, x: x + (node.offset?.x ?? 0), y: y + (node.offset?.y ?? 0), width: size.width, height: size.height,
50
+ opacity: inherited * (node.opacity ?? 1) };
51
+ boxes.push(box);
52
+ const list = children.get(node.id) ?? [];
53
+ if (node.kind === "stack") {
54
+ placeStack(node, box, list);
55
+ }
56
+ else if (node.kind === "grid") {
57
+ placeGrid(node, box, list);
58
+ }
59
+ else {
60
+ for (const child of list) {
61
+ anchored(child, box, box.opacity);
62
+ }
63
+ }
64
+ };
65
+ const anchored = (node, parent, inherited) => {
66
+ const size = sizeOf(node);
67
+ const anchor = node.anchor ?? { x: 0, y: 0 };
68
+ const pivot = node.pivot ?? anchor;
69
+ place(node, parent.x + anchor.x * parent.width - pivot.x * size.width, parent.y + anchor.y * parent.height - pivot.y * size.height, inherited);
70
+ };
71
+ const placeStack = (node, box, list) => {
72
+ const padding = node.padding ?? 0;
73
+ const gap = node.gap ?? 0;
74
+ const vertical = (node.direction ?? "vertical") === "vertical";
75
+ const cross = vertical ? box.width - padding * 2 : box.height - padding * 2;
76
+ const share = { start: 0, center: 0.5, end: 1 }[node.align ?? "start"];
77
+ let along = padding;
78
+ for (const child of list) {
79
+ const size = sizeOf(child);
80
+ const slack = (cross - (vertical ? size.width : size.height)) * share;
81
+ if (vertical) {
82
+ place(child, box.x + padding + slack, box.y + along, box.opacity);
83
+ }
84
+ else {
85
+ place(child, box.x + along, box.y + padding + slack, box.opacity);
86
+ }
87
+ along += (vertical ? size.height : size.width) + gap;
88
+ }
89
+ };
90
+ const placeGrid = (node, box, list) => {
91
+ const padding = node.padding ?? 0;
92
+ const gap = node.gap ?? 0;
93
+ const cell = gridCell(list, sizeOf);
94
+ list.forEach((child, index) => {
95
+ const column = index % node.columns;
96
+ const row = Math.floor(index / node.columns);
97
+ place(child, box.x + padding + column * (cell.width + gap), box.y + padding + row * (cell.height + gap), box.opacity);
98
+ });
99
+ };
100
+ for (const node of children.get(undefined) ?? []) {
101
+ anchored(node, root, 1);
102
+ }
103
+ return boxes;
104
+ }
105
+ function gridCell(list, sizeOf) {
106
+ let width = 0;
107
+ let height = 0;
108
+ for (const child of list) {
109
+ const size = sizeOf(child);
110
+ width = Math.max(width, size.width);
111
+ height = Math.max(height, size.height);
112
+ }
113
+ return { width, height };
114
+ }
115
+ function contentSize(node, list, sizeOf, measure) {
116
+ if (node.kind === "text") {
117
+ const size = node.size ?? GAME_UI_TEXT_SIZE;
118
+ return { width: measure(node.text, size, node.fontId), height: size * GAME_UI_LINE_HEIGHT };
119
+ }
120
+ if (node.kind === "stack") {
121
+ const padding = node.padding ?? 0;
122
+ const gap = list.length > 1 ? (node.gap ?? 0) * (list.length - 1) : 0;
123
+ const sizes = list.map(sizeOf);
124
+ const vertical = (node.direction ?? "vertical") === "vertical";
125
+ const along = sizes.reduce((sum, size) => sum + (vertical ? size.height : size.width), 0) + gap;
126
+ const across = sizes.reduce((maximum, size) => Math.max(maximum, vertical ? size.width : size.height), 0);
127
+ return vertical ? { width: across + padding * 2, height: along + padding * 2 } : { width: along + padding * 2, height: across + padding * 2 };
128
+ }
129
+ if (node.kind === "grid") {
130
+ const padding = node.padding ?? 0;
131
+ const gap = node.gap ?? 0;
132
+ const cell = gridCell(list, sizeOf);
133
+ const columns = Math.min(node.columns, list.length);
134
+ const rows = Math.ceil(list.length / node.columns);
135
+ return { width: columns * cell.width + Math.max(0, columns - 1) * gap + padding * 2,
136
+ height: rows * cell.height + Math.max(0, rows - 1) * gap + padding * 2 };
137
+ }
138
+ // Validation requires an explicit size for the other kinds. A document that skips validation draws nothing for them.
139
+ return { width: 0, height: 0 };
140
+ }
141
+ /** The topmost visible button under a HUD point, or undefined. */
142
+ export function hitGameUiButton(boxes, x, y) {
143
+ for (let index = boxes.length - 1; index >= 0; index--) {
144
+ const box = boxes[index];
145
+ if (box.node.kind === "button" && x >= box.x && y >= box.y && x < box.x + box.width && y < box.y + box.height) {
146
+ return box;
147
+ }
148
+ }
149
+ return undefined;
150
+ }
151
+ /**
152
+ * The button focus moves to from `currentId` in `direction`: the nearest button whose centre lies that way,
153
+ * with sideways distance counted double. Without a current focus it is the first button in paint order.
154
+ */
155
+ export function nextGameUiFocus(boxes, currentId, direction) {
156
+ const buttons = boxes.filter((box) => box.node.kind === "button");
157
+ const current = buttons.find((box) => box.node.id === currentId);
158
+ if (!current) {
159
+ return buttons[0]?.node.id;
160
+ }
161
+ const [dx, dy] = { up: [0, -1], down: [0, 1], left: [-1, 0], right: [1, 0] }[direction];
162
+ const cx = current.x + current.width / 2;
163
+ const cy = current.y + current.height / 2;
164
+ let best;
165
+ for (const box of buttons) {
166
+ if (box === current) {
167
+ continue;
168
+ }
169
+ const ox = box.x + box.width / 2 - cx;
170
+ const oy = box.y + box.height / 2 - cy;
171
+ const forward = ox * dx + oy * dy;
172
+ if (forward <= 0) {
173
+ continue;
174
+ }
175
+ const score = forward + 2 * Math.abs(ox * dy - oy * dx);
176
+ if (!best || score < best.score) {
177
+ best = { id: box.node.id, score };
178
+ }
179
+ }
180
+ return best?.id ?? current.node.id;
181
+ }
182
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/ui/layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { GameUiFrame } from "@nodetool-ai/protocol";
2
+ import { type GameUiBox, type GameUiInsets, type GameUiMeasureText, type GameUiViewport } from "./layout.js";
3
+ /** The Canvas2D calls the HUD painter makes. Browser, OffscreenCanvas and @napi-rs/canvas contexts all provide them. */
4
+ export interface GameUiPaintContext {
5
+ fillStyle: unknown;
6
+ strokeStyle: unknown;
7
+ lineWidth: number;
8
+ globalAlpha: number;
9
+ font: string;
10
+ textBaseline: string;
11
+ textAlign: string;
12
+ save(): void;
13
+ restore(): void;
14
+ scale(x: number, y: number): void;
15
+ fillRect(x: number, y: number, width: number, height: number): void;
16
+ strokeRect(x: number, y: number, width: number, height: number): void;
17
+ beginPath(): void;
18
+ roundRect(x: number, y: number, width: number, height: number, radius: number): void;
19
+ fill(): void;
20
+ fillText(text: string, x: number, y: number): void;
21
+ measureText(text: string): {
22
+ readonly width: number;
23
+ };
24
+ drawImage(image: never, x: number, y: number, width: number, height: number): void;
25
+ }
26
+ export interface GameUiPaintOptions {
27
+ /** Output pixels per HUD pixel. */
28
+ readonly scale?: number;
29
+ readonly gameId?: string;
30
+ /** Loaded HUD images by asset id. A missing image leaves its node empty. */
31
+ readonly images?: ReadonlyMap<string, unknown>;
32
+ readonly insets?: GameUiInsets;
33
+ }
34
+ /** The CSS font of HUD text, the same weight and fallback stack as `hud` labels. */
35
+ export declare function gameUiFont(size: number, fontId: string | undefined, gameId: string | undefined): string;
36
+ /** Measures HUD text with a Canvas2D context, so layout and painting agree on text widths. */
37
+ export declare function canvasGameUiMeasure(context: Pick<GameUiPaintContext, "font" | "measureText">, gameId: string | undefined): GameUiMeasureText;
38
+ /** Asset ids of the images a HUD tree draws, for the renderer to load before painting. */
39
+ export declare function gameUiImageIds(ui: GameUiFrame | undefined): string[];
40
+ /**
41
+ * Lays out and paints a HUD tree onto a Canvas2D context whose origin is the HUD rectangle's top-left corner.
42
+ * Returns the boxes it drew, in HUD pixels.
43
+ */
44
+ export declare function paintGameUi(context: GameUiPaintContext, ui: GameUiFrame, viewport: GameUiViewport, options?: GameUiPaintOptions): GameUiBox[];
45
+ //# sourceMappingURL=paint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paint.d.ts","sourceRoot":"","sources":["../../src/ui/paint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAmC,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9I,wHAAwH;AACxH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,IAAI,IAAI,CAAC;IACb,OAAO,IAAI,IAAI,CAAC;IAChB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACpE,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtE,SAAS,IAAI,IAAI,CAAC;IAClB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACrF,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACpF;AAED,MAAM,WAAW,kBAAkB;IACjC,mCAAmC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;CAChC;AASD,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGvG;AAED,8FAA8F;AAC9F,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,GAAG,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,CAK5I;AAED,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,EAAE,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,EAAE,CAEpE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,EAAE,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,GAAE,kBAAuB,GAAG,SAAS,EAAE,CAWjJ"}