@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,26 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import { toggleLabel } from './dom.js';
3
+ import type { Translate } from '../core/i18n.js';
4
+ /** Clamps the selected player back to 0 once it falls outside 0..numPlayers-1 (e.g. player count dropped). */
5
+ export declare function clampSelPlayer(sel: number, numPlayers: number): number;
6
+ /** Whether ANY player currently uses Easy Mode or a toggle — lights the #opt-movement bar button. */
7
+ export declare function anyMobilityActive(players: readonly {
8
+ readonly easy?: boolean;
9
+ readonly toggleMove?: boolean;
10
+ }[]): boolean;
11
+ /** The on/off label for #opt-facil and #opt-altmove. A re-export of ui/dom's, which is the only one — a local body would
12
+ * be a copy. */
13
+ export declare const onOffLabel: typeof toggleLabel;
14
+ /**
15
+ * Full innerHTML for #movement-players, given the player count and the active index. Pure string building —
16
+ * no DOM. NOTE: the panel keeps this list `hidden` — a single player edits only their own screen
17
+ * (scope = pauseActor) — but the tabs/buttons are still built and wired for >1 player.
18
+ */
19
+ export declare function playerTabsHTML(numPlayers: number, selected: number): string;
20
+ /**
21
+ * The player prefix that opens an announcement when there is more than one screen. A single screen gets no prefix —
22
+ * naming the player to whoever is alone is noise, and noise on a screen reader costs listening time.
23
+ */
24
+ export declare function playerPrefix(t: Translate, i: number, numPlayers: number): string;
25
+ /** srSay text for an Easy Mode change. The whole sentence comes from the dictionary — see `sr.motor.easyOn`. */
26
+ export declare function easyAnnouncement(t: Translate, i: number, numPlayers: number, on: boolean): string;
@@ -0,0 +1,41 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // ui/mobility-choices — what the mobility panel's choices ARE, with no panel: the selected player clamped to the players there
3
+ // are, whether any of them uses easy mode or a toggle, the player tabs, and the easy-mode announcement with its player prefix
4
+ // (ADR-0221; issue #203).
5
+ //
6
+ // It left `ui/settings-mobility` as the five `*-choices` modules before it did, and for the same reason: the node test drove
7
+ // these names with no document — the seam was already drawn by the suite. The stored KEYS stay there, beside the writers that
8
+ // use them. What stays is the panel: finding its controls, wiring them, writing the toggles, reflecting the choice.
9
+ import { toggleLabel } from './dom.js';
10
+ /** Clamps the selected player back to 0 once it falls outside 0..numPlayers-1 (e.g. player count dropped). */
11
+ export function clampSelPlayer(sel, numPlayers) {
12
+ return sel >= numPlayers ? 0 : sel;
13
+ }
14
+ /** Whether ANY player currently uses Easy Mode or a toggle — lights the #opt-movement bar button. */
15
+ export function anyMobilityActive(players) {
16
+ return players.some((p) => p.easy || p.toggleMove);
17
+ }
18
+ /** The on/off label for #opt-facil and #opt-altmove. A re-export of ui/dom's, which is the only one — a local body would
19
+ * be a copy. */
20
+ export const onOffLabel = toggleLabel;
21
+ /**
22
+ * Full innerHTML for #movement-players, given the player count and the active index. Pure string building —
23
+ * no DOM. NOTE: the panel keeps this list `hidden` — a single player edits only their own screen
24
+ * (scope = pauseActor) — but the tabs/buttons are still built and wired for >1 player.
25
+ */
26
+ export function playerTabsHTML(numPlayers, selected) {
27
+ if (numPlayers <= 1)
28
+ return '';
29
+ return Array.from({ length: numPlayers }, (_, p) => `<button class="mode-btn${p === selected ? ' is-on' : ''}" data-mp="${p}" type="button">Jogador ${p + 1}</button>`).join('');
30
+ }
31
+ /**
32
+ * The player prefix that opens an announcement when there is more than one screen. A single screen gets no prefix —
33
+ * naming the player to whoever is alone is noise, and noise on a screen reader costs listening time.
34
+ */
35
+ export function playerPrefix(t, i, numPlayers) {
36
+ return numPlayers > 1 ? t('sr.player.prefix', { n: i + 1 }) : '';
37
+ }
38
+ /** srSay text for an Easy Mode change. The whole sentence comes from the dictionary — see `sr.motor.easyOn`. */
39
+ export function easyAnnouncement(t, i, numPlayers, on) {
40
+ return playerPrefix(t, i, numPlayers) + t(on ? 'sr.motor.easyOn' : 'sr.motor.easyOff');
41
+ }
@@ -0,0 +1,31 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import type { Translate } from '../core/i18n.js';
3
+ import type { MotionSceneKey, MotionCharDef, MotionPlayer, MotionSceneFlags } from './motion-scene.js';
4
+ /**
5
+ * Target → i18n KEY of the label. KEYS, and not text, for the usual reason: a `const` table of text resolves ONCE, on
6
+ * import, and stays frozen in the boot language.
7
+ *
8
+ * And it is ONE table: `rmChar[].lbl` holds a key of THIS table rather than a copy of the label, because copies of the
9
+ * same labels with nothing linking them make changing one label a multi-file edit where forgetting one is silent.
10
+ */
11
+ export declare const RM_LABEL: Record<string, string>;
12
+ /** i18n KEYS of the three CRT effects (see `RM_LABEL`). */
13
+ export declare const CRT_LBL: Record<'scan' | 'vig' | 'round', string>;
14
+ export declare const CRT_ROUND_LEVELS: readonly string[];
15
+ /** The selected player never points outside the current number of screens. */
16
+ export declare function clampSelectedPlayer(selected: number, total: number): number;
17
+ /** true when EVERYTHING (scene + selected character) already has reduced motion ON, that is, frozen — the name follows
18
+ * `rm[k]`/`player[prop]`, which mean "reduced", not "animated". Decides whether the master button offers "Resume"
19
+ * (true) or "Stop" (false). */
20
+ export declare function allMotionFrozen(rmKeys: readonly MotionSceneKey[], rm: MotionSceneFlags, rmChar: readonly MotionCharDef[], player: MotionPlayer | undefined): boolean;
21
+ /** allFrozen=true (everything already frozen) → offers "Resume"; otherwise → offers "Stop". */
22
+ export declare function motionMasterLabel(t: Translate, allFrozen: boolean): string;
23
+ /** `label` arrives ALREADY TRANSLATED, and the state is a frame with `{alvo}` rather than a concatenated suffix — which
24
+ * lets a language put the state BEFORE the target, something a concatenation does not allow. */
25
+ export declare function sceneMotionAnnouncement(t: Translate, label: string, frozen: boolean): string;
26
+ export declare function crtToggleAnnouncement(t: Translate, label: string, on: boolean): string;
27
+ export declare function crtLevelLabel(t: Translate, level: number): string;
28
+ export declare function crtRoundAnnouncement(t: Translate, label: string, level: number): string;
29
+ /** `nowFrozen` = the NEW value of rm[k]/player[prop] applied by the master button (true = everything was just frozen;
30
+ * false = everything was just resumed). */
31
+ export declare function stopResumeAllAnnouncement(t: Translate, nowFrozen: boolean): string;
@@ -0,0 +1,68 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // ui/motion-choices — WHAT A MOVEMENT CHOICE IS, with no document anywhere near it.
3
+ //
4
+ // 📌 THE SUITE HAD ALREADY DRAWN THIS SEAM, which is what makes the cut a reading and not an opinion:
5
+ // `tests/settings-motion.node.test.js` exercises exactly these names, and the node project mounts no document — so
6
+ // whoever wrote those cases had to know where the panel stops being a panel. It is the fifth module to come out this
7
+ // way, after `ui/audio-choices`, `ui/typo-choices`, `ui/control-choices` and `ui/visual-choices`.
8
+ //
9
+ // What lives here answers «what is each target called, is everything already frozen, and what does the screen reader
10
+ // hear»; what stays in `ui/settings-motion` is the work its name never mentioned — mounting the rows, reconciling
11
+ // them with the cartridge, wiring them and reflecting the choice.
12
+ /**
13
+ * Target → i18n KEY of the label. KEYS, and not text, for the usual reason: a `const` table of text resolves ONCE, on
14
+ * import, and stays frozen in the boot language.
15
+ *
16
+ * And it is ONE table: `rmChar[].lbl` holds a key of THIS table rather than a copy of the label, because copies of the
17
+ * same labels with nothing linking them make changing one label a multi-file edit where forgetting one is silent.
18
+ */
19
+ export const RM_LABEL = {
20
+ parallax: 'rm.parallax', decor: 'rm.decor', items: 'rm.items',
21
+ walk: 'rm.walk', breath: 'rm.breath', flavor: 'rm.flavor', particles: 'rm.particles',
22
+ };
23
+ /** i18n KEYS of the three CRT effects (see `RM_LABEL`). */
24
+ export const CRT_LBL = { scan: 'rm.crt.scan', vig: 'rm.crt.vig', round: 'rm.crt.round' };
25
+ // ⚠️ KEYS, because the levels are words the child hears: a raw word here would announce a level in one language inside a
26
+ // game running in another (ADR-0151 made the corners steps ⯇ ⯈).
27
+ export const CRT_ROUND_LEVELS = ['crt.round.off', 'crt.round.small', 'crt.round.large'];
28
+ /** The selected player never points outside the current number of screens. */
29
+ export function clampSelectedPlayer(selected, total) {
30
+ return selected >= total ? 0 : selected;
31
+ }
32
+ /** true when EVERYTHING (scene + selected character) already has reduced motion ON, that is, frozen — the name follows
33
+ * `rm[k]`/`player[prop]`, which mean "reduced", not "animated". Decides whether the master button offers "Resume"
34
+ * (true) or "Stop" (false). */
35
+ export function allMotionFrozen(rmKeys, rm, rmChar, player) {
36
+ // 🔴 WITH NO CHARACTER, THE CHARACTER HALF DOES NOT COUNT. Requiring `player && player[c.prop]` for every target is
37
+ // ALWAYS FALSE when there is no player: in a game that declares no `players` — a quiz, a puzzle — `allFrozen` would
38
+ // stay `false`, the master button would compute `next = true` on EVERY click, and a child who stopped all the
39
+ // animations would have no way to bring them back. That costs most to whoever froze them because they needed to:
40
+ // that person does not press the button out of curiosity, they press it feeling sick.
41
+ //
42
+ // 📌 With a player nothing changes: `!player` is false and the count is target by target.
43
+ return rmKeys.every((k) => rm[k]) && (!player || rmChar.every((c) => !!player[c.prop]));
44
+ }
45
+ /** allFrozen=true (everything already frozen) → offers "Resume"; otherwise → offers "Stop". */
46
+ export function motionMasterLabel(t, allFrozen) {
47
+ return t(allFrozen ? 'a11y.resumeAll' : 'a11y.stopAll'); // no glyph in the name (ADR-0159 rule 12), in the page's language
48
+ }
49
+ /** `label` arrives ALREADY TRANSLATED, and the state is a frame with `{alvo}` rather than a concatenated suffix — which
50
+ * lets a language put the state BEFORE the target, something a concatenation does not allow. */
51
+ export function sceneMotionAnnouncement(t, label, frozen) {
52
+ return t(frozen ? 'sr.rm.frozen' : 'sr.rm.animated', { alvo: label });
53
+ }
54
+ export function crtToggleAnnouncement(t, label, on) {
55
+ return t(on ? 'sr.crt.on' : 'sr.crt.off', { efeito: label });
56
+ }
57
+ export function crtLevelLabel(t, level) {
58
+ const key = CRT_ROUND_LEVELS[level];
59
+ return key ? t(key) : '';
60
+ }
61
+ export function crtRoundAnnouncement(t, label, level) {
62
+ return t('sr.crt.round', { efeito: label, nivel: crtLevelLabel(t, level) });
63
+ }
64
+ /** `nowFrozen` = the NEW value of rm[k]/player[prop] applied by the master button (true = everything was just frozen;
65
+ * false = everything was just resumed). */
66
+ export function stopResumeAllAnnouncement(t, nowFrozen) {
67
+ return t(nowFrozen ? 'sr.rm.allStopped' : 'sr.rm.allResumed');
68
+ }
@@ -1,22 +1,25 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import type { Store } from '../platform/storage.js';
2
3
  import type { PlayerView } from '../core/entity.js';
