@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
@@ -1,100 +1,153 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- /** As quatorze posições que a engine conhece. Nenhuma delas é uma palavra que uma criança leia. */
2
+ /** The fourteen positions the engine knows. None of them is a word a child reads. */
3
3
  export declare const ACTIONS: readonly ["up", "down", "left", "right", "action1", "action2", "action3", "action4", "leftShoulder", "leftTrigger", "rightShoulder", "rightTrigger", "start", "select"];
4
4
  export type Action = (typeof ACTIONS)[number];
5
- /** As quatro direções, que todo transporte tem de alcançar. */
5
+ /** The four directions, which every transport has to reach. */
6
6
  export declare const DIRECTIONS: readonly ["up", "down", "left", "right"];
7
7
  /**
8
- * Os oito verbos, em DUAS metades que se nomeiam por critérios diferentes, e isso é decisão e não descuido:
8
+ * The eight verbs, in TWO halves named by different criteria, and that is a decision, not carelessness:
9
9
  *
10
- * · `action1`..`action4` — o losango. NUMERADOS, porque quatro posições em cruz não têm nomes que
11
- * atravessem gêneros: o que uma plataforma chama de pulo, um quiz chama de confirmar.
12
- * · `leftShoulder`, `leftTrigger`, `rightShoulder`, `rightTrigger` — NOMEADOS pela anatomia da mão: dois
13
- * dedos por mão, um por cima do outro. ADR-0086.
10
+ * · `action1`..`action4` — the diamond. NUMBERED, because four positions in a cross have no names that cross genres:
11
+ * what a platformer calls jump, a quiz calls confirm.
12
+ * · `leftShoulder`, `leftTrigger`, `rightShoulder`, `rightTrigger` — NAMED by the hand's anatomy: two fingers per
13
+ * hand, one above the other. ADR-0086.
14
14
  *
15
- * ⚠️ NÃO HÁ HIERARQUIA ENTRE ELES no contrato. A ordem é a de apresentação — no assistente do gamepad, na
16
- * tela de remapeamento — e não uma escala de importância: um jogo pode usar `rightShoulder` e nenhuma outra.
15
+ * ⚠️ THERE IS NO HIERARCHY BETWEEN THEM in the contract. The order is that of presentation — in the gamepad wizard, on
16
+ * the remap screen — and not a scale of importance: a game may use `rightShoulder` and nothing else.
17
17
  */
18
18
  export declare const VERBS: readonly ["action1", "action2", "action3", "action4", "leftShoulder", "leftTrigger", "rightShoulder", "rightTrigger"];
19
19
  /**
20
- * As duas de SISTEMA. Não pertencem ao mundo do jogo: `start` pausa e retoma, `select` abre o que é da sessão.
20
+ * The two SYSTEM ones. They do not belong to the game's world: `start` pauses and resumes, `select` opens what belongs
21
+ * to the session.
21
22
  *
22
- * ⚠️ E É POR ISSO QUE A ENGINE PODE NOMEÁ-LAS e não pode nomear as outras. O ADR-0074 proíbe um nome abstrato
23
- * chegar a uma pessoa porque `action1` não diz nada a ninguém — mas «start» e «select» são o que está escrito
24
- * no próprio controle desde 1983, e a criança lê a legenda antes de ler a nossa.
23
+ * ⚠️ AND THAT IS WHY THE ENGINE MAY NAME THEM and may not name the others. ADR-0074 forbids an abstract name reaching a
24
+ * person because `action1` says nothing to anyone — but "start" and "select" are what has been printed on the pad
25
+ * itself since 1983, and the child reads that legend before ours.
25
26
  */
26
27
  export declare const SYSTEM: readonly ["start", "select"];
27
- /** O que a criança lê e ouve para uma posição: o nome, e a frase que o explica quando ela pergunta. */
28
+ /**
29
+ * What the child reads and hears for a position: the name, and the sentence that explains it when they ask — RESOLVED, in
30
+ * the page's language. The engine builds these from the game's KEYS (`wordsOf`) each time it draws; a game declares keys.
31
+ */
28
32
  export interface ActionWord {
29
- /** «Pular», «Confirmar», «Colocar peça». NUNCA `action2` — nome abstrato que chega a uma pessoa é defeito. */
33
+ /** "Jump", "Confirm", "Place piece". NEVER `action2` — an abstract name reaching a person is a defect. */
30
34
  readonly label: string;
31
35
  /**
32
- * A versão CURTA, para onde não cabe a longa. Cai em `label` quando ausente.
36
+ * The SHORT version, for where the long one does not fit. Falls back to `label` when absent.
33
37
  *
34
- * ⚠️ NÃO É PREFERÊNCIA DE ESTILO: É LARGURA MEDIDA. A legenda do título põe a palavra debaixo de um glifo,
35
- * numa fileira de quatro, e `ui/shell` já trazia a nota de que ali não cabe o «Correr / interagir» que a
36
- * lista de remapeamento usa — por isso o dicionário tinha DUAS famílias de chaves para as mesmas quatro
37
- * ações, `act.*` e `legend.*`. A distinção é do jogo, não da engine, então atravessa com as palavras.
38
+ * ⚠️ NOT A STYLE PREFERENCE: MEASURED WIDTH. A legend puts the word under a glyph, in a row of four, where the longer
39
+ * remap-screen wording does not fit — which is why the dictionary once had TWO families of keys for the same four
40
+ * actions. The distinction is the game's, not the engine's, so it crosses with the words.
38
41
  *
39
- * ⚠️ E O RECUO PARA `label` DEGRADA VISUALMENTE, não funcionalmente: um jogo que não declare `short` vê a
40
- * palavra longa espremida, e não uma legenda vazia. Escolhido assim porque uma legenda muda é pior do que
41
- * uma legenda apertada — a primeira some para quem usa leitor de tela, a segunda não.
42
+ * ⚠️ AND THE FALLBACK TO `label` DEGRADES VISUALLY, not functionally: a game that declares no `short` gets the long
43
+ * word squeezed, not an empty legend. Chosen because a mute legend is worse than a tight one — the first vanishes for
44
+ * a screen reader user, the second does not.
42
45
  */
43
46
  readonly short?: string;
44
- /** Opcional, para a tela de remapeamento: o que este botão faz, numa frase. */
47
+ /** Optional, for the remap screen: what this button does, in one sentence. */
45
48
  readonly hint?: string;
46
49
  }
