hoi4-agent-tools 0.0.0-bootstrap.1 → 0.1.2

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 (416) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +201 -0
  3. package/README.md +140 -2
  4. package/SECURITY.md +17 -0
  5. package/dist/bin/http.d.ts +3 -0
  6. package/dist/bin/http.d.ts.map +1 -0
  7. package/dist/bin/http.js +27 -0
  8. package/dist/bin/http.js.map +1 -0
  9. package/dist/bin/setup.d.ts +3 -0
  10. package/dist/bin/setup.d.ts.map +1 -0
  11. package/dist/bin/setup.js +188 -0
  12. package/dist/bin/setup.js.map +1 -0
  13. package/dist/bin/stdio.d.ts +3 -0
  14. package/dist/bin/stdio.d.ts.map +1 -0
  15. package/dist/bin/stdio.js +36 -0
  16. package/dist/bin/stdio.js.map +1 -0
  17. package/dist/hoi4_agent_tools/core/artifacts.d.ts +117 -0
  18. package/dist/hoi4_agent_tools/core/artifacts.d.ts.map +1 -0
  19. package/dist/hoi4_agent_tools/core/artifacts.js +1047 -0
  20. package/dist/hoi4_agent_tools/core/artifacts.js.map +1 -0
  21. package/dist/hoi4_agent_tools/core/canonical.d.ts +13 -0
  22. package/dist/hoi4_agent_tools/core/canonical.d.ts.map +1 -0
  23. package/dist/hoi4_agent_tools/core/canonical.js +41 -0
  24. package/dist/hoi4_agent_tools/core/canonical.js.map +1 -0
  25. package/dist/hoi4_agent_tools/core/configuration.d.ts +137 -0
  26. package/dist/hoi4_agent_tools/core/configuration.d.ts.map +1 -0
  27. package/dist/hoi4_agent_tools/core/configuration.js +383 -0
  28. package/dist/hoi4_agent_tools/core/configuration.js.map +1 -0
  29. package/dist/hoi4_agent_tools/core/diagnostic-collector.d.ts +18 -0
  30. package/dist/hoi4_agent_tools/core/diagnostic-collector.d.ts.map +1 -0
  31. package/dist/hoi4_agent_tools/core/diagnostic-collector.js +45 -0
  32. package/dist/hoi4_agent_tools/core/diagnostic-collector.js.map +1 -0
  33. package/dist/hoi4_agent_tools/core/diagnostics.d.ts +26 -0
  34. package/dist/hoi4_agent_tools/core/diagnostics.d.ts.map +1 -0
  35. package/dist/hoi4_agent_tools/core/diagnostics.js +25 -0
  36. package/dist/hoi4_agent_tools/core/diagnostics.js.map +1 -0
  37. package/dist/hoi4_agent_tools/core/diff.d.ts +22 -0
  38. package/dist/hoi4_agent_tools/core/diff.d.ts.map +1 -0
  39. package/dist/hoi4_agent_tools/core/diff.js +93 -0
  40. package/dist/hoi4_agent_tools/core/diff.js.map +1 -0
  41. package/dist/hoi4_agent_tools/core/engine.d.ts +56 -0
  42. package/dist/hoi4_agent_tools/core/engine.d.ts.map +1 -0
  43. package/dist/hoi4_agent_tools/core/engine.js +319 -0
  44. package/dist/hoi4_agent_tools/core/engine.js.map +1 -0
  45. package/dist/hoi4_agent_tools/core/image-diff.d.ts +14 -0
  46. package/dist/hoi4_agent_tools/core/image-diff.d.ts.map +1 -0
  47. package/dist/hoi4_agent_tools/core/image-diff.js +121 -0
  48. package/dist/hoi4_agent_tools/core/image-diff.js.map +1 -0
  49. package/dist/hoi4_agent_tools/core/index.d.ts +64 -0
  50. package/dist/hoi4_agent_tools/core/index.d.ts.map +1 -0
  51. package/dist/hoi4_agent_tools/core/index.js +963 -0
  52. package/dist/hoi4_agent_tools/core/index.js.map +1 -0
  53. package/dist/hoi4_agent_tools/core/index.public.d.ts +16 -0
  54. package/dist/hoi4_agent_tools/core/index.public.d.ts.map +1 -0
  55. package/dist/hoi4_agent_tools/core/index.public.js +16 -0
  56. package/dist/hoi4_agent_tools/core/index.public.js.map +1 -0
  57. package/dist/hoi4_agent_tools/core/render-budget.d.ts +51 -0
  58. package/dist/hoi4_agent_tools/core/render-budget.d.ts.map +1 -0
  59. package/dist/hoi4_agent_tools/core/render-budget.js +109 -0
  60. package/dist/hoi4_agent_tools/core/render-budget.js.map +1 -0
  61. package/dist/hoi4_agent_tools/core/result.d.ts +45 -0
  62. package/dist/hoi4_agent_tools/core/result.d.ts.map +1 -0
  63. package/dist/hoi4_agent_tools/core/result.js +26 -0
  64. package/dist/hoi4_agent_tools/core/result.js.map +1 -0
  65. package/dist/hoi4_agent_tools/core/scanner.d.ts +28 -0
  66. package/dist/hoi4_agent_tools/core/scanner.d.ts.map +1 -0
  67. package/dist/hoi4_agent_tools/core/scanner.js +136 -0
  68. package/dist/hoi4_agent_tools/core/scanner.js.map +1 -0
  69. package/dist/hoi4_agent_tools/core/server-state.d.ts +31 -0
  70. package/dist/hoi4_agent_tools/core/server-state.d.ts.map +1 -0
  71. package/dist/hoi4_agent_tools/core/server-state.js +413 -0
  72. package/dist/hoi4_agent_tools/core/server-state.js.map +1 -0
  73. package/dist/hoi4_agent_tools/core/source/encoding.d.ts +10 -0
  74. package/dist/hoi4_agent_tools/core/source/encoding.d.ts.map +1 -0
  75. package/dist/hoi4_agent_tools/core/source/encoding.js +54 -0
  76. package/dist/hoi4_agent_tools/core/source/encoding.js.map +1 -0
  77. package/dist/hoi4_agent_tools/core/source/index.d.ts +7 -0
  78. package/dist/hoi4_agent_tools/core/source/index.d.ts.map +1 -0
  79. package/dist/hoi4_agent_tools/core/source/index.js +7 -0
  80. package/dist/hoi4_agent_tools/core/source/index.js.map +1 -0
  81. package/dist/hoi4_agent_tools/core/source/lexer.d.ts +30 -0
  82. package/dist/hoi4_agent_tools/core/source/lexer.d.ts.map +1 -0
  83. package/dist/hoi4_agent_tools/core/source/lexer.js +266 -0
  84. package/dist/hoi4_agent_tools/core/source/lexer.js.map +1 -0
  85. package/dist/hoi4_agent_tools/core/source/limits.d.ts +21 -0
  86. package/dist/hoi4_agent_tools/core/source/limits.d.ts.map +1 -0
  87. package/dist/hoi4_agent_tools/core/source/limits.js +49 -0
  88. package/dist/hoi4_agent_tools/core/source/limits.js.map +1 -0
  89. package/dist/hoi4_agent_tools/core/source/localisation.d.ts +20 -0
  90. package/dist/hoi4_agent_tools/core/source/localisation.d.ts.map +1 -0
  91. package/dist/hoi4_agent_tools/core/source/localisation.js +163 -0
  92. package/dist/hoi4_agent_tools/core/source/localisation.js.map +1 -0
  93. package/dist/hoi4_agent_tools/core/source/parser.d.ts +44 -0
  94. package/dist/hoi4_agent_tools/core/source/parser.d.ts.map +1 -0
  95. package/dist/hoi4_agent_tools/core/source/parser.js +334 -0
  96. package/dist/hoi4_agent_tools/core/source/parser.js.map +1 -0
  97. package/dist/hoi4_agent_tools/core/source/rewrite.d.ts +10 -0
  98. package/dist/hoi4_agent_tools/core/source/rewrite.d.ts.map +1 -0
  99. package/dist/hoi4_agent_tools/core/source/rewrite.js +28 -0
  100. package/dist/hoi4_agent_tools/core/source/rewrite.js.map +1 -0
  101. package/dist/hoi4_agent_tools/core/svg-text.d.ts +34 -0
  102. package/dist/hoi4_agent_tools/core/svg-text.d.ts.map +1 -0
  103. package/dist/hoi4_agent_tools/core/svg-text.js +127 -0
  104. package/dist/hoi4_agent_tools/core/svg-text.js.map +1 -0
  105. package/dist/hoi4_agent_tools/core/transaction-limits.d.ts +9 -0
  106. package/dist/hoi4_agent_tools/core/transaction-limits.d.ts.map +1 -0
  107. package/dist/hoi4_agent_tools/core/transaction-limits.js +9 -0
  108. package/dist/hoi4_agent_tools/core/transaction-limits.js.map +1 -0
  109. package/dist/hoi4_agent_tools/core/transactions.d.ts +162 -0
  110. package/dist/hoi4_agent_tools/core/transactions.d.ts.map +1 -0
  111. package/dist/hoi4_agent_tools/core/transactions.js +1181 -0
  112. package/dist/hoi4_agent_tools/core/transactions.js.map +1 -0
  113. package/dist/hoi4_agent_tools/core/workspace.d.ts +68 -0
  114. package/dist/hoi4_agent_tools/core/workspace.d.ts.map +1 -0
  115. package/dist/hoi4_agent_tools/core/workspace.js +794 -0
  116. package/dist/hoi4_agent_tools/core/workspace.js.map +1 -0
  117. package/dist/hoi4_agent_tools/focus/compiler.d.ts +9 -0
  118. package/dist/hoi4_agent_tools/focus/compiler.d.ts.map +1 -0
  119. package/dist/hoi4_agent_tools/focus/compiler.js +273 -0
  120. package/dist/hoi4_agent_tools/focus/compiler.js.map +1 -0
  121. package/dist/hoi4_agent_tools/focus/continuous-render.d.ts +32 -0
  122. package/dist/hoi4_agent_tools/focus/continuous-render.d.ts.map +1 -0
  123. package/dist/hoi4_agent_tools/focus/continuous-render.js +179 -0
  124. package/dist/hoi4_agent_tools/focus/continuous-render.js.map +1 -0
  125. package/dist/hoi4_agent_tools/focus/drift.d.ts +22 -0
  126. package/dist/hoi4_agent_tools/focus/drift.d.ts.map +1 -0
  127. package/dist/hoi4_agent_tools/focus/drift.js +124 -0
  128. package/dist/hoi4_agent_tools/focus/drift.js.map +1 -0
  129. package/dist/hoi4_agent_tools/focus/geometry.d.ts +17 -0
  130. package/dist/hoi4_agent_tools/focus/geometry.d.ts.map +1 -0
  131. package/dist/hoi4_agent_tools/focus/geometry.js +35 -0
  132. package/dist/hoi4_agent_tools/focus/geometry.js.map +1 -0
  133. package/dist/hoi4_agent_tools/focus/importer.d.ts +9 -0
  134. package/dist/hoi4_agent_tools/focus/importer.d.ts.map +1 -0
  135. package/dist/hoi4_agent_tools/focus/importer.js +732 -0
  136. package/dist/hoi4_agent_tools/focus/importer.js.map +1 -0
  137. package/dist/hoi4_agent_tools/focus/index.d.ts +14 -0
  138. package/dist/hoi4_agent_tools/focus/index.d.ts.map +1 -0
  139. package/dist/hoi4_agent_tools/focus/index.js +14 -0
  140. package/dist/hoi4_agent_tools/focus/index.js.map +1 -0
  141. package/dist/hoi4_agent_tools/focus/layout.d.ts +5 -0
  142. package/dist/hoi4_agent_tools/focus/layout.d.ts.map +1 -0
  143. package/dist/hoi4_agent_tools/focus/layout.js +653 -0
  144. package/dist/hoi4_agent_tools/focus/layout.js.map +1 -0
  145. package/dist/hoi4_agent_tools/focus/limits.d.ts +9 -0
  146. package/dist/hoi4_agent_tools/focus/limits.d.ts.map +1 -0
  147. package/dist/hoi4_agent_tools/focus/limits.js +9 -0
  148. package/dist/hoi4_agent_tools/focus/limits.js.map +1 -0
  149. package/dist/hoi4_agent_tools/focus/lint.d.ts +14 -0
  150. package/dist/hoi4_agent_tools/focus/lint.d.ts.map +1 -0
  151. package/dist/hoi4_agent_tools/focus/lint.js +839 -0
  152. package/dist/hoi4_agent_tools/focus/lint.js.map +1 -0
  153. package/dist/hoi4_agent_tools/focus/model.d.ts +303 -0
  154. package/dist/hoi4_agent_tools/focus/model.d.ts.map +1 -0
  155. package/dist/hoi4_agent_tools/focus/model.js +20 -0
  156. package/dist/hoi4_agent_tools/focus/model.js.map +1 -0
  157. package/dist/hoi4_agent_tools/focus/native-effects.d.ts +9 -0
  158. package/dist/hoi4_agent_tools/focus/native-effects.d.ts.map +1 -0
  159. package/dist/hoi4_agent_tools/focus/native-effects.js +563 -0
  160. package/dist/hoi4_agent_tools/focus/native-effects.js.map +1 -0
  161. package/dist/hoi4_agent_tools/focus/planning.d.ts +15 -0
  162. package/dist/hoi4_agent_tools/focus/planning.d.ts.map +1 -0
  163. package/dist/hoi4_agent_tools/focus/planning.js +241 -0
  164. package/dist/hoi4_agent_tools/focus/planning.js.map +1 -0
  165. package/dist/hoi4_agent_tools/focus/presentation.d.ts +24 -0
  166. package/dist/hoi4_agent_tools/focus/presentation.d.ts.map +1 -0
  167. package/dist/hoi4_agent_tools/focus/presentation.js +204 -0
  168. package/dist/hoi4_agent_tools/focus/presentation.js.map +1 -0
  169. package/dist/hoi4_agent_tools/focus/render.d.ts +35 -0
  170. package/dist/hoi4_agent_tools/focus/render.d.ts.map +1 -0
  171. package/dist/hoi4_agent_tools/focus/render.js +491 -0
  172. package/dist/hoi4_agent_tools/focus/render.js.map +1 -0
  173. package/dist/hoi4_agent_tools/focus/service.d.ts +82 -0
  174. package/dist/hoi4_agent_tools/focus/service.d.ts.map +1 -0
  175. package/dist/hoi4_agent_tools/focus/service.js +492 -0
  176. package/dist/hoi4_agent_tools/focus/service.js.map +1 -0
  177. package/dist/hoi4_agent_tools/focus/source-update.d.ts +6 -0
  178. package/dist/hoi4_agent_tools/focus/source-update.d.ts.map +1 -0
  179. package/dist/hoi4_agent_tools/focus/source-update.js +328 -0
  180. package/dist/hoi4_agent_tools/focus/source-update.js.map +1 -0
  181. package/dist/hoi4_agent_tools/gui/animation-manifest.d.ts +37 -0
  182. package/dist/hoi4_agent_tools/gui/animation-manifest.d.ts.map +1 -0
  183. package/dist/hoi4_agent_tools/gui/animation-manifest.js +66 -0
  184. package/dist/hoi4_agent_tools/gui/animation-manifest.js.map +1 -0
  185. package/dist/hoi4_agent_tools/gui/assets.d.ts +71 -0
  186. package/dist/hoi4_agent_tools/gui/assets.d.ts.map +1 -0
  187. package/dist/hoi4_agent_tools/gui/assets.js +629 -0
  188. package/dist/hoi4_agent_tools/gui/assets.js.map +1 -0
  189. package/dist/hoi4_agent_tools/gui/dds.d.ts +17 -0
  190. package/dist/hoi4_agent_tools/gui/dds.d.ts.map +1 -0
  191. package/dist/hoi4_agent_tools/gui/dds.js +245 -0
  192. package/dist/hoi4_agent_tools/gui/dds.js.map +1 -0
  193. package/dist/hoi4_agent_tools/gui/helpers.d.ts +101 -0
  194. package/dist/hoi4_agent_tools/gui/helpers.d.ts.map +1 -0
  195. package/dist/hoi4_agent_tools/gui/helpers.js +1072 -0
  196. package/dist/hoi4_agent_tools/gui/helpers.js.map +1 -0
  197. package/dist/hoi4_agent_tools/gui/index.d.ts +15 -0
  198. package/dist/hoi4_agent_tools/gui/index.d.ts.map +1 -0
  199. package/dist/hoi4_agent_tools/gui/index.js +15 -0
  200. package/dist/hoi4_agent_tools/gui/index.js.map +1 -0
  201. package/dist/hoi4_agent_tools/gui/layout.d.ts +6 -0
  202. package/dist/hoi4_agent_tools/gui/layout.d.ts.map +1 -0
  203. package/dist/hoi4_agent_tools/gui/layout.js +753 -0
  204. package/dist/hoi4_agent_tools/gui/layout.js.map +1 -0
  205. package/dist/hoi4_agent_tools/gui/limits.d.ts +25 -0
  206. package/dist/hoi4_agent_tools/gui/limits.d.ts.map +1 -0
  207. package/dist/hoi4_agent_tools/gui/limits.js +27 -0
  208. package/dist/hoi4_agent_tools/gui/limits.js.map +1 -0
  209. package/dist/hoi4_agent_tools/gui/renderer.d.ts +18 -0
  210. package/dist/hoi4_agent_tools/gui/renderer.d.ts.map +1 -0
  211. package/dist/hoi4_agent_tools/gui/renderer.js +388 -0
  212. package/dist/hoi4_agent_tools/gui/renderer.js.map +1 -0
  213. package/dist/hoi4_agent_tools/gui/scenario.d.ts +66 -0
  214. package/dist/hoi4_agent_tools/gui/scenario.d.ts.map +1 -0
  215. package/dist/hoi4_agent_tools/gui/scenario.js +191 -0
  216. package/dist/hoi4_agent_tools/gui/scenario.js.map +1 -0
  217. package/dist/hoi4_agent_tools/gui/source-graph.d.ts +7 -0
  218. package/dist/hoi4_agent_tools/gui/source-graph.d.ts.map +1 -0
  219. package/dist/hoi4_agent_tools/gui/source-graph.js +1074 -0
  220. package/dist/hoi4_agent_tools/gui/source-graph.js.map +1 -0
  221. package/dist/hoi4_agent_tools/gui/source-patch.d.ts +13 -0
  222. package/dist/hoi4_agent_tools/gui/source-patch.d.ts.map +1 -0
  223. package/dist/hoi4_agent_tools/gui/source-patch.js +90 -0
  224. package/dist/hoi4_agent_tools/gui/source-patch.js.map +1 -0
  225. package/dist/hoi4_agent_tools/gui/studio.d.ts +86 -0
  226. package/dist/hoi4_agent_tools/gui/studio.d.ts.map +1 -0
  227. package/dist/hoi4_agent_tools/gui/studio.js +830 -0
  228. package/dist/hoi4_agent_tools/gui/studio.js.map +1 -0
  229. package/dist/hoi4_agent_tools/gui/tga.d.ts +16 -0
  230. package/dist/hoi4_agent_tools/gui/tga.d.ts.map +1 -0
  231. package/dist/hoi4_agent_tools/gui/tga.js +157 -0
  232. package/dist/hoi4_agent_tools/gui/tga.js.map +1 -0
  233. package/dist/hoi4_agent_tools/gui/types.d.ts +322 -0
  234. package/dist/hoi4_agent_tools/gui/types.d.ts.map +1 -0
  235. package/dist/hoi4_agent_tools/gui/types.js +19 -0
  236. package/dist/hoi4_agent_tools/gui/types.js.map +1 -0
  237. package/dist/hoi4_agent_tools/gui/validators.d.ts +8 -0
  238. package/dist/hoi4_agent_tools/gui/validators.d.ts.map +1 -0
  239. package/dist/hoi4_agent_tools/gui/validators.js +951 -0
  240. package/dist/hoi4_agent_tools/gui/validators.js.map +1 -0
  241. package/dist/hoi4_agent_tools/map/bmp.d.ts +62 -0
  242. package/dist/hoi4_agent_tools/map/bmp.d.ts.map +1 -0
  243. package/dist/hoi4_agent_tools/map/bmp.js +363 -0
  244. package/dist/hoi4_agent_tools/map/bmp.js.map +1 -0
  245. package/dist/hoi4_agent_tools/map/diagnostic-limit.d.ts +5 -0
  246. package/dist/hoi4_agent_tools/map/diagnostic-limit.d.ts.map +1 -0
  247. package/dist/hoi4_agent_tools/map/diagnostic-limit.js +21 -0
  248. package/dist/hoi4_agent_tools/map/diagnostic-limit.js.map +1 -0
  249. package/dist/hoi4_agent_tools/map/index.d.ts +8 -0
  250. package/dist/hoi4_agent_tools/map/index.d.ts.map +1 -0
  251. package/dist/hoi4_agent_tools/map/index.js +8 -0
  252. package/dist/hoi4_agent_tools/map/index.js.map +1 -0
  253. package/dist/hoi4_agent_tools/map/limits.d.ts +13 -0
  254. package/dist/hoi4_agent_tools/map/limits.d.ts.map +1 -0
  255. package/dist/hoi4_agent_tools/map/limits.js +13 -0
  256. package/dist/hoi4_agent_tools/map/limits.js.map +1 -0
  257. package/dist/hoi4_agent_tools/map/model.d.ts +269 -0
  258. package/dist/hoi4_agent_tools/map/model.d.ts.map +1 -0
  259. package/dist/hoi4_agent_tools/map/model.js +1114 -0
  260. package/dist/hoi4_agent_tools/map/model.js.map +1 -0
  261. package/dist/hoi4_agent_tools/map/operations.d.ts +401 -0
  262. package/dist/hoi4_agent_tools/map/operations.d.ts.map +1 -0
  263. package/dist/hoi4_agent_tools/map/operations.js +2717 -0
  264. package/dist/hoi4_agent_tools/map/operations.js.map +1 -0
  265. package/dist/hoi4_agent_tools/map/render.d.ts +90 -0
  266. package/dist/hoi4_agent_tools/map/render.d.ts.map +1 -0
  267. package/dist/hoi4_agent_tools/map/render.js +759 -0
  268. package/dist/hoi4_agent_tools/map/render.js.map +1 -0
  269. package/dist/hoi4_agent_tools/map/service.d.ts +81 -0
  270. package/dist/hoi4_agent_tools/map/service.d.ts.map +1 -0
  271. package/dist/hoi4_agent_tools/map/service.js +695 -0
  272. package/dist/hoi4_agent_tools/map/service.js.map +1 -0
  273. package/dist/hoi4_agent_tools/map/validation.d.ts +23 -0
  274. package/dist/hoi4_agent_tools/map/validation.d.ts.map +1 -0
  275. package/dist/hoi4_agent_tools/map/validation.js +1177 -0
  276. package/dist/hoi4_agent_tools/map/validation.js.map +1 -0
  277. package/dist/hoi4_agent_tools/mcp/prompts/register.d.ts +3 -0
  278. package/dist/hoi4_agent_tools/mcp/prompts/register.d.ts.map +1 -0
  279. package/dist/hoi4_agent_tools/mcp/prompts/register.js +50 -0
  280. package/dist/hoi4_agent_tools/mcp/prompts/register.js.map +1 -0
  281. package/dist/hoi4_agent_tools/mcp/registry/metadata.d.ts +9 -0
  282. package/dist/hoi4_agent_tools/mcp/registry/metadata.d.ts.map +1 -0
  283. package/dist/hoi4_agent_tools/mcp/registry/metadata.js +10 -0
  284. package/dist/hoi4_agent_tools/mcp/registry/metadata.js.map +1 -0
  285. package/dist/hoi4_agent_tools/mcp/resources/register.d.ts +5 -0
  286. package/dist/hoi4_agent_tools/mcp/resources/register.d.ts.map +1 -0
  287. package/dist/hoi4_agent_tools/mcp/resources/register.js +278 -0
  288. package/dist/hoi4_agent_tools/mcp/resources/register.js.map +1 -0
  289. package/dist/hoi4_agent_tools/mcp/security/auth.d.ts +24 -0
  290. package/dist/hoi4_agent_tools/mcp/security/auth.d.ts.map +1 -0
  291. package/dist/hoi4_agent_tools/mcp/security/auth.js +234 -0
  292. package/dist/hoi4_agent_tools/mcp/security/auth.js.map +1 -0
  293. package/dist/hoi4_agent_tools/mcp/server/base-tools.d.ts +35 -0
  294. package/dist/hoi4_agent_tools/mcp/server/base-tools.d.ts.map +1 -0
  295. package/dist/hoi4_agent_tools/mcp/server/base-tools.js +835 -0
  296. package/dist/hoi4_agent_tools/mcp/server/base-tools.js.map +1 -0
  297. package/dist/hoi4_agent_tools/mcp/server/create.d.ts +5 -0
  298. package/dist/hoi4_agent_tools/mcp/server/create.d.ts.map +1 -0
  299. package/dist/hoi4_agent_tools/mcp/server/create.js +26 -0
  300. package/dist/hoi4_agent_tools/mcp/server/create.js.map +1 -0
  301. package/dist/hoi4_agent_tools/mcp/server/output-schemas.d.ts +133 -0
  302. package/dist/hoi4_agent_tools/mcp/server/output-schemas.d.ts.map +1 -0
  303. package/dist/hoi4_agent_tools/mcp/server/output-schemas.js +127 -0
  304. package/dist/hoi4_agent_tools/mcp/server/output-schemas.js.map +1 -0
  305. package/dist/hoi4_agent_tools/mcp/server/progress.d.ts +8 -0
  306. package/dist/hoi4_agent_tools/mcp/server/progress.d.ts.map +1 -0
  307. package/dist/hoi4_agent_tools/mcp/server/progress.js +21 -0
  308. package/dist/hoi4_agent_tools/mcp/server/progress.js.map +1 -0
  309. package/dist/hoi4_agent_tools/mcp/server/result.d.ts +232 -0
  310. package/dist/hoi4_agent_tools/mcp/server/result.d.ts.map +1 -0
  311. package/dist/hoi4_agent_tools/mcp/server/result.js +353 -0
  312. package/dist/hoi4_agent_tools/mcp/server/result.js.map +1 -0
  313. package/dist/hoi4_agent_tools/mcp/tools/focus.d.ts +5 -0
  314. package/dist/hoi4_agent_tools/mcp/tools/focus.d.ts.map +1 -0
  315. package/dist/hoi4_agent_tools/mcp/tools/focus.js +1059 -0
  316. package/dist/hoi4_agent_tools/mcp/tools/focus.js.map +1 -0
  317. package/dist/hoi4_agent_tools/mcp/tools/gui.d.ts +111 -0
  318. package/dist/hoi4_agent_tools/mcp/tools/gui.d.ts.map +1 -0
  319. package/dist/hoi4_agent_tools/mcp/tools/gui.js +598 -0
  320. package/dist/hoi4_agent_tools/mcp/tools/gui.js.map +1 -0
  321. package/dist/hoi4_agent_tools/mcp/tools/map.d.ts +5 -0
  322. package/dist/hoi4_agent_tools/mcp/tools/map.d.ts.map +1 -0
  323. package/dist/hoi4_agent_tools/mcp/tools/map.js +685 -0
  324. package/dist/hoi4_agent_tools/mcp/tools/map.js.map +1 -0
  325. package/dist/hoi4_agent_tools/mcp/transports/bounded-stdio.d.ts +58 -0
  326. package/dist/hoi4_agent_tools/mcp/transports/bounded-stdio.d.ts.map +1 -0
  327. package/dist/hoi4_agent_tools/mcp/transports/bounded-stdio.js +181 -0
  328. package/dist/hoi4_agent_tools/mcp/transports/bounded-stdio.js.map +1 -0
  329. package/dist/hoi4_agent_tools/mcp/transports/event-store.d.ts +26 -0
  330. package/dist/hoi4_agent_tools/mcp/transports/event-store.d.ts.map +1 -0
  331. package/dist/hoi4_agent_tools/mcp/transports/event-store.js +86 -0
  332. package/dist/hoi4_agent_tools/mcp/transports/event-store.js.map +1 -0
  333. package/dist/hoi4_agent_tools/mcp/transports/http.d.ts +28 -0
  334. package/dist/hoi4_agent_tools/mcp/transports/http.d.ts.map +1 -0
  335. package/dist/hoi4_agent_tools/mcp/transports/http.js +744 -0
  336. package/dist/hoi4_agent_tools/mcp/transports/http.js.map +1 -0
  337. package/dist/hoi4_agent_tools/mcp/transports/protocol-gate.d.ts +15 -0
  338. package/dist/hoi4_agent_tools/mcp/transports/protocol-gate.d.ts.map +1 -0
  339. package/dist/hoi4_agent_tools/mcp/transports/protocol-gate.js +51 -0
  340. package/dist/hoi4_agent_tools/mcp/transports/protocol-gate.js.map +1 -0
  341. package/dist/hoi4_agent_tools/runtime.d.ts +4 -0
  342. package/dist/hoi4_agent_tools/runtime.d.ts.map +1 -0
  343. package/dist/hoi4_agent_tools/runtime.js +27 -0
  344. package/dist/hoi4_agent_tools/runtime.js.map +1 -0
  345. package/dist/hoi4_agent_tools/schemas/common.d.ts +74 -0
  346. package/dist/hoi4_agent_tools/schemas/common.d.ts.map +1 -0
  347. package/dist/hoi4_agent_tools/schemas/common.js +51 -0
  348. package/dist/hoi4_agent_tools/schemas/common.js.map +1 -0
  349. package/dist/hoi4_agent_tools/schemas/focus.d.ts +784 -0
  350. package/dist/hoi4_agent_tools/schemas/focus.d.ts.map +1 -0
  351. package/dist/hoi4_agent_tools/schemas/focus.js +330 -0
  352. package/dist/hoi4_agent_tools/schemas/focus.js.map +1 -0
  353. package/dist/hoi4_agent_tools/schemas/index.d.ts +5 -0
  354. package/dist/hoi4_agent_tools/schemas/index.d.ts.map +1 -0
  355. package/dist/hoi4_agent_tools/schemas/index.js +5 -0
  356. package/dist/hoi4_agent_tools/schemas/index.js.map +1 -0
  357. package/dist/hoi4_agent_tools/schemas/map.d.ts +654 -0
  358. package/dist/hoi4_agent_tools/schemas/map.d.ts.map +1 -0
  359. package/dist/hoi4_agent_tools/schemas/map.js +570 -0
  360. package/dist/hoi4_agent_tools/schemas/map.js.map +1 -0
  361. package/dist/hoi4_agent_tools/schemas/transaction.d.ts +259 -0
  362. package/dist/hoi4_agent_tools/schemas/transaction.d.ts.map +1 -0
  363. package/dist/hoi4_agent_tools/schemas/transaction.js +104 -0
  364. package/dist/hoi4_agent_tools/schemas/transaction.js.map +1 -0
  365. package/dist/hoi4_agent_tools/version.d.ts +6 -0
  366. package/dist/hoi4_agent_tools/version.d.ts.map +1 -0
  367. package/dist/hoi4_agent_tools/version.js +7 -0
  368. package/dist/hoi4_agent_tools/version.js.map +1 -0
  369. package/dist/index.d.ts +3 -0
  370. package/dist/index.d.ts.map +1 -0
  371. package/dist/index.js +3 -0
  372. package/dist/index.js.map +1 -0
  373. package/docs/README.md +22 -0
  374. package/docs/adr/0001-runtime-and-language.md +16 -0
  375. package/docs/adr/0002-lossless-source-model.md +18 -0
  376. package/docs/adr/0003-image-and-font-codecs.md +18 -0
  377. package/docs/adr/0004-focus-layout.md +16 -0
  378. package/docs/adr/0005-offline-rendering.md +18 -0
  379. package/docs/adr/0006-mcp-sdk-and-protocol.md +16 -0
  380. package/docs/adr/0007-storage-and-transactions.md +24 -0
  381. package/docs/adr/0008-test-strategy.md +18 -0
  382. package/docs/adr/0009-packaging-and-registry.md +16 -0
  383. package/docs/adr/0010-unsupported-and-refusal-policy.md +18 -0
  384. package/docs/adr/0011-http-security.md +16 -0
  385. package/docs/adr/README.md +13 -0
  386. package/docs/architecture.md +60 -0
  387. package/docs/artifacts.md +133 -0
  388. package/docs/compatibility.md +33 -0
  389. package/docs/completion-report.md +60 -0
  390. package/docs/configuration.md +285 -0
  391. package/docs/focus-workflow.md +68 -0
  392. package/docs/gui-workflow.md +121 -0
  393. package/docs/limitations.md +30 -0
  394. package/docs/map-workflow.md +89 -0
  395. package/docs/performance.md +117 -0
  396. package/docs/release.md +181 -0
  397. package/docs/research/mcp-2026-07-10.md +46 -0
  398. package/docs/research/source-ledger.md +68 -0
  399. package/docs/security.md +139 -0
  400. package/docs/self-hosting.md +168 -0
  401. package/docs/testing.md +43 -0
  402. package/docs/third-party-notices.md +11 -0
  403. package/docs/transactions.md +162 -0
  404. package/docs/troubleshooting.md +46 -0
  405. package/package.json +98 -5
  406. package/schemas/configuration.schema.json +794 -0
  407. package/schemas/continuous-focus-palette.schema.json +325 -0
  408. package/schemas/focus-plan.schema.json +902 -0
  409. package/schemas/focus-planning-sidecar.schema.json +364 -0
  410. package/schemas/gui-animation-source.schema.json +176 -0
  411. package/schemas/gui-helper.schema.json +301 -0
  412. package/schemas/gui-scenario.schema.json +298 -0
  413. package/schemas/map-operation.schema.json +2284 -0
  414. package/schemas/operation-result.schema.json +344 -0
  415. package/schemas/transaction-manifest.schema.json +685 -0
  416. package/server.json +32 -0
