@the-inclusionist/engine 9.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 (532) hide show
  1. package/README.md +120 -78
  2. package/app/css/style.css +761 -377
  3. package/app/public/vendor/fonts/playwrite-cu.woff2 +0 -0
  4. package/app/public/vendor/fonts/playwrite-es-deco.woff2 +0 -0
  5. package/app/public/vendor/fonts/playwrite-es.woff2 +0 -0
  6. package/app/public/vendor/fonts/playwrite-gb-j.woff2 +0 -0
  7. package/app/public/vendor/fonts/playwrite-gb-s.woff2 +0 -0
  8. package/app/public/vendor/fonts/playwrite-pe.woff2 +0 -0
  9. package/app/public/vendor/fonts/playwrite-pt.woff2 +0 -0
  10. package/app/public/vendor/fonts-licences/NOTICE.txt +166 -0
  11. package/app/public/vendor/fonts-licences/OFL-1.1.txt +86 -0
  12. package/app/public/vendor/fonts.css +36 -84
  13. package/dist-pkg/boot/create-game.d.ts +499 -219
  14. package/dist-pkg/boot/create-game.js +3944 -562
  15. package/dist-pkg/core/a11y-sr.d.ts +25 -3
  16. package/dist-pkg/core/a11y-sr.js +38 -19
  17. package/dist-pkg/core/accessible-label.d.ts +17 -0
  18. package/dist-pkg/core/accessible-label.js +37 -0
  19. package/dist-pkg/core/accommodation-subjects.d.ts +26 -0
  20. package/dist-pkg/core/accommodation-subjects.js +32 -0
  21. package/dist-pkg/core/accommodations.d.ts +125 -0
  22. package/dist-pkg/core/accommodations.js +195 -0
  23. package/dist-pkg/core/actions.d.ts +108 -55
  24. package/dist-pkg/core/actions.js +122 -71
  25. package/dist-pkg/core/calm-mode.d.ts +31 -0
  26. package/dist-pkg/core/calm-mode.js +47 -0
  27. package/dist-pkg/core/camera-cycle.d.ts +15 -0
  28. package/dist-pkg/core/camera-cycle.js +7 -0
  29. package/dist-pkg/core/caption-duration.d.ts +15 -0
  30. package/dist-pkg/core/caption-duration.js +19 -0
  31. package/dist-pkg/core/cartridge-problems.d.ts +34 -0
  32. package/dist-pkg/core/cartridge-problems.js +53 -0
  33. package/dist-pkg/core/constants.d.ts +0 -54
  34. package/dist-pkg/core/constants.js +9 -76
  35. package/dist-pkg/core/contract.d.ts +142 -164
  36. package/dist-pkg/core/contract.js +222 -208
  37. package/dist-pkg/core/dom-query.d.ts +4 -4
  38. package/dist-pkg/core/dom-query.js +12 -20
  39. package/dist-pkg/core/entity.d.ts +62 -77
  40. package/dist-pkg/core/entity.js +18 -32
  41. package/dist-pkg/core/escape-html.d.ts +9 -10
  42. package/dist-pkg/core/escape-html.js +16 -20
  43. package/dist-pkg/core/flash-threshold.d.ts +17 -0
  44. package/dist-pkg/core/flash-threshold.js +113 -0
  45. package/dist-pkg/core/game-speed.d.ts +11 -0
  46. package/dist-pkg/core/game-speed.js +16 -0
  47. package/dist-pkg/core/genres.d.ts +20 -0
  48. package/dist-pkg/core/genres.js +44 -0
  49. package/dist-pkg/core/i18n.d.ts +71 -60
  50. package/dist-pkg/core/i18n.js +186 -200
  51. package/dist-pkg/core/loop.d.ts +17 -6
  52. package/dist-pkg/core/loop.js +26 -26
  53. package/dist-pkg/core/pause-icon-catalogue.d.ts +15 -0
  54. package/dist-pkg/core/pause-icon-catalogue.js +54 -0
  55. package/dist-pkg/core/ring.d.ts +17 -0
  56. package/dist-pkg/core/ring.js +29 -0
  57. package/dist-pkg/core/rng.d.ts +7 -12
  58. package/dist-pkg/core/rng.js +23 -53
  59. package/dist-pkg/core/route.d.ts +26 -26
  60. package/dist-pkg/core/route.js +126 -121
  61. package/dist-pkg/core/scenes.d.ts +37 -40
  62. package/dist-pkg/core/scenes.js +41 -43
  63. package/dist-pkg/core/screens.d.ts +4 -4
  64. package/dist-pkg/core/screens.js +11 -16
  65. package/dist-pkg/core/session-clock.d.ts +23 -0
  66. package/dist-pkg/core/session-clock.js +37 -0
  67. package/dist-pkg/core/setting-defaults.d.ts +61 -0
  68. package/dist-pkg/core/setting-defaults.js +66 -0
  69. package/dist-pkg/core/speech-rate.d.ts +29 -0
  70. package/dist-pkg/core/speech-rate.js +47 -0
  71. package/dist-pkg/core/state.d.ts +118 -118
  72. package/dist-pkg/core/state.js +322 -297
  73. package/dist-pkg/core/visual-cycles.d.ts +30 -0
  74. package/dist-pkg/core/visual-cycles.js +52 -0
  75. package/dist-pkg/core/visual-state.d.ts +13 -0
  76. package/dist-pkg/core/visual-state.js +6 -0
  77. package/dist-pkg/educational/activities-registry.d.ts +1 -1
  78. package/dist-pkg/educational/activities-registry.js +9 -8
  79. package/dist-pkg/educational/adaptive-engine.d.ts +11 -11
  80. package/dist-pkg/educational/adaptive-engine.js +17 -17
  81. package/dist-pkg/educational/segment-bar.d.ts +12 -12
  82. package/dist-pkg/educational/segment-bar.js +9 -9
  83. package/dist-pkg/i18n/en.js +324 -223
  84. package/dist-pkg/i18n/es.js +323 -223
  85. package/dist-pkg/i18n/pt.js +348 -226
  86. package/dist-pkg/input/default-bindings.d.ts +37 -38
  87. package/dist-pkg/input/default-bindings.js +127 -144
  88. package/dist-pkg/input/devices.d.ts +7 -7
  89. package/dist-pkg/input/devices.js +17 -16
  90. package/dist-pkg/input/edges.d.ts +23 -32
  91. package/dist-pkg/input/edges.js +23 -28
  92. package/dist-pkg/input/empathy-filter.d.ts +22 -0
  93. package/dist-pkg/input/empathy-filter.js +34 -0
  94. package/dist-pkg/input/face-map.d.ts +96 -0
  95. package/dist-pkg/input/face-map.js +255 -0
  96. package/dist-pkg/input/face-signals.d.ts +40 -0
  97. package/dist-pkg/input/face-signals.js +48 -0
  98. package/dist-pkg/input/gamepad.d.ts +195 -145
  99. package/dist-pkg/input/gamepad.js +383 -556
  100. package/dist-pkg/input/gaze-cycle.d.ts +64 -0
  101. package/dist-pkg/input/gaze-cycle.js +133 -0
  102. package/dist-pkg/input/gaze-relative.d.ts +68 -0
  103. package/dist-pkg/input/gaze-relative.js +142 -0
  104. package/dist-pkg/input/hand-map.d.ts +28 -0
  105. package/dist-pkg/input/hand-map.js +142 -0
  106. package/dist-pkg/input/input-cooldown.d.ts +17 -0
  107. package/dist-pkg/input/input-cooldown.js +39 -0
  108. package/dist-pkg/input/key-default.d.ts +30 -0
  109. package/dist-pkg/input/key-default.js +60 -0
  110. package/dist-pkg/input/keyboard-runtime.d.ts +15 -21
  111. package/dist-pkg/input/keyboard-runtime.js +23 -27
  112. package/dist-pkg/input/keyboard.d.ts +68 -63
  113. package/dist-pkg/input/keyboard.js +83 -105
  114. package/dist-pkg/input/keydown.d.ts +123 -137
  115. package/dist-pkg/input/keydown.js +284 -289
  116. package/dist-pkg/input/latch-edge.d.ts +33 -21
  117. package/dist-pkg/input/latch-edge.js +34 -35
  118. package/dist-pkg/input/latch-scope.d.ts +51 -50
  119. package/dist-pkg/input/latch-scope.js +61 -82
  120. package/dist-pkg/input/latch-store.d.ts +26 -30
  121. package/dist-pkg/input/latch-store.js +42 -50
  122. package/dist-pkg/input/latch-sync.d.ts +29 -29
  123. package/dist-pkg/input/latch-sync.js +25 -25
  124. package/dist-pkg/input/latch.d.ts +14 -17
  125. package/dist-pkg/input/latch.js +29 -37
  126. package/dist-pkg/input/pad-defaults.d.ts +13 -16
  127. package/dist-pkg/input/pad-defaults.js +21 -28
  128. package/dist-pkg/input/pad-reading.d.ts +76 -0
  129. package/dist-pkg/input/pad-reading.js +169 -0
  130. package/dist-pkg/input/pad-wizard.d.ts +99 -0
  131. package/dist-pkg/input/pad-wizard.js +256 -0
  132. package/dist-pkg/input/pointer-space.d.ts +19 -20
  133. package/dist-pkg/input/pointer-space.js +27 -32
  134. package/dist-pkg/input/pointer.d.ts +39 -40
  135. package/dist-pkg/input/pointer.js +42 -45
  136. package/dist-pkg/input/state.d.ts +101 -89
  137. package/dist-pkg/input/state.js +54 -134
  138. package/dist-pkg/input/switch-scan.d.ts +59 -0
  139. package/dist-pkg/input/switch-scan.js +67 -0
  140. package/dist-pkg/input/synthetic-source.d.ts +42 -0
  141. package/dist-pkg/input/synthetic-source.js +57 -0
  142. package/dist-pkg/input/touch-bindings.d.ts +127 -116
  143. package/dist-pkg/input/touch-bindings.js +158 -173
  144. package/dist-pkg/input/touch.d.ts +147 -72
  145. package/dist-pkg/input/touch.js +362 -126
  146. package/dist-pkg/input/transport-in-use.d.ts +107 -0
  147. package/dist-pkg/input/transport-in-use.js +130 -0
  148. package/dist-pkg/input/transports.d.ts +90 -117
  149. package/dist-pkg/input/transports.js +104 -106
  150. package/dist-pkg/input/virtual-controller.d.ts +82 -0
  151. package/dist-pkg/input/virtual-controller.js +69 -0
  152. package/dist-pkg/input/vocabulary-migration.d.ts +50 -49
  153. package/dist-pkg/input/vocabulary-migration.js +80 -79
  154. package/dist-pkg/input/voice-map.d.ts +59 -0
  155. package/dist-pkg/input/voice-map.js +123 -0
  156. package/dist-pkg/platform/audio-ambient.d.ts +13 -2
  157. package/dist-pkg/platform/audio-ambient.js +14 -14
  158. package/dist-pkg/platform/audio-earcons.d.ts +20 -19
  159. package/dist-pkg/platform/audio-earcons.js +51 -42
  160. package/dist-pkg/platform/audio-jingles.js +9 -10
  161. package/dist-pkg/platform/audio-mixer.d.ts +14 -2
  162. package/dist-pkg/platform/audio-mixer.js +31 -39
  163. package/dist-pkg/platform/audio-sonar.d.ts +49 -152
  164. package/dist-pkg/platform/audio-sonar.js +124 -302
  165. package/dist-pkg/platform/audio.d.ts +62 -19
  166. package/dist-pkg/platform/audio.js +193 -168
  167. package/dist-pkg/platform/choose-by-voice.d.ts +70 -0
  168. package/dist-pkg/platform/choose-by-voice.js +157 -0
  169. package/dist-pkg/platform/flash-sampler.d.ts +19 -0
  170. package/dist-pkg/platform/flash-sampler.js +79 -0
  171. package/dist-pkg/platform/font-library.d.ts +77 -0
  172. package/dist-pkg/platform/font-library.js +98 -0
  173. package/dist-pkg/platform/font-library.json +721 -0
  174. package/dist-pkg/platform/heavy-catalogue.d.ts +77 -0
  175. package/dist-pkg/platform/heavy-catalogue.js +256 -0
  176. package/dist-pkg/platform/heavy-mirror.d.ts +20 -0
  177. package/dist-pkg/platform/heavy-mirror.js +73 -0
  178. package/dist-pkg/platform/heavy.d.ts +136 -0
  179. package/dist-pkg/platform/heavy.js +324 -0
  180. package/dist-pkg/platform/interruptible-speech.d.ts +23 -16
  181. package/dist-pkg/platform/interruptible-speech.js +77 -54
  182. package/dist-pkg/platform/kokoro-port.d.ts +27 -0
  183. package/dist-pkg/platform/kokoro-port.js +50 -0
  184. package/dist-pkg/platform/kokoro-runtime.d.ts +20 -0
  185. package/dist-pkg/platform/kokoro-runtime.js +52 -0
  186. package/dist-pkg/platform/kokoro.d.ts +70 -0
  187. package/dist-pkg/platform/kokoro.js +133 -0
  188. package/dist-pkg/platform/listener-scope.d.ts +12 -0
  189. package/dist-pkg/platform/listener-scope.js +90 -0
  190. package/dist-pkg/platform/locale-host.d.ts +14 -0
  191. package/dist-pkg/platform/locale-host.js +45 -0
  192. package/dist-pkg/platform/microphone.d.ts +51 -0
  193. package/dist-pkg/platform/microphone.js +118 -0
  194. package/dist-pkg/platform/onnx-runtime.d.ts +34 -0
  195. package/dist-pkg/platform/onnx-runtime.js +42 -0
  196. package/dist-pkg/platform/reading-in-worker.d.ts +64 -0
  197. package/dist-pkg/platform/reading-in-worker.js +125 -0
  198. package/dist-pkg/platform/reading-model.d.ts +94 -0
  199. package/dist-pkg/platform/reading-model.js +272 -0
  200. package/dist-pkg/platform/reading-runtime.d.ts +24 -0
  201. package/dist-pkg/platform/reading-runtime.js +164 -0
  202. package/dist-pkg/platform/reading-worker.d.ts +41 -0
  203. package/dist-pkg/platform/reading-worker.js +58 -0
  204. package/dist-pkg/platform/reading.d.ts +80 -0
  205. package/dist-pkg/platform/reading.js +136 -0
  206. package/dist-pkg/platform/speech-recognition.d.ts +60 -0
  207. package/dist-pkg/platform/speech-recognition.js +104 -0
  208. package/dist-pkg/platform/speech.d.ts +23 -1
  209. package/dist-pkg/platform/speech.js +29 -18
  210. package/dist-pkg/platform/storage-keys.d.ts +96 -0
  211. package/dist-pkg/platform/storage-keys.js +106 -0
  212. package/dist-pkg/platform/storage.d.ts +46 -111
  213. package/dist-pkg/platform/storage.js +104 -169
  214. package/dist-pkg/platform/tts.d.ts +85 -39
  215. package/dist-pkg/platform/tts.js +447 -127
  216. package/dist-pkg/platform/vision-loop.d.ts +23 -0
  217. package/dist-pkg/platform/vision-loop.js +56 -0
  218. package/dist-pkg/platform/vision.d.ts +132 -0
  219. package/dist-pkg/platform/vision.js +117 -0
  220. package/dist-pkg/platform/voice-listener.d.ts +40 -0
  221. package/dist-pkg/platform/voice-listener.js +88 -0
  222. package/dist-pkg/platform/voice-plan.d.ts +15 -98
  223. package/dist-pkg/platform/voice-plan.js +56 -143
  224. package/dist-pkg/platform/vosk-runtime.d.ts +96 -0
  225. package/dist-pkg/platform/vosk-runtime.js +151 -0
  226. package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
  227. package/dist-pkg/platform/vosk-vocabulary.js +178 -0
  228. package/dist-pkg/render/canvas.d.ts +13 -7
  229. package/dist-pkg/render/canvas.js +13 -13
  230. package/dist-pkg/render/crt.d.ts +48 -12
  231. package/dist-pkg/render/crt.js +78 -80
  232. package/dist-pkg/render/cvd-matrices.d.ts +22 -18
  233. package/dist-pkg/render/cvd-matrices.js +37 -38
  234. package/dist-pkg/render/hc-role-data.d.ts +7 -7
  235. package/dist-pkg/render/hc-role-data.js +14 -14
  236. package/dist-pkg/render/high-contrast.d.ts +67 -56
  237. package/dist-pkg/render/high-contrast.js +226 -217
  238. package/dist-pkg/render/low-vision-drawing.d.ts +5 -0
  239. package/dist-pkg/render/low-vision-drawing.js +46 -0
  240. package/dist-pkg/render/lq-filter.d.ts +32 -20
  241. package/dist-pkg/render/lq-filter.js +59 -65
  242. package/dist-pkg/render/port.d.ts +86 -88
  243. package/dist-pkg/render/port.js +17 -23
  244. package/dist-pkg/render/screen-pipeline.d.ts +42 -42
  245. package/dist-pkg/render/screen-pipeline.js +80 -87
  246. package/dist-pkg/render/sprite-fx.d.ts +2 -1
  247. package/dist-pkg/render/sprite-fx.js +16 -14
  248. package/dist-pkg/render/viewports.d.ts +20 -15
  249. package/dist-pkg/render/viewports.js +83 -114
  250. package/dist-pkg/render/viz-axes-labels.d.ts +47 -0
  251. package/dist-pkg/render/viz-axes-labels.js +88 -0
  252. package/dist-pkg/render/viz-axes.d.ts +89 -86
  253. package/dist-pkg/render/viz-axes.js +128 -116
  254. package/dist-pkg/render/viz-modes.d.ts +28 -29
  255. package/dist-pkg/render/viz-modes.js +40 -45
  256. package/dist-pkg/render/viz-refusal.d.ts +32 -0
  257. package/dist-pkg/render/viz-refusal.js +57 -0
  258. package/dist-pkg/render/viz-setters.d.ts +104 -66
  259. package/dist-pkg/render/viz-setters.js +182 -191
  260. package/dist-pkg/ui/aac-sets.d.ts +45 -0
  261. package/dist-pkg/ui/aac-sets.js +41 -0
  262. package/dist-pkg/ui/audio-choices.d.ts +68 -0
  263. package/dist-pkg/ui/audio-choices.js +98 -0
  264. package/dist-pkg/ui/audio-rows-that-apply.d.ts +12 -0
  265. package/dist-pkg/ui/audio-rows-that-apply.js +43 -0
  266. package/dist-pkg/ui/camera-control.d.ts +53 -0
  267. package/dist-pkg/ui/camera-control.js +48 -0
  268. package/dist-pkg/ui/changed-mark.d.ts +9 -8
  269. package/dist-pkg/ui/changed-mark.js +22 -53
  270. package/dist-pkg/ui/control-choices.d.ts +37 -0
  271. package/dist-pkg/ui/control-choices.js +84 -0
  272. package/dist-pkg/ui/debug-panel.d.ts +59 -43
  273. package/dist-pkg/ui/debug-panel.js +68 -69
  274. package/dist-pkg/ui/declared-words.d.ts +21 -0
  275. package/dist-pkg/ui/declared-words.js +66 -0
  276. package/dist-pkg/ui/dom.d.ts +10 -14
  277. package/dist-pkg/ui/dom.js +10 -47
  278. package/dist-pkg/ui/drawing-problems.d.ts +25 -0
  279. package/dist-pkg/ui/drawing-problems.js +94 -0
  280. package/dist-pkg/ui/eye-control.d.ts +36 -0
  281. package/dist-pkg/ui/eye-control.js +178 -0
  282. package/dist-pkg/ui/face-control.d.ts +25 -0
  283. package/dist-pkg/ui/face-control.js +183 -0
  284. package/dist-pkg/ui/focus-trap.d.ts +39 -49
  285. package/dist-pkg/ui/focus-trap.js +56 -65
  286. package/dist-pkg/ui/fonts.d.ts +157 -68
  287. package/dist-pkg/ui/fonts.js +305 -115
  288. package/dist-pkg/ui/footer-scroll-driver.d.ts +14 -0
  289. package/dist-pkg/ui/footer-scroll-driver.js +201 -0
  290. package/dist-pkg/ui/footer-scroll.d.ts +38 -0
  291. package/dist-pkg/ui/footer-scroll.js +55 -0
  292. package/dist-pkg/ui/game-options.d.ts +47 -0
  293. package/dist-pkg/ui/game-options.js +158 -0
  294. package/dist-pkg/ui/gaze-overlay.d.ts +64 -0
  295. package/dist-pkg/ui/gaze-overlay.js +165 -0
  296. package/dist-pkg/ui/hand-control.d.ts +25 -0
  297. package/dist-pkg/ui/hand-control.js +143 -0
  298. package/dist-pkg/ui/help-panel.d.ts +87 -0
  299. package/dist-pkg/ui/help-panel.js +242 -0
  300. package/dist-pkg/ui/hud-bands.d.ts +62 -0
  301. package/dist-pkg/ui/hud-bands.js +146 -0
  302. package/dist-pkg/ui/hud-row.d.ts +34 -0
  303. package/dist-pkg/ui/hud-row.js +80 -0
  304. package/dist-pkg/ui/hud.d.ts +73 -73
  305. package/dist-pkg/ui/hud.js +94 -98
  306. package/dist-pkg/ui/item-announcement.d.ts +13 -12
  307. package/dist-pkg/ui/item-announcement.js +25 -26
  308. package/dist-pkg/ui/layout.d.ts +103 -28
  309. package/dist-pkg/ui/layout.js +117 -99
  310. package/dist-pkg/ui/libras-avatar-clip.d.ts +30 -0
  311. package/dist-pkg/ui/libras-avatar-clip.js +86 -0
  312. package/dist-pkg/ui/libras-avatar-load.d.ts +52 -0
  313. package/dist-pkg/ui/libras-avatar-load.js +134 -0
  314. package/dist-pkg/ui/libras-avatar-plan.d.ts +102 -0
  315. package/dist-pkg/ui/libras-avatar-plan.js +211 -0
  316. package/dist-pkg/ui/libras-avatar-player.d.ts +28 -0
  317. package/dist-pkg/ui/libras-avatar-player.js +226 -0
  318. package/dist-pkg/ui/libras-avatar-stage.d.ts +37 -0
  319. package/dist-pkg/ui/libras-avatar-stage.js +208 -0
  320. package/dist-pkg/ui/libras-glosses.d.ts +28 -0
  321. package/dist-pkg/ui/libras-glosses.js +161 -0
  322. package/dist-pkg/ui/locale-flags.d.ts +16 -0
  323. package/dist-pkg/ui/locale-flags.js +30 -0
  324. package/dist-pkg/ui/loop-crash.d.ts +17 -17
  325. package/dist-pkg/ui/loop-crash.js +33 -62
  326. package/dist-pkg/ui/menu-intent.d.ts +61 -0
  327. package/dist-pkg/ui/menu-intent.js +88 -0
  328. package/dist-pkg/ui/menu-items.d.ts +20 -0
  329. package/dist-pkg/ui/menu-items.js +51 -0
  330. package/dist-pkg/ui/menu-nav.d.ts +98 -92
  331. package/dist-pkg/ui/menu-nav.js +398 -286
  332. package/dist-pkg/ui/mobility-choices.d.ts +26 -0
  333. package/dist-pkg/ui/mobility-choices.js +41 -0
  334. package/dist-pkg/ui/motion-choices.d.ts +31 -0
  335. package/dist-pkg/ui/motion-choices.js +68 -0
  336. package/dist-pkg/ui/motion-scene.d.ts +24 -19
  337. package/dist-pkg/ui/motion-scene.js +29 -61
  338. package/dist-pkg/ui/mount-panel.d.ts +81 -0
  339. package/dist-pkg/ui/mount-panel.js +61 -0
  340. package/dist-pkg/ui/panel-shell.d.ts +65 -31
  341. package/dist-pkg/ui/panel-shell.js +92 -66
  342. package/dist-pkg/ui/panel-widgets.d.ts +150 -0
  343. package/dist-pkg/ui/panel-widgets.js +294 -0
  344. package/dist-pkg/ui/pause-buttons.d.ts +35 -0
  345. package/dist-pkg/ui/pause-buttons.js +66 -0
  346. package/dist-pkg/ui/pause-icons.d.ts +261 -347
  347. package/dist-pkg/ui/pause-icons.js +671 -601
  348. package/dist-pkg/ui/pause-markup.d.ts +86 -0
  349. package/dist-pkg/ui/pause-markup.js +125 -0
  350. package/dist-pkg/ui/reach-notice.d.ts +22 -23
  351. package/dist-pkg/ui/reach-notice.js +55 -58
  352. package/dist-pkg/ui/scan-overlay.d.ts +23 -0
  353. package/dist-pkg/ui/scan-overlay.js +50 -0
  354. package/dist-pkg/ui/screen-text.d.ts +25 -0
  355. package/dist-pkg/ui/screen-text.js +152 -0
  356. package/dist-pkg/ui/session-clock.d.ts +32 -0
  357. package/dist-pkg/ui/session-clock.js +67 -0
  358. package/dist-pkg/ui/settings-aac.d.ts +70 -0
  359. package/dist-pkg/ui/settings-aac.js +208 -0
  360. package/dist-pkg/ui/settings-audio.d.ts +97 -114
  361. package/dist-pkg/ui/settings-audio.js +493 -425
  362. package/dist-pkg/ui/settings-controls.d.ts +53 -96
  363. package/dist-pkg/ui/settings-controls.js +143 -215
  364. package/dist-pkg/ui/settings-empathy.d.ts +39 -30
  365. package/dist-pkg/ui/settings-empathy.js +53 -60
  366. package/dist-pkg/ui/settings-mobility.d.ts +192 -0
  367. package/dist-pkg/ui/settings-mobility.js +332 -0
  368. package/dist-pkg/ui/settings-motion.d.ts +91 -70
  369. package/dist-pkg/ui/settings-motion.js +287 -198
  370. package/dist-pkg/ui/settings-panel.d.ts +58 -45
  371. package/dist-pkg/ui/settings-panel.js +189 -94
  372. package/dist-pkg/ui/settings-typo.d.ts +29 -78
  373. package/dist-pkg/ui/settings-typo.js +158 -129
  374. package/dist-pkg/ui/settings-visual.d.ts +29 -87
  375. package/dist-pkg/ui/settings-visual.js +240 -193
  376. package/dist-pkg/ui/shell.d.ts +112 -135
  377. package/dist-pkg/ui/shell.js +148 -217
  378. package/dist-pkg/ui/simulation-list.d.ts +27 -0
  379. package/dist-pkg/ui/simulation-list.js +76 -0
  380. package/dist-pkg/ui/simulation-over-the-world.d.ts +23 -0
  381. package/dist-pkg/ui/simulation-over-the-world.js +131 -0
  382. package/dist-pkg/ui/simulation-refusal.d.ts +5 -31
  383. package/dist-pkg/ui/simulation-refusal.js +8 -56
  384. package/dist-pkg/ui/switchable-control.d.ts +11 -0
  385. package/dist-pkg/ui/switchable-control.js +19 -0
  386. package/dist-pkg/ui/title.d.ts +3 -12
  387. package/dist-pkg/ui/title.js +49 -18
  388. package/dist-pkg/ui/top-band.d.ts +26 -0
  389. package/dist-pkg/ui/top-band.js +96 -0
  390. package/dist-pkg/ui/typo-choices.d.ts +71 -0
  391. package/dist-pkg/ui/typo-choices.js +85 -0
  392. package/dist-pkg/ui/visual-axes-panel.d.ts +11 -47
  393. package/dist-pkg/ui/visual-axes-panel.js +12 -94
  394. package/dist-pkg/ui/visual-choices.d.ts +77 -0
  395. package/dist-pkg/ui/visual-choices.js +107 -0
  396. package/dist-pkg/ui/vlibras.d.ts +77 -10
  397. package/dist-pkg/ui/vlibras.js +130 -81
  398. package/dist-pkg/ui/voice-control.d.ts +68 -0
  399. package/dist-pkg/ui/voice-control.js +276 -0
  400. package/dist-pkg/ui/voice-settings.d.ts +95 -0
  401. package/dist-pkg/ui/voice-settings.js +352 -0
  402. package/dist-pkg/ui/where-the-child-is.d.ts +31 -0
  403. package/dist-pkg/ui/where-the-child-is.js +70 -0
  404. package/docs/CREDITS.md +300 -44
  405. package/docs/LICENSES.md +189 -145
  406. package/package.json +51 -27
  407. package/scripts/check-cartridge.mjs +78 -0
  408. package/scripts/game-build.d.mts +25 -0
  409. package/scripts/game-build.mjs +144 -0
  410. package/scripts/heavy-into-the-delivery.mjs +388 -0
  411. package/scripts/libras-avatar.json +680 -0
  412. package/scripts/libras-avatar.mjs +246 -0
  413. package/scripts/libras-glosses/gloss.py +95 -0
  414. package/scripts/libras-glosses/pyproject.toml +32 -0
  415. package/scripts/libras-glosses/uv.lock +781 -0
  416. package/scripts/libras-glosses.mjs +351 -0
  417. package/scripts/licences/Apache-2.0.txt +176 -0
  418. package/scripts/licences/GPL-3.0.txt +674 -0
  419. package/scripts/licences/MIT.txt +17 -0
  420. package/scripts/licences/OFL-1.1.txt +86 -0
  421. package/scripts/licences/UFL-1.0.txt +96 -0
  422. package/scripts/licences/fonts.mjs +389 -0
  423. package/scripts/licences/third-party.mjs +301 -0
  424. package/scripts/licences/vosk-browser.NOTICE.txt +268 -0
  425. package/app/public/vendor/fonts/comicneue-400.woff2 +0 -0
  426. package/app/public/vendor/fonts/comicneue-700.woff2 +0 -0
  427. package/app/public/vendor/fonts/fondamento-400-ext.woff2 +0 -0
  428. package/app/public/vendor/fonts/fondamento-400.woff2 +0 -0
  429. package/app/public/vendor/fonts/inter-400.woff2 +0 -0
  430. package/app/public/vendor/fonts/inter-700.woff2 +0 -0
  431. package/app/public/vendor/fonts/lato-400.woff2 +0 -0
  432. package/app/public/vendor/fonts/lato-700.woff2 +0 -0
  433. package/app/public/vendor/fonts/literata-400.woff2 +0 -0
  434. package/app/public/vendor/fonts/literata-700.woff2 +0 -0
  435. package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
  436. package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
  437. package/app/public/vendor/fonts/opendyslexic-400.woff2 +0 -0
  438. package/app/public/vendor/fonts/opensans-400.woff2 +0 -0
  439. package/app/public/vendor/fonts/opensans-700.woff2 +0 -0
  440. package/app/public/vendor/fonts/pinyon-400.woff2 +0 -0
  441. package/app/public/vendor/fonts/pressstart-400.woff2 +0 -0
  442. package/app/public/vendor/fonts/quattro-400.woff2 +0 -0
  443. package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
  444. package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
  445. package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
  446. package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
  447. package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
  448. package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
  449. package/dist-pkg/core/anel.d.ts +0 -17
  450. package/dist-pkg/core/anel.js +0 -31
  451. package/dist-pkg/core/collision.d.ts +0 -21
  452. package/dist-pkg/core/collision.js +0 -62
  453. package/dist-pkg/core/layers.d.ts +0 -63
  454. package/dist-pkg/core/layers.js +0 -95
  455. package/dist-pkg/core/letter-grid.d.ts +0 -55
  456. package/dist-pkg/core/letter-grid.js +0 -116
  457. package/dist-pkg/core/password.d.ts +0 -34
  458. package/dist-pkg/core/password.js +0 -205
  459. package/dist-pkg/core/rotulo-acessivel.d.ts +0 -17
  460. package/dist-pkg/core/rotulo-acessivel.js +0 -41
  461. package/dist-pkg/core/run-state.d.ts +0 -115
  462. package/dist-pkg/core/run-state.js +0 -40
  463. package/dist-pkg/core/tiles.d.ts +0 -12
  464. package/dist-pkg/core/tiles.js +0 -61
  465. package/dist-pkg/core/world.d.ts +0 -4
  466. package/dist-pkg/core/world.js +0 -58
  467. package/dist-pkg/input/origem-sintetica.d.ts +0 -44
  468. package/dist-pkg/input/origem-sintetica.js +0 -60
  469. package/dist-pkg/input/transporte-em-uso.d.ts +0 -101
  470. package/dist-pkg/input/transporte-em-uso.js +0 -130
  471. package/dist-pkg/platform/audio-nav.d.ts +0 -51
  472. package/dist-pkg/platform/audio-nav.js +0 -99
  473. package/dist-pkg/platform/guide-intensity.d.ts +0 -40
  474. package/dist-pkg/platform/guide-intensity.js +0 -73
  475. package/dist-pkg/platform/pesados-catalogo.d.ts +0 -14
  476. package/dist-pkg/platform/pesados-catalogo.js +0 -177
  477. package/dist-pkg/platform/pesados.d.ts +0 -31
  478. package/dist-pkg/platform/pesados.js +0 -75
  479. package/dist-pkg/platform/vozes-prontas.d.ts +0 -28
  480. package/dist-pkg/platform/vozes-prontas.js +0 -61
  481. package/dist-pkg/render/camera.d.ts +0 -58
  482. package/dist-pkg/render/camera.js +0 -105
  483. package/dist-pkg/render/cenario-data.d.ts +0 -127
  484. package/dist-pkg/render/cenario-data.js +0 -145
  485. package/dist-pkg/render/city-tex.d.ts +0 -63
  486. package/dist-pkg/render/city-tex.js +0 -228
  487. package/dist-pkg/render/city-tiles.d.ts +0 -11
  488. package/dist-pkg/render/city-tiles.js +0 -140
  489. package/dist-pkg/render/draw.d.ts +0 -149
  490. package/dist-pkg/render/draw.js +0 -231
  491. package/dist-pkg/render/fx.d.ts +0 -63
  492. package/dist-pkg/render/fx.js +0 -123
  493. package/dist-pkg/render/minimap.d.ts +0 -11
  494. package/dist-pkg/render/minimap.js +0 -94
  495. package/dist-pkg/render/parallax.d.ts +0 -85
  496. package/dist-pkg/render/parallax.js +0 -158
  497. package/dist-pkg/render/player-anim.d.ts +0 -71
  498. package/dist-pkg/render/player-anim.js +0 -152
  499. package/dist-pkg/render/recycling-tex.d.ts +0 -48
  500. package/dist-pkg/render/recycling-tex.js +0 -164
  501. package/dist-pkg/render/scene-city.d.ts +0 -77
  502. package/dist-pkg/render/scene-city.js +0 -181
  503. package/dist-pkg/render/scene-parallax.d.ts +0 -72
  504. package/dist-pkg/render/scene-parallax.js +0 -426
  505. package/dist-pkg/render/scene-sky.d.ts +0 -126
  506. package/dist-pkg/render/scene-sky.js +0 -295
  507. package/dist-pkg/render/set-cenario.d.ts +0 -54
  508. package/dist-pkg/render/set-cenario.js +0 -103
  509. package/dist-pkg/render/textures.d.ts +0 -75
  510. package/dist-pkg/render/textures.js +0 -240
  511. package/dist-pkg/render/title-scene.d.ts +0 -46
  512. package/dist-pkg/render/title-scene.js +0 -75
  513. package/dist-pkg/render/weather.d.ts +0 -96
  514. package/dist-pkg/render/weather.js +0 -171
  515. package/dist-pkg/render/wheelchair-sprites.d.ts +0 -32
  516. package/dist-pkg/render/wheelchair-sprites.js +0 -69
  517. package/dist-pkg/render/world-tex.d.ts +0 -18
  518. package/dist-pkg/render/world-tex.js +0 -87
  519. package/dist-pkg/ui/activities-menu.d.ts +0 -258
  520. package/dist-pkg/ui/activities-menu.js +0 -648
  521. package/dist-pkg/ui/caa-sets.d.ts +0 -39
  522. package/dist-pkg/ui/caa-sets.js +0 -65
  523. package/dist-pkg/ui/latch-refusal.d.ts +0 -32
  524. package/dist-pkg/ui/latch-refusal.js +0 -60
  525. package/dist-pkg/ui/map-hub.d.ts +0 -56
  526. package/dist-pkg/ui/map-hub.js +0 -138
  527. package/dist-pkg/ui/settings-caa.d.ts +0 -45
  528. package/dist-pkg/ui/settings-caa.js +0 -137
  529. package/dist-pkg/ui/settings-motor.d.ts +0 -175
  530. package/dist-pkg/ui/settings-motor.js +0 -342
  531. package/dist-pkg/ui/webcam.d.ts +0 -7
  532. package/dist-pkg/ui/webcam.js +0 -93
