@the-inclusionist/engine 10.0.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/README.md +32 -1
  2. package/app/css/style.css +216 -42
  3. package/app/public/vendor/fonts-licences/NOTICE.txt +166 -0
  4. package/app/public/vendor/fonts-licences/OFL-1.1.txt +86 -0
  5. package/app/public/vendor/fonts.css +11 -1175
  6. package/dist-pkg/boot/create-game.d.ts +84 -33
  7. package/dist-pkg/boot/create-game.js +708 -307
  8. package/dist-pkg/core/a11y-sr.d.ts +1 -1
  9. package/dist-pkg/core/a11y-sr.js +3 -5
  10. package/dist-pkg/core/accommodations.d.ts +26 -8
  11. package/dist-pkg/core/accommodations.js +27 -10
  12. package/dist-pkg/core/actions.d.ts +39 -10
  13. package/dist-pkg/core/actions.js +28 -6
  14. package/dist-pkg/core/contract.d.ts +0 -2
  15. package/dist-pkg/core/contract.js +0 -2
  16. package/dist-pkg/core/i18n.d.ts +36 -71
  17. package/dist-pkg/core/i18n.js +131 -198
  18. package/dist-pkg/core/session-clock.d.ts +23 -0
  19. package/dist-pkg/core/session-clock.js +37 -0
  20. package/dist-pkg/i18n/en.js +44 -49
  21. package/dist-pkg/i18n/es.js +44 -49
  22. package/dist-pkg/i18n/pt.js +49 -54
  23. package/dist-pkg/input/gamepad.d.ts +42 -11
  24. package/dist-pkg/input/gamepad.js +50 -15
  25. package/dist-pkg/input/key-default.d.ts +30 -0
  26. package/dist-pkg/input/key-default.js +60 -0
  27. package/dist-pkg/input/keyboard-runtime.d.ts +0 -4
  28. package/dist-pkg/input/keyboard.d.ts +0 -1
  29. package/dist-pkg/input/keydown.d.ts +5 -11
  30. package/dist-pkg/input/keydown.js +3 -3
  31. package/dist-pkg/input/latch-edge.d.ts +10 -2
  32. package/dist-pkg/input/latch-edge.js +4 -3
  33. package/dist-pkg/input/latch-scope.d.ts +27 -22
  34. package/dist-pkg/input/latch-scope.js +25 -37
  35. package/dist-pkg/input/latch-store.d.ts +9 -12
  36. package/dist-pkg/input/latch-store.js +13 -18
  37. package/dist-pkg/input/latch-sync.d.ts +5 -4
  38. package/dist-pkg/input/latch-sync.js +5 -5
  39. package/dist-pkg/input/pad-reading.js +7 -2
  40. package/dist-pkg/input/pad-wizard.d.ts +4 -1
  41. package/dist-pkg/input/pad-wizard.js +60 -9
  42. package/dist-pkg/input/switch-scan.d.ts +29 -12
  43. package/dist-pkg/input/switch-scan.js +15 -2
  44. package/dist-pkg/input/touch-bindings.d.ts +3 -6
  45. package/dist-pkg/input/touch.d.ts +17 -2
  46. package/dist-pkg/input/touch.js +55 -17
  47. package/dist-pkg/input/transport-in-use.d.ts +5 -5
  48. package/dist-pkg/input/transport-in-use.js +5 -5
  49. package/dist-pkg/input/transports.d.ts +0 -9
  50. package/dist-pkg/input/transports.js +1 -1
  51. package/dist-pkg/input/virtual-controller.d.ts +39 -3
  52. package/dist-pkg/input/virtual-controller.js +32 -4
  53. package/dist-pkg/input/voice-map.d.ts +27 -11
  54. package/dist-pkg/input/voice-map.js +41 -43
  55. package/dist-pkg/platform/audio-ambient.d.ts +0 -1
  56. package/dist-pkg/platform/audio-ambient.js +3 -1
  57. package/dist-pkg/platform/audio-mixer.js +4 -9
  58. package/dist-pkg/platform/audio-sonar.d.ts +8 -94
  59. package/dist-pkg/platform/audio-sonar.js +22 -207
  60. package/dist-pkg/platform/audio.d.ts +10 -1
  61. package/dist-pkg/platform/audio.js +35 -2
  62. package/dist-pkg/platform/choose-by-voice.d.ts +70 -0
  63. package/dist-pkg/platform/choose-by-voice.js +157 -0
  64. package/dist-pkg/platform/font-library.d.ts +77 -0
  65. package/dist-pkg/platform/font-library.js +98 -0
  66. package/dist-pkg/platform/font-library.json +721 -0
  67. package/dist-pkg/platform/heavy-catalogue.d.ts +46 -0
  68. package/dist-pkg/platform/heavy-catalogue.js +47 -14
  69. package/dist-pkg/platform/heavy-mirror.d.ts +3 -9
  70. package/dist-pkg/platform/heavy-mirror.js +14 -17
  71. package/dist-pkg/platform/heavy.d.ts +40 -8
  72. package/dist-pkg/platform/heavy.js +177 -22
  73. package/dist-pkg/platform/interruptible-speech.d.ts +15 -8
  74. package/dist-pkg/platform/interruptible-speech.js +37 -13
  75. package/dist-pkg/platform/listener-scope.js +22 -13
  76. package/dist-pkg/platform/locale-host.d.ts +7 -3
  77. package/dist-pkg/platform/locale-host.js +13 -2
  78. package/dist-pkg/platform/reading-in-worker.d.ts +24 -0
  79. package/dist-pkg/platform/reading-in-worker.js +38 -0
  80. package/dist-pkg/platform/reading-model.d.ts +21 -0
  81. package/dist-pkg/platform/reading-model.js +25 -0
  82. package/dist-pkg/platform/reading-runtime.js +13 -8
  83. package/dist-pkg/platform/reading.d.ts +12 -1
  84. package/dist-pkg/platform/reading.js +9 -1
  85. package/dist-pkg/platform/speech-recognition.d.ts +10 -1
  86. package/dist-pkg/platform/speech-recognition.js +29 -9
  87. package/dist-pkg/platform/speech.d.ts +10 -1
  88. package/dist-pkg/platform/speech.js +24 -13
  89. package/dist-pkg/platform/tts.d.ts +37 -4
  90. package/dist-pkg/platform/tts.js +279 -57
  91. package/dist-pkg/platform/voice-listener.d.ts +6 -2
  92. package/dist-pkg/platform/voice-listener.js +1 -1
  93. package/dist-pkg/platform/voice-plan.d.ts +13 -0
  94. package/dist-pkg/platform/voice-plan.js +57 -2
  95. package/dist-pkg/platform/vosk-runtime.d.ts +25 -0
  96. package/dist-pkg/platform/vosk-runtime.js +59 -1
  97. package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
  98. package/dist-pkg/platform/vosk-vocabulary.js +178 -0
  99. package/dist-pkg/render/crt.d.ts +11 -9
  100. package/dist-pkg/render/crt.js +6 -10
  101. package/dist-pkg/render/cvd-matrices.d.ts +5 -1
  102. package/dist-pkg/render/cvd-matrices.js +5 -1
  103. package/dist-pkg/render/high-contrast.d.ts +1 -2
  104. package/dist-pkg/render/high-contrast.js +5 -1
  105. package/dist-pkg/render/viz-axes.d.ts +9 -0
  106. package/dist-pkg/render/viz-axes.js +15 -2
  107. package/dist-pkg/ui/aac-sets.d.ts +29 -24
  108. package/dist-pkg/ui/aac-sets.js +22 -30
  109. package/dist-pkg/ui/audio-choices.d.ts +10 -5
  110. package/dist-pkg/ui/audio-choices.js +14 -10
  111. package/dist-pkg/ui/camera-control.d.ts +47 -0
  112. package/dist-pkg/ui/camera-control.js +35 -1
  113. package/dist-pkg/ui/declared-words.d.ts +21 -0
  114. package/dist-pkg/ui/declared-words.js +66 -0
  115. package/dist-pkg/ui/drawing-problems.js +4 -3
  116. package/dist-pkg/ui/eye-control.js +17 -17
  117. package/dist-pkg/ui/face-control.js +15 -15
  118. package/dist-pkg/ui/fonts.d.ts +42 -8
  119. package/dist-pkg/ui/fonts.js +58 -24
  120. package/dist-pkg/ui/footer-scroll-driver.d.ts +14 -0
  121. package/dist-pkg/ui/footer-scroll-driver.js +201 -0
  122. package/dist-pkg/ui/footer-scroll.d.ts +38 -0
  123. package/dist-pkg/ui/footer-scroll.js +55 -0
  124. package/dist-pkg/ui/game-options.d.ts +14 -9
  125. package/dist-pkg/ui/game-options.js +41 -21
  126. package/dist-pkg/ui/hand-control.js +15 -15
  127. package/dist-pkg/ui/help-panel.d.ts +19 -8
  128. package/dist-pkg/ui/help-panel.js +15 -5
  129. package/dist-pkg/ui/hud-bands.d.ts +29 -12
  130. package/dist-pkg/ui/hud-bands.js +63 -25
  131. package/dist-pkg/ui/hud-row.d.ts +34 -0
  132. package/dist-pkg/ui/hud-row.js +80 -0
  133. package/dist-pkg/ui/hud.d.ts +0 -3
  134. package/dist-pkg/ui/layout.js +5 -2
  135. package/dist-pkg/ui/libras-avatar-clip.d.ts +30 -0
  136. package/dist-pkg/ui/libras-avatar-clip.js +86 -0
  137. package/dist-pkg/ui/libras-avatar-load.d.ts +52 -0
  138. package/dist-pkg/ui/libras-avatar-load.js +134 -0
  139. package/dist-pkg/ui/libras-avatar-plan.d.ts +102 -0
  140. package/dist-pkg/ui/libras-avatar-plan.js +211 -0
  141. package/dist-pkg/ui/libras-avatar-player.d.ts +28 -0
  142. package/dist-pkg/ui/libras-avatar-player.js +226 -0
  143. package/dist-pkg/ui/libras-avatar-stage.d.ts +37 -0
  144. package/dist-pkg/ui/libras-avatar-stage.js +208 -0
  145. package/dist-pkg/ui/libras-glosses.d.ts +28 -0
  146. package/dist-pkg/ui/libras-glosses.js +161 -0
  147. package/dist-pkg/ui/menu-intent.d.ts +29 -0
  148. package/dist-pkg/ui/menu-intent.js +35 -1
  149. package/dist-pkg/ui/menu-items.d.ts +10 -0
  150. package/dist-pkg/ui/menu-items.js +29 -0
  151. package/dist-pkg/ui/menu-nav.d.ts +40 -4
  152. package/dist-pkg/ui/menu-nav.js +132 -47
  153. package/dist-pkg/ui/panel-widgets.d.ts +34 -0
  154. package/dist-pkg/ui/panel-widgets.js +86 -0
  155. package/dist-pkg/ui/pause-icons.d.ts +30 -14
  156. package/dist-pkg/ui/pause-icons.js +106 -45
  157. package/dist-pkg/ui/scan-overlay.d.ts +3 -3
  158. package/dist-pkg/ui/scan-overlay.js +11 -3
  159. package/dist-pkg/ui/screen-text.d.ts +25 -0
  160. package/dist-pkg/ui/screen-text.js +152 -0
  161. package/dist-pkg/ui/session-clock.d.ts +32 -0
  162. package/dist-pkg/ui/session-clock.js +67 -0
  163. package/dist-pkg/ui/settings-aac.d.ts +3 -1
  164. package/dist-pkg/ui/settings-aac.js +32 -13
  165. package/dist-pkg/ui/settings-audio.d.ts +10 -5
  166. package/dist-pkg/ui/settings-audio.js +101 -35
  167. package/dist-pkg/ui/settings-controls.d.ts +0 -4
  168. package/dist-pkg/ui/settings-mobility.d.ts +3 -6
  169. package/dist-pkg/ui/settings-mobility.js +4 -46
  170. package/dist-pkg/ui/settings-motion.js +2 -2
  171. package/dist-pkg/ui/settings-panel.d.ts +10 -0
  172. package/dist-pkg/ui/settings-panel.js +25 -1
  173. package/dist-pkg/ui/settings-typo.d.ts +5 -6
  174. package/dist-pkg/ui/settings-typo.js +20 -11
  175. package/dist-pkg/ui/settings-visual.js +2 -2
  176. package/dist-pkg/ui/shell.d.ts +1 -3
  177. package/dist-pkg/ui/shell.js +8 -4
  178. package/dist-pkg/ui/title.d.ts +2 -11
  179. package/dist-pkg/ui/title.js +39 -6
  180. package/dist-pkg/ui/top-band.d.ts +5 -3
  181. package/dist-pkg/ui/top-band.js +21 -25
  182. package/dist-pkg/ui/typo-choices.d.ts +3 -3
  183. package/dist-pkg/ui/typo-choices.js +9 -8
  184. package/dist-pkg/ui/vlibras.d.ts +71 -27
  185. package/dist-pkg/ui/vlibras.js +116 -44
  186. package/dist-pkg/ui/voice-control.d.ts +23 -1
  187. package/dist-pkg/ui/voice-control.js +149 -16
  188. package/dist-pkg/ui/voice-settings.d.ts +2 -3
  189. package/dist-pkg/ui/voice-settings.js +53 -3
  190. package/dist-pkg/ui/where-the-child-is.js +2 -2
  191. package/docs/CREDITS.md +122 -10
  192. package/docs/LICENSES.md +36 -7
  193. package/package.json +34 -9
  194. package/scripts/check-cartridge.mjs +78 -0
  195. package/scripts/game-build.d.mts +25 -0
  196. package/scripts/game-build.mjs +144 -0
  197. package/scripts/heavy-into-the-delivery.mjs +284 -40
  198. package/scripts/libras-avatar.json +680 -0
  199. package/scripts/libras-avatar.mjs +246 -0
  200. package/scripts/libras-glosses/gloss.py +95 -0
  201. package/scripts/libras-glosses/pyproject.toml +32 -0
  202. package/scripts/libras-glosses/uv.lock +781 -0
  203. package/scripts/libras-glosses.mjs +351 -0
  204. package/scripts/licences/OFL-1.1.txt +86 -0
  205. package/scripts/licences/UFL-1.0.txt +96 -0
  206. package/scripts/licences/fonts.mjs +389 -0
  207. package/scripts/licences/third-party.mjs +35 -21
  208. package/app/public/vendor/fonts/bitter-var-ext.woff2 +0 -0
  209. package/app/public/vendor/fonts/bitter-var.woff2 +0 -0
  210. package/app/public/vendor/fonts/bodonimoda-var-ext.woff2 +0 -0
  211. package/app/public/vendor/fonts/bodonimoda-var.woff2 +0 -0
  212. package/app/public/vendor/fonts/cat-abril_fatface-400-ext.woff2 +0 -0
  213. package/app/public/vendor/fonts/cat-abril_fatface-400.woff2 +0 -0
  214. package/app/public/vendor/fonts/cat-adlam_display-400-ext.woff2 +0 -0
  215. package/app/public/vendor/fonts/cat-adlam_display-400.woff2 +0 -0
  216. package/app/public/vendor/fonts/cat-agu_display-400-ext.woff2 +0 -0
  217. package/app/public/vendor/fonts/cat-agu_display-400.woff2 +0 -0
  218. package/app/public/vendor/fonts/cat-alfa_slab_one-400-ext.woff2 +0 -0
  219. package/app/public/vendor/fonts/cat-alfa_slab_one-400.woff2 +0 -0
  220. package/app/public/vendor/fonts/cat-are_you_serious-400-ext.woff2 +0 -0
  221. package/app/public/vendor/fonts/cat-are_you_serious-400.woff2 +0 -0
  222. package/app/public/vendor/fonts/cat-asimovian-400-ext.woff2 +0 -0
  223. package/app/public/vendor/fonts/cat-asimovian-400.woff2 +0 -0
  224. package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400-ext.woff2 +0 -0
  225. package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400.woff2 +0 -0
  226. package/app/public/vendor/fonts/cat-bakbak_one-400-ext.woff2 +0 -0
  227. package/app/public/vendor/fonts/cat-bakbak_one-400.woff2 +0 -0
  228. package/app/public/vendor/fonts/cat-bangers-400-ext.woff2 +0 -0
  229. package/app/public/vendor/fonts/cat-bangers-400.woff2 +0 -0
  230. package/app/public/vendor/fonts/cat-barriecito-400-ext.woff2 +0 -0
  231. package/app/public/vendor/fonts/cat-barriecito-400.woff2 +0 -0
  232. package/app/public/vendor/fonts/cat-berkshire_swash-400-ext.woff2 +0 -0
  233. package/app/public/vendor/fonts/cat-berkshire_swash-400.woff2 +0 -0
  234. package/app/public/vendor/fonts/cat-bevan-400-ext.woff2 +0 -0
  235. package/app/public/vendor/fonts/cat-bevan-400.woff2 +0 -0
  236. package/app/public/vendor/fonts/cat-bitcount-400-ext.woff2 +0 -0
  237. package/app/public/vendor/fonts/cat-bitcount-400.woff2 +0 -0
  238. package/app/public/vendor/fonts/cat-bowlby_one_sc-400-ext.woff2 +0 -0
  239. package/app/public/vendor/fonts/cat-bowlby_one_sc-400.woff2 +0 -0
  240. package/app/public/vendor/fonts/cat-bungee_shade-400-ext.woff2 +0 -0
  241. package/app/public/vendor/fonts/cat-bungee_shade-400.woff2 +0 -0
  242. package/app/public/vendor/fonts/cat-charm-400-ext.woff2 +0 -0
  243. package/app/public/vendor/fonts/cat-charm-400.woff2 +0 -0
  244. package/app/public/vendor/fonts/cat-charm-700-ext.woff2 +0 -0
  245. package/app/public/vendor/fonts/cat-charm-700.woff2 +0 -0
  246. package/app/public/vendor/fonts/cat-cherry_bomb_one-400-ext.woff2 +0 -0
  247. package/app/public/vendor/fonts/cat-cherry_bomb_one-400.woff2 +0 -0
  248. package/app/public/vendor/fonts/cat-chokokutai-400-ext.woff2 +0 -0
  249. package/app/public/vendor/fonts/cat-chokokutai-400.woff2 +0 -0
  250. package/app/public/vendor/fonts/cat-chonburi-400-ext.woff2 +0 -0
  251. package/app/public/vendor/fonts/cat-chonburi-400.woff2 +0 -0
  252. package/app/public/vendor/fonts/cat-climate_crisis-400-ext.woff2 +0 -0
  253. package/app/public/vendor/fonts/cat-climate_crisis-400.woff2 +0 -0
  254. package/app/public/vendor/fonts/cat-cookie-400.woff2 +0 -0
  255. package/app/public/vendor/fonts/cat-dela_gothic_one-400-ext.woff2 +0 -0
  256. package/app/public/vendor/fonts/cat-dela_gothic_one-400.woff2 +0 -0
  257. package/app/public/vendor/fonts/cat-fascinate_inline-400-ext.woff2 +0 -0
  258. package/app/public/vendor/fonts/cat-fascinate_inline-400.woff2 +0 -0
  259. package/app/public/vendor/fonts/cat-ga_maamli-400-ext.woff2 +0 -0
  260. package/app/public/vendor/fonts/cat-ga_maamli-400.woff2 +0 -0
  261. package/app/public/vendor/fonts/cat-itim-400-ext.woff2 +0 -0
  262. package/app/public/vendor/fonts/cat-itim-400.woff2 +0 -0
  263. package/app/public/vendor/fonts/cat-jacquard_24-400-ext.woff2 +0 -0
  264. package/app/public/vendor/fonts/cat-jacquard_24-400.woff2 +0 -0
  265. package/app/public/vendor/fonts/cat-kablammo-400-ext.woff2 +0 -0
  266. package/app/public/vendor/fonts/cat-kablammo-400.woff2 +0 -0
  267. package/app/public/vendor/fonts/cat-kalam-400-ext.woff2 +0 -0
  268. package/app/public/vendor/fonts/cat-kalam-400.woff2 +0 -0
  269. package/app/public/vendor/fonts/cat-kalam-700-ext.woff2 +0 -0
  270. package/app/public/vendor/fonts/cat-kalam-700.woff2 +0 -0
  271. package/app/public/vendor/fonts/cat-katibeh-400-ext.woff2 +0 -0
  272. package/app/public/vendor/fonts/cat-katibeh-400.woff2 +0 -0
  273. package/app/public/vendor/fonts/cat-lemonada-400-ext.woff2 +0 -0
  274. package/app/public/vendor/fonts/cat-lemonada-400.woff2 +0 -0
  275. package/app/public/vendor/fonts/cat-lilita_one-400-ext.woff2 +0 -0
  276. package/app/public/vendor/fonts/cat-lilita_one-400.woff2 +0 -0
  277. package/app/public/vendor/fonts/cat-lobster-400-ext.woff2 +0 -0
  278. package/app/public/vendor/fonts/cat-lobster-400.woff2 +0 -0
  279. package/app/public/vendor/fonts/cat-luckiest_guy-400-ext.woff2 +0 -0
  280. package/app/public/vendor/fonts/cat-luckiest_guy-400.woff2 +0 -0
  281. package/app/public/vendor/fonts/cat-marhey-400-ext.woff2 +0 -0
  282. package/app/public/vendor/fonts/cat-marhey-400.woff2 +0 -0
  283. package/app/public/vendor/fonts/cat-modak-400-ext.woff2 +0 -0
  284. package/app/public/vendor/fonts/cat-modak-400.woff2 +0 -0
  285. package/app/public/vendor/fonts/cat-momo_signature-400-ext.woff2 +0 -0
  286. package/app/public/vendor/fonts/cat-momo_signature-400.woff2 +0 -0
  287. package/app/public/vendor/fonts/cat-monofett-400-ext.woff2 +0 -0
  288. package/app/public/vendor/fonts/cat-monofett-400.woff2 +0 -0
  289. package/app/public/vendor/fonts/cat-monomakh-400-ext.woff2 +0 -0
  290. package/app/public/vendor/fonts/cat-monomakh-400.woff2 +0 -0
  291. package/app/public/vendor/fonts/cat-monoton-400-ext.woff2 +0 -0
  292. package/app/public/vendor/fonts/cat-monoton-400.woff2 +0 -0
  293. package/app/public/vendor/fonts/cat-nerko_one-400-ext.woff2 +0 -0
  294. package/app/public/vendor/fonts/cat-nerko_one-400.woff2 +0 -0
  295. package/app/public/vendor/fonts/cat-noto_sans_adlam-400-ext.woff2 +0 -0
  296. package/app/public/vendor/fonts/cat-noto_sans_adlam-400.woff2 +0 -0
  297. package/app/public/vendor/fonts/cat-noto_sans_arabic-400-ext.woff2 +0 -0
  298. package/app/public/vendor/fonts/cat-noto_sans_arabic-400.woff2 +0 -0
  299. package/app/public/vendor/fonts/cat-noto_sans_devanagari-400-ext.woff2 +0 -0
  300. package/app/public/vendor/fonts/cat-noto_sans_devanagari-400.woff2 +0 -0
  301. package/app/public/vendor/fonts/cat-noto_sans_hebrew-400-ext.woff2 +0 -0
  302. package/app/public/vendor/fonts/cat-noto_sans_hebrew-400.woff2 +0 -0
  303. package/app/public/vendor/fonts/cat-noto_sans_jp-400-ext.woff2 +0 -0
  304. package/app/public/vendor/fonts/cat-noto_sans_jp-400.woff2 +0 -0
  305. package/app/public/vendor/fonts/cat-noto_sans_khmer-400-ext.woff2 +0 -0
  306. package/app/public/vendor/fonts/cat-noto_sans_khmer-400.woff2 +0 -0
  307. package/app/public/vendor/fonts/cat-noto_sans_kr-400-ext.woff2 +0 -0
  308. package/app/public/vendor/fonts/cat-noto_sans_kr-400.woff2 +0 -0
  309. package/app/public/vendor/fonts/cat-noto_sans_sc-400-ext.woff2 +0 -0
  310. package/app/public/vendor/fonts/cat-noto_sans_sc-400.woff2 +0 -0
  311. package/app/public/vendor/fonts/cat-noto_sans_thai-400-ext.woff2 +0 -0
  312. package/app/public/vendor/fonts/cat-noto_sans_thai-400.woff2 +0 -0
  313. package/app/public/vendor/fonts/cat-ole-400-ext.woff2 +0 -0
  314. package/app/public/vendor/fonts/cat-ole-400.woff2 +0 -0
  315. package/app/public/vendor/fonts/cat-pacifico-400-ext.woff2 +0 -0
  316. package/app/public/vendor/fonts/cat-pacifico-400.woff2 +0 -0
  317. package/app/public/vendor/fonts/cat-patrick_hand-400-ext.woff2 +0 -0
  318. package/app/public/vendor/fonts/cat-patrick_hand-400.woff2 +0 -0
  319. package/app/public/vendor/fonts/cat-petit_formal_script-400-ext.woff2 +0 -0
  320. package/app/public/vendor/fonts/cat-petit_formal_script-400.woff2 +0 -0
  321. package/app/public/vendor/fonts/cat-pixelify_sans-400-ext.woff2 +0 -0
  322. package/app/public/vendor/fonts/cat-pixelify_sans-400.woff2 +0 -0
  323. package/app/public/vendor/fonts/cat-plaster-400-ext.woff2 +0 -0
  324. package/app/public/vendor/fonts/cat-plaster-400.woff2 +0 -0
  325. package/app/public/vendor/fonts/cat-playwrite_ar_guides-400-0.woff2 +0 -0
  326. package/app/public/vendor/fonts/cat-playwrite_at-400-0.woff2 +0 -0
  327. package/app/public/vendor/fonts/cat-playwrite_at_guides-400-0.woff2 +0 -0
  328. package/app/public/vendor/fonts/cat-playwrite_au_nsw-400-0.woff2 +0 -0
  329. package/app/public/vendor/fonts/cat-playwrite_au_nsw_guides-400-0.woff2 +0 -0
  330. package/app/public/vendor/fonts/cat-playwrite_au_qld-400-0.woff2 +0 -0
  331. package/app/public/vendor/fonts/cat-playwrite_au_qld_guides-400-0.woff2 +0 -0
  332. package/app/public/vendor/fonts/cat-playwrite_au_sa-400-0.woff2 +0 -0
  333. package/app/public/vendor/fonts/cat-playwrite_au_sa_guides-400-0.woff2 +0 -0
  334. package/app/public/vendor/fonts/cat-playwrite_au_tas-400-0.woff2 +0 -0
  335. package/app/public/vendor/fonts/cat-playwrite_au_tas_guides-400-0.woff2 +0 -0
  336. package/app/public/vendor/fonts/cat-playwrite_au_vic-400-0.woff2 +0 -0
  337. package/app/public/vendor/fonts/cat-playwrite_au_vic_guides-400-0.woff2 +0 -0
  338. package/app/public/vendor/fonts/cat-playwrite_be_vlg-400-0.woff2 +0 -0
  339. package/app/public/vendor/fonts/cat-playwrite_be_vlg_guides-400-0.woff2 +0 -0
  340. package/app/public/vendor/fonts/cat-playwrite_be_wal-400-0.woff2 +0 -0
  341. package/app/public/vendor/fonts/cat-playwrite_be_wal_guides-400-0.woff2 +0 -0
  342. package/app/public/vendor/fonts/cat-playwrite_br_guides-400-0.woff2 +0 -0
  343. package/app/public/vendor/fonts/cat-playwrite_ca_guides-400-0.woff2 +0 -0
  344. package/app/public/vendor/fonts/cat-playwrite_cl_guides-400-0.woff2 +0 -0
  345. package/app/public/vendor/fonts/cat-playwrite_co_guides-400-0.woff2 +0 -0
  346. package/app/public/vendor/fonts/cat-playwrite_cu_guides-400-0.woff2 +0 -0
  347. package/app/public/vendor/fonts/cat-playwrite_cz-400-0.woff2 +0 -0
  348. package/app/public/vendor/fonts/cat-playwrite_cz_guides-400-0.woff2 +0 -0
  349. package/app/public/vendor/fonts/cat-playwrite_de_grund-400-0.woff2 +0 -0
  350. package/app/public/vendor/fonts/cat-playwrite_de_grund_guides-400-0.woff2 +0 -0
  351. package/app/public/vendor/fonts/cat-playwrite_de_la-400-0.woff2 +0 -0
  352. package/app/public/vendor/fonts/cat-playwrite_de_la_guides-400-0.woff2 +0 -0
  353. package/app/public/vendor/fonts/cat-playwrite_de_sas-400-0.woff2 +0 -0
  354. package/app/public/vendor/fonts/cat-playwrite_de_sas_guides-400-0.woff2 +0 -0
  355. package/app/public/vendor/fonts/cat-playwrite_de_va-400-0.woff2 +0 -0
  356. package/app/public/vendor/fonts/cat-playwrite_de_va_guides-400-0.woff2 +0 -0
  357. package/app/public/vendor/fonts/cat-playwrite_dk_loopet-400-0.woff2 +0 -0
  358. package/app/public/vendor/fonts/cat-playwrite_dk_loopet_guides-400-0.woff2 +0 -0
  359. package/app/public/vendor/fonts/cat-playwrite_dk_uloopet-400-0.woff2 +0 -0
  360. package/app/public/vendor/fonts/cat-playwrite_dk_uloopet_guides-400-0.woff2 +0 -0
  361. package/app/public/vendor/fonts/cat-playwrite_es_deco_guides-400-0.woff2 +0 -0
  362. package/app/public/vendor/fonts/cat-playwrite_es_guides-400-0.woff2 +0 -0
  363. package/app/public/vendor/fonts/cat-playwrite_fr_moderne-400-0.woff2 +0 -0
  364. package/app/public/vendor/fonts/cat-playwrite_fr_moderne_guides-400-0.woff2 +0 -0
  365. package/app/public/vendor/fonts/cat-playwrite_fr_trad-400-0.woff2 +0 -0
  366. package/app/public/vendor/fonts/cat-playwrite_fr_trad_guides-400-0.woff2 +0 -0
  367. package/app/public/vendor/fonts/cat-playwrite_gb_j_guides-400-0.woff2 +0 -0
  368. package/app/public/vendor/fonts/cat-playwrite_gb_s_guides-400-0.woff2 +0 -0
  369. package/app/public/vendor/fonts/cat-playwrite_hr-400-0.woff2 +0 -0
  370. package/app/public/vendor/fonts/cat-playwrite_hr_guides-400-0.woff2 +0 -0
  371. package/app/public/vendor/fonts/cat-playwrite_hr_lijeva-400-0.woff2 +0 -0
  372. package/app/public/vendor/fonts/cat-playwrite_hr_lijeva_guides-400-0.woff2 +0 -0
  373. package/app/public/vendor/fonts/cat-playwrite_hu-400-0.woff2 +0 -0
  374. package/app/public/vendor/fonts/cat-playwrite_hu_guides-400-0.woff2 +0 -0
  375. package/app/public/vendor/fonts/cat-playwrite_id-400-0.woff2 +0 -0
  376. package/app/public/vendor/fonts/cat-playwrite_id_guides-400-0.woff2 +0 -0
  377. package/app/public/vendor/fonts/cat-playwrite_ie-400-0.woff2 +0 -0
  378. package/app/public/vendor/fonts/cat-playwrite_ie_guides-400-0.woff2 +0 -0
  379. package/app/public/vendor/fonts/cat-playwrite_in-400-0.woff2 +0 -0
  380. package/app/public/vendor/fonts/cat-playwrite_in_guides-400-0.woff2 +0 -0
  381. package/app/public/vendor/fonts/cat-playwrite_is-400-0.woff2 +0 -0
  382. package/app/public/vendor/fonts/cat-playwrite_is_guides-400-0.woff2 +0 -0
  383. package/app/public/vendor/fonts/cat-playwrite_it_moderna-400-0.woff2 +0 -0
  384. package/app/public/vendor/fonts/cat-playwrite_it_moderna_guides-400-0.woff2 +0 -0
  385. package/app/public/vendor/fonts/cat-playwrite_it_trad-400-0.woff2 +0 -0
  386. package/app/public/vendor/fonts/cat-playwrite_it_trad_guides-400-0.woff2 +0 -0
  387. package/app/public/vendor/fonts/cat-playwrite_mx_guides-400-0.woff2 +0 -0
  388. package/app/public/vendor/fonts/cat-playwrite_ng_modern-400-0.woff2 +0 -0
  389. package/app/public/vendor/fonts/cat-playwrite_ng_modern_guides-400-0.woff2 +0 -0
  390. package/app/public/vendor/fonts/cat-playwrite_nl-400-0.woff2 +0 -0
  391. package/app/public/vendor/fonts/cat-playwrite_nl_guides-400-0.woff2 +0 -0
  392. package/app/public/vendor/fonts/cat-playwrite_no-400-0.woff2 +0 -0
  393. package/app/public/vendor/fonts/cat-playwrite_no_guides-400-0.woff2 +0 -0
  394. package/app/public/vendor/fonts/cat-playwrite_nz-400-0.woff2 +0 -0
  395. package/app/public/vendor/fonts/cat-playwrite_nz_basic-400-0.woff2 +0 -0
  396. package/app/public/vendor/fonts/cat-playwrite_nz_basic_guides-400-0.woff2 +0 -0
  397. package/app/public/vendor/fonts/cat-playwrite_nz_guides-400-0.woff2 +0 -0
  398. package/app/public/vendor/fonts/cat-playwrite_pe_guides-400-0.woff2 +0 -0
  399. package/app/public/vendor/fonts/cat-playwrite_pl-400-0.woff2 +0 -0
  400. package/app/public/vendor/fonts/cat-playwrite_pl_guides-400-0.woff2 +0 -0
  401. package/app/public/vendor/fonts/cat-playwrite_pt_guides-400-0.woff2 +0 -0
  402. package/app/public/vendor/fonts/cat-playwrite_ro-400-0.woff2 +0 -0
  403. package/app/public/vendor/fonts/cat-playwrite_ro_guides-400-0.woff2 +0 -0
  404. package/app/public/vendor/fonts/cat-playwrite_sk-400-0.woff2 +0 -0
  405. package/app/public/vendor/fonts/cat-playwrite_sk_guides-400-0.woff2 +0 -0
  406. package/app/public/vendor/fonts/cat-playwrite_tz-400-0.woff2 +0 -0
  407. package/app/public/vendor/fonts/cat-playwrite_tz_guides-400-0.woff2 +0 -0
  408. package/app/public/vendor/fonts/cat-playwrite_us_modern_guides-400-0.woff2 +0 -0
  409. package/app/public/vendor/fonts/cat-playwrite_us_trad_guides-400-0.woff2 +0 -0
  410. package/app/public/vendor/fonts/cat-playwrite_vn-400-0.woff2 +0 -0
  411. package/app/public/vendor/fonts/cat-playwrite_vn_guides-400-0.woff2 +0 -0
  412. package/app/public/vendor/fonts/cat-playwrite_za-400-0.woff2 +0 -0
  413. package/app/public/vendor/fonts/cat-playwrite_za_guides-400-0.woff2 +0 -0
  414. package/app/public/vendor/fonts/cat-potta_one-400-ext.woff2 +0 -0
  415. package/app/public/vendor/fonts/cat-potta_one-400.woff2 +0 -0
  416. package/app/public/vendor/fonts/cat-ranchers-400-ext.woff2 +0 -0
  417. package/app/public/vendor/fonts/cat-ranchers-400.woff2 +0 -0
  418. package/app/public/vendor/fonts/cat-ranga-400-ext.woff2 +0 -0
  419. package/app/public/vendor/fonts/cat-ranga-400.woff2 +0 -0
  420. package/app/public/vendor/fonts/cat-ranga-700-ext.woff2 +0 -0
  421. package/app/public/vendor/fonts/cat-ranga-700.woff2 +0 -0
  422. package/app/public/vendor/fonts/cat-risque-400-ext.woff2 +0 -0
  423. package/app/public/vendor/fonts/cat-risque-400.woff2 +0 -0
  424. package/app/public/vendor/fonts/cat-rowdies-400-ext.woff2 +0 -0
  425. package/app/public/vendor/fonts/cat-rowdies-400.woff2 +0 -0
  426. package/app/public/vendor/fonts/cat-rowdies-700-ext.woff2 +0 -0
  427. package/app/public/vendor/fonts/cat-rowdies-700.woff2 +0 -0
  428. package/app/public/vendor/fonts/cat-ruge_boogie-400-ext.woff2 +0 -0
  429. package/app/public/vendor/fonts/cat-ruge_boogie-400.woff2 +0 -0
  430. package/app/public/vendor/fonts/cat-ruslan_display-400-ext.woff2 +0 -0
  431. package/app/public/vendor/fonts/cat-ruslan_display-400.woff2 +0 -0
  432. package/app/public/vendor/fonts/cat-sacramento-400-ext.woff2 +0 -0
  433. package/app/public/vendor/fonts/cat-sacramento-400.woff2 +0 -0
  434. package/app/public/vendor/fonts/cat-sancreek-400-ext.woff2 +0 -0
  435. package/app/public/vendor/fonts/cat-sancreek-400.woff2 +0 -0
  436. package/app/public/vendor/fonts/cat-sankofa_display-400-ext.woff2 +0 -0
  437. package/app/public/vendor/fonts/cat-sankofa_display-400.woff2 +0 -0
  438. package/app/public/vendor/fonts/cat-sedgwick_ave_display-400-ext.woff2 +0 -0
  439. package/app/public/vendor/fonts/cat-sedgwick_ave_display-400.woff2 +0 -0
  440. package/app/public/vendor/fonts/cat-shantell_sans-400-ext.woff2 +0 -0
  441. package/app/public/vendor/fonts/cat-shantell_sans-400.woff2 +0 -0
  442. package/app/public/vendor/fonts/cat-smokum-400-ext.woff2 +0 -0
  443. package/app/public/vendor/fonts/cat-smokum-400.woff2 +0 -0
  444. package/app/public/vendor/fonts/cat-solitreo-400-ext.woff2 +0 -0
  445. package/app/public/vendor/fonts/cat-solitreo-400.woff2 +0 -0
  446. package/app/public/vendor/fonts/cat-spicy_rice-400-ext.woff2 +0 -0
  447. package/app/public/vendor/fonts/cat-spicy_rice-400.woff2 +0 -0
  448. package/app/public/vendor/fonts/cat-sriracha-400-ext.woff2 +0 -0
  449. package/app/public/vendor/fonts/cat-sriracha-400.woff2 +0 -0
  450. package/app/public/vendor/fonts/cat-srisakdi-400-ext.woff2 +0 -0
  451. package/app/public/vendor/fonts/cat-srisakdi-400.woff2 +0 -0
  452. package/app/public/vendor/fonts/cat-srisakdi-700-ext.woff2 +0 -0
  453. package/app/public/vendor/fonts/cat-srisakdi-700.woff2 +0 -0
  454. package/app/public/vendor/fonts/cat-stix_two_math-400-0.woff2 +0 -0
  455. package/app/public/vendor/fonts/cat-tillana-400-ext.woff2 +0 -0
  456. package/app/public/vendor/fonts/cat-tillana-400.woff2 +0 -0
  457. package/app/public/vendor/fonts/cat-tillana-700-ext.woff2 +0 -0
  458. package/app/public/vendor/fonts/cat-tillana-700.woff2 +0 -0
  459. package/app/public/vendor/fonts/cat-titan_one-400-ext.woff2 +0 -0
  460. package/app/public/vendor/fonts/cat-titan_one-400.woff2 +0 -0
  461. package/app/public/vendor/fonts/cat-yatra_one-400-ext.woff2 +0 -0
  462. package/app/public/vendor/fonts/cat-yatra_one-400.woff2 +0 -0
  463. package/app/public/vendor/fonts/cat-yomogi-400-ext.woff2 +0 -0
  464. package/app/public/vendor/fonts/cat-yomogi-400.woff2 +0 -0
  465. package/app/public/vendor/fonts/dmserifdisplay-400-ext.woff2 +0 -0
  466. package/app/public/vendor/fonts/dmserifdisplay-400.woff2 +0 -0
  467. package/app/public/vendor/fonts/domine-var-ext.woff2 +0 -0
  468. package/app/public/vendor/fonts/domine-var.woff2 +0 -0
  469. package/app/public/vendor/fonts/fondamento-400-ext.woff2 +0 -0
  470. package/app/public/vendor/fonts/fondamento-400.woff2 +0 -0
  471. package/app/public/vendor/fonts/fraunces-var-ext.woff2 +0 -0
  472. package/app/public/vendor/fonts/fraunces-var.woff2 +0 -0
  473. package/app/public/vendor/fonts/fredoka-var-ext.woff2 +0 -0
  474. package/app/public/vendor/fonts/fredoka-var.woff2 +0 -0
  475. package/app/public/vendor/fonts/inter-400.woff2 +0 -0
  476. package/app/public/vendor/fonts/inter-700.woff2 +0 -0
  477. package/app/public/vendor/fonts/jakarta-var-ext.woff2 +0 -0
  478. package/app/public/vendor/fonts/jakarta-var.woff2 +0 -0
  479. package/app/public/vendor/fonts/lato-400.woff2 +0 -0
  480. package/app/public/vendor/fonts/lato-700.woff2 +0 -0
  481. package/app/public/vendor/fonts/literata-400.woff2 +0 -0
  482. package/app/public/vendor/fonts/literata-700.woff2 +0 -0
  483. package/app/public/vendor/fonts/lora-var-ext.woff2 +0 -0
  484. package/app/public/vendor/fonts/lora-var.woff2 +0 -0
  485. package/app/public/vendor/fonts/merriweather-var-ext.woff2 +0 -0
  486. package/app/public/vendor/fonts/merriweather-var.woff2 +0 -0
  487. package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
  488. package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
  489. package/app/public/vendor/fonts/notosans-var-ext.woff2 +0 -0
  490. package/app/public/vendor/fonts/notosans-var.woff2 +0 -0
  491. package/app/public/vendor/fonts/nunito-var-ext.woff2 +0 -0
  492. package/app/public/vendor/fonts/nunito-var.woff2 +0 -0
  493. package/app/public/vendor/fonts/opendyslexic-400.woff2 +0 -0
  494. package/app/public/vendor/fonts/opensans-400.woff2 +0 -0
  495. package/app/public/vendor/fonts/opensans-700.woff2 +0 -0
  496. package/app/public/vendor/fonts/pinyon-400.woff2 +0 -0
  497. package/app/public/vendor/fonts/playfair-var-ext.woff2 +0 -0
  498. package/app/public/vendor/fonts/playfair-var.woff2 +0 -0
  499. package/app/public/vendor/fonts/pressstart-400.woff2 +0 -0
  500. package/app/public/vendor/fonts/quattro-400.woff2 +0 -0
  501. package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
  502. package/app/public/vendor/fonts/quicksand-var-ext.woff2 +0 -0
  503. package/app/public/vendor/fonts/quicksand-var.woff2 +0 -0
  504. package/app/public/vendor/fonts/robotoflex-var-ext.woff2 +0 -0
  505. package/app/public/vendor/fonts/robotoflex-var.woff2 +0 -0
  506. package/app/public/vendor/fonts/sora-var-ext.woff2 +0 -0
  507. package/app/public/vendor/fonts/sora-var.woff2 +0 -0
  508. package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
  509. package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
  510. package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
  511. package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
  512. package/app/public/vendor/fonts/spacegrotesk-var-ext.woff2 +0 -0
  513. package/app/public/vendor/fonts/spacegrotesk-var.woff2 +0 -0
  514. package/app/public/vendor/fonts/spectral-400-ext.woff2 +0 -0
  515. package/app/public/vendor/fonts/spectral-400.woff2 +0 -0
  516. package/app/public/vendor/fonts/spectral-700-ext.woff2 +0 -0
  517. package/app/public/vendor/fonts/spectral-700.woff2 +0 -0
  518. package/app/public/vendor/fonts/teachers-var-ext.woff2 +0 -0
  519. package/app/public/vendor/fonts/teachers-var.woff2 +0 -0
  520. package/app/public/vendor/fonts/ubuntu-400-ext.woff2 +0 -0
  521. package/app/public/vendor/fonts/ubuntu-400.woff2 +0 -0
  522. package/app/public/vendor/fonts/ubuntu-700-ext.woff2 +0 -0
  523. package/app/public/vendor/fonts/ubuntu-700.woff2 +0 -0
  524. package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
  525. package/dist-pkg/platform/guide-intensity.d.ts +0 -39
  526. package/dist-pkg/platform/guide-intensity.js +0 -71
  527. package/dist-pkg/ui/latch-refusal.d.ts +0 -33
  528. package/dist-pkg/ui/latch-refusal.js +0 -60