47
50
  /**
48
- * O vocabulário de UM jogo: para cada posição que ele usa, a palavra dele.
51
+ * What a game DECLARES for a position: the KEYS of its words in its own dictionary (`CreateGameOptions.dictionaries`).
52
+ *
53
+ * 🔴 KEYS AND NOT WORDS (ADR-0232 D3, erratum of 2026-09-25). A word handed over at boot is in the boot language forever:
54
+ * 📏 measured, a preset built with `t` in Portuguese still read «Acima» after `setLocale('en')`. A key is resolved by the
55
+ * root's translator each time the engine draws or speaks it, so changing the language changes every word at once
56
+ * (ADR-0225), and the game never needs to know how (ADR-0216).
57
+ */
58
+ export interface ActionKeys {
59
+ /** The key of the name: «Jump», «Confirm». A key the game's dictionaries lack leaves the position unnamed, and `problems` says so. */
60
+ readonly labelKey: string;
61
+ /** The key of the SHORT name, for a legend under a glyph. Falls back to the name when absent. */
62
+ readonly shortKey?: string;
63
+ /** The key of the sentence that says what this button does, for the help and the remap screen. */
64
+ readonly hintKey?: string;
65
+ }
66
+ /**
67
+ * The vocabulary of ONE game: for each position it uses, the keys of its words.
68
+ *
69
+ * ⚠️ PARTIAL ON PURPOSE. A game declares ONLY the positions it uses. Requiring all fourteen would make a quiz invent a
70
+ * name for a trigger it does not have, and an invented name ends up on a remap screen in front of a child.
71
+ */
72
+ export type ActionPreset = Partial<Readonly<Record<Action, ActionKeys>>>;
73
+ /** A preset RESOLVED into words, in the page's language — what the engine's surfaces read (`wordsOf`). */
74
+ export type ActionWords = Partial<Readonly<Record<Action, ActionWord>>>;
75
+ /** The positions this preset names, in the canonical order of `ACTIONS`. */
76
+ export declare function presetActions(p: ActionPreset | ActionWords): Action[];
77
+ /**
78
+ * THE GAME'S KEYS, RESOLVED NOW — called at every drawing, never kept (ADR-0232 D3 erratum).
49
79
  *
50
- * ⚠️ PARCIAL DE PROPÓSITO. Um jogo declara SÓ as posições que usa. Exigir as quatorze obrigaria um quiz a
51
- * inventar nome para um gatilho que ele não tem, e um nome inventado acaba numa tela de remapeamento à
52
- * frente de uma criança.
80
+ * A position whose NAME resolves to nothing is left out, so every surface treats it as unnamed — the rule `labellerFrom`
81
+ * already applies: an absence is one step fewer, never a mute step, and never the key itself on screen.
53
82
  */
54
- export type ActionPreset = Partial<Readonly<Record<Action, ActionWord>>>;
55
- /** As posições que este preset nomeia, na ordem canônica de `ACTIONS`. */
56
- export declare function presetActions(p: ActionPreset): Action[];
83
+ export declare function wordsOf(p: ActionPreset, word: (key: string) => string | null): ActionWords;
57
84
  /**
58
- * A pergunta que a engine faz ao jogo quando precisa MOSTRAR uma ação: «como é que isto se chama?».
85
+ * The question the engine asks the game when it has to SHOW an action: "what is this called?".
59
86
  *
60
- * É a fronteira do corte em forma de função. A engine sabe que existe uma posição; só o jogo sabe a palavra,
61
- * e é esta função que atravessa.
87
+ * It is the cut's boundary in the shape of a function. The engine knows a position exists; only the game knows the
88
+ * word, and this function is what crosses.
62
89
  */
63
90
  export type ActionLabeller = (a: Action) => string;