3
- /** As quatro animações de CENA, como vocabulário fechado. */
4
+ /** What the scene flags are read and written through: the page's store, built by the root (ADR-0232, issue #207). */
5
+ export type SceneStore = Pick<Store, 'getJSON' | 'setJSON'>;
6
+ /** The four SCENE animations, as a closed vocabulary. */
4
7
  export type MotionSceneKey = 'parallax' | 'decor' | 'items' | 'particles';
5
- /** As três do PERSONAGEM, que são campos do jogador. */
8
+ /** The three CHARACTER ones, which are player fields. */
6
9
  export type MotionCharProp = 'rmWalk' | 'rmBreath' | 'rmFlavor';
7
- /** Uma animação do personagem e a chave i18n do seu rótulo. */
10
+ /** A character animation and the i18n key of its label. */
8
11
  export interface MotionCharDef {
9
12
  readonly prop: MotionCharProp;
10
13
  readonly lbl: string;
11
14
  }
12
- /** ⚠️ `PlayerView` e não `Record`: um `Record` aceita qualquer objecto com essas chaves, jogador ou não. */
15
+ /** ⚠️ `PlayerView` and not `Record`: a `Record` accepts any object with those keys, player or not. */
13
16
  export type MotionPlayer = PlayerView<'rmWalk' | 'rmBreath' | 'rmFlavor'>;