@@ -0,0 +1,86 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import type { Translate, Translator } from '../core/i18n.js';
3
+ import { type PauseIcon } from '../core/pause-icon-catalogue.js';
4
+ /**
5
+ * What the bar's markup reads of the root's translator (ADR-0232 D3 erratum): its `t`, and the page's language, which the
6
+ * 🌐 button shows as a flag. A Pick and not a bare `t`, because the flag reads the language.
7
+ */
8
+ export type BarTranslator = Pick<Translator, 't' | 'locale'>;
9
+ /** One `.pm-btn` descriptor — the shape of an entry of `PM_BTNS` (owned by ui/pause-buttons). */
10
+ export interface PauseMenuButton {
11
+ act: string;
12
+ /** Read ONLY when the button has a dynamic label; see the note on `PauseBtnDef` (ui/pause-buttons). */
13
+ lbl?: string;
14
+ /** Dynamic label (the ABC cycle) — rendered from `lbl`, not from i18n, and NOT given `data-i18n`. */
15
+ dynamicLabel?: boolean;
16
+ /** Dynamic label (the literacy level) — rendered from quizLevel + qlName. Currently dormant: no PM_BTNS
17
+ * entry sets it, but the branch is live code and is ported verbatim. */
18
+ level?: boolean;
19
+ }
20
+ /** One `.pi-btn`. The label is the RESTING one: reflectIconBtn overwrites it with the stateful label as soon as the bar is
21
+ * reflected. `ic.n` is an i18n key, so it must be resolved here too — the markup is rendered once at build
22
+ * time and would otherwise ship the raw key to a screen reader. */
23
+ export declare function iconBtnMarkup(tr: BarTranslator, ic: PauseIcon): string;
24
+ /** The whole icon bar. Used by the pause screen AND by the splash `#title-icons` — one builder, so the two bars
25
+ * cannot drift apart.
26
+ * The parameter is ADDITIVE and the default is the whole list: whoever already called it with no arguments gets the same
27
+ * string back. */
28
+ export declare function iconsMarkup(tr: BarTranslator, icons?: readonly PauseIcon[]): string;
29
+ /**
30
+ * One `.pm-btn`. Dynamic labels (`letra`/`nivel`) are rendered eagerly and carry NO `data-i18n`, so `i18n.applyDom()` cannot
31
+ * overwrite them.
32
+ *
33
+ * ⚠️ THE DYNAMIC LABEL ARRIVES READY-MADE, and that change fixed TWO things at once.
34
+ *
35
+ * The line used to be `'📚 Nível ' + level + ' · ' + qlName[level]`, and it had two defects that only show together:
36
+ *
37
+ * 1. BOUNDARY. `level` came from `core/state.quizLevel` and `qlName` from a table owned by the game. An ENGINE pause menu
38
+ * was assembling the label of a literacy activity — pedagogical content, not mechanics.
39
+ * 2. LANGUAGE. «Nível» is raw pt-BR inside an engine module. The gate of that time did not reach `ui/`, so this line
40
+ * crossed the whole i18n pass unseen. In an English build, a child's pause menu said «📚 Nível 2 · …».
41
+ *
42
+ * Now the game hands over the finished phrase (`dynLabel`) and the engine only puts it on the button. The game is the one who
43
+ * knows what a level is, what it is called, and in which language to say it.
44
+ */
45
+ export declare function pmBtnMarkup(b: PauseMenuButton, dynLabel: (b: PauseMenuButton) => string | null, tr: (key: string) => string): string;
46
+ /**
47
+ * WHICH of the lists the pause card is showing.
48
+ *
49
+ * THREE lists in the markup, ONE visible — and the hidden ones carry `hidden`, which takes them out of the accessibility
50
+ * tree entirely. That is what makes «one menu per screen» (ADR-0044 §5) true for whoever listens and not only for whoever
51
+ * sees, and it is what lets the ring wrap around INSIDE the visible list without ever crossing into another.
52
+ *
53
+ * ⚠️ THREE since 2026-09-12 (ADR-0146): `jogo` is the list of what belongs to THIS game, beside the list of what the child
54
+ * carries between games. The rule above does not change for being three.
55
+ */
56
+ export type PauseSub = 'raiz' | 'opcoes' | 'jogo';
57
+ /**
58
+ * THE ACCESSIBILITY QUICK BAR — the toggles and the caption that explains them (ADR-0044, item 7).
59
+ *
60
+ * It left the pause card and went to live in the HUD. The reason is about use, not tidiness: it is DURING the game that a
61
+ * child needs to change a setting that is getting in her way, not after pausing. The secondary reason is structural — without
62
+ * it, the card stops having two zones and becomes a LIST, which is what finally authorises the ring (XAG 106 allows wrapping
63
+ * for a linear menu and forbids it for a grid).
64
+ *
65
+ * THE CAPTION TRAVELS WITH IT. It is the hint that replaces, for whoever does not see, the `title` only a mouse reveals;
66
+ * leaving it behind in the card would have made the HUD bar mute.
67
+ */
68
+ export declare function quickBarMarkup(tr: BarTranslator, icons?: readonly PauseIcon[]): string;
69
+ export interface ScreenPauseMarkupOpts {
70
+ /** Screen/player index (0-based); the dialog label and the seat suffix are 1-based. */
71
+ player: number;
72
+ /** Live player count — the suffix only appears in multiplayer. */
73
+ numPlayers: number;
74
+ /** The ROOT list: the items of ADR-0044, `resume` first and `quit` last. */
75
+ pmButtons: readonly PauseMenuButton[];
76
+ /** The settings submenu: the adjustment panels, with «back» in front. */
77
+ optionsButtons: readonly PauseMenuButton[];
78
+ /** The GAME's submenu (ADR-0146). Absent = only «back», which is the case of a game that declares nothing of its own. */
79
+ gameButtons?: readonly PauseMenuButton[];
80
+ /** The finished label of a DYNAMIC button, or `null` if that button has none. The game is who builds the phrase. */
81
+ dynLabel: (b: PauseMenuButton) => string | null;
82
+ /** Translates in the page's language — the root's translator (ADR-0232 D3), with the {param}s the seat needs. */
83
+ t: Translate;
84
+ }
85
+ /** The full innerHTML of a `.screen-pause`. Pure — every input is a parameter. */
86
+ export declare function screenPauseMarkup(o: ScreenPauseMarkupOpts): string;
@@ -0,0 +1,125 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // ui/pause-markup — THE HTML OF THE PAUSE CARD AND OF THE ACCESSIBILITY BAR, as pure strings (ADR-0221; issue #203).
3
+ //
4
+ // Every function here takes what it needs and returns a string: no `document`, no injected ctx, no state. That is what lets a
5
+ // node test read the card's markup without mounting a browser, and it is the half of `ui/pause-icons` that never had to know
6
+ // anything about the DOM.
7
+ //
8
+ // 🔴 WHY IT LEFT: `ui/pause-icons` was 645 lines and 122 decision nodes after the catalogue left, and it held two jobs that do
9
+ // not need each other — BUILDING the strings, and then wiring, reflecting and navigating the elements the browser made from
10
+ // them. 📌 And the DATA had to leave FIRST: the markup needs the icon catalogue, so with all three in one file the markup
11
+ // could not be extracted without the two modules importing each other — the cycle ADR-0173 forbids. Catalogue in `core`,
12
+ // markup here, DOM next door.
13
+ //
14
+ // ⚠️ THE i18n KEY IS RESOLVED HERE, and that is not a matter of style: this markup is rendered ONCE and assigned to
15
+ // `innerHTML`, so a key left unresolved would ship the literal `icon.blind` to a screen reader. Where a label is rewritten
16
+ // later (state, seat, dynamic rows) the element that carries it is rendered with its own `<span>` or `data-i18n`, which is the
17
+ // seam `ui/pause-icons` writes through.
18
+ import { PAUSE_ICONS } from '../core/pause-icon-catalogue.js';
19
+ import { flagOf } from './locale-flags.js';
20
+ import { PM_GAME_BTNS } from './pause-buttons.js';
21
+ /** One `.pi-btn`. The label is the RESTING one: reflectIconBtn overwrites it with the stateful label as soon as the bar is
22
+ * reflected. `ic.n` is an i18n key, so it must be resolved here too — the markup is rendered once at build
23
+ * time and would otherwise ship the raw key to a screen reader. */
24
+ export function iconBtnMarkup(tr, ic) {
25
+ return '<button class="pi-btn" type="button" data-pi="' + ic.k +
26
+ '" aria-label="' + tr.t(ic.n) + '">' + (ic.k === 'idioma' ? flagOf(tr.locale()) : ic.e) + '</button>';
27
+ }
28
+ /** The whole icon bar. Used by the pause screen AND by the splash `#title-icons` — one builder, so the two bars
29
+ * cannot drift apart.
30
+ * The parameter is ADDITIVE and the default is the whole list: whoever already called it with no arguments gets the same
31
+ * string back. */
32
+ export function iconsMarkup(tr, icons = PAUSE_ICONS) {
33
+ return icons.map((ic) => iconBtnMarkup(tr, ic)).join('');
34
+ }
35
+ /**
36
+ * One `.pm-btn`. Dynamic labels (`letra`/`nivel`) are rendered eagerly and carry NO `data-i18n`, so `i18n.applyDom()` cannot
37
+ * overwrite them.
38
+ *
39
+ * ⚠️ THE DYNAMIC LABEL ARRIVES READY-MADE, and that change fixed TWO things at once.
40
+ *
41
+ * The line used to be `'📚 Nível ' + level + ' · ' + qlName[level]`, and it had two defects that only show together:
42
+ *
43
+ * 1. BOUNDARY. `level` came from `core/state.quizLevel` and `qlName` from a table owned by the game. An ENGINE pause menu
44
+ * was assembling the label of a literacy activity — pedagogical content, not mechanics.
45
+ * 2. LANGUAGE. «Nível» is raw pt-BR inside an engine module. The gate of that time did not reach `ui/`, so this line
46
+ * crossed the whole i18n pass unseen. In an English build, a child's pause menu said «📚 Nível 2 · …».
47
+ *
48
+ * Now the game hands over the finished phrase (`dynLabel`) and the engine only puts it on the button. The game is the one who
49
+ * knows what a level is, what it is called, and in which language to say it.
50
+ */
51
+ export function pmBtnMarkup(b, dynLabel, tr) {
52
+ const dyn = b.dynamicLabel || b.level;
53
+ const lbl = dynLabel(b) ?? (dyn ? (b.lbl ?? '') : tr('pause.' + b.act));
54
+ const glyph = ITEM_GLYPH[b.act];
55
+ return '<button class="pm-btn' + (b.dynamicLabel ? ' pm-letra' : '') + (b.level ? ' pm-nivel' : '') +
56
+ '" role="menuitem" type="button" data-act="' + b.act + '"' +
57
+ (glyph ? ' data-glifo="' + glyph + '"' : '') +
58
+ (dyn ? '' : (' data-i18n="pause.' + b.act + '"')) + '>' + lbl + '</button>';
59
+ }
60
+ /**
61
+ * THE GLYPH OF EACH PAUSE ITEM, drawn by the stylesheet and never part of the name (ADR-0159 rule 12: «An emoji or
62
+ * symbol in a menu is decorative and hidden from narration»). It lived at the start of each dictionary value, so the
63
+ * engine's narration and a screen reader both said «⚙ Inclusion settings». The glyph is the same in every language;
64
+ * the words stay in the dictionary.
65
+ *
66
+ * 📌 NOT exported any more, and the `exports-without-consumer` gate is what said so: it sat in the declared debt of
67
+ * `ui/pause-icons` — published with nobody importing it — and moving house was the moment to stop publishing it. Its only
68
+ * reader is `pmBtnMarkup`, one screen above.
69
+ */
70
+ const ITEM_GLYPH = {
71
+ // 🔴 `resume` HAS THE BACK GLYPH, not a «tocar» arrow: the Dev asked «não seria melhor usar "↩ Voltar" para o primeiro
72
+ // item do menu pausado também?». ADR-0158 had already made «Voltar» item 1 of every panel; the card was the only
73
+ // exception, with no reason of its own. From the child's point of view it is one word — leave here and go back to what
74
+ // I was doing —, and the destination is always the previous level: from the panel, the card; from the submenu, the
75
+ // root; from the root, the game. «Voltar ao jogo» named the DESTINATION instead of the action, and it was the only one.
76
+ resume: '↩', acessibilidade: '♿', options: '⚙', opcoesdojogo: '🎮', pmback: '↩', tipo: '🔤', addplayer: '👥',
77
+ audio: '🦻', som: '🔊', motora: '♿', anim: '🎞', visual: '🎨', empatia: '🫂', ajuda: '❓', print: '📷', quit: '🚪',
78
+ caa: '🔠',
79
+ };
80
+ /** The innerHTML of ONE `.pause-menu`: the list, and nothing else.
81
+ * 📌 Also no longer exported, by the same measurement as `ITEM_GLYPH`: it was in the declared debt, and what calls it is
82
+ * `screenPauseMarkup`, three times, right below. */
83
+ function pauseMenuHtml(bs, sub, dynLabel, tr) {
84
+ return '<div class="pause-menu" role="menu" data-sub="' + sub + '"' + (sub === 'raiz' ? '' : ' hidden') + '>' +
85
+ bs.map((b) => pmBtnMarkup(b, dynLabel, tr)).join('') + '</div>';
86
+ }
87
+ /**
88
+ * THE ACCESSIBILITY QUICK BAR — the toggles and the caption that explains them (ADR-0044, item 7).
89
+ *
90
+ * It left the pause card and went to live in the HUD. The reason is about use, not tidiness: it is DURING the game that a
91
+ * child needs to change a setting that is getting in her way, not after pausing. The secondary reason is structural — without
92
+ * it, the card stops having two zones and becomes a LIST, which is what finally authorises the ring (XAG 106 allows wrapping
93
+ * for a linear menu and forbids it for a grid).
94
+ *
95
+ * THE CAPTION TRAVELS WITH IT. It is the hint that replaces, for whoever does not see, the `title` only a mouse reveals;
96
+ * leaving it behind in the card would have made the HUD bar mute.
97
+ */
98
+ export function quickBarMarkup(tr, icons = PAUSE_ICONS) {
99
+ return '<div class="pause-icons" role="group" aria-label="' + tr.t('pause.iconBarAria') + '">' + iconsMarkup(tr, icons) +
100
+ '</div><p class="pause-icons-cap" aria-live="polite"></p>';
101
+ }
102
+ /** The full innerHTML of a `.screen-pause`. Pure — every input is a parameter. */
103
+ export function screenPauseMarkup(o) {
104
+ // THE DIALOG'S ACCESSIBLE NAME goes through the dictionary. It was raw text, and MEASURED in an English game the effect was
105
+ // this: the visible title said «Paused» and the dialog's name «Menu de pausa do jogador 1». Whoever saw read English;
106
+ // whoever listened got the menu announced in Portuguese — the same asymmetry as item 4 of ADR-0044, one level up. And
107
+ // `aria-label`, not `aria-labelledby`: the `<h2>` is a VISUAL label, which is why hiding it in a tight frame does not take
108
+ // the dialog's name away from whoever listens.
109
+ return '<div class="pause-card" role="dialog" aria-modal="true" aria-label="' + o.t('pause.cardAria', { n: o.player + 1 }) + '">' +
110
+ '<h2><span data-i18n="pause.title">' + o.t('pause.title') + '</span>'
111
+ // ⚠️ THE SEAT SUFFIX USED TO BE `' · Jogador ' + (o.player + 1)` — raw Portuguese inside an engine module, and an English
112
+ // game read «Paused · Jogador 2». It is a key now, and it lives in a `<span>` of its own because the item refresh needs
113
+ // somewhere to REPAINT it: since `pause.cardSeat` takes a parameter, the `data-i18n` path of `applyDom` — which calls
114
+ // `t(k)` with no parameters — does not serve here.
115
+ // 📌 `o.t` is the root's `Translate` (ADR-0232 D3), which carries the seat's `{n}` across.
116
+ + '<span class="pause-seat">' + (o.numPlayers > 1 ? o.t('pause.cardSeat', { n: o.player + 1 }) : '') + '</span></h2>' +
117
+ pauseMenuHtml(o.pmButtons, 'raiz', o.dynLabel, o.t) +
118
+ pauseMenuHtml(o.optionsButtons, 'opcoes', o.dynLabel, o.t) +
119
+ // ⚠️ THE THIRD LIST IS ALWAYS IN THE MARKUP, even for a game that declares nothing — and it is not waste: it is the same
120
+ // reason the other two are built whole and hidden afterwards (see the note on `buildScreenPause`). The game's table
121
+ // arrives LATE, and a list filtered at mount time would erase for ever what only came to exist after boot. What decides
122
+ // what is SEEN is the item refresh.
123
+ pauseMenuHtml(o.gameButtons ?? PM_GAME_BTNS, 'jogo', o.dynLabel, o.t) +
124
+ '<p class="pause-legend"></p></div>';
125
+ }
@@ -1,34 +1,33 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- import type { Alcance } from '../input/transports.js';
3
- /** `core/i18n.t` — injetado para o núcleo continuar puro e para o teste poder ver as chaves cruas. */
4
- export type Tradutor = (chave: string, params?: Record<string, string | number>) => string;
2
+ import type { Reach } from '../input/transports.js';
3
+ /** `core/i18n.t` — injected so the core stays pure and the test can see the raw keys. */
4
+ export type Translator = (key: string, params?: Record<string, string | number>) => string;
5
5
  /**
6
- * AS FRASES DO AVISO, na ordem em que são lidas. Vazio = não há nada a dizer, e é o caso comum.
6
+ * THE NOTICE'S SENTENCES, in reading order. Empty = there is nothing to say, which is the common case.
7
7
  *
8
- * ⚠️ A ÚLTIMA LINHA TEM DUAS FORMAS, e a diferença entre elas é a diferença entre ajudar e mentir:
8
+ * ⚠️ THE LAST LINE HAS TWO FORMS, and the difference between them is the difference between helping and lying:
9
9
  *
10
- * · há transporte que serviria se ligado → «ligue um controle», que é acionável.
11
- * · não há nenhum → dizer «ligue um controle» seria mandar a criança procurar uma coisa que não resolve.
12
- * Nesse caso o problema é do JOGO, que pede mais posições do que qualquer transporte deste aparelho
13
- * oferece, e a frase honesta é outra.
10
+ * · some transport would serve if switched on → tell the child to switch it on, which is actionable.
11
+ * · there is none → telling them to plug in a controller would send the child looking for something that does not
12
+ * solve it. Then the problem is the GAME's, which asks for more positions than any transport on this device
13
+ * offers, and the honest sentence is a different one.
14
14
  */