64
91
  /**
65
- * Constrói o tradutor a partir de um preset.
92
+ * Builds the translator from a preset.
66
93
  *
67
- * ⚠️ E O QUE ELE FAZ COM UMA AÇÃO SEM NOME É A DECISÃO INTEIRA. Devolver `action7` seria pôr um nome abstrato
68
- * à frente de uma criança, que o ADR-0074 chama de defeito em tantas palavras. Devolver vazio calaria o leitor
69
- * de tela, que é o defeito silencioso que `speakableProblems` já persegue noutro sítio.
94
+ * ⚠️ AND WHAT IT DOES WITH AN UNNAMED ACTION IS THE WHOLE DECISION. Returning `action7` would put an abstract name in
95
+ * front of a child, which ADR-0074 calls a defect in so many words. Returning empty would silence the screen reader,
96
+ * the silent defect `speakableProblems` already chases elsewhere.
70
97
  *
71
- * Devolve `null`, e quem chama decide: o assistente de controle NÃO PERGUNTA por uma ação que o jogo não
72
- * nomeia — se o jogo não a usa, não há o que mapear. Uma ausência vira menos um passo, nunca um passo mudo.
98
+ * It returns `null`, and the caller decides: the pad wizard DOES NOT ASK for an action the game does not name — if the
99
+ * game does not use it, there is nothing to map. An absence becomes one step fewer, never a mute step. (`SYSTEM` is the
100
+ * exception there: the wizard asks START and SELECT in its own words, since no preset may name them — ADR-0144 erratum.)
73
101
  */
74
- export declare function labellerFrom(p: ActionPreset): (a: Action) => string | null;
102
+ export declare function labellerFrom(p: ActionWords): (a: Action) => string | null;
75
103
  /**
76
- * O mesmo, na versão CURTA — para a legenda do título, onde a palavra vive debaixo de um glifo.
104
+ * The same, in the SHORT version — for a legend, where the word lives under a glyph.
77
105
  *
78
- * ⚠️ RECUA PARA `label`, e o recuo é a decisão: uma legenda apertada é pior que uma bonita e melhor que uma
79
- * vazia. Vazia sumiria também para quem usa leitor de tela, que é o custo que não se aceita aqui.
106
+ * ⚠️ IT FALLS BACK TO `label`, and the fallback is the decision: a tight legend is worse than a neat one and better than
107
+ * an empty one. Empty would also vanish for a screen reader user, which is the cost not accepted here.
80
108
  */
81
- export declare function shortLabellerFrom(p: ActionPreset): (a: Action) => string | null;
109
+ export declare function shortLabellerFrom(p: ActionWords): (a: Action) => string | null;
82
110
  /**
83
- * Um preset é bem-formado? Devolve os problemas — VAZIA quer dizer conforme.
111
+ * Is a preset well formed? Returns the problems — EMPTY means conformant.
84
112
  *
85
- * ⚠️ O QUE ELE APANHA É O RÓTULO VAZIO, e é o mesmo defeito silencioso de `speakableProblems` em
86
- * `core/contract`: um `label` em branco não quebra nada, não avisa ninguém, e deixa a tela de remapeamento
87
- * com uma linha muda — que para quem usa leitor de tela é um botão que existe e não tem nome.
113
+ * ⚠️ WHAT IT CATCHES IS THE EMPTY KEY, the same silent defect as `speakableProblems` in `core/contract`: a blank
114
+ * `labelKey` breaks nothing, warns nobody, and leaves the remap screen with a mute row — for a screen reader user, a button
115
+ * that exists and has no name. Whether the key is IN the game's dictionaries is the root's question (`ui/declared-words`).
88
116
  */
89
117
  export declare function presetProblems(p: ActionPreset | null | undefined): string[];
90
- /** É uma ação conhecida? Guarda de fronteira para dado que veio de fora (mapa salvo, remapeamento). */
118
+ /**
119
+ * `start` IS THE PAUSE'S, AND A GAME DOES NOT TAKE IT (ADR-0144 §4). Returns the reason, or `null`.
120
+ *
121
+ * ⚠️ THIS IS THE ONE CLAUSE OF THAT RECORD THAT ADDS A RESTRICTION instead of reusing something that was
122
+ * already there, and it is written down — rather than discovered in a conflict — because the record asked
123
+ * for exactly that. Since ADR-0122 the pause is not declinable, and `start` is the only position that
124
+ * reaches it: a game that claimed it for something else would be declining the pause by the back door, and
125
+ * the child would get four settings panels that are mounted, in the document, and unreachable.
126
+ *
127
+ * 📌 SEPARATE FROM `presetProblems`, and on purpose. That one answers «is this preset well formed?» and
128
+ * nobody calls it yet (issue for the wiring); this one is a PRE-CONDITION the boot refuses on, which is a
129
+ * different rubric — a malformed label degrades a remap screen, a stolen `start` removes the pause.
130
+ *
131
+ * 📌 `select` has its own sibling below, since ADR-0155 made it the door to the pause menus. Until then it stayed
132
+ * free on purpose: refusing it would have been deciding, in advance, something nobody had decided.
133
+ */
134
+ export declare function startClaimProblem(p: ActionPreset | null | undefined): string | null;
135
+ /**
136
+ * `select` OPENS THE PAUSE MENUS, AND A GAME DOES NOT TAKE IT EITHER (ADR-0155 §4). Returns the reason, or `null`.
137
+ *
138
+ * ⚠️ The same argument as `start`, one door over: START is now the quick pause and SELECT the six-item card, so
139
+ * a game claiming `select` would leave quitting, the number of players and the inclusion settings unreachable.
140
+ * 📏 Measured when written: no game repository declares `select` in a preset.
141
+ */
142
+ export declare function selectClaimProblem(p: ActionPreset | null | undefined): string | null;
143
+ /** Is it a known action? A boundary guard for data that came from outside (a saved map, a remap). */
91
144
  export declare function isAction(x: unknown): x is Action;
