@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,5 +1,6 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- type CatState = {
2
+ import { type AudioCatStore } from './audio-mixer.js';
3
+ export type CatState = {
3
4
  on: boolean;
4
5
  vol: number;
5
6
  };
@@ -10,23 +11,65 @@ type PlayerCtx = {
10
11
  type ACWithCache = AudioContext & {
11
12
  _noiseBuf?: AudioBuffer;
12
13
  };
13
- export declare let soundOn: boolean;
14
- export declare function setSoundOn(v: boolean): void;
15
- export declare let volume: number;
16
- export declare function setVolume(v: number): void;
17
- export declare let audioCtx: AudioContext | null;
18
- export declare function ensureAC(): AudioContext | null;
19
- export declare let hearingLoss: boolean;
20
- export declare function audioOut(): GainNode | null;
21
- export declare function setHearingLossGraph(on: boolean): void;
22
- export declare function setMasterMuted(muted: boolean): void;
23
- export declare let audioCat: Record<string, CatState> | null;
24
- export declare function initAudioMixer(): void;
25
- export declare function catNode(cat: string): GainNode | null;
26
- export declare function setCatGain(cat: string): void;
27
- export declare function tone(freq: number, dur: number, type?: OscillatorType, when?: number, vol?: number): void;
28
- export declare function tonePan(freq: number, dur: number, cat: string, pan?: number | null, vol?: number, type?: OscillatorType, pc?: PlayerCtx | null): void;
29
- export declare let _footCount: number;
14
+ export interface AudioDeps {
15
+ /**
16
+ * Makes the engine's AudioContext, or answers `null` where the host has none. Called at the FIRST sound and not before: a
17
+ * context made before the child's first gesture is born suspended, and the browser only lets it run from a gesture. The root
18
+ * builds it from `host.win` (ADR-0232 point 2); REQUIRED, because a default would be the page's window reached from here.
19
+ */
20
+ readonly newContext: () => AudioContext | null;
21
+ /** Where the mixer's categories are read from and kept: the page's store, built by the root. */
22
+ readonly store: AudioCatStore;
23
+ }
24
+ /**
25
+ * ONE ROOT'S SOUND. The reads are GETTERS, so `audio.soundOn` is the value of now; copying one into a local freezes it. The
26
+ * methods hold no `this` and can be destructured.
27
+ */
28
+ export interface Audio {
29
+ /** The game's master switch. Session only (not stored). */
30
+ readonly soundOn: boolean;
31
+ setSoundOn(v: boolean): void;
32
+ /** The master volume, 0..1, which every synthesis multiplies by. Session only. */
33
+ readonly volume: number;
34
+ setVolume(v: number): void;
35
+ /** The engine's context, `null` until the first sound asks for one. */
36
+ readonly audioCtx: AudioContext | null;
37
+ /** The context, made on the first call and resumed if the browser suspended it; `null` where the host has none. */
38
+ ensureAC(): AudioContext | null;
39
+ /** The master node (master gain → optional hearing-loss filter → destination), made on the first call. */
40
+ audioOut(): GainNode | null;
41
+ /** Whether the hearing-loss empathy simulation is on the master node. */
42
+ readonly hearingLoss: boolean;
43
+ /** Switches the hearing-loss filter on the master node. Storing it and announcing it are the caller's. */
44
+ setHearingLossGraph(on: boolean): void;
45
+ /** The pause and title silence everything; playing brings it back. Acts only if the master exists — never makes one. */
46
+ setMasterMuted(muted: boolean): void;
47
+ /**
48
+ * The mixer's live state per category, loaded from the store when the audio is built. Written in place — `on`, `vol`, or the
49
+ * whole category — by the panels, the bar and any game, and EVERY write that changes a value is told to `onCatChange`.
50
+ */
51
+ readonly audioCat: Record<string, CatState>;
52
+ /**
53
+ * Listens to every change of a category — its `on` or its `vol` — WHOEVER made it: the engine's panels and bar, and a game
54
+ * writing `audio.audioCat.tts.on = false` itself (ADR-0247). Called with the category's key, after the value changed; a write
55
+ * of the value already there is no change. Answers the function that stops listening.
56
+ */
57
+ onCatChange(listener: (cat: string) => void): () => void;
58
+ /** A category's bus, hanging off the master node. */
59
+ catNode(cat: string): GainNode | null;
60
+ /** Moves a category's bus to its state now, and keeps that state in the store. */
61
+ setCatGain(cat: string): void;
62
+ tone(freq: number, dur: number, type?: OscillatorType, when?: number, vol?: number): void;
63
+ /** `pc` = a per-player audio context, passed to route the cue to that player's device. */
64
+ tonePan(freq: number, dur: number, cat: string, pan?: number | null, vol?: number, type?: OscillatorType, pc?: PlayerCtx | null): void;
65
+ noiseHit(mat: string, pan?: number | null, pc?: PlayerCtx | null): void;
66
+ /** A count of steps and taps (an accessibility statistic). */
67
+ readonly footCount: number;
68
+ }
30
69
  export declare function noiseBuffer(ac: ACWithCache): AudioBuffer;
31
- export declare function noiseHit(mat: string, pan?: number | null, pc?: PlayerCtx | null): void;
70
+ /**
71
+ * Builds one root's sound. The mixer's state is read from `store` HERE, so a voice built after it finds its categories — the
72
+ * order the second consumer once found by the silence (create-game, finding 3) is now the order of construction.
73
+ */
74
+ export declare function createAudio(deps: AudioDeps): Audio;
32
75
  export {};
@@ -1,40 +1,21 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- // platform/audio.ts — base do áudio: ciclo do AudioContext (ensureAC) + definições de SFX (dados). Módulo-folha.
3
- // O grafo (master/mixer), soundOn/volume e as sínteses (tone/noiseHit/tonePan/sfx) ainda ficam no game.js —
4
- // migram numa rodada dedicada (injeção de dependência). audioCtx é binding vivo; só ensureAC o (re)cria. (Fase 2)
5
- import { loadAudioCat, saveAudioCat } from './audio-mixer.js'; // mixer por categoria (dados + persistência)
6
- // Som mestre: liga/desliga + volume (0..1). Sessão-only (sem persistência). Bindings vivos: as sínteses
7
- // (tone/noiseHit/…) e a narração leem soundOn/volume; o botão/slider mestre do game.js escreve pelos setters.
8
- export let soundOn = true;
9
- export function setSoundOn(v) { soundOn = v; }
10
- export let volume = 0.6;
11
- export function setVolume(v) { volume = v; }
12
- export let audioCtx = null;
13
- export function ensureAC() {
14
- if (!audioCtx) {
15
- const AC = window.AudioContext || window.webkitAudioContext;
16
- if (AC)
17
- audioCtx = new AC();
18
- }
19
- if (audioCtx && audioCtx.state === 'suspended')
20
- audioCtx.resume();
21
- return audioCtx;
22
- }
23
- // ===== Nó MESTRE: master gain → (filtro de perda auditiva opcional) → destino. =====
24
- export let hearingLoss = false;
25
- let _masterGain = null, _hlChain = null;
26
- export function audioOut() { const ac = ensureAC(); if (!ac)
27
- return null; if (!_masterGain) {
28
- _masterGain = ac.createGain();
29
- wireMaster();
30
- } return _masterGain; }
2
+ // platform/audio.ts — the audio base: the AudioContext's lifecycle (ensureAC), the master and mixer graph, and the
3
+ // oscillator and noise syntheses every game's cues are made of. One per root (ADR-0232 D4, issue #207): `createAudio` holds
4
+ // the context, the master, the mixer and the counters in its closure, and receives the host's context maker and store.
5
+ import { loadAudioCat, saveAudioCat } from './audio-mixer.js'; // per-category mixer (data + persistence)
6
+ export function noiseBuffer(ac) { if (ac._noiseBuf && ac._noiseBuf.length === ((ac.sampleRate * 0.2) | 0))
7
+ return ac._noiseBuf; const n = (ac.sampleRate * 0.2) | 0, b = ac.createBuffer(1, n, ac.sampleRate), d = b.getChannelData(0); for (let i = 0; i < n; i++)
8
+ d[i] = Math.random() * 2 - 1; return ac._noiseBuf = b; }
9
+ const FOOT = { grama: { f: 'highpass', hz: 2000, d: 0.09, v: 0.10 }, piso: { f: 'bandpass', hz: 1200, d: 0.06, v: 0.15 }, pedra: { f: 'highpass', hz: 1600, d: 0.05, v: 0.19 },
10
+ areia: { f: 'lowpass', hz: 650, d: 0.13, v: 0.10 }, madeira: { f: 'bandpass', hz: 480, d: 0.08, v: 0.15 }, ferro: { f: 'bandpass', hz: 2600, d: 0.12, v: 0.16 }, parede: { f: 'highpass', hz: 3200, d: 0.10, v: 0.08 },
11
+ terra: { f: 'lowpass', hz: 520, d: 0.11, v: 0.12 }, agua: { f: 'lowpass', hz: 330, d: 0.15, v: 0.13 } };
31
12
  function buildHearingChain(ac) {
32
13
  const lp = ac.createBiquadFilter();
33
14
  lp.type = 'lowpass';
34
15
  lp.frequency.value = 1400;
35
- lp.Q.value = 0.7; // agudos primeiro
16
+ lp.Q.value = 0.7; // the highs go first
36
17
  const sp = ac.createScriptProcessor(512, 1, 1);
37
- const TH = 0.06, RED = 0.12; // frame < limiar → ×0.12 (contrário de aparelho auditivo)
18
+ const TH = 0.06, RED = 0.12; // a frame below the threshold → ×0.12 (a hearing aid in reverse)
38
19
  sp.onaudioprocess = (e) => { const inp = e.inputBuffer.getChannelData(0), out = e.outputBuffer.getChannelData(0); let s = 0; for (let i = 0; i < inp.length; i++)
39
20
  s += inp[i] * inp[i]; const g = Math.sqrt(s / inp.length) < TH ? RED : 1; for (let i = 0; i < inp.length; i++)
40
21
  out[i] = inp[i] * g; };
@@ -42,150 +23,194 @@ function buildHearingChain(ac) {
42
23
  sp.connect(ac.destination);
43
24
  return { input: lp };
44
25
  }
45
- function wireMaster() {
46
- const ac = audioCtx;
47
- if (!ac || !_masterGain)
48
- return;
49
- try {
50
- _masterGain.disconnect();
26
+ /**
27
+ * THE CATEGORIES AS THE MIXER HOLDS THEM, each write heard (ADR-0247). A game reaches the mixer itself (`Engine.audio`), and
28
+ * its door to a category is a plain property write — `audioCat.tts.on = false` — with no call after it that an event could
29
+ * hang on. So the write IS the door: `on` and `vol` are accessors that tell `changed`, and so is the category itself, whose
30
+ * replacement (`audioCat.tts = {…}`) is copied INTO the mixer's object — replaced, the object every surface reads would come
31
+ * apart from the one the engine and the game write, and no later write would be heard.
32
+ */
33
+ function heardCategories(stored, changed) {
34
+ const cats = {};
35
+ for (const [k, first] of Object.entries(stored)) {
36
+ let on = first.on, vol = first.vol;
37
+ const live = {};
38
+ Object.defineProperties(live, {
39
+ on: { enumerable: true, get: () => on, set: (v) => { if (v !== on) {
40
+ on = v;
41
+ changed(k);
42
+ } } },
43
+ vol: { enumerable: true, get: () => vol, set: (v) => { if (v !== vol) {
44
+ vol = v;
45
+ changed(k);
46
+ } } },
47
+ });
48
+ Object.defineProperty(cats, k, { enumerable: true, get: () => live, set: (v) => { live.on = v.on; live.vol = v.vol; } });
51
49
  }
52
- catch (e) { /* noop */ }
53
- if (hearingLoss) {
54
- if (!_hlChain)
55
- _hlChain = buildHearingChain(ac);
56
- _masterGain.connect(_hlChain.input);
57
- }
58
- else
59
- _masterGain.connect(ac.destination);
50
+ return cats;
60
51
  }
61
- // Empatia de perda auditiva: liga/desliga o filtro no nó mestre. A persistência + srSay ficam no game.js.
62
- export function setHearingLossGraph(on) { hearingLoss = on; if (audioCtx) {
63
- audioOut();
64
- wireMaster();
65
- } }
66
- // Mute mestre (pausa/título silenciam tudo; volta ao jogar). Só age se o nó mestre já existe (não o cria à toa).
67
- export function setMasterMuted(muted) { if (!_masterGain || !audioCtx)
68
- return; try {
69
- _masterGain.gain.setTargetAtTime(muted ? 0 : 1, audioCtx.currentTime, 0.04);
52
+ /** The last node before the output: a panner clamped to the two ears when a pan is asked, the gain itself when not. */
53
+ function panned(ac, g, pan) {
54
+ if (pan == null || !ac.createStereoPanner)
55
+ return g;
56
+ const p = ac.createStereoPanner();
57
+ p.pan.value = Math.max(-1, Math.min(1, pan));
58
+ g.connect(p);
59
+ return p;
70
60
  }
71
- catch (e) { /* noop */ } }
72
- // ===== Mixer por categoria: cada categoria tem seu gain (liga/desliga + volume), pendurado no nó mestre. =====
73
- // audioCat é a fonte viva do estado do mixer (mutada pela UI/calmMode no game.js — objeto, nunca reatribuído
74
- // APÓS init). NULL até initAudioMixer(): o import fica PURO (não lê localStorage). initAudioMixer é chamado no
75
- // boot do game.js — todos os leitores de audioCat (mixer/ambiente/narração) rodam depois. (Fase 2.25)
76
- export let audioCat = null;
77
- // Carrega o estado do mixer (defaults do audio-mixer.js + o que estiver salvo). I/O EXPLÍCITO, idempotente.
78
- export function initAudioMixer() { if (!audioCat)
79
- audioCat = loadAudioCat(); }
80
- const _catNodes = {};
81
- export function catNode(cat) { const ac = ensureAC(); if (!ac || !audioCat)
82
- return null; const out = audioOut(); if (!out)
83
- return null; if (!_catNodes[cat]) {
84
- const g = ac.createGain();
85
- g.gain.value = audioCat[cat].on ? audioCat[cat].vol : 0;
86
- g.connect(out);
87
- _catNodes[cat] = g;
88
- } return _catNodes[cat]; }
89
- export function setCatGain(cat) { if (!audioCat)
90
- return; const g = _catNodes[cat]; if (g && audioCtx)
91
- g.gain.setTargetAtTime(audioCat[cat].on ? audioCat[cat].vol : 0, audioCtx.currentTime, 0.02); saveAudioCat(cat, audioCat[cat]); }
92
- // ===== Sínteses de oscilador (earcons/melodias). Leem soundOn/volume; roteiam pelo mixer→mestre. =====
93
- // pc = contexto de áudio por-jogador (opcional; o game.js o passa p/ rotear a pista ao dispositivo do jogador).
94
- export function tone(freq, dur, type, when, vol) {
95
- if (!soundOn || volume <= 0)
96
- return;
97
- try {
98
- const ac = ensureAC();
99
- if (!ac)
61
+ /**
62
+ * Builds one root's sound. The mixer's state is read from `store` HERE, so a voice built after it finds its categories — the
63
+ * order the second consumer once found by the silence (create-game, finding 3) is now the order of construction.
64
+ */
65
+ export function createAudio(deps) {
66
+ let soundOn = true, volume = 0.6;
67
+ let audioCtx = null;
68
+ let hearingLoss = false;
69
+ let masterGain = null, hlChain = null;
70
+ let footCount = 0;
71
+ const catListeners = new Set();
72
+ // a copy of the listeners, so one that stops listening while it is told does not skip the next
73
+ const audioCat = heardCategories(loadAudioCat(deps.store), (cat) => { for (const l of [...catListeners])
74
+ l(cat); });
75
+ const catNodes = {};
76
+ function onCatChange(listener) {
77
+ catListeners.add(listener);
78
+ return () => { catListeners.delete(listener); };
79
+ }
80
+ function ensureAC() {
81
+ if (!audioCtx)
82
+ audioCtx = deps.newContext();
83
+ if (audioCtx && audioCtx.state === 'suspended')
84
+ audioCtx.resume();
85
+ return audioCtx;
86
+ }
87
+ // ===== The MASTER node: master gain → (optional hearing-loss filter) → destination. =====
88
+ function audioOut() { const ac = ensureAC(); if (!ac)
89
+ return null; if (!masterGain) {
90
+ masterGain = ac.createGain();
91
+ wireMaster();
92
+ } return masterGain; }
93
+ function wireMaster() {
94
+ const ac = audioCtx;
95
+ if (!ac || !masterGain)
100
96
  return;
101
- const o = ac.createOscillator(), g = ac.createGain(), t = ac.currentTime + (when || 0);
102
- o.type = type || 'square';
103
- o.frequency.setValueAtTime(freq, t);
104
- g.gain.setValueAtTime(0.0001, t);
105
- g.gain.exponentialRampToValueAtTime(Math.max(0.02, (vol || 0.22) * volume), t + 0.01);
106
- g.gain.exponentialRampToValueAtTime(0.0001, t + dur);
107
- o.connect(g).connect(catNode('earcons') || audioOut() || ac.destination);
108
- o.start(t);
109
- o.stop(t + dur + 0.02);
97
+ try {
98
+ masterGain.disconnect();
99
+ }
100
+ catch (e) { /* noop */ }
101
+ if (hearingLoss) {
102
+ if (!hlChain)
103
+ hlChain = buildHearingChain(ac);
104
+ masterGain.connect(hlChain.input);
105
+ }
106
+ else
107
+ masterGain.connect(ac.destination);
110
108
  }
111
- catch (e) { /* noop */ }
112
- }
113
- export function tonePan(freq, dur, cat, pan, vol, type, pc) {
114
- if (!soundOn || volume <= 0)
115
- return;
116
- const ac = pc ? pc.ac : ensureAC();
117
- if (!ac)
118
- return;
119
- try {
120
- const o = ac.createOscillator(), g = ac.createGain(), t = ac.currentTime;
121
- o.type = type || 'sine';
122
- o.frequency.value = freq;
123
- g.gain.setValueAtTime(0.0001, t);
124
- g.gain.exponentialRampToValueAtTime(Math.max(0.02, (vol || 0.2) * volume), t + 0.01);
125
- g.gain.exponentialRampToValueAtTime(0.0001, t + dur);
126
- let node = g;
127
- if (pan != null && ac.createStereoPanner) {
128
- const p = ac.createStereoPanner();
129
- p.pan.value = Math.max(-1, Math.min(1, pan));
130
- g.connect(p);
131
- node = p;
109
+ function setHearingLossGraph(on) { hearingLoss = on; if (audioCtx) {
110
+ audioOut();
111
+ wireMaster();
112
+ } }
113
+ function setMasterMuted(muted) { if (!masterGain || !audioCtx)
114
+ return; try {
115
+ masterGain.gain.setTargetAtTime(muted ? 0 : 1, audioCtx.currentTime, 0.04);
116
+ }
117
+ catch (e) { /* noop */ } }
118
+ // ===== The per-category mixer: each category has its gain (on/off + volume), hanging off the master node. =====
119
+ /** A category's level: silence when it is switched off, its volume when on — asked the same way when its bus is made and when the slider moves. */
120
+ function catLevel(cat) { const c = audioCat[cat]; return c.on ? c.vol : 0; }
121
+ function catNode(cat) { const ac = ensureAC(); if (!ac)
122
+ return null; const out = audioOut(); if (!out)
123
+ return null; if (!catNodes[cat]) {
124
+ const g = ac.createGain();
125
+ g.gain.value = catLevel(cat);
126
+ g.connect(out);
127
+ catNodes[cat] = g;
128
+ } return catNodes[cat]; }
129
+ function setCatGain(cat) { const g = catNodes[cat]; if (g && audioCtx)
130
+ g.gain.setTargetAtTime(catLevel(cat), audioCtx.currentTime, 0.02); saveAudioCat(deps.store, cat, audioCat[cat]); }
131
+ // ===== The questions a cue asks before it sounds, the same for the tone and the noise. =====
132
+ /** Whether a sound may play at all: the game's sound on, and the master above zero. */
133
+ function audible() { return soundOn && volume > 0; }
134
+ /** The context a cue plays in: the player's own device when one is given, the engine's otherwise. */
135
+ function contextFor(pc) { return pc ? pc.ac : ensureAC(); }
136
+ /** Where a cue goes out: the player's own device; otherwise its category's bus, the master, or the device itself. */
137
+ function outFor(ac, cat, pc) { return pc ? pc.out : (catNode(cat) || audioOut() || ac.destination); }
138
+ // ===== Oscillator syntheses (earcons/melodies). They read soundOn/volume and route through mixer → master. =====
139
+ function tone(freq, dur, type, when, vol) {
140
+ if (!audible())
141
+ return;
142
+ try {
143
+ const ac = contextFor();
144
+ if (!ac)
145
+ return;
146
+ const o = ac.createOscillator(), g = ac.createGain(), t = ac.currentTime + (when || 0);
147
+ o.type = type || 'square';
148
+ o.frequency.setValueAtTime(freq, t);
149
+ g.gain.setValueAtTime(0.0001, t);
150
+ g.gain.exponentialRampToValueAtTime(Math.max(0.02, (vol || 0.22) * volume), t + 0.01);
151
+ g.gain.exponentialRampToValueAtTime(0.0001, t + dur);
152
+ o.connect(g).connect(outFor(ac, 'earcons'));
153
+ o.start(t);
154
+ o.stop(t + dur + 0.02);
132
155
  }
133
- o.connect(g);
134
- node.connect(pc ? pc.out : (catNode(cat) || audioOut() || ac.destination));
135
- o.start(t);
136
- o.stop(t + dur + 0.02);
156
+ catch (e) { /* noop */ }
137
157
  }
138
- catch (e) { /* noop */ }
139
- }
140
- // ===== Synth de RUÍDO (passos por material, bengala). noiseBuffer cacheia por-contexto (suporta AC por jogador). =====
141
- export let _footCount = 0; // contador de passos/pancadas (estatística de a11y; o __incl do game.js lê via getter)
142
- export function noiseBuffer(ac) { if (ac._noiseBuf && ac._noiseBuf.length === ((ac.sampleRate * 0.2) | 0))
143
- return ac._noiseBuf; const n = (ac.sampleRate * 0.2) | 0, b = ac.createBuffer(1, n, ac.sampleRate), d = b.getChannelData(0); for (let i = 0; i < n; i++)
144
- d[i] = Math.random() * 2 - 1; return ac._noiseBuf = b; }
145
- const FOOT = { grama: { f: 'highpass', hz: 2000, d: 0.09, v: 0.10 }, piso: { f: 'bandpass', hz: 1200, d: 0.06, v: 0.15 }, pedra: { f: 'highpass', hz: 1600, d: 0.05, v: 0.19 },
146
- areia: { f: 'lowpass', hz: 650, d: 0.13, v: 0.10 }, madeira: { f: 'bandpass', hz: 480, d: 0.08, v: 0.15 }, ferro: { f: 'bandpass', hz: 2600, d: 0.12, v: 0.16 }, parede: { f: 'highpass', hz: 3200, d: 0.10, v: 0.08 },
147
- terra: { f: 'lowpass', hz: 520, d: 0.11, v: 0.12 }, agua: { f: 'lowpass', hz: 330, d: 0.15, v: 0.13 } };
148
- export function noiseHit(mat, pan, pc) {
149
- if (!soundOn || volume <= 0)
150
- return;
151
- const ac = pc ? pc.ac : ensureAC();
152
- if (!ac)
153
- return;
154
- const f = FOOT[mat] || FOOT.piso;
155
- try {
156
- const src = ac.createBufferSource();
157
- src.buffer = noiseBuffer(ac);
158
- const bq = ac.createBiquadFilter();
159
- bq.type = f.f;
160
- bq.frequency.value = f.hz;
161
- bq.Q.value = 1.2;
162
- const g = ac.createGain(), t = ac.currentTime;
163
- g.gain.setValueAtTime(0.0001, t);
164
- g.gain.exponentialRampToValueAtTime(Math.max(0.02, f.v * volume), t + 0.006);
165
- g.gain.exponentialRampToValueAtTime(0.0001, t + f.d);
166
- let node = g;
167
- if (pan != null && ac.createStereoPanner) {
168
- const p = ac.createStereoPanner();
169
- p.pan.value = Math.max(-1, Math.min(1, pan));
170
- g.connect(p);
171
- node = p;
158
+ function tonePan(freq, dur, cat, pan, vol, type, pc) {
159
+ if (!audible())
160
+ return;
161
+ const ac = contextFor(pc);
162
+ if (!ac)
163
+ return;
164
+ try {
165
+ const o = ac.createOscillator(), g = ac.createGain(), t = ac.currentTime;
166
+ o.type = type || 'sine';
167
+ o.frequency.value = freq;
168
+ g.gain.setValueAtTime(0.0001, t);
169
+ g.gain.exponentialRampToValueAtTime(Math.max(0.02, (vol || 0.2) * volume), t + 0.01);
170
+ g.gain.exponentialRampToValueAtTime(0.0001, t + dur);
171
+ o.connect(g);
172
+ panned(ac, g, pan).connect(outFor(ac, cat, pc));
173
+ o.start(t);
174
+ o.stop(t + dur + 0.02);
175
+ }
176
+ catch (e) { /* noop */ }
177
+ }
178
+ // ===== The NOISE synth (footsteps by material, the cane). noiseBuffer caches per context (supports one per player). =====
179
+ function noiseHit(mat, pan, pc) {
180
+ if (!audible())
181
+ return;
182
+ const ac = contextFor(pc);
183
+ if (!ac)
184
+ return;
185
+ const f = FOOT[mat] || FOOT.piso;
186
+ try {
187
+ const src = ac.createBufferSource();
188
+ src.buffer = noiseBuffer(ac);
189
+ const bq = ac.createBiquadFilter();
190
+ bq.type = f.f;
191
+ bq.frequency.value = f.hz;
192
+ bq.Q.value = 1.2;
193
+ const g = ac.createGain(), t = ac.currentTime;
194
+ g.gain.setValueAtTime(0.0001, t);
195
+ g.gain.exponentialRampToValueAtTime(Math.max(0.02, f.v * volume), t + 0.006);
196
+ g.gain.exponentialRampToValueAtTime(0.0001, t + f.d);
197
+ src.connect(bq).connect(g);
198
+ panned(ac, g, pan).connect(outFor(ac, 'interact', pc));
199
+ src.start(t);
200
+ src.stop(t + f.d + 0.03);
201
+ footCount++;
172
202
  }
173
- src.connect(bq).connect(g);
174
- node.connect(pc ? pc.out : (catNode('interact') || audioOut() || ac.destination));
175
- src.start(t);
176
- src.stop(t + f.d + 0.03);
177
- _footCount++;
203
+ catch (e) { /* noop */ }
178
204
  }
179
- catch (e) { /* noop */ }
205
+ return {
206
+ get soundOn() { return soundOn; }, setSoundOn: (v) => { soundOn = v; },
207
+ get volume() { return volume; }, setVolume: (v) => { volume = v; },
208
+ get audioCtx() { return audioCtx; }, ensureAC, audioOut,
209
+ get hearingLoss() { return hearingLoss; }, setHearingLossGraph, setMasterMuted,
210
+ audioCat, onCatChange, catNode, setCatGain,
211
+ tone, tonePan, noiseHit,
212
+ get footCount() { return footCount; },
213
+ };
180
214
  }
181
- /* A TABELA DE EARCONS SAIU daqui em 2026-08-25 (item 19) — está em `game/earcons`.
182
- *
183
- * De dez earcons, sete eram deste jogo: `coin`/`key`/`gate`/`power` são objetos deste mundo e
184
- * `correct`/`wrong`/`place` são eventos da atividade. O gate acusava só a linha do `coin`, porque é a única
185
- * com palavra que o casador conhece — e a linha acusada era a menos interessante das dez.
186
- *
187
- * As legendas eram pt-BR CRU (`'🔊 Coletou'`, `'🔊 Portão abriu'`): nove frases dentro de um módulo de
188
- * plataforma, que o gate de i18n do `main.js` não alcança. Viraram CHAVES, e quem exibe resolve.
189
- *
190
- * O que ficou aqui é a SÍNTESE — oscilador, envelope, ruído, roteamento por categoria —, que serve a
191
- * qualquer jogo. O que é 880 Hz de triangular por 0,14 s ao pegar uma moeda, não. */
215
+ /* What lives here is the SYNTHESIS — oscillator, envelope, noise, routing by category — which serves any game. A table of
216
+ * earcons does not: "880 Hz of triangle for 0.14 s when a coin is taken" is one game's world, and it lives with that game. */
@@ -0,0 +1,70 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import { type VoskDeps, type VoskLoad } from './vosk-runtime.js';
3
+ import { type VoiceListenerDeps } from './voice-listener.js';
4
+ /** What a choice gives back: the index of the option said, or `null`; what was heard; why it ended. */
5
+ export interface ChoiceHeard {
6
+ readonly chosen: number | null;
7
+ readonly heard: string;
8
+ /** One option said · more than one said in one sentence · no option in time · asked to stop. */
9
+ readonly ended: 'chosen' | 'unclear' | 'timeout' | 'asked';
10
+ }
11
+ export interface ChooseSettings {
12
+ /** The language the options are in — the content's, when it is not the page's (ADR-0225). Default: the page's. */
13
+ readonly language?: string;
14
+ /** How long to wait for an option. Default 10 s: time to think, and a microphone that is never forgotten open. */
15
+ readonly maxMs?: number;
16
+ /**
17
+ * Called once, when the ear is OPEN and a word said now would be heard — at once when the 👄's ear is lent, after the model
18
+ * has loaded when one had to be opened. Before it, a game says «loading», not «say the answer»: the first choice in a language
19
+ * waits a few seconds for its model, and a child told to speak into that wait is not heard (the Dev, 2026-09-27).
20
+ */
21
+ readonly onListening?: () => void;
22
+ }
23
+ /** A recogniser listening with a grammar: it can be stopped, and it may say which words its model knows. */
24
+ export interface OpenedChoice {
25
+ stop(): Promise<void>;
26
+ /** The words the language's model knows, when they can be read — an option with a word outside them can never be chosen. */
27
+ readonly vocabulary?: () => Promise<ReadonlySet<string> | null>;
28
+ }
29
+ export interface VoiceChooserDeps {
30
+ /** The page's language (`core/i18n.bcp47`). */
31
+ readonly language: () => string;
32
+ /**
33
+ * Opens the command recogniser for `language` with this grammar and the microphone, calling `onHeard` with every text it hears
34
+ * — `final` when the sentence ended. REJECTS, with the reason, when the model or the microphone cannot be had.
35
+ */
36
+ readonly open: (language: string, grammar: readonly string[], onHeard: (text: string, final: boolean) => void) => Promise<OpenedChoice>;
37
+ readonly after: (fn: () => void, ms: number) => unknown;
38
+ readonly cancel: (handle: unknown) => void;
39
+ /** A line for `problems`, written once per reason (ADR-0169). */
40
+ readonly report: (line: string) => void;
41
+ /**
42
+ * An ear ALREADY LISTENING in `language`, lent for this choice with the grammar given — the 👄's (`ui/voice-control.borrow`) — or
43
+ * `null`. Borrowed, nothing is opened and nothing paused: one model and one microphone, however many choices.
44
+ */
45
+ readonly borrow?: (language: string, grammar: readonly string[], onHeard: (text: string, final: boolean) => void) => OpenedChoice | null;
46
+ /** Called before an ear of its own is opened and after it is let go: the root pauses the 👄 in between (one ear per word). */
47
+ readonly pause?: () => void;
48
+ readonly resume?: () => void;
49
+ }
50
+ export interface VoiceChooser {
51
+ choose(options: readonly string[], settings?: ChooseSettings): Promise<ChoiceHeard>;
52
+ /** Ends the choice in hand now: it answers `null`, `ended: 'asked'`. */
53
+ stop(): void;
54
+ }
55
+ /** What opening the command recogniser for a choice uses of the delivery and the browser, lent by the root (ADR-0232 D4). */
56
+ export type CommandRecogniserDeps = Omit<VoskDeps, 'language'> & Pick<VoiceListenerDeps, 'getUserMedia' | 'createContext'> & {
57
+ /** How a language's model is had — the root's `keepVoskModels(…).load`, so it is loaded once; default a fresh load. */
58
+ readonly load?: (d: VoskDeps) => Promise<VoskLoad>;
59
+ };
60
+ /**
61
+ * THE `open` A CHOOSER IS GIVEN WHERE THE COMMAND RECOGNISER IS THE EAR: the language's model from the delivery, then the
62
+ * microphone with the grammar. A model that opened for a microphone that did not is let go before the refusal travels.
63
+ */
64
+ export declare function openWithCommandRecogniser(d: CommandRecogniserDeps): VoiceChooserDeps['open'];
65
+ /**
66
+ * The options a sentence names, in the order said, each once: read word by word, the LONGEST option that starts at each word —
67
+ * so «cavalo marinho» is one option and not also «cavalo» — accents and case aside, whole words only.
68
+ */
69
+ export declare function optionsNamed(options: readonly string[], sentence: string): number[];
70
+ export declare function createVoiceChooser(d: VoiceChooserDeps): VoiceChooser;