15
- export declare function linhasDoAviso(a: Alcance, t: Tradutor): string[];
15
+ export declare function noticeRows(a: Reach, t: Translator): string[];
16
16
  export interface ReachNoticeCtx {
17
- /** `querySelector` do documento deste jogo. */
18
- procurar: (sel: string) => HTMLElement | null;
19
- /** `document.createElement`. Injetado como tudo o mais que toca o documento. */
20
- criar: (tag: string) => HTMLElement;
21
- t: Tradutor;
22
- /** Anúncio assertivo. Uma criança cega tem de OUVIR isto — ela não vai ver o cartão. */
23
- srAlert: (texto: string) => void;
17
+ /** `querySelector` of this game's document. */
18
+ find: (sel: string) => HTMLElement | null;
19
+ /** `document.createElement`. Injected like everything else that touches the document. */
20
+ create: (tag: string) => HTMLElement;
21
+ t: Translator;
22
+ /** Assertive announcement. A blind child has to HEAR this — they will not see the card. */
23
+ srAlert: (text: string) => void;
24
24
  }
25
- /** O id do cartão. Estável porque o teste e a folha de estilo o procuram. */
25
+ /** The card's id. Stable because the test and the stylesheet look for it. */
26
26
  export declare const REACH_NOTICE_ID = "reach-notice";