92
145
  /**
93
- * Uma declaração de ações usadas por um jogo é bem-formada? Devolve os problemas — VAZIA quer dizer conforme.
146
+ * Is a declaration of the actions a game uses well formed? Returns the problems — EMPTY means conformant.
94
147
  *
95
- * ⚠️ EXIGIR AS QUATRO DIREÇÕES SERIA ERRADO, e a tentação é grande: um quiz navega por `up`/`down` e não usa
96
- * `left`/`right`; um jogo de um botão não usa nenhuma. Quem decide o conjunto é o jogo. O que esta função
97
- * confere é que o conjunto é NOMEÁVEL e não está vazio — um jogo sem ação nenhuma não tem como ser jogado, e
98
- * hoje isso falharia em silêncio no primeiro transporte que tentasse ligar-se a nada.
148
+ * ⚠️ REQUIRING THE FOUR DIRECTIONS WOULD BE WRONG, and the temptation is strong: a quiz walks by `up`/`down` and uses
149
+ * no `left`/`right`; a one-button game uses none. The game decides the set. What this checks is that the set is
150
+ * NAMEABLE and not empty — a game with no action cannot be played, and that would otherwise fail in silence in the
151
+ * first transport that tried to bind to nothing.
99
152
  */
100
153
  export declare function actionSetProblems(used: readonly string[] | null | undefined): string[];
@@ -1,79 +1,95 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- // core/actions — AS QUATORZE AÇÕES ABSTRATAS. A fonte única do vocabulário de entrada da engine.
2
+ // core/actions — THE FOURTEEN ABSTRACT ACTIONS. The single source of the engine's input vocabulary.
3
3
  //
4
- // ========================= O QUE ISTO É =========================
5
- // O ADR-0074 decidiu que a engine conhece POSIÇÕES, não verbos, e que o JOGO fornece as palavras. Este módulo
6
- // é a lista dessas posições e nada mais: zero dependências, zero I/O, importável dos dois lados da fronteira.
4
+ // ========================= WHAT THIS IS =========================
5
+ // ADR-0074 decided that the engine knows POSITIONS, not verbs, and that the GAME supplies the words. This module is
6
+ // the list of those positions and nothing else: no dependencies, no I/O, importable from both sides of the boundary.
7
+ // It was written before the transports migrated to it (issue #103), so the migration had a destination instead of
8
+ // inventing one.
7
9
  //
8
- // ⚠️ ATÉ AQUI A LISTA SÓ EXISTIA NUM REGISTRO. O código continua com os oito nomes de plataforma
9
- // (`jump`, `run`, `swap`, `especial`) espalhados por `input/gamepad`, `input/edges`, `input/devices` e
10
- // `input/keydown` — a migração é a issue #103 e não aconteceu. Este módulo é o alvo dela: um sítio para onde
11
- // os transportes passam a apontar, escrito antes para que a migração tenha destino em vez de o inventar.
10
+ // ========================= WHY FOURTEEN AND NOT NINE =========================
11
+ // ADR-0074 recorded nine and wrote, among its own drawbacks, that nine is a CEILING a genre may want to exceed and
12
+ // that the record must say what happens then. The Dev exceeded it, asking for five more for richer games.
12
13
  //
13
- // ========================= POR QUE QUATORZE E NÃO NOVE =========================
14
- // O ADR-0074 registrou nove e escreveu, entre as suas próprias desvantagens, que «nove é um TETO que um gênero
15
- // pode querer exceder, e o registro tem de dizer o que acontece». O Dev excedeu-o em 2026-09-06, pedindo mais
16
- // cinco para jogos mais elaborados. O ADR-0085 é o que acontece.
14
+ // ⚠️ AND THE FOUR NEW ONES ARE `leftShoulder`, `leftTrigger`, `rightShoulder`, `rightTrigger` — NOT
15
+ // `action5`..`action8`. I argued for numbers and the Dev decided against, for a reason ADR-0086 records: `action7` is
16
+ // unreadable where someone programs, and a vocabulary nobody can read aloud is not abstraction, it is cipher.
17
17
  //
18
- // ⚠️ E OS QUATRO NOVOS CHAMAM-SE `leftShoulder`, `leftTrigger`, `rightShoulder`, `rightTrigger` — NÃO
19
- // `action5`..`action8`. Eu argumentei pelos números e o Dev decidiu contra, em 2026-09-06, com uma razão que
20
- // o ADR-0086 registra: `action7` é ilegível no ponto onde alguém programa, e um vocabulário que ninguém
21
- // consegue ler em voz alta não é abstração, é cifra. O ADR-0085 dizia o contrário; foi supersedido, não
22
- // emendado.
18
+ // ⚠️ AND THE OBJECTION STAYS WRITTEN, because it does not vanish when the decision went the other way: shoulder and
19
+ // trigger are a GAMEPAD's shape. On a keyboard `leftTrigger` is a key; on touch, a slot; for a speech recogniser, a
20
+ // word. ADR-0086 answers that the shape is ANATOMICAL before it is a gamepad's — two fingers per hand, one above the
21
+ // other — and that this crosses transports better than a number does. Whoever disagrees should read both records.
23
22
  //