@@ -18,7 +18,7 @@ export interface Announcer {
18
18
  /** "Assertive" announcement (alert): interrupts and speaks now (errors, important warnings). */
19
19
  readonly alert: (text: string) => void;
20
20
  /**
21
- * Sends every announcement of THIS announcer also to `sink` (the Libras interpreter's `say`), until the returned release
21
+ * Sends every announcement of THIS announcer also to `sink`, until the returned release
22
22
  * is called. One sink at a time: a second call replaces the first, and releasing a replaced sink changes nothing.
23
23
  */
24
24
  readonly mirrorTo: (sink: (text: string) => void) => () => void;
@@ -9,11 +9,9 @@
9
9
  // Now each root builds its own over the document and the frames its host lends. The factory stays PUBLISHED for a game
10
10
  // that must announce with no root at all — its boot failed before `createGame` returned (game-chess's rootless alert).
11
11
  //
12
- // THE LIBRAS MIRROR IS AN EXPLICIT SINK OF EACH ANNOUNCER, and nothing connects it by default. Today a game that wants
13
- // its announcements signed connects it (`Engine.mirrorAnnouncements(engine.libras.say)`); the games that do not, do not
14
- // sign — the behaviour before this factory, kept on purpose until the Dev decides (D4 decision DD1). Having the root
15
- // mirror everything is the one line `announcer.mirrorTo(libras.say)` in the root. The sink arrives by injection so this
16
- // core module never imports ui/ (ADR-0173).
12
+ // THE MIRROR IS AN EXPLICIT SINK OF EACH ANNOUNCER, and nothing connects it by default. It was the Libras interpreter's
13
+ // door; ADR-0234 closed that question (DD1): deaf mode signs what the sonar finds, when the child asks, and never the
14
+ // announcements — so no queue of messages. The sink arrives by injection so this core module never imports ui/ (ADR-0173).
17
15
  const NO_MIRROR = () => { };
18
16
  export function createAnnouncer({ doc, raf }) {
19
17
  const nextFrame = (cb) => { if (raf)
@@ -30,7 +30,10 @@ export declare const CONTRACT_KEYED: readonly ["visionSimulation", "audioDescrip
30
30
  * exact defect ADR-0145 was written about.
31
31
  */
32
32
  export declare const GAME_KEYED: readonly ["cameraSway", "easyMode", "wheelchairMode", "detectionLeniency", "intensity", "hints", "reducedCharacterMotion", "caneSpacing", "textPace", "lexicalDifficulty", "wordHighlight", "pieceSets", "distinguishableSuits", "timingWindow", "aimAssist", "repeatedInput", "ownerColors", "contrastOutlines"];
33
- /** What the child reads and hears for an accommodation: the name, and the sentence that explains it. */
33
+ /**
34
+ * What the child reads and hears for an accommodation: the name, and the sentence that explains it — RESOLVED, in the page's
35
+ * language. A cartridge's ANSWER declares keys (`AccommodationKeys`), and `subjectWord` resolves them at every drawing.
36
+ */
34
37
  export interface AccommodationWord {
35
38
  /** «Wheelchair mode», «Board pieces». NEVER `wheelchairMode` — an id that reaches a person is a defect. */
36
39
  readonly label: string;
@@ -75,8 +78,21 @@ export declare function accommodationPresetProblems(p: AccommodationPreset | nul
75
78
  /** The accommodations only the game can answer. */
76
79
  export type GameKeyedAccommodation = (typeof GAME_KEYED)[number];
77
80
  /**
78
- * THE CARTRIDGE'S ANSWER, for every GAME_KEYED accommodation: its WORD when the accommodation has a subject in this
79
- * game, or `false` when it has none.
81
+ * What a cartridge DECLARES for an accommodation it has a subject for: the KEYS of its words in its own dictionary
82
+ * (`CreateGameOptions.dictionaries`). Keys and not words, so the row follows a language change (ADR-0232 D3, erratum of
83
+ * 2026-09-25; the rule and its measured defect are written on `core/actions.ActionKeys`).
84
+ */
85
+ export interface AccommodationKeys {
86
+ /** The key of the name: «Wheelchair mode», «Board pieces». */
87
+ readonly labelKey: string;
88
+ /** The key of the SHORT form. Falls back to the name when absent. */
89
+ readonly shortKey?: string;
90
+ /** The key of the sentence the menu row explains itself with, in the footer (`CLAUDE.md` §4). */
91
+ readonly hintKey?: string;
92
+ }
93
+ /**
94
+ * THE CARTRIDGE'S ANSWER, for every GAME_KEYED accommodation: the KEYS of its word when the accommodation has a subject in
95
+ * this game, or `false` when it has none.
80
96
  *
81
97
  * 🔴 COMPLETE, NOT PARTIAL — and that is the difference from `AccommodationPreset`, and the decision. The Dev:
82
98
  * «Gênero não precisa responder todas as acomodações, mas sim o cartucho, obrigatoriamente.» A partial map lets
@@ -87,7 +103,7 @@ export type GameKeyedAccommodation = (typeof GAME_KEYED)[number];
87
103
  * always and CONTRACT_KEYED ones are derived from the contract, so neither is asked here — asking twice would let
88
104
  * the two answers disagree.
89
105
  */
90
- export type AccommodationAnswers = Readonly<Record<GameKeyedAccommodation, AccommodationWord | false>>;
106
+ export type AccommodationAnswers = Readonly<Record<GameKeyedAccommodation, AccommodationKeys | false>>;
91
107
  /** Is it one of the accommodations the cartridge must answer? */
92
108
  export declare function isGameKeyed(x: unknown): x is GameKeyedAccommodation;
93
109
  /**
@@ -99,9 +115,11 @@ export declare function isGameKeyed(x: unknown): x is GameKeyedAccommodation;
99
115
  */
100
116
  export declare function accommodationAnswersProblems(a: unknown): string[];
101
117
  /**
102
- * Does this accommodation have a subject in this game? The question a panel asks before mounting a row.
118
+ * Does this accommodation have a subject in this game — and what is it called NOW? The question a panel asks before
119
+ * mounting a row, at every drawing.
103
120
  *
104
- * 📌 It returns the WORD, or `null` — never the id, never `true`: a row that mounts must have a name to show, and
105
- * «has a subject» without a word is the `action2` defect one level up.
121
+ * 📌 It returns the WORD, resolved through `word` (the root's translator, ADR-0232 D3), or `null` — never the id, never the
122
+ * key, never `true`: a row that mounts must have a name to show, and «has a subject» without a word is the `action2` defect
123
+ * one level up. A key the game's dictionaries lack is `null` here and a line of `problems` (`ui/declared-words`).
106
124
  */
107
- export declare function subjectWord(answers: AccommodationAnswers, k: GameKeyedAccommodation): AccommodationWord | null;
125
+ export declare function subjectWord(answers: AccommodationAnswers, k: GameKeyedAccommodation, word: (key: string) => string | null): AccommodationWord | null;
@@ -21,7 +21,7 @@
21
21
  // · GENERAL — there is text, sound, a screen and a menu in every game. The engine mounts these always.
22
22
  // · CONTRACT_KEYED — the subject is answered by a declaration the contract ALREADY asks every game
23
23
  // (`tick`, `holdsKeys()`, `needsPointer()`, `world()` × `topology()`, the players list). The engine can
24
- // derive these without a genre, which is the `sonarPlayers` precedent: absent ⇒ derive from the contract.
24
+ // derive these without a genre, by the rule the engine keeps for what a contract already answers: absent ⇒ derive from the contract.
25
25
  // · GAME_KEYED — nothing the engine holds answers it (genre, perspective, avatar, text, pieces, timing).
26
26
  // The game — or the template of its genre — declares it.
27
27
  //
@@ -149,7 +149,7 @@ export function isGameKeyed(x) {
149
149
  */
150
150
  export function accommodationAnswersProblems(a) {
151
151
  if (a === null || a === undefined) {
152
- return ['accommodations: missing - the cartridge must answer every game-keyed accommodation (ADR-0153): its word, or false'];
152
+ return ['accommodations: missing - the cartridge must answer every game-keyed accommodation (ADR-0153): the keys of its word, or false'];
153
153
  }
154
154
  if (!isKeyed(a))
155
155
  return [NOT_KEYED];
@@ -159,20 +159,37 @@ export function accommodationAnswersProblems(a) {
159
159
  : `accommodations: «${k}» is not in the catalogue - a game's own accommodation is an addition (ADR-0145 §2)`));
160
160
  return [...unanswered, ...strangers];
161
161
  }
162
- /** What is wrong with the cartridge's answer to ONE accommodation, or `null`: it must be written, and be `false` or a word. */
162
+ /** What is wrong with the cartridge's answer to ONE accommodation, or `null`: it must be written, and be `false` or keys. */
163
163
  function answerProblem(answers, k) {
164
164
  if (!(k in answers))
165
- return `accommodations: ${k} is not answered - write its word if it has a subject in this game, or false`;
165
+ return `accommodations: ${k} is not answered - write the keys of its word if it has a subject in this game, or false`;
166
166
  const v = answers[k];
167
- return v === false || isWord(v) ? null : `accommodations: ${k} must be false or a word with a non-empty label`;
167
+ return v === false || isDeclared(v) ? null : `accommodations: ${k} must be false or { labelKey } naming a key of the game's dictionary`;
168
+ }
169
+ /** DECLARED KEYS: an object whose `labelKey` is text and not blank, and whose optional keys are text when present. */
170
+ function isDeclared(v) {
171
+ if (!v || typeof v !== 'object')
172
+ return false;
173
+ const { labelKey, shortKey, hintKey } = v;
174
+ const optionalKey = (k) => k === undefined || typeof k === 'string';
175
+ return typeof labelKey === 'string' && labelKey.trim() !== '' && optionalKey(shortKey) && optionalKey(hintKey);
168
176
  }
169
177
  /**
170
- * Does this accommodation have a subject in this game? The question a panel asks before mounting a row.
178
+ * Does this accommodation have a subject in this game — and what is it called NOW? The question a panel asks before
179
+ * mounting a row, at every drawing.
171
180
  *
172
- * 📌 It returns the WORD, or `null` — never the id, never `true`: a row that mounts must have a name to show, and
173
- * «has a subject» without a word is the `action2` defect one level up.
181
+ * 📌 It returns the WORD, resolved through `word` (the root's translator, ADR-0232 D3), or `null` — never the id, never the
182
+ * key, never `true`: a row that mounts must have a name to show, and «has a subject» without a word is the `action2` defect
183
+ * one level up. A key the game's dictionaries lack is `null` here and a line of `problems` (`ui/declared-words`).
174
184
  */
175
- export function subjectWord(answers, k) {
185
+ export function subjectWord(answers, k, word) {
176
186
  const v = answers[k];
177
- return v && v.label.trim() ? v : null;
187
+ if (!v)
188
+ return null;
189
+ const label = word(v.labelKey);
190
+ if (!label || !label.trim())
191
+ return null;
192
+ const short = v.shortKey ? word(v.shortKey) : null;
193
+ const hint = v.hintKey ? word(v.hintKey) : null;
194
+ return { label, ...(short ? { short } : {}), ...(hint ? { hint } : {}) };
178
195
  }
@@ -25,7 +25,10 @@ export declare const VERBS: readonly ["action1", "action2", "action3", "action4"
25
25
  * itself since 1983, and the child reads that legend before ours.
26
26
  */
27
27
  export declare const SYSTEM: readonly ["start", "select"];
28
- /** What the child reads and hears for a position: the name, and the sentence that explains it when they ask. */
28
+ /**
29
+ * What the child reads and hears for a position: the name, and the sentence that explains it when they ask — RESOLVED, in
30
+ * the page's language. The engine builds these from the game's KEYS (`wordsOf`) each time it draws; a game declares keys.
31
+ */
29
32
  export interface ActionWord {
30
33
  /** "Jump", "Confirm", "Place piece". NEVER `action2` — an abstract name reaching a person is a defect. */
31
34
  readonly label: string;
@@ -45,14 +48,39 @@ export interface ActionWord {
45
48
  readonly hint?: string;
46
49
  }
47
50
  /**
48
- * The vocabulary of ONE game: for each position it uses, its word.
51
+ * What a game DECLARES for a position: the KEYS of its words in its own dictionary (`CreateGameOptions.dictionaries`).
52
+ *
53
+ * 🔴 KEYS AND NOT WORDS (ADR-0232 D3, erratum of 2026-09-25). A word handed over at boot is in the boot language forever:
54
+ * 📏 measured, a preset built with `t` in Portuguese still read «Acima» after `setLocale('en')`. A key is resolved by the
55
+ * root's translator each time the engine draws or speaks it, so changing the language changes every word at once
56
+ * (ADR-0225), and the game never needs to know how (ADR-0216).
57
+ */
58
+ export interface ActionKeys {
59
+ /** The key of the name: «Jump», «Confirm». A key the game's dictionaries lack leaves the position unnamed, and `problems` says so. */
60
+ readonly labelKey: string;
61
+ /** The key of the SHORT name, for a legend under a glyph. Falls back to the name when absent. */
62
+ readonly shortKey?: string;
63
+ /** The key of the sentence that says what this button does, for the help and the remap screen. */
64
+ readonly hintKey?: string;
65
+ }
66
+ /**
67
+ * The vocabulary of ONE game: for each position it uses, the keys of its words.
49
68
  *
50
69
  * ⚠️ PARTIAL ON PURPOSE. A game declares ONLY the positions it uses. Requiring all fourteen would make a quiz invent a
51
70
  * name for a trigger it does not have, and an invented name ends up on a remap screen in front of a child.
52
71
  */
53
- export type ActionPreset = Partial<Readonly<Record<Action, ActionWord>>>;
72
+ export type ActionPreset = Partial<Readonly<Record<Action, ActionKeys>>>;
73
+ /** A preset RESOLVED into words, in the page's language — what the engine's surfaces read (`wordsOf`). */
74
+ export type ActionWords = Partial<Readonly<Record<Action, ActionWord>>>;
54
75
  /** The positions this preset names, in the canonical order of `ACTIONS`. */
55
- export declare function presetActions(p: ActionPreset): Action[];
76
+ export declare function presetActions(p: ActionPreset | ActionWords): Action[];
77
+ /**
78
+ * THE GAME'S KEYS, RESOLVED NOW — called at every drawing, never kept (ADR-0232 D3 erratum).
79
+ *
80
+ * A position whose NAME resolves to nothing is left out, so every surface treats it as unnamed — the rule `labellerFrom`
81
+ * already applies: an absence is one step fewer, never a mute step, and never the key itself on screen.
82
+ */
83
+ export declare function wordsOf(p: ActionPreset, word: (key: string) => string | null): ActionWords;
56
84
  /**
57
85
  * The question the engine asks the game when it has to SHOW an action: "what is this called?".
58
86
  *
@@ -68,22 +96,23 @@ export type ActionLabeller = (a: Action) => string;
68
96
  * the silent defect `speakableProblems` already chases elsewhere.
69
97
  *
70
98
  * It returns `null`, and the caller decides: the pad wizard DOES NOT ASK for an action the game does not name — if the
71
- * game does not use it, there is nothing to map. An absence becomes one step fewer, never a mute step.
99
+ * game does not use it, there is nothing to map. An absence becomes one step fewer, never a mute step. (`SYSTEM` is the
100
+ * exception there: the wizard asks START and SELECT in its own words, since no preset may name them — ADR-0144 erratum.)
72
101
  */
73
- export declare function labellerFrom(p: ActionPreset): (a: Action) => string | null;
102
+ export declare function labellerFrom(p: ActionWords): (a: Action) => string | null;
74
103
  /**
75
104
  * The same, in the SHORT version — for a legend, where the word lives under a glyph.
76
105
  *
77
106
  * ⚠️ IT FALLS BACK TO `label`, and the fallback is the decision: a tight legend is worse than a neat one and better than
78
107
  * an empty one. Empty would also vanish for a screen reader user, which is the cost not accepted here.
79
108
  */
80
- export declare function shortLabellerFrom(p: ActionPreset): (a: Action) => string | null;
109
+ export declare function shortLabellerFrom(p: ActionWords): (a: Action) => string | null;
81
110
  /**
82
111
  * Is a preset well formed? Returns the problems — EMPTY means conformant.
83
112
  *
84
- * ⚠️ WHAT IT CATCHES IS THE EMPTY LABEL, the same silent defect as `speakableProblems` in `core/contract`: a blank
85
- * `label` breaks nothing, warns nobody, and leaves the remap screen with a mute row — for a screen reader user, a button
86
- * that exists and has no name.
113
+ * ⚠️ WHAT IT CATCHES IS THE EMPTY KEY, the same silent defect as `speakableProblems` in `core/contract`: a blank
114
+ * `labelKey` breaks nothing, warns nobody, and leaves the remap screen with a mute row — for a screen reader user, a button
115
+ * that exists and has no name. Whether the key is IN the game's dictionaries is the root's question (`ui/declared-words`).
87
116
  */
88
117
  export declare function presetProblems(p: ActionPreset | null | undefined): string[];
89
118
  /**
@@ -59,6 +59,27 @@ export const SYSTEM = ['start', 'select'];
59
59
  export function presetActions(p) {
60
60
  return ACTIONS.filter((a) => p[a] !== undefined);
61
61
  }
62
+ /** Resolves one declared key through `word`; a key that is not text resolves to nothing. */
63
+ const resolved = (word, key) => (typeof key === 'string' && key.trim() ? word(key) : null);
64
+ /**
65
+ * THE GAME'S KEYS, RESOLVED NOW — called at every drawing, never kept (ADR-0232 D3 erratum).
66
+ *
67
+ * A position whose NAME resolves to nothing is left out, so every surface treats it as unnamed — the rule `labellerFrom`
68
+ * already applies: an absence is one step fewer, never a mute step, and never the key itself on screen.
69
+ */
70
+ export function wordsOf(p, word) {
71
+ const words = {};
72
+ for (const a of presetActions(p)) {
73
+ const keys = p[a];
74
+ const label = resolved(word, keys.labelKey);
75
+ if (!label)
76
+ continue;
77
+ const short = resolved(word, keys.shortKey);
78
+ const hint = resolved(word, keys.hintKey);
79
+ words[a] = { label, ...(short ? { short } : {}), ...(hint ? { hint } : {}) };
80
+ }
81
+ return words;
82
+ }
62
83
  /**
63
84
  * Builds the translator from a preset.
64
85
  *
@@ -67,7 +88,8 @@ export function presetActions(p) {
67
88
  * the silent defect `speakableProblems` already chases elsewhere.
68
89
  *
69
90
  * It returns `null`, and the caller decides: the pad wizard DOES NOT ASK for an action the game does not name — if the
70
- * game does not use it, there is nothing to map. An absence becomes one step fewer, never a mute step.
91
+ * game does not use it, there is nothing to map. An absence becomes one step fewer, never a mute step. (`SYSTEM` is the
92
+ * exception there: the wizard asks START and SELECT in its own words, since no preset may name them — ADR-0144 erratum.)
71
93
  */
72
94
  export function labellerFrom(p) {
73
95
  return (a) => {
@@ -93,9 +115,9 @@ export function shortLabellerFrom(p) {
93
115
  /**
94
116
  * Is a preset well formed? Returns the problems — EMPTY means conformant.
95
117
  *
96
- * ⚠️ WHAT IT CATCHES IS THE EMPTY LABEL, the same silent defect as `speakableProblems` in `core/contract`: a blank
97
- * `label` breaks nothing, warns nobody, and leaves the remap screen with a mute row — for a screen reader user, a button
98
- * that exists and has no name.
118
+ * ⚠️ WHAT IT CATCHES IS THE EMPTY KEY, the same silent defect as `speakableProblems` in `core/contract`: a blank
119
+ * `labelKey` breaks nothing, warns nobody, and leaves the remap screen with a mute row — for a screen reader user, a button
120
+ * that exists and has no name. Whether the key is IN the game's dictionaries is the root's question (`ui/declared-words`).
99
121
  */
100
122
  export function presetProblems(p) {
101
123
  if (!p)
@@ -110,8 +132,8 @@ export function presetProblems(p) {
110
132
  }
111
133
  for (const a of named) {
112
134
  const w = p[a];
113
- if (!w || !w.label || !w.label.trim()) {
114
- problemas.push(`preset: ${a} has an empty label - the remap screen would show a nameless button`);
135
+ if (!w || typeof w.labelKey !== 'string' || !w.labelKey.trim()) {
136
+ problemas.push(`preset: ${a} has an empty labelKey - the remap screen would show a nameless button`);
115
137
  }
116
138
  }
117
139
  return problemas;
@@ -74,8 +74,6 @@ export interface Spot {
74
74
  readonly y: number;
75
75
  readonly z?: number;
76
76
  }
77
- /** The dimension the topology declares. `hotspots` has no space, so no dimension. */
78
- export declare function dimension(t: Topology): number;
79
77
  export type Role = 'hazard' | 'climb' | 'water' | 'goal' | 'gate' | 'key' | 'structure' | 'free';
80
78
  /**
81
79
  * ⚠️ `zenith` AND `nadir` EXIST BECAUSE `up`/`down` ALREADY MEAN TWO THINGS. `ACTIONS` (core/actions) has `up` and
@@ -27,8 +27,6 @@
27
27
  // ========================= EVIDENCE =========================
28
28
  // Each field was born from a REAL consumer that used to guess, and ADR-0030 records that "the contract is enough" only
29
29
  // becomes a result when TWO presets exist.
30
- /** The dimension the topology declares. `hotspots` has no space, so no dimension. */
31
- export function dimension(t) { return t.kind === 'hotspots' ? 0 : t.size.length; }
32
30
  /** Axis `i` of a point, for whoever walks dimensions instead of naming them. */
33
31
  function axis(s, i) { return i === 0 ? s.x : i === 1 ? s.y : (s.z ?? 0); }
34
32
  function topologyProblems(d) {
@@ -1,16 +1,16 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ /** One language's dictionary: a key and its text. */
2
3
  type LocaleDict = Record<string, string>;
4
+ /** The languages a page can switch to — a constant, so it stays a function of the module (ADR-0232 D3). */
5
+ export declare function availableLocales(): string[];
3
6
  /**
4
7
  * The port the chosen language is kept through (ADR-0178): `platform/storage` has this shape.
5
8
  *
6
- * 🔴 AND IT CARRIES THE BROWSER TOO, since 2026-09-22 (ADR-0221 step 7g). This module used to write
7
- * `document.documentElement.lang`, dispatch on `window` and read `navigator.language` — three reaches into globals from
8
- * `core`, the layer ADR-0173 defines as «what the engine IS, without a browser». The health ratchet measured them (step 7d)
9
- * and the Dev chose to split rather than to move the module: the decisions stay here, the page effects arrive as two
10
- * optional hooks that `platform/locale-host` builds and the composition root passes in.
9
+ * 🔴 AND IT CARRIES THE BROWSER TOO (ADR-0221 step 7g): the page effects arrive as optional hooks that
10
+ * `platform/locale-host` builds and the composition root passes in, so `core` reaches no `document` or `window`.
11
11
  *
12
- * ⚠️ Both are OPTIONAL, and absent they mean «no page to tell»: a node test, a worker, a second engine in the same process.
13
- * Before this split those three lines threw there instead.
12
+ * ⚠️ The hooks are OPTIONAL, and absent they mean «no page to tell»: a node test, a worker, a second engine in the same
13
+ * process.
14
14
  */
15
15
  export interface LocalePort {
16
16
  get(key: string, fallback: string | null): string | null;
@@ -22,56 +22,21 @@ export interface LocalePort {
22
22
  readonly applied?: (locale: string, tag: string) => void;
23
23
  /** The language the host prefers when nothing is stored (the browser's `navigator.language`). */
24
24
  readonly preferred?: () => string | null;
25
+ /**
26
+ * Hears a language ANOTHER root on the same page switched to — the page's signal to its host (`i18n:change`).
27
+ * The LANGUAGE is the page's (`<html lang>` is one attribute), so every root follows it (ADR-0232 D3 erratum point 3).
28
+ */
29
+ readonly follow?: (react: (locale: string) => void) => void;
25
30
  }
26
- /** Gives this module the port for the chosen language; the composition root calls it before `initI18n`. */
27
- export declare function loadLocale(p: LocalePort): void;
28
- /**
29
- * Registers THIS game's keys for a language. Callable before the language exists — whoever registers `en` before any
30
- * `setLocale('en')` is served when the switch happens.
31
- *
32
- * ⚠️ IT DOES NOT RE-APPLY THE DOM, on purpose. `applyDom` needs a ROOT, and reaching the global `document` under the
33
- * caller's feet is a defect that already cost one fix. A consumer registering after the static markup was translated
34
- * calls `applyDom(root)` itself — and the normal case is to register at boot, before any text is on screen.
35
- */
36
- export declare function registerDict(code: string, entries: LocaleDict): string[];
37
31
  /** What a module that only TRANSLATES receives (ADR-0232 D3): a key and its `{param}`s in, the text of the page's language out. */
38
32
  export type Translate = (key: string, params?: Record<string, string | number>) => string;
39
- export declare function t(key: string, params?: Record<string, string | number>): string;
40
- export declare function getLocale(): string;
41
- export declare function bcp47(code?: string): string;
42
- declare function availableLocales(): string[];
43
- declare function applyDom(root: ParentNode): void;
44
- export declare function setLocale(code: string): Promise<void>;
45
- /**
46
- * Boot: applies pt (synchronously, so the page is never blank) and, if the preferred language is another, ASKS for the
47
- * switch — which is asynchronous, because the other locales are on-demand chunks.
48
- *
49
- * It still returns the locale synchronously and does NOT block on its own: whoever needs to wait calls `localeReady()`.
50
- *
51
- * `root` COMES IN instead of being read from the global: the composition root receives the host's document by
52
- * injection and had no way to pass it on while this line reached the global `document` under it. In a browser it is
53
- * the same; in the `node` project it is the difference between booting against a fake DOM and not booting.
54
- */
55
- export declare function initI18n(root: ParentNode): string;
33
+ export declare function bcp47(code: string): string;
56
34
  /**
57
- * Resolves when the language chosen at boot has finished loading (at once, if it is pt).
35
+ * THE TRANSLATOR A ROOT BUILDS AND HANDS DOWN (ADR-0232 D3, and its errata).
58
36
  *
59
- * ========================= WHY THIS HAD TO EXIST =========================
60
- * When the language loaded LAST, after the HUD and the menus were built, pt cost nothing — and en/es cost half the
61
- * interface: `applyDom` fixes the STATIC markup (`data-i18n`), but what JavaScript builds had captured the pt text and
62
- * nobody rebuilt it. `t()` answered "City" and the button on screen said "Cidade".
63
- *
64
- * This answers the narrow question, which has one answer: the interface is not built before the language is known.
65
- * Switching language AT RUN TIME is a different question, answered by the redraw on `i18n:change` (ADR-0225).
66
- */
67
- export declare function localeReady(): Promise<void>;
68
- /**
69
- * THE TRANSLATOR A ROOT BUILDS AND HANDS DOWN (ADR-0232 D3, and its erratum of docs dac7a6d).
70
- *
71
- * The LANGUAGE is the page's — `<html lang>` is one attribute, so two roots in two languages would tell a screen reader one
72
- * of them wrongly — and it stays in this module. What a translator adds is the root's side: its `t`, its markup pass, and
73
- * the subscription to a change that its root can release. A module that only translates receives the bare `t`; one that
74
- * reads or sets the language receives this object.
37
+ * It holds everything that changes: the page's language as this root knows it, the dictionaries loaded, and the GAME's own
38
+ * dictionary, which no other root on the page reads. A module that only translates receives the bare `t`; one that reads or
39
+ * sets the language receives this object.
75
40
  */
76
41
  export interface Translator {
77
42
  readonly t: Translate;
@@ -79,12 +44,18 @@ export interface Translator {
79
44
  readonly locale: () => string;
80
45
  /** The BCP-47 tag of a language, the page's by default — what speech and recognition are given. */
81
46
  readonly bcp47: (code?: string) => string;
82
- /** Switches the PAGE's language; every root on the page follows. */
47
+ /** Switches the PAGE's language; every root on the page follows (through the port's `follow`). */
83
48
  readonly setLocale: (code: string) => Promise<void>;
84
49
  /** Hears a language change; returns the release (the root passes this through its disposing door, ADR-0220). */
85
50
  readonly onChange: (react: (locale: string) => void) => () => void;
86
51
  /** Translates the declarative markup (`data-i18n`, `data-i18n-aria`) under `root`. */
87
52
  readonly applyDom: (root: ParentNode) => void;
53
+ /**
54
+ * Boot: translates `root` in pt (synchronously, so the page is never blank) and, if the stored or preferred language is
55
+ * another, ASKS for the switch — asynchronous, because the other locales are on-demand chunks. Returns the locale now;
56
+ * whoever needs to wait calls `ready()`. `root` comes in, never the global `document` (finding 15 of `boot/create-game`).
57
+ */
58
+ readonly init: (root: ParentNode) => string;
88
59
  /** Resolves when the language chosen at boot has loaded. */
89
60
  readonly ready: () => Promise<void>;
90
61
  /**
@@ -94,24 +65,18 @@ export interface Translator {
94
65
  readonly registerDict: (code: string, entries: LocaleDict) => string[];
95
66
  /** The keys this translator's game registered in one language and not another, for `problems` (study item E4). */
96
67
  readonly dictionaryGaps: () => string[];
68
+ /**
69
+ * A WORD THE GAME DECLARED, by its key (ADR-0232 D3 erratum of 2026-09-25): resolved in the page's language from THIS
70
+ * game's dictionary, falling back to its pt — and `null` when the game's dictionary has it in neither. Never the key: a
71
+ * key on screen is an identifier in front of a child. Whoever draws decides what an absent word means (a row not drawn).
72
+ */
73
+ readonly word: (key: string) => string | null;
74
+ /** Does this game's dictionary have `key` in any language? What `problems` asks of every declared key. */
75
+ readonly declares: (key: string) => boolean;
97
76
  }
98
77
  /**
99
- * Builds a translator, with a game dictionary of its OWN (ADR-0232 D3 erratum): what one root registers, another root on the
100
- * same page does not read. The language stays the page's.
101
- *
102
- * ⚠️ TRANSITIONAL: after its own dictionary it still reads the page-wide one that the module-level `registerDict` writes,
103
- * so a game that registers there before `createGame` keeps its words — until the Dev decides how a game translates what it
104
- * declares, and the module-level `t` and `registerDict` leave (issue #207).
78
+ * Builds a translator. `port` keeps the chosen language and tells the page (ADR-0178); without one there is no page to tell
79
+ * and nothing to keep, and `setLocale` refuses — a test that only translates needs none.
105
80
  */
106
- export declare function createTranslator(): Translator;
107
- declare const i18n: {
108
- t: typeof t;
109
- getLocale: typeof getLocale;
110
- availableLocales: typeof availableLocales;
111
- applyDom: typeof applyDom;
112
- setLocale: typeof setLocale;
113
- initI18n: typeof initI18n;
114
- localeReady: typeof localeReady;
115
- registerDict: typeof registerDict;
116
- };
117
- export default i18n;
81
+ export declare function createTranslator(port?: LocalePort): Translator;
82
+ export {};