14
- /** Os quatro interruptores de cena. Objecto VIVO — ver a nota sobre partilha por referência no topo. */
17
+ /** The four scene switches. A LIVE object — see the note on sharing by reference at the top. */
15
18
  export type MotionSceneFlags = Record<MotionSceneKey, boolean>;
16
- /** As quatro animações de CENA. São a união inteira, e o compilador prova-o logo abaixo. */
17
- export declare const CHAVES_DE_CENA: readonly ["parallax", "decor", "items", "particles"];
18
- /** As três animações do PERSONAGEM, com as chaves que o `RM_LABEL` desta mesma camada já traduz. */
19
- export declare const ANIMACOES_DO_PERSONAGEM: readonly [{
19
+ /** The four SCENE animations. They are the whole union, and the compiler proves it just below. */
20
+ export declare const SCENE_KEYS: readonly ["parallax", "decor", "items", "particles"];
21
+ /** The three CHARACTER animations, with the keys `RM_LABEL` in this same layer already translates. */
22
+ export declare const CHARACTER_ANIMATIONS: readonly [{
20
23
  readonly prop: "rmWalk";
21
24
  readonly lbl: "rm.walk";
22
25
  }, {
@@ -26,16 +29,18 @@ export declare const ANIMACOES_DO_PERSONAGEM: readonly [{
26
29
  readonly prop: "rmFlavor";
27
30
  readonly lbl: "rm.flavor";
28
31
  }];
29
- /** Os quatro interruptores no padrão do sistema — `prefers-reduced-motion`, por `defaultReducedMotion()`. */
30
- export declare function padraoDeCena(): MotionSceneFlags;
31
32
  /**
32
- * O estado guardado, ou o padrão do sistema quando não há nada guardado.
33
+ * The four switches at the system default. `reducedByDefault` is what `prefers-reduced-motion` answers — the caller asks
34
+ * through `defaultReducedMotion(matchMedia)`.
35
+ */
36
+ export declare function sceneDefault(reducedByDefault: boolean): MotionSceneFlags;
37
+ /**
38
+ * The stored state, or the system default (`reducedByDefault`, as in `sceneDefault`) when nothing is stored.
33
39
  *
34
- * ⚠️ CADA CHAVE É LIDA UMA A UMA, e não `{...guardado}`. O que está no armazenamento veio do navegador de uma
35
- * criança e pode estar truncado ou de uma versão anterior: espalhar o objecto traria chaves a mais e deixaria
36
- * chaves a menos por preencher, e uma chave em falta lê-se como `undefined` — que é «não reduzido» para quem
37
- * pediu redução. O laço garante exactamente as quatro.
40
+ * ⚠️ EACH KEY IS READ ONE BY ONE, not spread. What is in storage came from a child's browser and may be truncated or
41
+ * from an earlier version: spreading the object would bring extra keys and leave missing ones unfilled, and a missing
42
+ * key reads as `undefined` — which is "not reduced" for whoever asked for reduction. The loop guarantees exactly four.
38
43
  */
39
- export declare function lerCenaGuardada(): MotionSceneFlags;
40
- /** Guarda os quatro interruptores. Chamada depois de cada mudança, como o `saveRM` do cartucho fazia. */
41
- export declare function guardarCena(rm: MotionSceneFlags): void;
44
+ export declare function readStoredScene(store: SceneStore, reducedByDefault: boolean): MotionSceneFlags;
45
+ /** Stores the four switches. Called after each change. */
46
+ export declare function storeScene(store: SceneStore, rm: MotionSceneFlags): void;
@@ -1,76 +1,44 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- // ui/motion-scene — O MOVIMENTO REDUZIDO DE CENA VOLTA PARA A ENGINE (ADR-0106 §4, etapa 1).
3
- //
4
- // ========================= O QUE ESTAVA ERRADO, MEDIDO E NÃO SUPOSTO =========================
5
- // O `PauseIconsCtx` e o `SettingsMotionCtx` pediam ao JOGO quatro coisas — `rm`, `rmKeys`, `rmChar`,
6
- // `saveRM` — e o ADR-0106 chamou-lhes «do jogo POR ACIDENTE». A medição de 2026-09-08 no `game-platformer`
7
- // mostra que a palavra é exacta, porque nenhuma das quatro contém uma escolha do jogo:
8
- //
9
- // · `RM_KEYS` era `['parallax','decor','items','particles']` escrito à mão — que é a união `MotionSceneKey`
10
- // INTEIRA, declarada na engine. Não é «quais destes este jogo tem»: são os quatro, sempre;
11
- // · `RM_CHAR` era as três propriedades de `MotionCharProp` com as chaves i18n `rm.walk`/`rm.breath`/
12
- // `rm.flavor` — e o `RM_LABEL` da engine já traduz essas mesmas chaves;
13
- // · `rm` era lido de `store.KEYS.reducedMotion` (chave da engine) com `defaultReducedMotion()` (padrão da
14
- // engine);
15
- // · `saveRM` era `store.setJSON` para a mesma chave da engine.
16
- //
17
- // ⚠️ ERA UMA CÓPIA, NÃO UMA DECISÃO. E o custo não é elegância: **cinco jogos não têm nada disto**, porque
18
- // cada cartucho tinha de se lembrar de escrever as quatro linhas. Uma criança que precisa de parar o
19
- // movimento da cena abre esses cinco e não tem por onde.
20
- //
21
- // ⚠️ O QUE CONTINUA A SER DO JOGO, e por natureza: o EFEITO. Quem lê `rm.decor` para congelar as nuvens é o
22
- // jogo — a engine possui o interruptor, não o que ele apaga. É a mesma divisão do ADR-0106: o valor é da
23
- // engine, o efeito colateral é do cartucho.
24
- //
25
- // ⚠️ E O OBJECTO É PARTILHADO POR REFERÊNCIA, de propósito. No cartucho ele entra em oito módulos
26
- // (`weather`, `life`, `fx`, …) que leem `rm.decor`/`rm.particles` a cada quadro. Devolver uma cópia faria
27
- // cada leitor ver um valor congelado no arranque, e o interruptor deixaria de fazer nada — em silêncio.
28
- // ⚠️ O VOCABULÁRIO DESCEU PARA CÁ, e foi um gate que o mandou. Escrito ao contrário — os tipos no
29
- // `settings-motion` e este módulo a importá-los —, o `tests/lotes-passo5` reprovou por CICLO: o painel importa
30
- // os valores daqui e este importava os tipos de lá. O analisador conta o `import type` como aresta, e tem
31
- // razão para o que mede (ordem de extração). A saída certa não era calar o gate: o vocabulário pertence a quem
32
- // possui os VALORES, e o painel é consumidor dele. O `settings-motion` mantém os nomes publicados por alias,
33
- // então nenhuma linha de importação de nenhum consumidor muda.
34
- import * as store from '../platform/storage.js';
35
- import { defaultReducedMotion } from '../core/state.js';
36
- /** As quatro animações de CENA. São a união inteira, e o compilador prova-o logo abaixo. */
37
- export const CHAVES_DE_CENA = ['parallax', 'decor', 'items', 'particles'];
38
- const _COBRE_A_UNIAO = true;
39
- void _COBRE_A_UNIAO;
40
- /** As três animações do PERSONAGEM, com as chaves que o `RM_LABEL` desta mesma camada já traduz. */
41
- export const ANIMACOES_DO_PERSONAGEM = Object.freeze([
2
+ import { KEYS } from '../platform/storage-keys.js';
3
+ /** The four SCENE animations. They are the whole union, and the compiler proves it just below. */
4
+ export const SCENE_KEYS = ['parallax', 'decor', 'items', 'particles'];
5
+ const _COVERS_THE_UNION = true;
6
+ void _COVERS_THE_UNION;
7
+ /** The three CHARACTER animations, with the keys `RM_LABEL` in this same layer already translates. */
8
+ export const CHARACTER_ANIMATIONS = Object.freeze([
42
9
  { prop: 'rmWalk', lbl: 'rm.walk' },
43
10
  { prop: 'rmBreath', lbl: 'rm.breath' },
44
11
  { prop: 'rmFlavor', lbl: 'rm.flavor' },
45
12
  ]);
46
- const _COBRE_O_PERSONAGEM = true;
47
- void _COBRE_O_PERSONAGEM;
48
- /** Os quatro interruptores no padrão do sistema — `prefers-reduced-motion`, por `defaultReducedMotion()`. */
49
- export function padraoDeCena() {
13
+ const _COVERS_THE_CHARACTER = true;
14
+ void _COVERS_THE_CHARACTER;
15
+ /**
16
+ * The four switches at the system default. `reducedByDefault` is what `prefers-reduced-motion` answers — the caller asks
17
+ * through `defaultReducedMotion(matchMedia)`.
18
+ */
19
+ export function sceneDefault(reducedByDefault) {
50
20
  const o = {};
51
- const padrao = defaultReducedMotion();
52
- for (const k of CHAVES_DE_CENA)
53
- o[k] = padrao;
21
+ for (const k of SCENE_KEYS)
22
+ o[k] = reducedByDefault;
54
23
  return o;
55
24
  }
56
25
  /**
57
- * O estado guardado, ou o padrão do sistema quando não há nada guardado.
26
+ * The stored state, or the system default (`reducedByDefault`, as in `sceneDefault`) when nothing is stored.
58
27
  *
59
- * ⚠️ CADA CHAVE É LIDA UMA A UMA, e não `{...guardado}`. O que está no armazenamento veio do navegador de uma
60
- * criança e pode estar truncado ou de uma versão anterior: espalhar o objecto traria chaves a mais e deixaria
61
- * chaves a menos por preencher, e uma chave em falta lê-se como `undefined` — que é «não reduzido» para quem
62
- * pediu redução. O laço garante exactamente as quatro.
28
+ * ⚠️ EACH KEY IS READ ONE BY ONE, not spread. What is in storage came from a child's browser and may be truncated or
29
+ * from an earlier version: spreading the object would bring extra keys and leave missing ones unfilled, and a missing
30
+ * key reads as `undefined` — which is "not reduced" for whoever asked for reduction. The loop guarantees exactly four.
63
31
  */
64
- export function lerCenaGuardada() {
65
- const guardado = store.getJSON(store.KEYS.reducedMotion, null);
66
- if (!guardado || typeof guardado !== 'object')
67
- return padraoDeCena();
32
+ export function readStoredScene(store, reducedByDefault) {
33
+ const stored = store.getJSON(KEYS.reducedMotion, null);
34
+ if (!stored || typeof stored !== 'object')
35
+ return sceneDefault(reducedByDefault);
68
36
  const o = {};
69
- for (const k of CHAVES_DE_CENA)
70
- o[k] = !!guardado[k];
37
+ for (const k of SCENE_KEYS)
38
+ o[k] = !!stored[k];
71
39
  return o;
72
40
  }
73
- /** Guarda os quatro interruptores. Chamada depois de cada mudança, como o `saveRM` do cartucho fazia. */
74
- export function guardarCena(rm) {
75
- store.setJSON(store.KEYS.reducedMotion, rm);
41
+ /** Stores the four switches. Called after each change. */
42
+ export function storeScene(store, rm) {
43
+ store.setJSON(KEYS.reducedMotion, rm);
76
44
  }
@@ -0,0 +1,81 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import type { PanelLabels, PanelShell, PanelShellCtx } from './panel-shell.js';
3
+ /** The slice of the overlay stack a panel needs. Narrow on purpose: this file never opens a second panel. */
4
+ export interface PanelStack {
5
+ /** Brings the overlay to the front of the z-order, as `ui/settings-panel` computes it. */
6
+ readonly frontOverlay: (el: HTMLElement) => void;
7
+ /** Joins the Escape chain. Without it, Escape walks an empty registry and the panel traps the child. */
8
+ readonly register: (id: string, entry: {
9
+ close: () => void;
10
+ inEscapeChain: boolean;
11
+ }) => void;
12
+ /** Returns focus to whatever opened the panel (WCAG 2.4.3). */
13
+ readonly restoreFocus?: (id: string) => void;
14
+ }
15
+ export interface MountPanelCtx extends PanelShellCtx {
16
+ /** Where the overlay lives. The composition root resolves it; this file does not guess at `#game-region`. */
17
+ readonly host: HTMLElement;
18
+ readonly overlays: PanelStack;
19
+ /**
20
+ * HEARS A LANGUAGE CHANGE, and returns its release — the root's `localeOn` (ADR-0232 D3 erratum point 4), which hands
21
+ * that release to the root's disposing door, so a panel of an ended root stops redrawing (ADR-0220). REQUIRED (ADR-0232
22
+ * D4): the panel used to listen for `i18n:change` on the window, a listener nothing ever took off.
23
+ */
24
+ readonly localeOn: (react: (locale: string) => void) => () => void;
25
+ }
26
+ export interface MountPanelSpec {
27
+ /** The panel's id: `typo`, `audio`, `visual`… Identity, resolved once — unlike the words below. */
28
+ readonly id: string;
29
+ /** The list's id when it is not `${id}-list`. One of the eight needs it — see `PanelShellSpec.idDaLista`. */
30
+ readonly listId?: string;
31
+ /**
32
+ * The panel's WORDS, already translated — and resolved AT EVERY OPEN rather than once at mount.
33
+ *
34
+ * 🔴 A function and not four strings, because the panel is born hidden and the boot has a gap. `initI18n`
35
+ * applies the fallback language synchronously — so the page is never blank — and then ASKS for en/es, which
36
+ * is asynchronous. Anything the JavaScript builds inside that gap captures the fallback text and nothing
37
+ * rebuilds it; 📏 measured in a browser on 2026-09-08, the icon bar served five labels in English and three
38
+ * still in the fallback, on the same line.
39
+ *
40
+ * 🎯 AND THE PANEL IS THE ONE PLACE WHERE THAT COSTS NOTHING TO FIX. Nobody reads a hidden dialog, so its
41
+ * words only have to be right when it opens — no `localeReady()` wiring per panel, and a language changed
42
+ * mid-game is right on the next open too.
43
+ */
44
+ readonly labels: () => PanelLabels;
45
+ /**
46
+ * The panel's own `render()`.
47
+ *
48
+ * ⚠️ CALLED ON EVERY OPEN, not once at mount. Two reasons, both measured in this tree: a panel that renders
49
+ * once shows a stale state after the child changes the same setting from the quick bar; and
50
+ * `ui/settings-panel.fillExplain` has to run after every render or the prose climbs back inside the rows
51
+ * on the first click — the defect ADR-0129 measured in `settings-visual` and `settings-empathy`.
52
+ */
53
+ readonly render: () => void;
54
+ /**
55
+ * THIS PANEL ALREADY WIRES ITS OWN `#X-close`, so pass its `close()` here instead of letting this file wire
56
+ * a second listener onto the same button.
57
+ *
58
+ * 📏 Measured across the eight on 2026-09-11, and the three-way split is why this field is a function rather
59
+ * than a flag: `settings-typo`, `-motor`, `-controls`, `-visual` and `-audio` have no `close()` at all and
60
+ * need the whole five lines; `settings-aac` and `-empathy` have one AND bind the button themselves at init;
61
+ * `settings-motion` has one and does NOT bind the button, so it takes the default path and its `close()`
62
+ * simply goes unused.
63
+ *
64
+ * ⚠️ AND IT IS THE ESCAPE CHAIN THAT MAKES THIS MATTER, not tidiness. If this file wired its own closer and
65
+ * registered it while the panel's button ran the panel's closer, one control would take two paths to the
66
+ * same job — and the day one of them learns to do something extra, only half the ways out learn it.
67
+ */
68
+ readonly closeOwn?: () => void;
69
+ }
70
+ export interface MountedPanel {
71
+ readonly shell: PanelShell;
72
+ readonly open: () => void;
73
+ readonly close: () => void;
74
+ }
75
+ /**
76
+ * Builds a panel's shell, puts it in the document, and wires open/close/Escape.
77
+ *
78
+ * Idempotent through `mountShell`, which reuses an overlay that already carries the id — so mounting twice
79
+ * leaves one panel, which is what ADR-0139's third gate asks of two cartridges on one page.
80
+ */
81
+ export declare function mountPanel(ctx: MountPanelCtx, spec: MountPanelSpec): MountedPanel;
@@ -0,0 +1,61 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import { applyLabels, mountShell } from './panel-shell.js';
3
+ import { navigableItems } from './menu-items.js';
4
+ /**
5
+ * Builds a panel's shell, puts it in the document, and wires open/close/Escape.
6
+ *
7
+ * Idempotent through `mountShell`, which reuses an overlay that already carries the id — so mounting twice
8
+ * leaves one panel, which is what ADR-0139's third gate asks of two cartridges on one page.
9
+ */
10
+ export function mountPanel(ctx, spec) {
11
+ const panelShell = mountShell(ctx, { id: spec.id, listId: spec.listId, ...spec.labels() });
12
+ // Appending an element that is already a child moves it; it never duplicates. Guarding on `parentNode`
13
+ // would be the same operation written twice.
14
+ ctx.host.appendChild(panelShell.overlay);
15
+ const closePanel = spec.closeOwn ?? (() => {
16
+ panelShell.overlay.hidden = true;
17
+ ctx.overlays.restoreFocus?.(spec.id);
18
+ });
19
+ // 🔴 NO NUMBERING (ADR-0167): the stops drew their index here, renumbered by an observer on every render; the place is
20
+ // now only spoken, after the name, by the navigation.
21
+ const openPanel = () => {
22
+ // ⚠️ THE LABELS BEFORE `render()`, and the order has a consequence: `ui/settings-panel.fillExplain` reads the card's
23
+ // `data-explain-idle` to build the footer, and each panel's render is what calls it.
24
+ applyLabels(panelShell, spec.labels());
25
+ spec.render();
26
+ panelShell.overlay.hidden = false;
27
+ ctx.overlays.frontOverlay(panelShell.overlay);
28
+ panelShell.close.focus?.();
29
+ };
30
+ /*
31
+ * A LANGUAGE CHANGED WITH THE PANEL OPEN REDRAWS IT, AND THE CHILD STAYS WHERE THEY WERE (ADR-0031). 📏 Measured: with
32
+ * the panel open, `setLocale` left every word of it in the old language until it was closed and reopened.
33
+ * 📌 Focus is kept by PLACE: the control itself when the render left it in the document, else the stop at the same
34
+ * position — `render()` rebuilds rows by `innerHTML`, and a redraw that drops focus on «Voltar» loses the child's place.
35
+ * A hidden panel does nothing: its words are resolved when it opens.
36
+ */
37
+ ctx.localeOn(() => {
38
+ if (panelShell.overlay.hidden)
39
+ return;
40
+ const doc = panelShell.card.ownerDocument;
41
+ const focused = doc.activeElement;
42
+ const focusedIndex = focused && panelShell.card.contains(focused) ? navigableItems(panelShell.card).indexOf(focused) : -1;
43
+ applyLabels(panelShell, spec.labels());
44
+ spec.render();
45
+ if (focusedIndex < 0 || !focused)
46
+ return;
47
+ const destino = focused.isConnected ? focused : navigableItems(panelShell.card)[focusedIndex];
48
+ if (destino && destino !== doc.activeElement)
49
+ destino.focus();
50
+ });
51
+ // Only when the panel does NOT wire its own button. See `closeOwn`: two listeners on the same control are two owners of
52
+ // the same exit, and that is how exits drift.
53
+ if (!spec.closeOwn)
54
+ panelShell.close.addEventListener('click', closePanel);
55
+ // ⚠️ THE ESCAPE CHAIN IS NOT DECORATION. `ui/settings-panel.escapeTarget()` walks the registry, and under
56
+ // `createGame` that registry was EMPTY — nothing had ever registered. A modal dialog no key closes is the
57
+ // trap ADR-0044 §2 names about the pause itself: «a menu you cannot leave is a trap, and the trap costs
58
+ // most to whoever cannot see it».
59
+ ctx.overlays.register(spec.id, { close: closePanel, inEscapeChain: true });
60
+ return { shell: panelShell, open: openPanel, close: closePanel };
61
+ }
@@ -1,53 +1,87 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- /** As três coisas do `document` de que a casca precisa. Mesma forma de `ui/loop-crash`. */
2
+ /** The things from `document` the shell needs. The same shape as `ui/loop-crash`. */
3
3
  export interface PanelShellCtx {
4
- /** `document.querySelector`, injetado — a casca nunca alcança o `document` global. */
5
- procurar: (sel: string) => HTMLElement | null;
6
- /** `document.createElement`, injetado. */
7
- criar: (tag: string) => HTMLElement;
4
+ /** `document.querySelector`, injected — the shell never reaches the global `document`. */
5
+ find: (sel: string) => HTMLElement | null;
6
+ /** `document.createElement`, injected. */
7
+ create: (tag: string) => HTMLElement;
8
8
  }
9
9
  export interface PanelShellSpec {
10
- /** O id do painel: `typo`, `audio`, `visual`… Gera `#X`, `#X-title`, `#X-list`, `#X-reset`, `#X-close`. */
10
+ /** The panel's id: `typo`, `audio`, `visual`… It produces `#X`, `#X-title`, `#X-list`, `#X-reset`, `#X-close`. */
11
11
  id: string;
12
- /** O título, JÁ TRADUZIDO. Vai por `textContent`. */
13
- titulo: string;
14
- /** O `aria-label` da lista, já traduzido — o nome do grupo que a criança ouve ao entrar nele. */
15
- rotuloDaLista: string;
16
- /** Os rótulos dos dois botões, já traduzidos. */
17
- rotuloReset: string;
18
- rotuloFechar: string;
19
12
  /**
20
- * A introdução do painel, já traduzida. Vira o texto de REPOUSO do rodapé, via `data-explain-idle`.
13
+ * The LIST's id, when it is not `${id}-list`.
21
14
  *
22
- * ⚠️ É O ÚNICO CAMINHO QUE ESTA CASCA OFERECE PARA UMA INTRODUÇÃO, e é o ponto da issue #62: não há por
23
- * onde passar um parágrafo de prosa para o topo do cartão. Ausente = o painel não tem introdução, que é
24
- * uma resposta legítima e não uma omissão.
15
+ * 📏 Exactly one panel diverges: `settings-motion` lives in the `#animation` overlay — with `#animation-reset` and
16
+ * `#animation-close`, which match — and reads its list at **`#motion-list`**.
17
+ *
18
+ * ⚠️ AND THE ANSWER IS NOT TO RENAME. The id a `settings-*` reads is a contract with the markup of whoever already uses
19
+ * it. An optional field costs one line and breaks no one; the rename would cost the motion panel to whoever already has
20
+ * markup.
21
+ */
22
+ listId?: string;
23
+ /** The title, ALREADY TRANSLATED. It goes in through `textContent`. */
24
+ title: string;
25
+ /** The list's `aria-label`, already translated — the group name the child hears on entering it. */
26
+ listLabel: string;
27
+ /** The two buttons' labels, already translated. `closeLabel` is the word for BACK (item 1, ADR-0158). */
28
+ resetLabel: string;
29
+ closeLabel: string;
30
+ /**
31
+ * The panel's introduction, already translated. It becomes the footer's RESTING text, via `data-explain-idle`.
32
+ *
33
+ * ⚠️ IT IS THE ONLY PATH THIS SHELL OFFERS FOR AN INTRODUCTION, which is the point of issue #62: there is no way to
34
+ * pass a paragraph of prose to the top of the card. Absent = the panel has no introduction, which is a legitimate
35
+ * answer and not an omission.
25
36
  */
26
- introducao?: string;
37
+ intro?: string;
27
38
  }
28
- /** O que a casca devolve: o nó e os ids que ela criou, para o painel não os adivinhar. */
39
+ /**
40
+ * THE SHELL'S WORDS, without the id — everything that changes when the language changes, and nothing that does not.
41
+ *
42
+ * ⚠️ SEPARATE FROM THE `id` ON PURPOSE, the separation `ui/mount-panel` needs: the id is identity and resolves once; the
43
+ * labels are TRANSLATED TEXT and resolve on every open. A type joining them would make whoever retranslates repeat the
44
+ * id, and repeating an identity is how it drifts.
45
+ */
46
+ export type PanelLabels = Omit<PanelShellSpec, 'id'>;
47
+ /** What the shell returns: the node and the ids it created, so the panel does not guess them. */
29
48
  export interface PanelShell {
30
49
  overlay: HTMLElement;
31
50
  card: HTMLElement;
32
- lista: HTMLElement;
51
+ /** The card's `<h2>`. Exposed because whoever retranslates the panel writes into it — see `applyLabels`. */
52
+ title: HTMLElement;
53
+ list: HTMLElement;
33
54
  reset: HTMLElement;
34
- fechar: HTMLElement;
35
- /** Os cinco selectores que este painel passa a garantir. É o contrato, agora dito em vez de descoberto. */
55
+ close: HTMLElement;
56
+ /** The five selectors this panel guarantees. It is the contract, stated instead of discovered. */
36
57
  ids: {
37
58
  overlay: string;
38
59
  title: string;
39
- lista: string;
60
+ list: string;
40
61
  reset: string;
41
- fechar: string;
62
+ close: string;
42
63
  };
43
64
  }
44
- /** Os ids que um painel de `id` ocupa. Exportado porque um gate e um consumidor precisam de os nomear. */
45
- export declare function idsDaCasca(id: string): PanelShell['ids'];
65
+ /** The ids a panel of `id` occupies. Exported because a gate and a consumer need to name them. */
66
+ export declare function shellIds(id: string, customListId?: string): PanelShell['ids'];
67
+ /**
68
+ * Mounts (or reuses) the shell of panel `spec.id` and returns its parts.
69
+ *
70
+ * IDEMPOTENT: if a `#id` already exists, it is reused and the card's content is rebuilt. A panel mounted twice cannot
71
+ * end up with two veils — and it can be mounted more than once (two cartridges on one page, ADR-0139).
72
+ */
73
+ export declare function mountShell(ctx: PanelShellCtx, spec: PanelShellSpec): PanelShell;
46
74
  /**
47
- * Monta (ou reaproveita) a casca do painel `spec.id` e devolve as suas partes.
75
+ * WRITES THE SHELL'S WORDS — separate from construction because they change AFTER it exists.
76
+ *
77
+ * 🔴 `initI18n` applies the fallback language synchronously — so the page is never blank — and, if the preferred
78
+ * language is another, REQUESTS the switch, which is asynchronous. Anything JavaScript builds in that gap captures the
79
+ * fallback text and nothing rebuilds it; and the language can also change mid-game.
80
+ *
81
+ * ⚠️ AND REBUILDING THE SHELL TO FIX THE TITLE DOES NOT WORK. `mountShell` empties the card, and each `ui/settings-*`
82
+ * wires its `#X-reset` ONCE, at `init` — remounting leaves the reset button in the document with no listener, a dead
83
+ * button that looks alive (ADR-0106 §5). Writing only the words touches no listener.
48
84
  *
49
- * IDEMPOTENTE: se já existir um `#id`, ele é reutilizado e o conteúdo do cartão é reconstruído. Um painel que
50
- * a raiz monte duas vezes não pode acabar com dois véus — e a raiz monta mais do que uma vez, porque a
51
- * contagem de jogadores muda a grade de telas.
85
+ * IDEMPOTENT: writing the same labels twice is writing the same labels.
52
86
  */
53
- export declare function montarCasca(ctx: PanelShellCtx, spec: PanelShellSpec): PanelShell;
87
+ export declare function applyLabels(shell: PanelShell, r: PanelLabels): void;