24
- // ⚠️ E A OBJEÇÃO CONTINUA ESCRITA, porque ela não some por a decisão ter sido outra: ombro e gatilho são
25
- // FORMA DE GAMEPAD. Num teclado, `leftTrigger` é a tecla Y; num toque, um slot; num reconhecedor de fala, uma
26
- // palavra. O ADR-0086 responde que a forma é ANATÔMICA antes de ser de gamepad — dois dedos por mão, um por
27
- // cima do outro — e que isso atravessa transportes melhor do que um número atravessa. Quem discordar leia os
28
- // dois registros, que é para isso que eles existem.
29
- //
30
- // `start` e `select` mantêm nome pelo critério que já valia para `start`: são FUNÇÃO, não posição — o que é
31
- // do sistema e não do mundo do jogo.
32
- /** As quatorze posições que a engine conhece. Nenhuma delas é uma palavra que uma criança leia. */
23
+ // `start` and `select` keep names by the criterion that already held for `start`: they are a FUNCTION, not a
24
+ // position — what belongs to the system and not to the game's world.
25
+ /** The fourteen positions the engine knows. None of them is a word a child reads. */
33
26
  export const ACTIONS = [
34
27
  'up', 'down', 'left', 'right',
35
28
  'action1', 'action2', 'action3', 'action4',
36
29
  'leftShoulder', 'leftTrigger', 'rightShoulder', 'rightTrigger',
37
30
  'start', 'select',
38
31
  ];
39
- /** As quatro direções, que todo transporte tem de alcançar. */
32
+ /** The four directions, which every transport has to reach. */
40
33
  export const DIRECTIONS = ['up', 'down', 'left', 'right'];
41
34
  /**
42
- * Os oito verbos, em DUAS metades que se nomeiam por critérios diferentes, e isso é decisão e não descuido:
35
+ * The eight verbs, in TWO halves named by different criteria, and that is a decision, not carelessness:
43
36
  *
44
- * · `action1`..`action4` — o losango. NUMERADOS, porque quatro posições em cruz não têm nomes que
45
- * atravessem gêneros: o que uma plataforma chama de pulo, um quiz chama de confirmar.
46
- * · `leftShoulder`, `leftTrigger`, `rightShoulder`, `rightTrigger` — NOMEADOS pela anatomia da mão: dois
47
- * dedos por mão, um por cima do outro. ADR-0086.
37
+ * · `action1`..`action4` — the diamond. NUMBERED, because four positions in a cross have no names that cross genres:
38
+ * what a platformer calls jump, a quiz calls confirm.
39
+ * · `leftShoulder`, `leftTrigger`, `rightShoulder`, `rightTrigger` — NAMED by the hand's anatomy: two fingers per
40
+ * hand, one above the other. ADR-0086.
48
41
  *
49
- * ⚠️ NÃO HÁ HIERARQUIA ENTRE ELES no contrato. A ordem é a de apresentação — no assistente do gamepad, na
50
- * tela de remapeamento — e não uma escala de importância: um jogo pode usar `rightShoulder` e nenhuma outra.
42
+ * ⚠️ THERE IS NO HIERARCHY BETWEEN THEM in the contract. The order is that of presentation — in the gamepad wizard, on
43
+ * the remap screen — and not a scale of importance: a game may use `rightShoulder` and nothing else.
51
44
  */
52
45
  export const VERBS = [
53
46
  'action1', 'action2', 'action3', 'action4',
54
47
  'leftShoulder', 'leftTrigger', 'rightShoulder', 'rightTrigger',
55
48
  ];
56
49
  /**
57
- * As duas de SISTEMA. Não pertencem ao mundo do jogo: `start` pausa e retoma, `select` abre o que é da sessão.
50
+ * The two SYSTEM ones. They do not belong to the game's world: `start` pauses and resumes, `select` opens what belongs
51
+ * to the session.
58
52
  *
59
- * ⚠️ E É POR ISSO QUE A ENGINE PODE NOMEÁ-LAS e não pode nomear as outras. O ADR-0074 proíbe um nome abstrato
60
- * chegar a uma pessoa porque `action1` não diz nada a ninguém — mas «start» e «select» são o que está escrito
61
- * no próprio controle desde 1983, e a criança lê a legenda antes de ler a nossa.
53
+ * ⚠️ AND THAT IS WHY THE ENGINE MAY NAME THEM and may not name the others. ADR-0074 forbids an abstract name reaching a
54
+ * person because `action1` says nothing to anyone — but "start" and "select" are what has been printed on the pad
55
+ * itself since 1983, and the child reads that legend before ours.
62
56
  */
63
57
  export const SYSTEM = ['start', 'select'];
64
- /** As posições que este preset nomeia, na ordem canônica de `ACTIONS`. */
58
+ /** The positions this preset names, in the canonical order of `ACTIONS`. */
65
59
  export function presetActions(p) {
66
60
  return ACTIONS.filter((a) => p[a] !== undefined);
67
61
  }