27
27
  /**
28
- * Mostra o aviso, se houver o que dizer. Devolve `true` quando mostrou.
28
+ * Shows the notice, if there is something to say. Returns `true` when it showed.
29
29
  *
30
- * ⚠️ MONTA POR NÓS E NÃO POR `innerHTML`. As frases passam por `t()` e um dicionário é conteúdo que muda sem
31
- * passar por revisão de código — é exatamente a fronteira que a issue #106 mapeia. `textContent` fecha a
32
- * questão sem precisar de escapar nada.
30
+ * ⚠️ BUILT FROM NODES AND NOT `innerHTML`. The sentences go through `t()`, and a dictionary is content that changes
31
+ * without code review — exactly the boundary issue #106 maps. `textContent` settles it with nothing to escape.
33
32
  */
34
- export declare function mostrarAvisoDeAlcance(ctx: ReachNoticeCtx, a: Alcance): boolean;
33
+ export declare function showReachNotice(ctx: ReachNoticeCtx, a: Reach): boolean;
@@ -1,79 +1,76 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  /**
3
- * AS FRASES DO AVISO, na ordem em que são lidas. Vazio = não há nada a dizer, e é o caso comum.
3
+ * THE NOTICE'S SENTENCES, in reading order. Empty = there is nothing to say, which is the common case.
4
4
  *
5
- * ⚠️ A ÚLTIMA LINHA TEM DUAS FORMAS, e a diferença entre elas é a diferença entre ajudar e mentir:
5
+ * ⚠️ THE LAST LINE HAS TWO FORMS, and the difference between them is the difference between helping and lying:
6
6
  *
7
- * · há transporte que serviria se ligado → «ligue um controle», que é acionável.
8
- * · não há nenhum → dizer «ligue um controle» seria mandar a criança procurar uma coisa que não resolve.
9
- * Nesse caso o problema é do JOGO, que pede mais posições do que qualquer transporte deste aparelho
10
- * oferece, e a frase honesta é outra.
7
+ * · some transport would serve if switched on → tell the child to switch it on, which is actionable.
8
+ * · there is none → telling them to plug in a controller would send the child looking for something that does not
9
+ * solve it. Then the problem is the GAME's, which asks for more positions than any transport on this device
10
+ * offers, and the honest sentence is a different one.
11
11
  */