@@ -0,0 +1,753 @@
1
+ import { compareCodeUnits, hashCanonical } from '../core/canonical.js';
2
+ import { assertRenderDimensions } from '../core/render-budget.js';
3
+ import { sortDiagnostics } from '../core/diagnostics.js';
4
+ import { ServiceError } from '../core/result.js';
5
+ import { GuiAssetCatalog } from './assets.js';
6
+ import { GUI_GRAPH_MAX_EDGES, GUI_GRAPH_MAX_ELEMENTS, GUI_GRAPH_MAX_NODES, GUI_SCENE_MAX_DEPTH, GUI_SCENE_MAX_ELEMENTS, GUI_SCENE_MAX_TEXT_CHARACTERS, GUI_SCENE_MAX_TEXT_LAYOUT_OPERATIONS, GUI_SCENE_MAX_WORK, GUI_TEXT_MAX_CHARACTERS, GUI_TEXT_MAX_MISSING_GLYPH_SAMPLES, } from './limits.js';
7
+ import { guiElementAttributeFidelity } from './source-graph.js';
8
+ import { emptyFidelityReport } from './types.js';
9
+ const clickableTypes = /(?:button|checkbox|editbox|scrollbar|progressbar)/iu;
10
+ const partialSpriteSemantics = {
11
+ textSpriteType: {
12
+ field: 'text_sprite_semantics',
13
+ detail: 'Engine text-sprite generation is not modelled; only the resolved primary texture is shown.',
14
+ },
15
+ corneredTileSpriteType: {
16
+ field: 'cornered_tile_semantics',
17
+ detail: 'Corner and edge tiling is not modelled; the primary texture is stretched as one frame.',
18
+ },
19
+ progressbarType: {
20
+ field: 'progressbar_sprite_semantics',
21
+ detail: 'Progressbar sprite composition is not modelled; only the resolved primary texture is shown.',
22
+ },
23
+ maskedShieldType: {
24
+ field: 'masked_shield_semantics',
25
+ detail: 'Mask, shield, and secondary-texture composition is not modelled; only the resolved primary texture is shown.',
26
+ },
27
+ };
28
+ function property(attributes, ...names) {
29
+ const lowered = new Set(names.map((name) => name.toLowerCase()));
30
+ const entry = Object.entries(attributes).find(([name]) => lowered.has(name.toLowerCase()));
31
+ return entry?.[1];
32
+ }
33
+ function objectProperty(value) {
34
+ return typeof value === 'object' && !Array.isArray(value) ? value : undefined;
35
+ }
36
+ function scalarString(value) {
37
+ if (typeof value === 'string')
38
+ return value;
39
+ if (typeof value === 'number' || typeof value === 'boolean')
40
+ return String(value);
41
+ return undefined;
42
+ }
43
+ function visibleHoiText(value) {
44
+ return value.replace(/\u00a7[A-Za-z0-9!]/gu, '').replace(/\u00a3[^\u00a3\s]+/gu, '\u25c6');
45
+ }
46
+ function scalarNumber(value, reference) {
47
+ if (typeof value === 'number')
48
+ return value;
49
+ if (typeof value !== 'string')
50
+ return undefined;
51
+ if (value.endsWith('%')) {
52
+ const percent = Number(value.slice(0, -1));
53
+ return Number.isFinite(percent) ? (reference * percent) / 100 : undefined;
54
+ }
55
+ const parsed = Number(value);
56
+ return Number.isFinite(parsed) ? parsed : undefined;
57
+ }
58
+ function scalarBoolean(value) {
59
+ if (typeof value === 'boolean')
60
+ return value;
61
+ if (value === 'yes' || value === 'true')
62
+ return true;
63
+ if (value === 'no' || value === 'false')
64
+ return false;
65
+ return undefined;
66
+ }
67
+ function rectIntersection(left, right) {
68
+ const x = Math.max(left.x, right.x);
69
+ const y = Math.max(left.y, right.y);
70
+ const edgeX = Math.min(left.x + left.width, right.x + right.width);
71
+ const edgeY = Math.min(left.y + left.height, right.y + right.height);
72
+ return edgeX <= x || edgeY <= y ? undefined : { x, y, width: edgeX - x, height: edgeY - y };
73
+ }
74
+ function equalRect(left, right) {
75
+ return (left.x === right.x &&
76
+ left.y === right.y &&
77
+ left.width === right.width &&
78
+ left.height === right.height);
79
+ }
80
+ function unionRects(rectangles) {
81
+ if (rectangles.length === 0)
82
+ return { x: 0, y: 0, width: 0, height: 0 };
83
+ const minX = Math.min(...rectangles.map(({ x }) => x));
84
+ const minY = Math.min(...rectangles.map(({ y }) => y));
85
+ const maxX = Math.max(...rectangles.map(({ x, width }) => x + width));
86
+ const maxY = Math.max(...rectangles.map(({ y, height }) => y + height));
87
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
88
+ }
89
+ function addFidelity(report, category, field, detail, element) {
90
+ const item = {
91
+ field,
92
+ detail,
93
+ ...(element === undefined ? {} : { elementId: element.id, sourcePath: element.sourcePath }),
94
+ };
95
+ if (!report[category].some((candidate) => candidate.field === item.field &&
96
+ candidate.detail === item.detail &&
97
+ candidate.elementId === item.elementId)) {
98
+ report[category].push(item);
99
+ }
100
+ }
101
+ function diagnostic(code, severity, message, element) {
102
+ return {
103
+ code,
104
+ severity,
105
+ category: 'rendering',
106
+ message,
107
+ ...(element?.location === undefined ? {} : { location: element.location }),
108
+ };
109
+ }
110
+ function assertTextLength(text, phase) {
111
+ if (text.length <= GUI_TEXT_MAX_CHARACTERS)
112
+ return;
113
+ throw new ServiceError('GUI_TEXT_BUDGET_BLOCKED', `${phase} exceeds the fixed character ceiling`, {
114
+ phase,
115
+ characters: text.length,
116
+ maximumCharacters: GUI_TEXT_MAX_CHARACTERS,
117
+ });
118
+ }
119
+ function replaceTextBounded(input, pattern, replacement, phase) {
120
+ assertTextLength(input, phase);
121
+ const parts = [];
122
+ let cursor = 0;
123
+ let outputLength = 0;
124
+ for (const match of input.matchAll(pattern)) {
125
+ const start = match.index;
126
+ const prefix = input.slice(cursor, start);
127
+ const value = replacement(match);
128
+ const requested = outputLength + prefix.length + value.length;
129
+ if (requested > GUI_TEXT_MAX_CHARACTERS) {
130
+ throw new ServiceError('GUI_TEXT_BUDGET_BLOCKED', `${phase} exceeds the fixed character ceiling`, { phase, characters: requested, maximumCharacters: GUI_TEXT_MAX_CHARACTERS });
131
+ }
132
+ parts.push(prefix, value);
133
+ outputLength = requested;
134
+ cursor = start + match[0].length;
135
+ }
136
+ const suffix = input.slice(cursor);
137
+ if (outputLength + suffix.length > GUI_TEXT_MAX_CHARACTERS) {
138
+ throw new ServiceError('GUI_TEXT_BUDGET_BLOCKED', `${phase} exceeds the fixed character ceiling`, {
139
+ phase,
140
+ characters: outputLength + suffix.length,
141
+ maximumCharacters: GUI_TEXT_MAX_CHARACTERS,
142
+ });
143
+ }
144
+ parts.push(suffix);
145
+ return parts.join('');
146
+ }
147
+ function resolveTokenText(value, scenario, localisation, rowValues) {
148
+ const unresolved = [];
149
+ let missingLocalisation = false;
150
+ const localised = scenario.localisation[value] ?? localisation.get(value);
151
+ let text = localised ?? value;
152
+ assertTextLength(text, 'GUI resolved localisation');
153
+ if (localised === undefined &&
154
+ /^[A-Za-z0-9_.-]+$/u.test(value) &&
155
+ (value.includes('_') || value === value.toUpperCase()))
156
+ missingLocalisation = true;
157
+ text = replaceTextBounded(text, /\$([A-Za-z0-9_.-]+)\$/gu, (match) => {
158
+ const key = match[1] ?? '';
159
+ const replacement = scenario.localisation[key] ?? localisation.get(key);
160
+ if (replacement === undefined) {
161
+ unresolved.push(`$${key}$`);
162
+ return `$${key}$`;
163
+ }
164
+ return replacement;
165
+ }, 'GUI localisation substitution');
166
+ text = replaceTextBounded(text, /\[\?([A-Za-z0-9_.-]+)(?:\|[^\]]+)?\]/gu, (match) => {
167
+ const key = match[1] ?? '';
168
+ const replacement = rowValues?.[key] ?? scenario.variables[key] ?? scenario.scriptedGui[key];
169
+ if (replacement === undefined) {
170
+ unresolved.push(`[?${key}]`);
171
+ return `[?${key}]`;
172
+ }
173
+ return String(replacement);
174
+ }, 'GUI variable substitution');
175
+ text = replaceTextBounded(text, /\[([A-Za-z0-9_.:-]+)\]/gu, (match) => {
176
+ const key = match[1] ?? '';
177
+ const countryKey = key.replace(/^(?:ROOT|This)\./u, '');
178
+ const replacement = rowValues?.[countryKey] ??
179
+ scenario.country?.[countryKey] ??
180
+ scenario.stateValues?.[countryKey] ??
181
+ scenario.scriptedGui[key];
182
+ if (replacement === undefined) {
183
+ unresolved.push(match[0]);
184
+ return match[0];
185
+ }
186
+ return String(replacement);
187
+ }, 'GUI scope substitution');
188
+ return { text, unresolved: [...new Set(unresolved)].sort(), missingLocalisation };
189
+ }
190
+ function wrapText(catalog, fontName, text, fontSize, maximumWidth, work) {
191
+ const paragraphs = text.replaceAll('\\n', '\n').split('\n');
192
+ const lines = [];
193
+ const widths = [];
194
+ const missingGlyphs = new Set();
195
+ const retainMissingGlyphs = (values) => {
196
+ for (const value of values) {
197
+ if (missingGlyphs.size >= GUI_TEXT_MAX_MISSING_GLYPH_SAMPLES)
198
+ return;
199
+ missingGlyphs.add(value);
200
+ }
201
+ };
202
+ let lineHeight = fontSize * 1.2;
203
+ let metricSource = 'approximation';
204
+ for (const paragraph of paragraphs) {
205
+ work.spendTextLayout('text paragraph layout');
206
+ const words = paragraph.split(/\s+/u).filter((word) => word.length > 0);
207
+ if (words.length === 0) {
208
+ lines.push('');
209
+ widths.push(0);
210
+ continue;
211
+ }
212
+ let currentWords = [];
213
+ let currentWidth = 0;
214
+ let previousWord;
215
+ let previousWordWidth = 0;
216
+ for (const word of words) {
217
+ work.spendTextLayout('text word measurement');
218
+ const measuredWord = catalog.measureText(fontName, word, fontSize);
219
+ retainMissingGlyphs(measuredWord.missingGlyphs);
220
+ let candidateWidth = measuredWord.width;
221
+ if (previousWord !== undefined) {
222
+ work.spendTextLayout('text word-boundary measurement');
223
+ const boundary = catalog.measureText(fontName, `${previousWord} ${word}`, fontSize);
224
+ retainMissingGlyphs(boundary.missingGlyphs);
225
+ candidateWidth = currentWidth + boundary.width - previousWordWidth;
226
+ }
227
+ if (maximumWidth > 0 && candidateWidth > maximumWidth && currentWords.length > 0) {
228
+ const committedText = currentWords.join(' ');
229
+ work.spendTextLayout('committed text line measurement');
230
+ const committed = catalog.measureText(fontName, committedText, fontSize);
231
+ lines.push(committedText);
232
+ widths.push(committed.width);
233
+ retainMissingGlyphs(committed.missingGlyphs);
234
+ currentWords = [word];
235
+ currentWidth = measuredWord.width;
236
+ }
237
+ else {
238
+ currentWords.push(word);
239
+ currentWidth = candidateWidth;
240
+ }
241
+ previousWord = word;
242
+ previousWordWidth = measuredWord.width;
243
+ }
244
+ const committedText = currentWords.join(' ');
245
+ work.spendTextLayout('committed text line measurement');
246
+ const committed = catalog.measureText(fontName, committedText, fontSize);
247
+ lines.push(committedText);
248
+ widths.push(committed.width);
249
+ retainMissingGlyphs(committed.missingGlyphs);
250
+ lineHeight = committed.lineHeight;
251
+ metricSource = committed.source;
252
+ }
253
+ return {
254
+ lines,
255
+ widths,
256
+ lineHeight,
257
+ metricSource,
258
+ missingGlyphs: [...missingGlyphs].sort((a, b) => a - b),
259
+ };
260
+ }
261
+ function frameFor(element, sprite, scenario) {
262
+ const frameCount = Math.max(1, sprite.frameCount);
263
+ const selected = scenario.selectedFrames[element.name] ?? scenario.selectedFrames[sprite.name];
264
+ if (selected !== undefined)
265
+ return Math.min(frameCount - 1, selected);
266
+ const explicit = scalarNumber(property(element.attributes, 'frame'), frameCount);
267
+ if (explicit !== undefined)
268
+ return Math.min(frameCount - 1, Math.max(0, Math.trunc(explicit > 0 ? explicit - 1 : explicit)));
269
+ if (sprite.frameAnimated) {
270
+ const framesPerSecond = Math.max(Number.EPSILON, sprite.animationRateFps ?? 1);
271
+ const clockSeconds = sprite.playOnShow === true
272
+ ? (scenario.visibleTimeSeconds ?? scenario.animationTimeSeconds)
273
+ : scenario.animationTimeSeconds;
274
+ const animationDuration = frameCount / framesPerSecond;
275
+ if (sprite.looping === false)
276
+ return Math.min(frameCount - 1, Math.floor(clockSeconds * framesPerSecond));
277
+ const cycleDuration = animationDuration + Math.max(0, sprite.pauseOnLoop ?? 0);
278
+ const phase = cycleDuration === 0 ? 0 : clockSeconds % cycleDuration;
279
+ return phase >= animationDuration
280
+ ? frameCount - 1
281
+ : Math.min(frameCount - 1, Math.floor(phase * framesPerSecond));
282
+ }
283
+ const state = scenario.elementStates[element.name] ?? scenario.state;
284
+ const mapped = state === 'hover'
285
+ ? 1
286
+ : state === 'selected' || state === 'active'
287
+ ? 2
288
+ : state === 'locked' || state === 'disabled'
289
+ ? 3
290
+ : 0;
291
+ return Math.min(frameCount - 1, mapped);
292
+ }
293
+ function alignment(attributes) {
294
+ const format = scalarString(property(attributes, 'format'))?.toLowerCase() ?? '';
295
+ const horizontalAlignment = format.includes('center')
296
+ ? 'center'
297
+ : format.includes('right')
298
+ ? 'right'
299
+ : 'left';
300
+ const verticalAlignment = format.includes('bottom')
301
+ ? 'bottom'
302
+ : format.includes('center')
303
+ ? 'center'
304
+ : 'top';
305
+ return { horizontalAlignment, verticalAlignment };
306
+ }
307
+ class GuiSceneWorkBudget {
308
+ work = 0;
309
+ elements = 0;
310
+ textCharacters = 0;
311
+ textLayoutOperations = 0;
312
+ spend(phase, amount = 1) {
313
+ if (!Number.isSafeInteger(amount) || amount < 0 || amount > GUI_SCENE_MAX_WORK - this.work) {
314
+ throw new ServiceError('GUI_SCENE_WORK_BUDGET_BLOCKED', 'GUI scene expansion exceeds the fixed construction work ceiling', { phase, used: this.work, requested: amount, maximumWork: GUI_SCENE_MAX_WORK });
315
+ }
316
+ this.work += amount;
317
+ }
318
+ admitElement(depth) {
319
+ if (depth > GUI_SCENE_MAX_DEPTH) {
320
+ throw new ServiceError('GUI_SCENE_DEPTH_BUDGET_BLOCKED', 'GUI scene expansion exceeds the fixed nesting depth ceiling', { depth, maximumDepth: GUI_SCENE_MAX_DEPTH });
321
+ }
322
+ if (this.elements >= GUI_SCENE_MAX_ELEMENTS) {
323
+ throw new ServiceError('GUI_SCENE_ELEMENT_BUDGET_BLOCKED', 'GUI scene expansion exceeds the fixed rendered element ceiling', { elements: this.elements + 1, maximumElements: GUI_SCENE_MAX_ELEMENTS });
324
+ }
325
+ this.elements += 1;
326
+ this.spend('scene element construction');
327
+ }
328
+ admitText(text, phase) {
329
+ assertTextLength(text, phase);
330
+ if (text.length > GUI_SCENE_MAX_TEXT_CHARACTERS - this.textCharacters) {
331
+ throw new ServiceError('GUI_SCENE_TEXT_BUDGET_BLOCKED', 'GUI scene exceeds the fixed aggregate rendered-text ceiling', {
332
+ phase,
333
+ usedCharacters: this.textCharacters,
334
+ requestedCharacters: text.length,
335
+ maximumCharacters: GUI_SCENE_MAX_TEXT_CHARACTERS,
336
+ });
337
+ }
338
+ this.textCharacters += text.length;
339
+ }
340
+ spendTextLayout(phase, amount = 1) {
341
+ if (!Number.isSafeInteger(amount) ||
342
+ amount < 0 ||
343
+ amount > GUI_SCENE_MAX_TEXT_LAYOUT_OPERATIONS - this.textLayoutOperations) {
344
+ throw new ServiceError('GUI_TEXT_LAYOUT_WORK_BUDGET_BLOCKED', 'GUI scene text layout exceeds the fixed measurement-operation ceiling', {
345
+ phase,
346
+ usedOperations: this.textLayoutOperations,
347
+ requestedOperations: amount,
348
+ maximumOperations: GUI_SCENE_MAX_TEXT_LAYOUT_OPERATIONS,
349
+ });
350
+ }
351
+ this.textLayoutOperations += amount;
352
+ }
353
+ }
354
+ async function layoutElement(definition, parentRect, inheritedClip, parentScale, depth, context, instanceSuffix = '', rowIndex, rowValues, parentInstanceId) {
355
+ context.work.admitElement(depth);
356
+ const { scenario, catalog, fidelity, diagnostics } = context;
357
+ const instanceId = instanceSuffix.length === 0 ? definition.id : `${definition.id}${instanceSuffix}`;
358
+ const localScale = scalarNumber(property(definition.attributes, 'scale'), 1) ?? 1;
359
+ const scale = parentScale * localScale;
360
+ const position = objectProperty(property(definition.attributes, 'position'));
361
+ const size = objectProperty(property(definition.attributes, 'size'));
362
+ const localX = scalarNumber(position === undefined ? undefined : property(position, 'x'), parentRect.width) ??
363
+ 0;
364
+ const localY = scalarNumber(position === undefined ? undefined : property(position, 'y'), parentRect.height) ??
365
+ 0;
366
+ let width = (scalarNumber(size === undefined ? undefined : property(size, 'width', 'x'), parentRect.width) ?? 0) * scale;
367
+ let height = (scalarNumber(size === undefined ? undefined : property(size, 'height', 'y'), parentRect.height) ?? 0) * scale;
368
+ const background = objectProperty(property(definition.attributes, 'background'));
369
+ const spriteName = scalarString(property(definition.attributes, 'spriteType', 'quadTextureSprite')) ??
370
+ scalarString(background === undefined
371
+ ? undefined
372
+ : property(background, 'spriteType', 'quadTextureSprite'));
373
+ const spriteDefinition = spriteName === undefined ? undefined : context.spritesByName.get(spriteName.toLowerCase());
374
+ let sprite;
375
+ if (spriteName !== undefined && spriteDefinition === undefined) {
376
+ const partialInventory = context.graph.edges.some((edge) => edge.kind === 'uses_sprite' &&
377
+ edge.from === definition.id &&
378
+ !edge.resolved &&
379
+ edge.partialInventory === true);
380
+ addFidelity(fidelity, 'missing', 'spriteType', `Sprite ${spriteName} is not defined.`, definition);
381
+ diagnostics.push(diagnostic(partialInventory ? 'GUI_REFERENCE_UNRESOLVED_PARTIAL' : 'GUI_SPRITE_MISSING', partialInventory ? 'warning' : 'error', partialInventory
382
+ ? `The partial GUI inventory cannot resolve sprite ${spriteName} for ${definition.name}; a skipped source could define it.`
383
+ : `Element ${definition.name} references missing sprite ${spriteName}.`, definition));
384
+ }
385
+ else if (spriteDefinition !== undefined) {
386
+ const partialAppearance = [];
387
+ const specialSemantics = partialSpriteSemantics[spriteDefinition.spriteType];
388
+ if (specialSemantics !== undefined) {
389
+ addFidelity(fidelity, 'unsupported', specialSemantics.field, specialSemantics.detail, definition);
390
+ partialAppearance.push(specialSemantics.detail);
391
+ }
392
+ if (spriteDefinition.texturePath2 !== undefined) {
393
+ const detail = `Secondary texture ${spriteDefinition.texturePath2} is retained in the source graph but is not composited.`;
394
+ addFidelity(fidelity, 'unsupported', 'textureFile2', detail, definition);
395
+ partialAppearance.push(detail);
396
+ }
397
+ if (spriteDefinition.effectFile !== undefined) {
398
+ const detail = `Effect ${spriteDefinition.effectFile} is retained in the source graph but is not executed by the offline renderer.`;
399
+ addFidelity(fidelity, 'unsupported', 'effectFile', detail, definition);
400
+ partialAppearance.push(detail);
401
+ }
402
+ if (partialAppearance.length > 0)
403
+ diagnostics.push(diagnostic('GUI_SPRITE_RENDER_PARTIAL', 'warning', `Element ${definition.name} has a partial sprite appearance: ${partialAppearance.join(' ')}`, definition));
404
+ const frame = frameFor(definition, spriteDefinition, scenario);
405
+ sprite = await catalog.loadSpriteFrame(spriteDefinition, frame);
406
+ if (!sprite?.supported) {
407
+ addFidelity(fidelity, 'unsupported', 'texture', sprite?.reason ?? `Sprite ${spriteDefinition.name} has no texture.`, definition);
408
+ diagnostics.push(diagnostic('GUI_TEXTURE_UNSUPPORTED', 'warning', sprite?.reason ?? `Sprite ${spriteDefinition.name} has no texture.`, definition));
409
+ }
410
+ else {
411
+ if (width === 0)
412
+ width = sprite.width * scale;
413
+ if (height === 0)
414
+ height = sprite.height * scale;
415
+ addFidelity(fidelity, partialAppearance.length === 0 ? 'modelled' : 'approximated', 'sprite_frame', partialAppearance.length === 0
416
+ ? `${spriteDefinition.name} frame ${sprite.frame + 1}/${sprite.frameCount}`
417
+ : `${spriteDefinition.name} frame ${sprite.frame + 1}/${sprite.frameCount} shows only the primary resolved texture; additional sprite semantics are omitted.`, definition);
418
+ if (spriteDefinition.frameAnimated) {
419
+ addFidelity(fidelity, spriteDefinition.looping === undefined ? 'approximated' : 'modelled', 'animation_looping', spriteDefinition.looping === false
420
+ ? 'Animation stops on its final frame.'
421
+ : spriteDefinition.looping === true
422
+ ? `Animation loops with a ${spriteDefinition.pauseOnLoop ?? 0}s end pause.`
423
+ : 'Animation uses the renderer looping default because the source omits looping.', definition);
424
+ addFidelity(fidelity, spriteDefinition.playOnShow === undefined ? 'approximated' : 'modelled', 'animation_clock', spriteDefinition.playOnShow === true
425
+ ? 'Animation samples time since the element became visible.'
426
+ : spriteDefinition.playOnShow === false
427
+ ? 'Animation samples the global scenario clock.'
428
+ : 'Animation uses the global scenario clock because the source omits play_on_show.', definition);
429
+ }
430
+ }
431
+ }
432
+ const rawText = scalarString(property(definition.attributes, 'text', 'buttonText'));
433
+ let text;
434
+ if (rawText !== undefined) {
435
+ const resolved = resolveTokenText(rawText, scenario, context.localisation, rowValues);
436
+ let displayText = resolved.text;
437
+ const state = scenario.elementStates[definition.name] ?? scenario.state;
438
+ if (state === 'long-text')
439
+ displayText = `${displayText} — ${displayText} — ${displayText}`;
440
+ if (state === 'missing-localisation')
441
+ displayText = `\u00a7R${rawText}_MISSING\u00a7!`;
442
+ displayText = visibleHoiText(displayText);
443
+ context.work.admitText(displayText, `GUI text for ${definition.name}`);
444
+ const fontName = scalarString(property(definition.attributes, 'font', 'buttonFont'));
445
+ const resolvedFontMetrics = catalog.resolvedFontMetrics(fontName);
446
+ const explicitFontSize = scalarNumber(property(definition.attributes, 'fontSize'), 16);
447
+ const fontSize = explicitFontSize ??
448
+ resolvedFontMetrics.nativeSize ??
449
+ context.catalog.fontDefinition(fontName ?? '')?.size ??
450
+ 16;
451
+ const maxWidth = (scalarNumber(property(definition.attributes, 'maxWidth'), width / scale) ?? width / scale) *
452
+ scale;
453
+ const wrapped = wrapText(catalog, fontName, displayText, fontSize * scale, maxWidth, context.work);
454
+ const glyphLines = [];
455
+ for (const line of wrapped.lines)
456
+ glyphLines.push(await catalog.shapeText(fontName, line, fontSize * scale));
457
+ const maximumLineWidth = wrapped.widths.reduce((maximum, value) => Math.max(maximum, value), 0);
458
+ if (width === 0)
459
+ width = maximumLineWidth;
460
+ if (height === 0)
461
+ height = wrapped.lines.length * wrapped.lineHeight;
462
+ const measuredWidth = maximumLineWidth;
463
+ const measuredHeight = wrapped.lines.length * wrapped.lineHeight;
464
+ text = {
465
+ text: displayText,
466
+ lines: wrapped.lines,
467
+ lineWidths: wrapped.widths,
468
+ lineHeight: wrapped.lineHeight,
469
+ fontSize: fontSize * scale,
470
+ measuredWidth,
471
+ measuredHeight,
472
+ metricSource: wrapped.metricSource,
473
+ ...alignment(definition.attributes),
474
+ ...(fontName === undefined ? {} : { fontName }),
475
+ glyphLines,
476
+ overflowX: width > 0 && measuredWidth > width + 0.01,
477
+ overflowY: height > 0 && measuredHeight > height + 0.01,
478
+ unresolvedTokens: resolved.unresolved,
479
+ };
480
+ if (wrapped.metricSource === 'approximation')
481
+ addFidelity(fidelity, 'approximated', 'font_metrics', `No supplied font metrics for ${fontName ?? '<default>'}.`, definition);
482
+ else
483
+ addFidelity(fidelity, 'modelled', 'font_metrics', `${wrapped.metricSource} metrics for ${fontName ?? '<default>'}.`, definition);
484
+ const missingGlyphs = [
485
+ ...new Set([...wrapped.missingGlyphs, ...glyphLines.flatMap((line) => line.missingGlyphs)]),
486
+ ].slice(0, GUI_TEXT_MAX_MISSING_GLYPH_SAMPLES);
487
+ if (missingGlyphs.length > 0)
488
+ addFidelity(fidelity, 'missing', 'font_glyphs', `Missing glyphs: ${missingGlyphs.join(', ')}.`, definition);
489
+ const glyphSources = [...new Set(glyphLines.map(({ source }) => source))];
490
+ const glyphsModelled = glyphSources.every((source) => source === 'fontkit-path' || source === 'bmfont-atlas') &&
491
+ glyphLines.every(({ baselineModelled }) => baselineModelled);
492
+ addFidelity(fidelity, glyphsModelled ? 'modelled' : 'approximated', 'font_glyph_rendering', glyphsModelled
493
+ ? `Deterministic ${glyphSources.join('/')} glyphs from scanned font assets.`
494
+ : 'Deterministic project font paths substitute for unavailable workspace glyph data.', definition);
495
+ if (resolvedFontMetrics.source === 'bmfont')
496
+ addFidelity(fidelity, resolvedFontMetrics.baselineModelled ? 'modelled' : 'approximated', 'font_native_metrics', `BMFont native size ${resolvedFontMetrics.nativeSize}, line height ${resolvedFontMetrics.nativeLineHeight}, and baseline ${resolvedFontMetrics.nativeBaseline}${explicitFontSize === undefined ? ' determine this element layout' : ' are scaled to the element fontSize'}.`, definition);
497
+ if (resolved.missingLocalisation)
498
+ addFidelity(fidelity, 'missing', 'localisation', `No ${scenario.language} localisation for ${rawText}.`, definition);
499
+ if (resolved.unresolved.length > 0)
500
+ addFidelity(fidelity, 'unresolved', 'dynamic_text', `Unresolved tokens: ${resolved.unresolved.join(', ')}.`, definition);
501
+ }
502
+ const orientation = scalarString(property(definition.attributes, 'orientation'))?.toLowerCase() ?? 'upper_left';
503
+ const origo = scalarString(property(definition.attributes, 'origo'))?.toLowerCase() ?? 'upper_left';
504
+ let x = parentRect.x + localX * scale;
505
+ let y = parentRect.y + localY * scale;
506
+ if (orientation.includes('right'))
507
+ x = parentRect.x + parentRect.width - localX * scale - width;
508
+ else if (orientation.includes('center'))
509
+ x = parentRect.x + parentRect.width / 2 + localX * scale;
510
+ if (orientation.includes('lower') || orientation.includes('bottom'))
511
+ y = parentRect.y + parentRect.height - localY * scale - height;
512
+ else if (orientation.includes('center'))
513
+ y = parentRect.y + parentRect.height / 2 + localY * scale;
514
+ if (origo.includes('center')) {
515
+ x -= width / 2;
516
+ y -= height / 2;
517
+ }
518
+ else {
519
+ if (origo.includes('right'))
520
+ x -= width;
521
+ if (origo.includes('lower') || origo.includes('bottom'))
522
+ y -= height;
523
+ }
524
+ const scrollOffset = (scenario.scrollOffsets[definition.name] ?? scenario.scrollOffsets[definition.id] ?? 0) * scale;
525
+ const unclippedRect = { x, y, width: Math.max(0, width), height: Math.max(0, height) };
526
+ const ownClipping = scalarBoolean(property(definition.attributes, 'clipping')) ?? false;
527
+ const availableClip = inheritedClip === undefined ? unclippedRect : rectIntersection(inheritedClip, unclippedRect);
528
+ const clipRect = inheritedClip;
529
+ const clipped = clipRect !== undefined &&
530
+ (availableClip === undefined || !equalRect(unclippedRect, availableClip));
531
+ const explicitlyVisible = scenario.visibility[definition.name] ?? scenario.visibility[definition.id];
532
+ const visible = explicitlyVisible ?? (availableClip !== undefined || inheritedClip === undefined);
533
+ const clickThrough = scalarBoolean(property(definition.attributes, 'clickThrough', 'alwaystransparent', 'allwaystransparent')) ?? false;
534
+ const clickable = clickableTypes.test(definition.elementType) && !clickThrough;
535
+ const state = scenario.elementStates[definition.name] ?? scenario.state;
536
+ const zPriority = scalarNumber(property(definition.attributes, 'priority'), 0) ?? 0;
537
+ let progressRatio;
538
+ if (/progressbar/iu.test(definition.elementType)) {
539
+ const minimum = scalarNumber(property(definition.attributes, 'minValue'), 1) ?? 0;
540
+ const maximum = scalarNumber(property(definition.attributes, 'maxValue'), 1) ?? 100;
541
+ const scriptedValue = scenario.scriptedGui[definition.name];
542
+ let value = typeof scriptedValue === 'number'
543
+ ? scriptedValue
544
+ : (scalarNumber(property(definition.attributes, 'startValue'), maximum) ?? minimum);
545
+ if (state === 'minimum-value')
546
+ value = minimum;
547
+ if (state === 'maximum-value' || state === 'completed')
548
+ value = maximum;
549
+ progressRatio =
550
+ maximum === minimum ? 0 : Math.max(0, Math.min(1, (value - minimum) / (maximum - minimum)));
551
+ }
552
+ const sceneElement = {
553
+ id: instanceId,
554
+ sourceId: definition.id,
555
+ name: definition.name,
556
+ elementType: definition.elementType,
557
+ ...(parentInstanceId === undefined
558
+ ? definition.parentId === undefined
559
+ ? {}
560
+ : {
561
+ parentId: instanceSuffix.length === 0
562
+ ? definition.parentId
563
+ : `${definition.parentId}${instanceSuffix}`,
564
+ }
565
+ : { parentId: parentInstanceId }),
566
+ depth,
567
+ zIndex: Math.trunc(zPriority * 1_000_000 + definition.definitionOrder),
568
+ visible,
569
+ clickable,
570
+ clickThrough,
571
+ rect: availableClip ?? { x: unclippedRect.x, y: unclippedRect.y, width: 0, height: 0 },
572
+ unclippedRect,
573
+ ...(clipRect === undefined ? {} : { clipRect }),
574
+ clipped,
575
+ scale,
576
+ state,
577
+ ...(progressRatio === undefined ? {} : { progressRatio }),
578
+ ...(sprite === undefined ? {} : { sprite }),
579
+ ...(text === undefined ? {} : { text }),
580
+ sourcePath: definition.sourcePath,
581
+ ...(definition.location === undefined ? {} : { location: definition.location }),
582
+ unsupportedAttributes: definition.unsupportedAttributes,
583
+ ...(rowIndex === undefined ? {} : { rowIndex }),
584
+ };
585
+ context.output.push(sceneElement);
586
+ context.instancesById.set(instanceId, sceneElement);
587
+ addFidelity(fidelity, 'modelled', 'nested_offset', `Positioned ${definition.name} at ${x},${y} with scale ${scale}.`, definition);
588
+ for (const attribute of Object.keys(definition.attributes).sort((left, right) => compareCodeUnits(left, right))) {
589
+ const classification = guiElementAttributeFidelity(attribute);
590
+ if (classification === 'structural' || classification === 'unsupported')
591
+ continue;
592
+ addFidelity(fidelity, classification, attribute, classification === 'modelled'
593
+ ? 'Parsed and applied by the offline scene model.'
594
+ : 'Parsed and preserved, but intentionally omitted from the offline render.', definition);
595
+ }
596
+ if (clipRect !== undefined)
597
+ addFidelity(fidelity, 'modelled', 'clipping', `${definition.name} intersected its inherited clip rectangle.`, definition);
598
+ for (const unsupportedAttribute of definition.unsupportedAttributes)
599
+ addFidelity(fidelity, 'unsupported', unsupportedAttribute, `Parsed and preserved, but not rendered.`, definition);
600
+ const childParentRect = { ...unclippedRect, y: unclippedRect.y - scrollOffset };
601
+ const childClip = ownClipping
602
+ ? inheritedClip === undefined
603
+ ? unclippedRect
604
+ : rectIntersection(inheritedClip, unclippedRect)
605
+ : inheritedClip;
606
+ const childDefinitions = definition.childIds
607
+ .map((id) => context.elementsById.get(id))
608
+ .filter((element) => element !== undefined);
609
+ let rows = scenario.lists[definition.name] ?? scenario.lists[definition.id];
610
+ if (state === 'empty-list')
611
+ rows = [];
612
+ if (state === 'full-list' && rows === undefined)
613
+ rows = Array.from({ length: 12 }, (_unused, index) => ({ index }));
614
+ if (rows !== undefined &&
615
+ childDefinitions.length > 0 &&
616
+ /(?:grid|listbox|scroll)/iu.test(definition.elementType)) {
617
+ const spacingValue = objectProperty(property(definition.attributes, 'spacing'));
618
+ const spacingY = scalarNumber(spacingValue === undefined
619
+ ? property(definition.attributes, 'spacing')
620
+ : property(spacingValue, 'y'), height) ?? 0;
621
+ let rowY = 0;
622
+ for (const [index, row] of rows.entries()) {
623
+ context.work.spend('scenario list row expansion');
624
+ let rowHeight = 0;
625
+ for (const child of childDefinitions) {
626
+ context.work.spend('scenario list child expansion');
627
+ const childPosition = objectProperty(property(child.attributes, 'position'));
628
+ const originalY = scalarNumber(childPosition === undefined ? undefined : property(childPosition, 'y'), height) ?? 0;
629
+ const shiftedParent = {
630
+ ...childParentRect,
631
+ y: childParentRect.y + rowY - originalY * scale,
632
+ };
633
+ await layoutElement(child, shiftedParent, childClip, scale, depth + 1, context, `${instanceSuffix}#row-${index}`, index, row, instanceId);
634
+ const rendered = context.instancesById.get(`${child.id}${instanceSuffix}#row-${index}`);
635
+ rowHeight = Math.max(rowHeight, rendered?.unclippedRect.height ?? 0);
636
+ }
637
+ rowY += rowHeight + spacingY * scale;
638
+ }
639
+ addFidelity(fidelity, 'modelled', 'scroll_rows', `Expanded ${rows.length} scenario rows for ${definition.name}.`, definition);
640
+ }
641
+ else {
642
+ for (const child of childDefinitions) {
643
+ context.work.spend('nested child expansion');
644
+ await layoutElement(child, childParentRect, childClip, scale, depth + 1, context, instanceSuffix, rowIndex, rowValues, instanceId);
645
+ }
646
+ }
647
+ }
648
+ /** Build a deterministic, offline approximation of a GUI window without launching HOI4. */
649
+ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, catalog = new GuiAssetCatalog(graph, scannedFiles)) {
650
+ if (graph.nodes.length > GUI_GRAPH_MAX_NODES ||
651
+ graph.edges.length > GUI_GRAPH_MAX_EDGES ||
652
+ graph.elements.length > GUI_GRAPH_MAX_ELEMENTS) {
653
+ throw new ServiceError('GUI_SCENE_GRAPH_BUDGET_BLOCKED', 'GUI source graph exceeds the fixed scene-construction ceiling', {
654
+ nodes: graph.nodes.length,
655
+ maximumNodes: GUI_GRAPH_MAX_NODES,
656
+ edges: graph.edges.length,
657
+ maximumEdges: GUI_GRAPH_MAX_EDGES,
658
+ elements: graph.elements.length,
659
+ maximumElements: GUI_GRAPH_MAX_ELEMENTS,
660
+ });
661
+ }
662
+ assertRenderDimensions(scenario.resolution.width, scenario.resolution.height, 'GUI scene resolution');
663
+ const fidelity = emptyFidelityReport();
664
+ const diagnostics = [];
665
+ const elementsById = new Map(graph.elements.map((element) => [element.id, element]));
666
+ const candidates = graph.elements.filter((element) => element.name === windowName);
667
+ const root = candidates.toSorted((left, right) => compareCodeUnits(right.sourcePath, left.sourcePath) ||
668
+ right.definitionOrder - left.definitionOrder)[0];
669
+ const baseScale = Math.min(scenario.resolution.width / 1920, scenario.resolution.height / 1080) *
670
+ scenario.uiScale;
671
+ addFidelity(fidelity, 'approximated', 'resolution_scale', `Coordinates use a 1920x1080 reference with UI scale ${scenario.uiScale}.`);
672
+ if (root === undefined) {
673
+ diagnostics.push({
674
+ code: 'GUI_WINDOW_MISSING',
675
+ severity: 'error',
676
+ category: 'reference',
677
+ message: `GUI window ${windowName} was not found.`,
678
+ });
679
+ addFidelity(fidelity, 'missing', 'window', `GUI window ${windowName} was not found.`);
680
+ return {
681
+ windowName,
682
+ scenario,
683
+ resolution: scenario.resolution,
684
+ elements: [],
685
+ bounds: { x: 0, y: 0, width: 0, height: 0 },
686
+ fidelity,
687
+ diagnostics: sortDiagnostics(diagnostics),
688
+ sourceRevision: hashCanonical(graph.sourceHashes),
689
+ };
690
+ }
691
+ const localisation = new Map(graph.localisation
692
+ .filter((entry) => entry.language.toLowerCase() === scenario.language.toLowerCase() ||
693
+ entry.language.toLowerCase() === `l_${scenario.language.toLowerCase()}`)
694
+ .map((entry) => [entry.key, entry.value]));
695
+ if (localisation.size === 0) {
696
+ for (const entry of graph.localisation)
697
+ if (!localisation.has(entry.key))
698
+ localisation.set(entry.key, entry.value);
699
+ addFidelity(fidelity, 'approximated', 'language', `No exact ${scenario.language} bucket; used available localisation entries.`);
700
+ }
701
+ let scriptedWindowVisible = true;
702
+ for (const scripted of graph.scriptedGuis.filter((definition) => definition.windowName === windowName || definition.parentWindowName === windowName)) {
703
+ addFidelity(fidelity, 'modelled', 'scripted_gui_context', `${scripted.name} uses ${scripted.contextType ?? '<unspecified>'} context.`);
704
+ if (scripted.visibleExpression === undefined)
705
+ continue;
706
+ const mockedVisibility = scenario.visibility[scripted.name] ?? scenario.scriptedGui[`${scripted.name}.visible`];
707
+ if (typeof mockedVisibility === 'boolean') {
708
+ scriptedWindowVisible &&= mockedVisibility;
709
+ addFidelity(fidelity, 'modelled', 'scripted_gui_visibility', `${scripted.name}.visible was supplied by the preview scenario.`);
710
+ }
711
+ else {
712
+ addFidelity(fidelity, 'unresolved', 'scripted_gui_visibility', `${scripted.name}.visible requires an explicit scenario mock; the offline renderer leaves it visible.`);
713
+ }
714
+ }
715
+ const layoutScenario = scriptedWindowVisible
716
+ ? scenario
717
+ : { ...scenario, visibility: { ...scenario.visibility, [root.name]: false } };
718
+ const output = [];
719
+ const context = {
720
+ graph,
721
+ scenario: layoutScenario,
722
+ catalog,
723
+ fidelity,
724
+ diagnostics,
725
+ elementsById,
726
+ spritesByName: new Map(graph.sprites.map((sprite) => [sprite.name.toLowerCase(), sprite])),
727
+ localisation,
728
+ output,
729
+ instancesById: new Map(),
730
+ work: new GuiSceneWorkBudget(),
731
+ baseScale,
732
+ };
733
+ const viewport = {
734
+ x: 0,
735
+ y: 0,
736
+ width: scenario.resolution.width,
737
+ height: scenario.resolution.height,
738
+ };
739
+ await layoutElement(root, viewport, viewport, baseScale, 0, context);
740
+ output.sort((left, right) => left.zIndex - right.zIndex || compareCodeUnits(left.id, right.id));
741
+ const bounds = unionRects(output.filter(({ visible }) => visible).map(({ unclippedRect }) => unclippedRect));
742
+ return {
743
+ windowName,
744
+ scenario,
745
+ resolution: scenario.resolution,
746
+ elements: output,
747
+ bounds,
748
+ fidelity,
749
+ diagnostics: sortDiagnostics(diagnostics),
750
+ sourceRevision: hashCanonical(graph.sourceHashes),
751
+ };
752
+ }
753
+ //# sourceMappingURL=layout.js.map