62
+ /** Resolves one declared key through `word`; a key that is not text resolves to nothing. */
63
+ const resolved = (word, key) => (typeof key === 'string' && key.trim() ? word(key) : null);
64
+ /**
65
+ * THE GAME'S KEYS, RESOLVED NOW — called at every drawing, never kept (ADR-0232 D3 erratum).
66
+ *
67
+ * A position whose NAME resolves to nothing is left out, so every surface treats it as unnamed — the rule `labellerFrom`
68
+ * already applies: an absence is one step fewer, never a mute step, and never the key itself on screen.
69
+ */
70
+ export function wordsOf(p, word) {
71
+ const words = {};
72
+ for (const a of presetActions(p)) {
73
+ const keys = p[a];
74
+ const label = resolved(word, keys.labelKey);
75
+ if (!label)
76
+ continue;
77
+ const short = resolved(word, keys.shortKey);
78
+ const hint = resolved(word, keys.hintKey);
79
+ words[a] = { label, ...(short ? { short } : {}), ...(hint ? { hint } : {}) };
80
+ }
81
+ return words;
82
+ }
68
83
  /**
69
- * Constrói o tradutor a partir de um preset.
84
+ * Builds the translator from a preset.
70
85
  *
71
- * ⚠️ E O QUE ELE FAZ COM UMA AÇÃO SEM NOME É A DECISÃO INTEIRA. Devolver `action7` seria pôr um nome abstrato
72
- * à frente de uma criança, que o ADR-0074 chama de defeito em tantas palavras. Devolver vazio calaria o leitor
73
- * de tela, que é o defeito silencioso que `speakableProblems` já persegue noutro sítio.
86
+ * ⚠️ AND WHAT IT DOES WITH AN UNNAMED ACTION IS THE WHOLE DECISION. Returning `action7` would put an abstract name in
87
+ * front of a child, which ADR-0074 calls a defect in so many words. Returning empty would silence the screen reader,
88
+ * the silent defect `speakableProblems` already chases elsewhere.
74
89
  *
75
- * Devolve `null`, e quem chama decide: o assistente de controle NÃO PERGUNTA por uma ação que o jogo não
76
- * nomeia — se o jogo não a usa, não há o que mapear. Uma ausência vira menos um passo, nunca um passo mudo.
90
+ * It returns `null`, and the caller decides: the pad wizard DOES NOT ASK for an action the game does not name — if the
91
+ * game does not use it, there is nothing to map. An absence becomes one step fewer, never a mute step. (`SYSTEM` is the
92
+ * exception there: the wizard asks START and SELECT in its own words, since no preset may name them — ADR-0144 erratum.)
77
93
  */