12
- export function linhasDoAviso(a, t) {
12
+ export function noticeRows(a, t) {
13
13
  if (a.ok)
14
14
  return [];
15
- const nome = (id) => t('reach.nome.' + id);
16
- const linhas = [t('reach.titulo', { pedidas: a.pedidas })];
17
- for (const c of a.curtos) {
18
- linhas.push(t('reach.curto', { transporte: nome(c.id), lugares: c.slots }));
15
+ const name = (id) => t('reach.nome.' + id);
16
+ const rows = [t('reach.titulo', { pedidas: a.asked })];
17
+ for (const c of a.short) {
18
+ rows.push(t('reach.curto', { transporte: name(c.id), lugares: c.slots }));
19
19
  }
20
- // ⚠️ A TERCEIRA FRASE, e ela existe porque um transporte pode CHEGAR a todas as ações e ainda assim não
21
- // deixar a criança jogar (ADR-0104). Medido: a plataforma pede nove ações, o controle de tela tem nove
22
- // lugares, e o cartão nunca aparecia — mas correr, andar e pular ao mesmo tempo são três dedos, e um
23
- // telemóvel que reconhece dois não os dá. A criança tentava, não acontecia nada, e concluía que o jogo
24
- // estava partido. Uma frase antes de começar é a resposta honesta; meia tela jogável não é.
25
- for (const s of a.naoSeguram) {
26
- linhas.push(t('reach.naoSegura', { transporte: nome(s.id), segura: s.holds, pedidas: a.seguraPedidas }));
20
+ // ⚠️ THE THIRD SENTENCE exists because a transport can REACH every action and still not let the child play
21
+ // (ADR-0104): holding three actions at once takes three fingers, and a phone that recognises two does not give
22
+ // them. The child would try, nothing would happen, and they would conclude the game was broken.
23
+ for (const s of a.cannotHold) {
24
+ rows.push(t('reach.naoSegura', { transporte: name(s.id), segura: s.holds, pedidas: a.holdsAsked }));
27
25
  }
28
- linhas.push(a.serviriamSeLigados.length
29
- ? t('reach.ligue', { saida: a.serviriamSeLigados.map(nome).join(t('reach.ou')) })
26
+ rows.push(a.wouldServeIfOn.length
27
+ ? t('reach.ligue', { saida: a.wouldServeIfOn.map(name).join(t('reach.ou')) })
30
28
  : t('reach.semSaida'));
31
- return linhas;
29
+ return rows;
32
30
  }
33
- /** O id do cartão. Estável porque o teste e a folha de estilo o procuram. */
31
+ /** The card's id. Stable because the test and the stylesheet look for it. */
34
32
  export const REACH_NOTICE_ID = 'reach-notice';
35
33
  /**
36
- * Mostra o aviso, se houver o que dizer. Devolve `true` quando mostrou.
34
+ * Shows the notice, if there is something to say. Returns `true` when it showed.
37
35
  *
38
- * ⚠️ MONTA POR NÓS E NÃO POR `innerHTML`. As frases passam por `t()` e um dicionário é conteúdo que muda sem
39
- * passar por revisão de código — é exatamente a fronteira que a issue #106 mapeia. `textContent` fecha a
40
- * questão sem precisar de escapar nada.
36
+ * ⚠️ BUILT FROM NODES AND NOT `innerHTML`. The sentences go through `t()`, and a dictionary is content that changes
37
+ * without code review — exactly the boundary issue #106 maps. `textContent` settles it with nothing to escape.
41
38
  */
42
- export function mostrarAvisoDeAlcance(ctx, a) {
43
- const linhas = linhasDoAviso(a, ctx.t);
44
- if (linhas.length === 0)
39
+ export function showReachNotice(ctx, a) {
40
+ const rows = noticeRows(a, ctx.t);
41
+ if (rows.length === 0)
45
42
  return false;
46
- const dentro = ctx.procurar('#game-region');
47
- if (!dentro)
48
- return false; // sem a marcação do hospedeiro não há onde mostrar; o `problems` já o denuncia
49
- const fora = ctx.criar('div');
50
- fora.id = REACH_NOTICE_ID;
51
- fora.className = 'overlay';
52
- const cartao = ctx.criar('div');
53
- cartao.className = 'overlay__card';
54
- cartao.setAttribute('role', 'dialog');
55
- cartao.setAttribute('aria-modal', 'true');
56
- cartao.setAttribute('tabindex', '-1');
57
- for (const [i, texto] of linhas.entries()) {
58
- const p = ctx.criar('p');
59
- p.textContent = texto;
43
+ const isInside = ctx.find('#game-region');
44
+ if (!isInside)
45
+ return false; // without the host's markup there is nowhere to show it; `problems` already reports that
46
+ const overlay = ctx.create('div');
47
+ overlay.id = REACH_NOTICE_ID;
48
+ overlay.className = 'overlay';
49
+ const card = ctx.create('div');
50
+ card.className = 'overlay__card';
51
+ card.setAttribute('role', 'dialog');
52
+ card.setAttribute('aria-modal', 'true');
53
+ card.setAttribute('tabindex', '-1');
54
+ for (const [i, text] of rows.entries()) {
55
+ const p = ctx.create('p');
56
+ p.textContent = text;
60
57
  if (i === 0)
61
58
  p.className = 'reach-notice__titulo';
62
- cartao.appendChild(p);
59
+ card.appendChild(p);
63
60
  }
64
- // ⚠️ O BOTÃO É O QUE FAZ DISTO UM AVISO E NÃO UMA PORTA FECHADA. Ver o cabeçalho: a detecção de teclado
65
- // erra, e o erro só é aceitável enquanto a criança puder seguir em frente.
66
- const seguir = ctx.criar('button');
67
- seguir.setAttribute('type', 'button');
68
- seguir.className = 'mode-btn';
69
- seguir.textContent = ctx.t('reach.continuar');
70
- seguir.addEventListener('click', () => fora.remove());
71
- cartao.appendChild(seguir);
72
- fora.appendChild(cartao);
73
- dentro.appendChild(fora);
74
- // O foco vai para o cartão, não para o botão: a criança tem de OUVIR o motivo antes de encontrar a saída.
75
- // (Se fosse para o botão, o leitor de tela leria «Jogar assim mesmo» e o resto ficaria para quem procurasse.)
76
- cartao.focus();
77
- ctx.srAlert(linhas.join(' '));
61
+ // ⚠️ THE BUTTON IS WHAT MAKES THIS A NOTICE AND NOT A CLOSED DOOR. See the header: keyboard detection errs, and the
62
+ // error is only acceptable while the child can carry on.
63
+ const continueButton = ctx.create('button');
64
+ continueButton.setAttribute('type', 'button');
65
+ continueButton.className = 'mode-btn';
66
+ continueButton.textContent = ctx.t('reach.continuar');
67
+ continueButton.addEventListener('click', () => overlay.remove());
68
+ card.appendChild(continueButton);
69
+ overlay.appendChild(card);
70
+ isInside.appendChild(overlay);
71
+ // Focus goes to the card, not the button: the child has to HEAR the reason before finding the way out.
72
+ // (On the button, a screen reader would read "Play anyway" and the rest would be left for whoever looked.)
73
+ card.focus();
74
+ ctx.srAlert(rows.join(' '));
78
75
  return true;
79
76
  }
@@ -0,0 +1,23 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import type { Action } from '../core/actions.js';
3
+ import type { Translate } from '../core/i18n.js';
4
+ /** What the chip reads for one item. Pure: the engine's word where the item is the engine's, else the game's own word. */
5
+ export declare function scanItemText(item: string, label: (a: Action) => string | null, t: Translate): string;
6
+ export interface ScanOverlay {
7
+ /**
8
+ * Puts the item on screen, and answers whether the words CHANGED. The same item twice does not rewrite the node — a live
9
+ * region that repeats itself says it twice — and the answer is what lets the caller re-measure the room only when a word of
10
+ * a different length arrives, instead of every frame.
11
+ */
12
+ showing(text: string): boolean;
13
+ /** Takes the chip off screen; the scan is off. */
14
+ hide(): void;
15
+ remove(): void;
16
+ }
17
+ /**
18
+ * Mounts the chip inside the game's region, under the quick bar's band.
19
+ *
20
+ * ⚠️ `role="status"`, not `alert`: a child who plays by ear hears each item as it comes, and an alert would interrupt whatever
21
+ * the game is saying at every step of a scan that never stops.
22
+ */
23
+ export declare function mountScanOverlay(doc: Document, host: HTMLElement): ScanOverlay;
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // ui/scan-overlay — WHAT «ONE BUTTON ONLY» IS OFFERING RIGHT NOW (ADR-0218, issue #201).
3
+ //
4
+ // A scan is the machine offering and the child taking, and she cannot take what she cannot see: the whole accommodation is the
5
+ // list going by, so the list going by has to be ON SCREEN, in the game's own words, and it has to reach a child who plays by
6
+ // ear as well — which is why the chip is a live region and not a picture.
7
+ //
8
+ // 📌 THE WORDS ARE THE GAME'S. What is offered is a position the cartridge declared and NAMED (`preset`), so the chip says
9
+ // «Confirmar» or «Dizer a resposta», never `action2` (ADR-0074). A position the game did not name is not offered at all — the
10
+ // list is built from the named ones — because a scan that stopped on a word nobody wrote would cost the child a full pass.
11
+ import { SCAN_CANCEL } from '../input/switch-scan.js';
12
+ /** The ENGINE's words, by dictionary key — the wording is an interface choice (interface log 2026-09-26). */
13
+ const ENGINE_WORDS = new Map([
14
+ [SCAN_CANCEL, 'scan.nothing'],
15
+ ['select', 'scan.door.menus'], ['start', 'scan.door.pause'],
16
+ ['next', 'scan.menu.next'], ['confirm', 'scan.menu.confirm'], ['back', 'scan.menu.back'], ['previous', 'scan.menu.previous'],
17
+ ['increase', 'scan.menu.increase'], ['decrease', 'scan.menu.decrease'],
18
+ ]);
19
+ /** What the chip reads for one item. Pure: the engine's word where the item is the engine's, else the game's own word. */
20
+ export function scanItemText(item, label, t) {
21
+ const key = ENGINE_WORDS.get(item);
22
+ return key ? t(key) : (label(item) ?? '');
23
+ }
24
+ /**
25
+ * Mounts the chip inside the game's region, under the quick bar's band.
26
+ *
27
+ * ⚠️ `role="status"`, not `alert`: a child who plays by ear hears each item as it comes, and an alert would interrupt whatever
28
+ * the game is saying at every step of a scan that never stops.
29
+ */
30
+ export function mountScanOverlay(doc, host) {
31
+ const el = doc.createElement('div');
32
+ el.className = 'scan-now';
33
+ el.setAttribute('role', 'status');
34
+ el.hidden = true;
35
+ host.appendChild(el);
36
+ let last = null;
37
+ return {
38
+ showing(text) {
39
+ const appeared = el.hidden;
40
+ el.hidden = false;
41
+ if (text === last)
42
+ return appeared;
43
+ last = text;
44
+ el.textContent = text;
45
+ return true;
46
+ },
47
+ hide() { el.hidden = true; last = null; el.textContent = ''; },
48
+ remove() { el.remove(); },
49
+ };
50
+ }
@@ -0,0 +1,25 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import type { Action } from '../core/actions.js';
3
+ import type { WorldScope } from '../core/contract.js';
4
+ /** What the reader is built over. Both are read at every call: a `mount()` swaps the cartridge, a panel opens. */
5
+ export interface ScreenTextCtx {
6
+ /** The root's document. */
7
+ readonly doc: Document;
8
+ /** The world the mounted game declares (`GameDeclaration.world`). */
9
+ readonly world: () => WorldScope;
10
+ }
11
+ /**
12
+ * WHAT IS ON THE SCREEN NOW, as the sonar reads it — `''` when there is nothing the engine can read: no world, an empty one,
13
+ * or a world drawn on a canvas.
14
+ */
15
+ export declare function screenText(ctx: ScreenTextCtx): string;
16
+ /**
17
+ * The `problems` line for a world the sonar cannot read — none, or one (ADR-0169: the subject, the child's cost, the fix).
18
+ * Measured at every read of `problems`: a canvas is often drawn after the boot.
19
+ */
20
+ export declare function unreadableWorldProblems(ctx: ScreenTextCtx): string[];
21
+ /**
22
+ * A press made WITH A MENU OPEN: the menu sonar's position reads what is in front (`read`) and takes the press. Any other
23
+ * position is left to the menus — answers whether this one was taken.
24
+ */
25
+ export declare function menuSonarPress(action: Action, ctx: ScreenTextCtx, read: (text: string) => void): boolean;