78
94
  export function labellerFrom(p) {
79
95
  return (a) => {
@@ -82,57 +98,92 @@ export function labellerFrom(p) {
82
98
  };
83
99
  }
84
100
  /**
85
- * O mesmo, na versão CURTA — para a legenda do título, onde a palavra vive debaixo de um glifo.
101
+ * The same, in the SHORT version — for a legend, where the word lives under a glyph.
86
102
  *
87
- * ⚠️ RECUA PARA `label`, e o recuo é a decisão: uma legenda apertada é pior que uma bonita e melhor que uma
88
- * vazia. Vazia sumiria também para quem usa leitor de tela, que é o custo que não se aceita aqui.
103
+ * ⚠️ IT FALLS BACK TO `label`, and the fallback is the decision: a tight legend is worse than a neat one and better than
104
+ * an empty one. Empty would also vanish for a screen reader user, which is the cost not accepted here.
89
105
  */
90
106
  export function shortLabellerFrom(p) {
91
107
  return (a) => {
92
108
  const w = p[a];
93
109
  if (!w)
94
110
  return null;
95
- const curto = w.short && w.short.trim() ? w.short : w.label;
96
- return curto && curto.trim() ? curto : null;
111
+ const short = w.short && w.short.trim() ? w.short : w.label;
112
+ return short && short.trim() ? short : null;
97
113
  };
98
114
  }
99
115
  /**
100
- * Um preset é bem-formado? Devolve os problemas — VAZIA quer dizer conforme.
116
+ * Is a preset well formed? Returns the problems — EMPTY means conformant.
101
117
  *
102
- * ⚠️ O QUE ELE APANHA É O RÓTULO VAZIO, e é o mesmo defeito silencioso de `speakableProblems` em
103
- * `core/contract`: um `label` em branco não quebra nada, não avisa ninguém, e deixa a tela de remapeamento
104
- * com uma linha muda — que para quem usa leitor de tela é um botão que existe e não tem nome.
118
+ * ⚠️ WHAT IT CATCHES IS THE EMPTY KEY, the same silent defect as `speakableProblems` in `core/contract`: a blank
119
+ * `labelKey` breaks nothing, warns nobody, and leaves the remap screen with a mute row — for a screen reader user, a button
120
+ * that exists and has no name. Whether the key is IN the game's dictionaries is the root's question (`ui/declared-words`).
105
121
  */
106
122
  export function presetProblems(p) {
107
123
  if (!p)
108
124
  return ['preset: missing'];
109
125
  const problemas = [];
110
- const nomeadas = presetActions(p);
111
- if (nomeadas.length === 0)
126
+ const named = presetActions(p);
127
+ if (named.length === 0)
112
128
  problemas.push('preset: names no action - the child would see an unlabelled control');
113
- for (const chave of Object.keys(p)) {
114
- if (!isAction(chave))
115
- problemas.push(`preset: ${chave} is not an action`);
129
+ for (const key of Object.keys(p)) {
130
+ if (!isAction(key))
131
+ problemas.push(`preset: ${key} is not an action`);
116
132
  }
117
- for (const a of nomeadas) {
133
+ for (const a of named) {
118
134
  const w = p[a];
119
- if (!w || !w.label || !w.label.trim()) {
120
- problemas.push(`preset: ${a} has an empty label - the remap screen would show a nameless button`);
135
+ if (!w || typeof w.labelKey !== 'string' || !w.labelKey.trim()) {
136
+ problemas.push(`preset: ${a} has an empty labelKey - the remap screen would show a nameless button`);
121
137
  }
122
138
  }
123
139
  return problemas;
124
140
  }
125
- /** É uma ação conhecida? Guarda de fronteira para dado que veio de fora (mapa salvo, remapeamento). */
141
+ /**
142
+ * `start` IS THE PAUSE'S, AND A GAME DOES NOT TAKE IT (ADR-0144 §4). Returns the reason, or `null`.
143
+ *
144
+ * ⚠️ THIS IS THE ONE CLAUSE OF THAT RECORD THAT ADDS A RESTRICTION instead of reusing something that was
145
+ * already there, and it is written down — rather than discovered in a conflict — because the record asked
146
+ * for exactly that. Since ADR-0122 the pause is not declinable, and `start` is the only position that
147
+ * reaches it: a game that claimed it for something else would be declining the pause by the back door, and
148
+ * the child would get four settings panels that are mounted, in the document, and unreachable.
149
+ *
150
+ * 📌 SEPARATE FROM `presetProblems`, and on purpose. That one answers «is this preset well formed?» and
151
+ * nobody calls it yet (issue for the wiring); this one is a PRE-CONDITION the boot refuses on, which is a
152
+ * different rubric — a malformed label degrades a remap screen, a stolen `start` removes the pause.
153
+ *
154
+ * 📌 `select` has its own sibling below, since ADR-0155 made it the door to the pause menus. Until then it stayed
155
+ * free on purpose: refusing it would have been deciding, in advance, something nobody had decided.
156
+ */
157
+ export function startClaimProblem(p) {
158
+ if (!p || p.start === undefined)
159
+ return null;
160
+ return 'preset: «start» is the position that opens the pause (ADR-0144 §4) and a game may not claim it; '
161
+ + 'use one of the eight verb positions instead (action1..action4, leftShoulder, leftTrigger, rightShoulder, rightTrigger)';
162
+ }
163
+ /**
164
+ * `select` OPENS THE PAUSE MENUS, AND A GAME DOES NOT TAKE IT EITHER (ADR-0155 §4). Returns the reason, or `null`.
165
+ *
166
+ * ⚠️ The same argument as `start`, one door over: START is now the quick pause and SELECT the six-item card, so
167
+ * a game claiming `select` would leave quitting, the number of players and the inclusion settings unreachable.
168
+ * 📏 Measured when written: no game repository declares `select` in a preset.
169
+ */
170
+ export function selectClaimProblem(p) {
171
+ if (!p || p.select === undefined)
172
+ return null;
173
+ return 'preset: «select» is the position that opens the pause menus (ADR-0155 §4) and a game may not claim it; '
174
+ + 'use one of the eight verb positions instead (action1..action4, leftShoulder, leftTrigger, rightShoulder, rightTrigger)';
175
+ }
176
+ /** Is it a known action? A boundary guard for data that came from outside (a saved map, a remap). */
126
177
  export function isAction(x) {
127
178
  return typeof x === 'string' && ACTIONS.includes(x);
128
179
  }
129
180
  /**
130
- * Uma declaração de ações usadas por um jogo é bem-formada? Devolve os problemas — VAZIA quer dizer conforme.
181
+ * Is a declaration of the actions a game uses well formed? Returns the problems — EMPTY means conformant.
131
182
  *
132
- * ⚠️ EXIGIR AS QUATRO DIREÇÕES SERIA ERRADO, e a tentação é grande: um quiz navega por `up`/`down` e não usa
133
- * `left`/`right`; um jogo de um botão não usa nenhuma. Quem decide o conjunto é o jogo. O que esta função
134
- * confere é que o conjunto é NOMEÁVEL e não está vazio — um jogo sem ação nenhuma não tem como ser jogado, e
135
- * hoje isso falharia em silêncio no primeiro transporte que tentasse ligar-se a nada.
183
+ * ⚠️ REQUIRING THE FOUR DIRECTIONS WOULD BE WRONG, and the temptation is strong: a quiz walks by `up`/`down` and uses
184
+ * no `left`/`right`; a one-button game uses none. The game decides the set. What this checks is that the set is
185
+ * NAMEABLE and not empty — a game with no action cannot be played, and that would otherwise fail in silence in the
186
+ * first transport that tried to bind to nothing.
136
187
  */
137
188
  export function actionSetProblems(used) {
138
189
  const p = [];
@@ -140,9 +191,9 @@ export function actionSetProblems(used) {
140
191
  return ['action set: missing'];
141
192
  if (used.length === 0)
142
193
  return ['action set: empty - a game with no action cannot be played'];
143
- const desconhecidas = used.filter((a) => !isAction(a));
144
- if (desconhecidas.length)
145
- p.push(`action set: unknown action(s) ${desconhecidas.join(', ')}`);
194
+ const unknown = used.filter((a) => !isAction(a));
195
+ if (unknown.length)
196
+ p.push(`action set: unknown action(s) ${unknown.join(', ')}`);
146
197
  if (new Set(used).size !== used.length)
147
198
  p.push('action set: has a repeated action');
148
199
  return p;
@@ -0,0 +1,31 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ /** The calm cycle: 0 = normal · 1 = quiet (reduces) · 2 = silent (switches off). */
3
+ export declare const CALM_NAMES: readonly string[];
4
+ /** The audio categories calm mode governs. The others are left intact on purpose (see the header). */
5
+ export declare const CALM_AUDIO_CATS: readonly string[];
6
+ /** One step of the cycle. */
7
+ export declare const nextCalmMode: (cur: number) => number;
8
+ /**
9
+ * The stored level, sanitised, with the caller's fallback.
10
+ *
11
+ * ⚠️ Data from the browser is data from OUTSIDE: an invented level would pick `CALM_NAMES[3]`, which is `undefined`, and the
12
+ * announcement to the screen reader would come out empty — the child who depends on it would hear silence and not know which
13
+ * level she is in.
14
+ */
15
+ export declare function sanitiseTeaLevel(raw: number, fallback: number): number;
16
+ /**
17
+ * What the level does to ONE audio category.
18
+ *
19
+ * 📌 The clamp of level 1 is DESTRUCTIVE, and it is in plain sight for that reason: it writes 0.3 over the volume the child
20
+ * chose, and going back to level 0 returns the stored value, not the one she had before. Extracted so that this can be
21
+ * measured by a case.
22
+ */
23
+ export declare function calmAudioPlan(calmMode: number, vol: number): {
24
+ on: boolean;
25
+ vol: number;
26
+ };
27
+ /** What the level does to the two reduced-motion flags. */
28
+ export declare function calmMotionPlan(calmMode: number): {
29
+ sceneReduced: boolean;
30
+ charFrozen: boolean;
31
+ };
@@ -0,0 +1,47 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // core/calm-mode — SENSORY COMFORT IN THREE LEVELS, and what each one silences (ADR-0028; issue #203).
3
+ //
4
+ // 🔴 WHY THIS LEFT `ui/pause-icons`: that module had reached 695 lines of code and 127 decision nodes (ADR-0221), and this
5
+ // group is not about ICONS. It is about what a child who cannot bear noise needs the engine to silence — the icon is one of
6
+ // the surfaces she asks through; the panel row is another. A module that answers «what does level 2 do to the audio?» should
7
+ // not require reading a file about the accessibility bar to be found.
8
+ //
9
+ // ⚠️ A LEAF MODULE: zero imports, zero DOM, zero storage. Everything here is a question with an answer — which is what makes
10
+ // the destructive clamp of level 1 testable without mounting anything.
11
+ //
12
+ // 📌 WHAT IT NEVER TOUCHES, and it is the decision that defines it: TTS, sonar, ledge guard and guide. The calm level is about
13
+ // NOISE, not about losing navigation — a child in silent mode still needs to hear where she is.
14
+ /** The calm cycle: 0 = normal · 1 = quiet (reduces) · 2 = silent (switches off). */
15
+ export const CALM_NAMES = ['calm.off', 'calm.quiet', 'calm.silent'];
16
+ /** The audio categories calm mode governs. The others are left intact on purpose (see the header). */
17
+ export const CALM_AUDIO_CATS = ['ambient', 'music', 'earcons', 'interact'];
18
+ /** One step of the cycle. */
19
+ export const nextCalmMode = (cur) => (cur + 1) % CALM_NAMES.length;
20
+ /**
21
+ * The stored level, sanitised, with the caller's fallback.
22
+ *
23
+ * ⚠️ Data from the browser is data from OUTSIDE: an invented level would pick `CALM_NAMES[3]`, which is `undefined`, and the
24
+ * announcement to the screen reader would come out empty — the child who depends on it would hear silence and not know which
25
+ * level she is in.
26
+ */
27
+ export function sanitiseTeaLevel(raw, fallback) {
28
+ return Number.isInteger(raw) && raw >= 0 && raw < CALM_NAMES.length ? raw : fallback;
29
+ }
30
+ /**
31
+ * What the level does to ONE audio category.
32
+ *
33
+ * 📌 The clamp of level 1 is DESTRUCTIVE, and it is in plain sight for that reason: it writes 0.3 over the volume the child
34
+ * chose, and going back to level 0 returns the stored value, not the one she had before. Extracted so that this can be
35
+ * measured by a case.
36
+ */
37
+ export function calmAudioPlan(calmMode, vol) {
38
+ if (calmMode === 0)
39
+ return { on: true, vol };
40
+ if (calmMode === 1)
41
+ return { on: true, vol: Math.min(vol, 0.3) };
42
+ return { on: false, vol };
43
+ }
44
+ /** What the level does to the two reduced-motion flags. */
45
+ export function calmMotionPlan(calmMode) {
46
+ return { sceneReduced: calmMode >= 1, charFrozen: calmMode === 2 };
47
+ }