@the-inclusionist/engine 10.0.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/README.md +32 -1
  2. package/app/css/style.css +216 -42
  3. package/app/public/vendor/fonts-licences/NOTICE.txt +166 -0
  4. package/app/public/vendor/fonts-licences/OFL-1.1.txt +86 -0
  5. package/app/public/vendor/fonts.css +11 -1175
  6. package/dist-pkg/boot/create-game.d.ts +84 -33
  7. package/dist-pkg/boot/create-game.js +708 -307
  8. package/dist-pkg/core/a11y-sr.d.ts +1 -1
  9. package/dist-pkg/core/a11y-sr.js +3 -5
  10. package/dist-pkg/core/accommodations.d.ts +26 -8
  11. package/dist-pkg/core/accommodations.js +27 -10
  12. package/dist-pkg/core/actions.d.ts +39 -10
  13. package/dist-pkg/core/actions.js +28 -6
  14. package/dist-pkg/core/contract.d.ts +0 -2
  15. package/dist-pkg/core/contract.js +0 -2
  16. package/dist-pkg/core/i18n.d.ts +36 -71
  17. package/dist-pkg/core/i18n.js +131 -198
  18. package/dist-pkg/core/session-clock.d.ts +23 -0
  19. package/dist-pkg/core/session-clock.js +37 -0
  20. package/dist-pkg/i18n/en.js +44 -49
  21. package/dist-pkg/i18n/es.js +44 -49
  22. package/dist-pkg/i18n/pt.js +49 -54
  23. package/dist-pkg/input/gamepad.d.ts +42 -11
  24. package/dist-pkg/input/gamepad.js +50 -15
  25. package/dist-pkg/input/key-default.d.ts +30 -0
  26. package/dist-pkg/input/key-default.js +60 -0
  27. package/dist-pkg/input/keyboard-runtime.d.ts +0 -4
  28. package/dist-pkg/input/keyboard.d.ts +0 -1
  29. package/dist-pkg/input/keydown.d.ts +5 -11
  30. package/dist-pkg/input/keydown.js +3 -3
  31. package/dist-pkg/input/latch-edge.d.ts +10 -2
  32. package/dist-pkg/input/latch-edge.js +4 -3
  33. package/dist-pkg/input/latch-scope.d.ts +27 -22
  34. package/dist-pkg/input/latch-scope.js +25 -37
  35. package/dist-pkg/input/latch-store.d.ts +9 -12
  36. package/dist-pkg/input/latch-store.js +13 -18
  37. package/dist-pkg/input/latch-sync.d.ts +5 -4
  38. package/dist-pkg/input/latch-sync.js +5 -5
  39. package/dist-pkg/input/pad-reading.js +7 -2
  40. package/dist-pkg/input/pad-wizard.d.ts +4 -1
  41. package/dist-pkg/input/pad-wizard.js +60 -9
  42. package/dist-pkg/input/switch-scan.d.ts +29 -12
  43. package/dist-pkg/input/switch-scan.js +15 -2
  44. package/dist-pkg/input/touch-bindings.d.ts +3 -6
  45. package/dist-pkg/input/touch.d.ts +17 -2
  46. package/dist-pkg/input/touch.js +55 -17
  47. package/dist-pkg/input/transport-in-use.d.ts +5 -5
  48. package/dist-pkg/input/transport-in-use.js +5 -5
  49. package/dist-pkg/input/transports.d.ts +0 -9
  50. package/dist-pkg/input/transports.js +1 -1
  51. package/dist-pkg/input/virtual-controller.d.ts +39 -3
  52. package/dist-pkg/input/virtual-controller.js +32 -4
  53. package/dist-pkg/input/voice-map.d.ts +27 -11
  54. package/dist-pkg/input/voice-map.js +41 -43
  55. package/dist-pkg/platform/audio-ambient.d.ts +0 -1
  56. package/dist-pkg/platform/audio-ambient.js +3 -1
  57. package/dist-pkg/platform/audio-mixer.js +4 -9
  58. package/dist-pkg/platform/audio-sonar.d.ts +8 -94
  59. package/dist-pkg/platform/audio-sonar.js +22 -207
  60. package/dist-pkg/platform/audio.d.ts +10 -1
  61. package/dist-pkg/platform/audio.js +35 -2
  62. package/dist-pkg/platform/choose-by-voice.d.ts +70 -0
  63. package/dist-pkg/platform/choose-by-voice.js +157 -0
  64. package/dist-pkg/platform/font-library.d.ts +77 -0
  65. package/dist-pkg/platform/font-library.js +98 -0
  66. package/dist-pkg/platform/font-library.json +721 -0
  67. package/dist-pkg/platform/heavy-catalogue.d.ts +46 -0
  68. package/dist-pkg/platform/heavy-catalogue.js +47 -14
  69. package/dist-pkg/platform/heavy-mirror.d.ts +3 -9
  70. package/dist-pkg/platform/heavy-mirror.js +14 -17
  71. package/dist-pkg/platform/heavy.d.ts +40 -8
  72. package/dist-pkg/platform/heavy.js +177 -22
  73. package/dist-pkg/platform/interruptible-speech.d.ts +15 -8
  74. package/dist-pkg/platform/interruptible-speech.js +37 -13
  75. package/dist-pkg/platform/listener-scope.js +22 -13
  76. package/dist-pkg/platform/locale-host.d.ts +7 -3
  77. package/dist-pkg/platform/locale-host.js +13 -2
  78. package/dist-pkg/platform/reading-in-worker.d.ts +24 -0
  79. package/dist-pkg/platform/reading-in-worker.js +38 -0
  80. package/dist-pkg/platform/reading-model.d.ts +21 -0
  81. package/dist-pkg/platform/reading-model.js +25 -0
  82. package/dist-pkg/platform/reading-runtime.js +13 -8
  83. package/dist-pkg/platform/reading.d.ts +12 -1
  84. package/dist-pkg/platform/reading.js +9 -1
  85. package/dist-pkg/platform/speech-recognition.d.ts +10 -1
  86. package/dist-pkg/platform/speech-recognition.js +29 -9
  87. package/dist-pkg/platform/speech.d.ts +10 -1
  88. package/dist-pkg/platform/speech.js +24 -13
  89. package/dist-pkg/platform/tts.d.ts +37 -4
  90. package/dist-pkg/platform/tts.js +279 -57
  91. package/dist-pkg/platform/voice-listener.d.ts +6 -2
  92. package/dist-pkg/platform/voice-listener.js +1 -1
  93. package/dist-pkg/platform/voice-plan.d.ts +13 -0
  94. package/dist-pkg/platform/voice-plan.js +57 -2
  95. package/dist-pkg/platform/vosk-runtime.d.ts +25 -0
  96. package/dist-pkg/platform/vosk-runtime.js +59 -1
  97. package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
  98. package/dist-pkg/platform/vosk-vocabulary.js +178 -0
  99. package/dist-pkg/render/crt.d.ts +11 -9
  100. package/dist-pkg/render/crt.js +6 -10
  101. package/dist-pkg/render/cvd-matrices.d.ts +5 -1
  102. package/dist-pkg/render/cvd-matrices.js +5 -1
  103. package/dist-pkg/render/high-contrast.d.ts +1 -2
  104. package/dist-pkg/render/high-contrast.js +5 -1
  105. package/dist-pkg/render/viz-axes.d.ts +9 -0
  106. package/dist-pkg/render/viz-axes.js +15 -2
  107. package/dist-pkg/ui/aac-sets.d.ts +29 -24
  108. package/dist-pkg/ui/aac-sets.js +22 -30
  109. package/dist-pkg/ui/audio-choices.d.ts +10 -5
  110. package/dist-pkg/ui/audio-choices.js +14 -10
  111. package/dist-pkg/ui/camera-control.d.ts +47 -0
  112. package/dist-pkg/ui/camera-control.js +35 -1
  113. package/dist-pkg/ui/declared-words.d.ts +21 -0
  114. package/dist-pkg/ui/declared-words.js +66 -0
  115. package/dist-pkg/ui/drawing-problems.js +4 -3
  116. package/dist-pkg/ui/eye-control.js +17 -17
  117. package/dist-pkg/ui/face-control.js +15 -15
  118. package/dist-pkg/ui/fonts.d.ts +42 -8
  119. package/dist-pkg/ui/fonts.js +58 -24
  120. package/dist-pkg/ui/footer-scroll-driver.d.ts +14 -0
  121. package/dist-pkg/ui/footer-scroll-driver.js +201 -0
  122. package/dist-pkg/ui/footer-scroll.d.ts +38 -0
  123. package/dist-pkg/ui/footer-scroll.js +55 -0
  124. package/dist-pkg/ui/game-options.d.ts +14 -9
  125. package/dist-pkg/ui/game-options.js +41 -21
  126. package/dist-pkg/ui/hand-control.js +15 -15
  127. package/dist-pkg/ui/help-panel.d.ts +19 -8
  128. package/dist-pkg/ui/help-panel.js +15 -5
  129. package/dist-pkg/ui/hud-bands.d.ts +29 -12
  130. package/dist-pkg/ui/hud-bands.js +63 -25
  131. package/dist-pkg/ui/hud-row.d.ts +34 -0
  132. package/dist-pkg/ui/hud-row.js +80 -0
  133. package/dist-pkg/ui/hud.d.ts +0 -3
  134. package/dist-pkg/ui/layout.js +5 -2
  135. package/dist-pkg/ui/libras-avatar-clip.d.ts +30 -0
  136. package/dist-pkg/ui/libras-avatar-clip.js +86 -0
  137. package/dist-pkg/ui/libras-avatar-load.d.ts +52 -0
  138. package/dist-pkg/ui/libras-avatar-load.js +134 -0
  139. package/dist-pkg/ui/libras-avatar-plan.d.ts +102 -0
  140. package/dist-pkg/ui/libras-avatar-plan.js +211 -0
  141. package/dist-pkg/ui/libras-avatar-player.d.ts +28 -0
  142. package/dist-pkg/ui/libras-avatar-player.js +226 -0
  143. package/dist-pkg/ui/libras-avatar-stage.d.ts +37 -0
  144. package/dist-pkg/ui/libras-avatar-stage.js +208 -0
  145. package/dist-pkg/ui/libras-glosses.d.ts +28 -0
  146. package/dist-pkg/ui/libras-glosses.js +161 -0
  147. package/dist-pkg/ui/menu-intent.d.ts +29 -0
  148. package/dist-pkg/ui/menu-intent.js +35 -1
  149. package/dist-pkg/ui/menu-items.d.ts +10 -0
  150. package/dist-pkg/ui/menu-items.js +29 -0
  151. package/dist-pkg/ui/menu-nav.d.ts +40 -4
  152. package/dist-pkg/ui/menu-nav.js +132 -47
  153. package/dist-pkg/ui/panel-widgets.d.ts +34 -0
  154. package/dist-pkg/ui/panel-widgets.js +86 -0
  155. package/dist-pkg/ui/pause-icons.d.ts +30 -14
  156. package/dist-pkg/ui/pause-icons.js +106 -45
  157. package/dist-pkg/ui/scan-overlay.d.ts +3 -3
  158. package/dist-pkg/ui/scan-overlay.js +11 -3
  159. package/dist-pkg/ui/screen-text.d.ts +25 -0
  160. package/dist-pkg/ui/screen-text.js +152 -0
  161. package/dist-pkg/ui/session-clock.d.ts +32 -0
  162. package/dist-pkg/ui/session-clock.js +67 -0
  163. package/dist-pkg/ui/settings-aac.d.ts +3 -1
  164. package/dist-pkg/ui/settings-aac.js +32 -13
  165. package/dist-pkg/ui/settings-audio.d.ts +10 -5
  166. package/dist-pkg/ui/settings-audio.js +101 -35
  167. package/dist-pkg/ui/settings-controls.d.ts +0 -4
  168. package/dist-pkg/ui/settings-mobility.d.ts +3 -6
  169. package/dist-pkg/ui/settings-mobility.js +4 -46
  170. package/dist-pkg/ui/settings-motion.js +2 -2
  171. package/dist-pkg/ui/settings-panel.d.ts +10 -0
  172. package/dist-pkg/ui/settings-panel.js +25 -1
  173. package/dist-pkg/ui/settings-typo.d.ts +5 -6
  174. package/dist-pkg/ui/settings-typo.js +20 -11
  175. package/dist-pkg/ui/settings-visual.js +2 -2
  176. package/dist-pkg/ui/shell.d.ts +1 -3
  177. package/dist-pkg/ui/shell.js +8 -4
  178. package/dist-pkg/ui/title.d.ts +2 -11
  179. package/dist-pkg/ui/title.js +39 -6
  180. package/dist-pkg/ui/top-band.d.ts +5 -3
  181. package/dist-pkg/ui/top-band.js +21 -25
  182. package/dist-pkg/ui/typo-choices.d.ts +3 -3
  183. package/dist-pkg/ui/typo-choices.js +9 -8
  184. package/dist-pkg/ui/vlibras.d.ts +71 -27
  185. package/dist-pkg/ui/vlibras.js +116 -44
  186. package/dist-pkg/ui/voice-control.d.ts +23 -1
  187. package/dist-pkg/ui/voice-control.js +149 -16
  188. package/dist-pkg/ui/voice-settings.d.ts +2 -3
  189. package/dist-pkg/ui/voice-settings.js +53 -3
  190. package/dist-pkg/ui/where-the-child-is.js +2 -2
  191. package/docs/CREDITS.md +122 -10
  192. package/docs/LICENSES.md +36 -7
  193. package/package.json +34 -9
  194. package/scripts/check-cartridge.mjs +78 -0
  195. package/scripts/game-build.d.mts +25 -0
  196. package/scripts/game-build.mjs +144 -0
  197. package/scripts/heavy-into-the-delivery.mjs +284 -40
  198. package/scripts/libras-avatar.json +680 -0
  199. package/scripts/libras-avatar.mjs +246 -0
  200. package/scripts/libras-glosses/gloss.py +95 -0
  201. package/scripts/libras-glosses/pyproject.toml +32 -0
  202. package/scripts/libras-glosses/uv.lock +781 -0
  203. package/scripts/libras-glosses.mjs +351 -0
  204. package/scripts/licences/OFL-1.1.txt +86 -0
  205. package/scripts/licences/UFL-1.0.txt +96 -0
  206. package/scripts/licences/fonts.mjs +389 -0
  207. package/scripts/licences/third-party.mjs +35 -21
  208. package/app/public/vendor/fonts/bitter-var-ext.woff2 +0 -0
  209. package/app/public/vendor/fonts/bitter-var.woff2 +0 -0
  210. package/app/public/vendor/fonts/bodonimoda-var-ext.woff2 +0 -0
  211. package/app/public/vendor/fonts/bodonimoda-var.woff2 +0 -0
  212. package/app/public/vendor/fonts/cat-abril_fatface-400-ext.woff2 +0 -0
  213. package/app/public/vendor/fonts/cat-abril_fatface-400.woff2 +0 -0
  214. package/app/public/vendor/fonts/cat-adlam_display-400-ext.woff2 +0 -0
  215. package/app/public/vendor/fonts/cat-adlam_display-400.woff2 +0 -0
  216. package/app/public/vendor/fonts/cat-agu_display-400-ext.woff2 +0 -0
  217. package/app/public/vendor/fonts/cat-agu_display-400.woff2 +0 -0
  218. package/app/public/vendor/fonts/cat-alfa_slab_one-400-ext.woff2 +0 -0
  219. package/app/public/vendor/fonts/cat-alfa_slab_one-400.woff2 +0 -0
  220. package/app/public/vendor/fonts/cat-are_you_serious-400-ext.woff2 +0 -0
  221. package/app/public/vendor/fonts/cat-are_you_serious-400.woff2 +0 -0
  222. package/app/public/vendor/fonts/cat-asimovian-400-ext.woff2 +0 -0
  223. package/app/public/vendor/fonts/cat-asimovian-400.woff2 +0 -0
  224. package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400-ext.woff2 +0 -0
  225. package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400.woff2 +0 -0
  226. package/app/public/vendor/fonts/cat-bakbak_one-400-ext.woff2 +0 -0
  227. package/app/public/vendor/fonts/cat-bakbak_one-400.woff2 +0 -0
  228. package/app/public/vendor/fonts/cat-bangers-400-ext.woff2 +0 -0
  229. package/app/public/vendor/fonts/cat-bangers-400.woff2 +0 -0
  230. package/app/public/vendor/fonts/cat-barriecito-400-ext.woff2 +0 -0
  231. package/app/public/vendor/fonts/cat-barriecito-400.woff2 +0 -0
  232. package/app/public/vendor/fonts/cat-berkshire_swash-400-ext.woff2 +0 -0
  233. package/app/public/vendor/fonts/cat-berkshire_swash-400.woff2 +0 -0
  234. package/app/public/vendor/fonts/cat-bevan-400-ext.woff2 +0 -0
  235. package/app/public/vendor/fonts/cat-bevan-400.woff2 +0 -0
  236. package/app/public/vendor/fonts/cat-bitcount-400-ext.woff2 +0 -0
  237. package/app/public/vendor/fonts/cat-bitcount-400.woff2 +0 -0
  238. package/app/public/vendor/fonts/cat-bowlby_one_sc-400-ext.woff2 +0 -0
  239. package/app/public/vendor/fonts/cat-bowlby_one_sc-400.woff2 +0 -0
  240. package/app/public/vendor/fonts/cat-bungee_shade-400-ext.woff2 +0 -0
  241. package/app/public/vendor/fonts/cat-bungee_shade-400.woff2 +0 -0
  242. package/app/public/vendor/fonts/cat-charm-400-ext.woff2 +0 -0
  243. package/app/public/vendor/fonts/cat-charm-400.woff2 +0 -0
  244. package/app/public/vendor/fonts/cat-charm-700-ext.woff2 +0 -0
  245. package/app/public/vendor/fonts/cat-charm-700.woff2 +0 -0
  246. package/app/public/vendor/fonts/cat-cherry_bomb_one-400-ext.woff2 +0 -0
  247. package/app/public/vendor/fonts/cat-cherry_bomb_one-400.woff2 +0 -0
  248. package/app/public/vendor/fonts/cat-chokokutai-400-ext.woff2 +0 -0
  249. package/app/public/vendor/fonts/cat-chokokutai-400.woff2 +0 -0
  250. package/app/public/vendor/fonts/cat-chonburi-400-ext.woff2 +0 -0
  251. package/app/public/vendor/fonts/cat-chonburi-400.woff2 +0 -0
  252. package/app/public/vendor/fonts/cat-climate_crisis-400-ext.woff2 +0 -0
  253. package/app/public/vendor/fonts/cat-climate_crisis-400.woff2 +0 -0
  254. package/app/public/vendor/fonts/cat-cookie-400.woff2 +0 -0
  255. package/app/public/vendor/fonts/cat-dela_gothic_one-400-ext.woff2 +0 -0
  256. package/app/public/vendor/fonts/cat-dela_gothic_one-400.woff2 +0 -0
  257. package/app/public/vendor/fonts/cat-fascinate_inline-400-ext.woff2 +0 -0
  258. package/app/public/vendor/fonts/cat-fascinate_inline-400.woff2 +0 -0
  259. package/app/public/vendor/fonts/cat-ga_maamli-400-ext.woff2 +0 -0
  260. package/app/public/vendor/fonts/cat-ga_maamli-400.woff2 +0 -0
  261. package/app/public/vendor/fonts/cat-itim-400-ext.woff2 +0 -0
  262. package/app/public/vendor/fonts/cat-itim-400.woff2 +0 -0
  263. package/app/public/vendor/fonts/cat-jacquard_24-400-ext.woff2 +0 -0
  264. package/app/public/vendor/fonts/cat-jacquard_24-400.woff2 +0 -0
  265. package/app/public/vendor/fonts/cat-kablammo-400-ext.woff2 +0 -0
  266. package/app/public/vendor/fonts/cat-kablammo-400.woff2 +0 -0
  267. package/app/public/vendor/fonts/cat-kalam-400-ext.woff2 +0 -0
  268. package/app/public/vendor/fonts/cat-kalam-400.woff2 +0 -0
  269. package/app/public/vendor/fonts/cat-kalam-700-ext.woff2 +0 -0
  270. package/app/public/vendor/fonts/cat-kalam-700.woff2 +0 -0
  271. package/app/public/vendor/fonts/cat-katibeh-400-ext.woff2 +0 -0
  272. package/app/public/vendor/fonts/cat-katibeh-400.woff2 +0 -0
  273. package/app/public/vendor/fonts/cat-lemonada-400-ext.woff2 +0 -0
  274. package/app/public/vendor/fonts/cat-lemonada-400.woff2 +0 -0
  275. package/app/public/vendor/fonts/cat-lilita_one-400-ext.woff2 +0 -0
  276. package/app/public/vendor/fonts/cat-lilita_one-400.woff2 +0 -0
  277. package/app/public/vendor/fonts/cat-lobster-400-ext.woff2 +0 -0
  278. package/app/public/vendor/fonts/cat-lobster-400.woff2 +0 -0
  279. package/app/public/vendor/fonts/cat-luckiest_guy-400-ext.woff2 +0 -0
  280. package/app/public/vendor/fonts/cat-luckiest_guy-400.woff2 +0 -0
  281. package/app/public/vendor/fonts/cat-marhey-400-ext.woff2 +0 -0
  282. package/app/public/vendor/fonts/cat-marhey-400.woff2 +0 -0
  283. package/app/public/vendor/fonts/cat-modak-400-ext.woff2 +0 -0
  284. package/app/public/vendor/fonts/cat-modak-400.woff2 +0 -0
  285. package/app/public/vendor/fonts/cat-momo_signature-400-ext.woff2 +0 -0
  286. package/app/public/vendor/fonts/cat-momo_signature-400.woff2 +0 -0
  287. package/app/public/vendor/fonts/cat-monofett-400-ext.woff2 +0 -0
  288. package/app/public/vendor/fonts/cat-monofett-400.woff2 +0 -0
  289. package/app/public/vendor/fonts/cat-monomakh-400-ext.woff2 +0 -0
  290. package/app/public/vendor/fonts/cat-monomakh-400.woff2 +0 -0
  291. package/app/public/vendor/fonts/cat-monoton-400-ext.woff2 +0 -0
  292. package/app/public/vendor/fonts/cat-monoton-400.woff2 +0 -0
  293. package/app/public/vendor/fonts/cat-nerko_one-400-ext.woff2 +0 -0
  294. package/app/public/vendor/fonts/cat-nerko_one-400.woff2 +0 -0
  295. package/app/public/vendor/fonts/cat-noto_sans_adlam-400-ext.woff2 +0 -0
  296. package/app/public/vendor/fonts/cat-noto_sans_adlam-400.woff2 +0 -0
  297. package/app/public/vendor/fonts/cat-noto_sans_arabic-400-ext.woff2 +0 -0
  298. package/app/public/vendor/fonts/cat-noto_sans_arabic-400.woff2 +0 -0
  299. package/app/public/vendor/fonts/cat-noto_sans_devanagari-400-ext.woff2 +0 -0
  300. package/app/public/vendor/fonts/cat-noto_sans_devanagari-400.woff2 +0 -0
  301. package/app/public/vendor/fonts/cat-noto_sans_hebrew-400-ext.woff2 +0 -0
  302. package/app/public/vendor/fonts/cat-noto_sans_hebrew-400.woff2 +0 -0
  303. package/app/public/vendor/fonts/cat-noto_sans_jp-400-ext.woff2 +0 -0
  304. package/app/public/vendor/fonts/cat-noto_sans_jp-400.woff2 +0 -0
  305. package/app/public/vendor/fonts/cat-noto_sans_khmer-400-ext.woff2 +0 -0
  306. package/app/public/vendor/fonts/cat-noto_sans_khmer-400.woff2 +0 -0
  307. package/app/public/vendor/fonts/cat-noto_sans_kr-400-ext.woff2 +0 -0
  308. package/app/public/vendor/fonts/cat-noto_sans_kr-400.woff2 +0 -0
  309. package/app/public/vendor/fonts/cat-noto_sans_sc-400-ext.woff2 +0 -0
  310. package/app/public/vendor/fonts/cat-noto_sans_sc-400.woff2 +0 -0
  311. package/app/public/vendor/fonts/cat-noto_sans_thai-400-ext.woff2 +0 -0
  312. package/app/public/vendor/fonts/cat-noto_sans_thai-400.woff2 +0 -0
  313. package/app/public/vendor/fonts/cat-ole-400-ext.woff2 +0 -0
  314. package/app/public/vendor/fonts/cat-ole-400.woff2 +0 -0
  315. package/app/public/vendor/fonts/cat-pacifico-400-ext.woff2 +0 -0
  316. package/app/public/vendor/fonts/cat-pacifico-400.woff2 +0 -0
  317. package/app/public/vendor/fonts/cat-patrick_hand-400-ext.woff2 +0 -0
  318. package/app/public/vendor/fonts/cat-patrick_hand-400.woff2 +0 -0
  319. package/app/public/vendor/fonts/cat-petit_formal_script-400-ext.woff2 +0 -0
  320. package/app/public/vendor/fonts/cat-petit_formal_script-400.woff2 +0 -0
  321. package/app/public/vendor/fonts/cat-pixelify_sans-400-ext.woff2 +0 -0
  322. package/app/public/vendor/fonts/cat-pixelify_sans-400.woff2 +0 -0
  323. package/app/public/vendor/fonts/cat-plaster-400-ext.woff2 +0 -0
  324. package/app/public/vendor/fonts/cat-plaster-400.woff2 +0 -0
  325. package/app/public/vendor/fonts/cat-playwrite_ar_guides-400-0.woff2 +0 -0
  326. package/app/public/vendor/fonts/cat-playwrite_at-400-0.woff2 +0 -0
  327. package/app/public/vendor/fonts/cat-playwrite_at_guides-400-0.woff2 +0 -0
  328. package/app/public/vendor/fonts/cat-playwrite_au_nsw-400-0.woff2 +0 -0
  329. package/app/public/vendor/fonts/cat-playwrite_au_nsw_guides-400-0.woff2 +0 -0
  330. package/app/public/vendor/fonts/cat-playwrite_au_qld-400-0.woff2 +0 -0
  331. package/app/public/vendor/fonts/cat-playwrite_au_qld_guides-400-0.woff2 +0 -0
  332. package/app/public/vendor/fonts/cat-playwrite_au_sa-400-0.woff2 +0 -0
  333. package/app/public/vendor/fonts/cat-playwrite_au_sa_guides-400-0.woff2 +0 -0
  334. package/app/public/vendor/fonts/cat-playwrite_au_tas-400-0.woff2 +0 -0
  335. package/app/public/vendor/fonts/cat-playwrite_au_tas_guides-400-0.woff2 +0 -0
  336. package/app/public/vendor/fonts/cat-playwrite_au_vic-400-0.woff2 +0 -0
  337. package/app/public/vendor/fonts/cat-playwrite_au_vic_guides-400-0.woff2 +0 -0
  338. package/app/public/vendor/fonts/cat-playwrite_be_vlg-400-0.woff2 +0 -0
  339. package/app/public/vendor/fonts/cat-playwrite_be_vlg_guides-400-0.woff2 +0 -0
  340. package/app/public/vendor/fonts/cat-playwrite_be_wal-400-0.woff2 +0 -0
  341. package/app/public/vendor/fonts/cat-playwrite_be_wal_guides-400-0.woff2 +0 -0
  342. package/app/public/vendor/fonts/cat-playwrite_br_guides-400-0.woff2 +0 -0
  343. package/app/public/vendor/fonts/cat-playwrite_ca_guides-400-0.woff2 +0 -0
  344. package/app/public/vendor/fonts/cat-playwrite_cl_guides-400-0.woff2 +0 -0
  345. package/app/public/vendor/fonts/cat-playwrite_co_guides-400-0.woff2 +0 -0
  346. package/app/public/vendor/fonts/cat-playwrite_cu_guides-400-0.woff2 +0 -0
  347. package/app/public/vendor/fonts/cat-playwrite_cz-400-0.woff2 +0 -0
  348. package/app/public/vendor/fonts/cat-playwrite_cz_guides-400-0.woff2 +0 -0
  349. package/app/public/vendor/fonts/cat-playwrite_de_grund-400-0.woff2 +0 -0
  350. package/app/public/vendor/fonts/cat-playwrite_de_grund_guides-400-0.woff2 +0 -0
  351. package/app/public/vendor/fonts/cat-playwrite_de_la-400-0.woff2 +0 -0
  352. package/app/public/vendor/fonts/cat-playwrite_de_la_guides-400-0.woff2 +0 -0
  353. package/app/public/vendor/fonts/cat-playwrite_de_sas-400-0.woff2 +0 -0
  354. package/app/public/vendor/fonts/cat-playwrite_de_sas_guides-400-0.woff2 +0 -0
  355. package/app/public/vendor/fonts/cat-playwrite_de_va-400-0.woff2 +0 -0
  356. package/app/public/vendor/fonts/cat-playwrite_de_va_guides-400-0.woff2 +0 -0
  357. package/app/public/vendor/fonts/cat-playwrite_dk_loopet-400-0.woff2 +0 -0
  358. package/app/public/vendor/fonts/cat-playwrite_dk_loopet_guides-400-0.woff2 +0 -0
  359. package/app/public/vendor/fonts/cat-playwrite_dk_uloopet-400-0.woff2 +0 -0
  360. package/app/public/vendor/fonts/cat-playwrite_dk_uloopet_guides-400-0.woff2 +0 -0
  361. package/app/public/vendor/fonts/cat-playwrite_es_deco_guides-400-0.woff2 +0 -0
  362. package/app/public/vendor/fonts/cat-playwrite_es_guides-400-0.woff2 +0 -0
  363. package/app/public/vendor/fonts/cat-playwrite_fr_moderne-400-0.woff2 +0 -0
  364. package/app/public/vendor/fonts/cat-playwrite_fr_moderne_guides-400-0.woff2 +0 -0
  365. package/app/public/vendor/fonts/cat-playwrite_fr_trad-400-0.woff2 +0 -0
  366. package/app/public/vendor/fonts/cat-playwrite_fr_trad_guides-400-0.woff2 +0 -0
  367. package/app/public/vendor/fonts/cat-playwrite_gb_j_guides-400-0.woff2 +0 -0
  368. package/app/public/vendor/fonts/cat-playwrite_gb_s_guides-400-0.woff2 +0 -0
  369. package/app/public/vendor/fonts/cat-playwrite_hr-400-0.woff2 +0 -0
  370. package/app/public/vendor/fonts/cat-playwrite_hr_guides-400-0.woff2 +0 -0
  371. package/app/public/vendor/fonts/cat-playwrite_hr_lijeva-400-0.woff2 +0 -0
  372. package/app/public/vendor/fonts/cat-playwrite_hr_lijeva_guides-400-0.woff2 +0 -0
  373. package/app/public/vendor/fonts/cat-playwrite_hu-400-0.woff2 +0 -0
  374. package/app/public/vendor/fonts/cat-playwrite_hu_guides-400-0.woff2 +0 -0
  375. package/app/public/vendor/fonts/cat-playwrite_id-400-0.woff2 +0 -0
  376. package/app/public/vendor/fonts/cat-playwrite_id_guides-400-0.woff2 +0 -0
  377. package/app/public/vendor/fonts/cat-playwrite_ie-400-0.woff2 +0 -0
  378. package/app/public/vendor/fonts/cat-playwrite_ie_guides-400-0.woff2 +0 -0
  379. package/app/public/vendor/fonts/cat-playwrite_in-400-0.woff2 +0 -0
  380. package/app/public/vendor/fonts/cat-playwrite_in_guides-400-0.woff2 +0 -0
  381. package/app/public/vendor/fonts/cat-playwrite_is-400-0.woff2 +0 -0
  382. package/app/public/vendor/fonts/cat-playwrite_is_guides-400-0.woff2 +0 -0
  383. package/app/public/vendor/fonts/cat-playwrite_it_moderna-400-0.woff2 +0 -0
  384. package/app/public/vendor/fonts/cat-playwrite_it_moderna_guides-400-0.woff2 +0 -0
  385. package/app/public/vendor/fonts/cat-playwrite_it_trad-400-0.woff2 +0 -0
  386. package/app/public/vendor/fonts/cat-playwrite_it_trad_guides-400-0.woff2 +0 -0
  387. package/app/public/vendor/fonts/cat-playwrite_mx_guides-400-0.woff2 +0 -0
  388. package/app/public/vendor/fonts/cat-playwrite_ng_modern-400-0.woff2 +0 -0
  389. package/app/public/vendor/fonts/cat-playwrite_ng_modern_guides-400-0.woff2 +0 -0
  390. package/app/public/vendor/fonts/cat-playwrite_nl-400-0.woff2 +0 -0
  391. package/app/public/vendor/fonts/cat-playwrite_nl_guides-400-0.woff2 +0 -0
  392. package/app/public/vendor/fonts/cat-playwrite_no-400-0.woff2 +0 -0
  393. package/app/public/vendor/fonts/cat-playwrite_no_guides-400-0.woff2 +0 -0
  394. package/app/public/vendor/fonts/cat-playwrite_nz-400-0.woff2 +0 -0
  395. package/app/public/vendor/fonts/cat-playwrite_nz_basic-400-0.woff2 +0 -0
  396. package/app/public/vendor/fonts/cat-playwrite_nz_basic_guides-400-0.woff2 +0 -0
  397. package/app/public/vendor/fonts/cat-playwrite_nz_guides-400-0.woff2 +0 -0
  398. package/app/public/vendor/fonts/cat-playwrite_pe_guides-400-0.woff2 +0 -0
  399. package/app/public/vendor/fonts/cat-playwrite_pl-400-0.woff2 +0 -0
  400. package/app/public/vendor/fonts/cat-playwrite_pl_guides-400-0.woff2 +0 -0
  401. package/app/public/vendor/fonts/cat-playwrite_pt_guides-400-0.woff2 +0 -0
  402. package/app/public/vendor/fonts/cat-playwrite_ro-400-0.woff2 +0 -0
  403. package/app/public/vendor/fonts/cat-playwrite_ro_guides-400-0.woff2 +0 -0
  404. package/app/public/vendor/fonts/cat-playwrite_sk-400-0.woff2 +0 -0
  405. package/app/public/vendor/fonts/cat-playwrite_sk_guides-400-0.woff2 +0 -0
  406. package/app/public/vendor/fonts/cat-playwrite_tz-400-0.woff2 +0 -0
  407. package/app/public/vendor/fonts/cat-playwrite_tz_guides-400-0.woff2 +0 -0
  408. package/app/public/vendor/fonts/cat-playwrite_us_modern_guides-400-0.woff2 +0 -0
  409. package/app/public/vendor/fonts/cat-playwrite_us_trad_guides-400-0.woff2 +0 -0
  410. package/app/public/vendor/fonts/cat-playwrite_vn-400-0.woff2 +0 -0
  411. package/app/public/vendor/fonts/cat-playwrite_vn_guides-400-0.woff2 +0 -0
  412. package/app/public/vendor/fonts/cat-playwrite_za-400-0.woff2 +0 -0
  413. package/app/public/vendor/fonts/cat-playwrite_za_guides-400-0.woff2 +0 -0
  414. package/app/public/vendor/fonts/cat-potta_one-400-ext.woff2 +0 -0
  415. package/app/public/vendor/fonts/cat-potta_one-400.woff2 +0 -0
  416. package/app/public/vendor/fonts/cat-ranchers-400-ext.woff2 +0 -0
  417. package/app/public/vendor/fonts/cat-ranchers-400.woff2 +0 -0
  418. package/app/public/vendor/fonts/cat-ranga-400-ext.woff2 +0 -0
  419. package/app/public/vendor/fonts/cat-ranga-400.woff2 +0 -0
  420. package/app/public/vendor/fonts/cat-ranga-700-ext.woff2 +0 -0
  421. package/app/public/vendor/fonts/cat-ranga-700.woff2 +0 -0
  422. package/app/public/vendor/fonts/cat-risque-400-ext.woff2 +0 -0
  423. package/app/public/vendor/fonts/cat-risque-400.woff2 +0 -0
  424. package/app/public/vendor/fonts/cat-rowdies-400-ext.woff2 +0 -0
  425. package/app/public/vendor/fonts/cat-rowdies-400.woff2 +0 -0
  426. package/app/public/vendor/fonts/cat-rowdies-700-ext.woff2 +0 -0
  427. package/app/public/vendor/fonts/cat-rowdies-700.woff2 +0 -0
  428. package/app/public/vendor/fonts/cat-ruge_boogie-400-ext.woff2 +0 -0
  429. package/app/public/vendor/fonts/cat-ruge_boogie-400.woff2 +0 -0
  430. package/app/public/vendor/fonts/cat-ruslan_display-400-ext.woff2 +0 -0
  431. package/app/public/vendor/fonts/cat-ruslan_display-400.woff2 +0 -0
  432. package/app/public/vendor/fonts/cat-sacramento-400-ext.woff2 +0 -0
  433. package/app/public/vendor/fonts/cat-sacramento-400.woff2 +0 -0
  434. package/app/public/vendor/fonts/cat-sancreek-400-ext.woff2 +0 -0
  435. package/app/public/vendor/fonts/cat-sancreek-400.woff2 +0 -0
  436. package/app/public/vendor/fonts/cat-sankofa_display-400-ext.woff2 +0 -0
  437. package/app/public/vendor/fonts/cat-sankofa_display-400.woff2 +0 -0
  438. package/app/public/vendor/fonts/cat-sedgwick_ave_display-400-ext.woff2 +0 -0
  439. package/app/public/vendor/fonts/cat-sedgwick_ave_display-400.woff2 +0 -0
  440. package/app/public/vendor/fonts/cat-shantell_sans-400-ext.woff2 +0 -0
  441. package/app/public/vendor/fonts/cat-shantell_sans-400.woff2 +0 -0
  442. package/app/public/vendor/fonts/cat-smokum-400-ext.woff2 +0 -0
  443. package/app/public/vendor/fonts/cat-smokum-400.woff2 +0 -0
  444. package/app/public/vendor/fonts/cat-solitreo-400-ext.woff2 +0 -0
  445. package/app/public/vendor/fonts/cat-solitreo-400.woff2 +0 -0
  446. package/app/public/vendor/fonts/cat-spicy_rice-400-ext.woff2 +0 -0
  447. package/app/public/vendor/fonts/cat-spicy_rice-400.woff2 +0 -0
  448. package/app/public/vendor/fonts/cat-sriracha-400-ext.woff2 +0 -0
  449. package/app/public/vendor/fonts/cat-sriracha-400.woff2 +0 -0
  450. package/app/public/vendor/fonts/cat-srisakdi-400-ext.woff2 +0 -0
  451. package/app/public/vendor/fonts/cat-srisakdi-400.woff2 +0 -0
  452. package/app/public/vendor/fonts/cat-srisakdi-700-ext.woff2 +0 -0
  453. package/app/public/vendor/fonts/cat-srisakdi-700.woff2 +0 -0
  454. package/app/public/vendor/fonts/cat-stix_two_math-400-0.woff2 +0 -0
  455. package/app/public/vendor/fonts/cat-tillana-400-ext.woff2 +0 -0
  456. package/app/public/vendor/fonts/cat-tillana-400.woff2 +0 -0
  457. package/app/public/vendor/fonts/cat-tillana-700-ext.woff2 +0 -0
  458. package/app/public/vendor/fonts/cat-tillana-700.woff2 +0 -0
  459. package/app/public/vendor/fonts/cat-titan_one-400-ext.woff2 +0 -0
  460. package/app/public/vendor/fonts/cat-titan_one-400.woff2 +0 -0
  461. package/app/public/vendor/fonts/cat-yatra_one-400-ext.woff2 +0 -0
  462. package/app/public/vendor/fonts/cat-yatra_one-400.woff2 +0 -0
  463. package/app/public/vendor/fonts/cat-yomogi-400-ext.woff2 +0 -0
  464. package/app/public/vendor/fonts/cat-yomogi-400.woff2 +0 -0
  465. package/app/public/vendor/fonts/dmserifdisplay-400-ext.woff2 +0 -0
  466. package/app/public/vendor/fonts/dmserifdisplay-400.woff2 +0 -0
  467. package/app/public/vendor/fonts/domine-var-ext.woff2 +0 -0
  468. package/app/public/vendor/fonts/domine-var.woff2 +0 -0
  469. package/app/public/vendor/fonts/fondamento-400-ext.woff2 +0 -0
  470. package/app/public/vendor/fonts/fondamento-400.woff2 +0 -0
  471. package/app/public/vendor/fonts/fraunces-var-ext.woff2 +0 -0
  472. package/app/public/vendor/fonts/fraunces-var.woff2 +0 -0
  473. package/app/public/vendor/fonts/fredoka-var-ext.woff2 +0 -0
  474. package/app/public/vendor/fonts/fredoka-var.woff2 +0 -0
  475. package/app/public/vendor/fonts/inter-400.woff2 +0 -0
  476. package/app/public/vendor/fonts/inter-700.woff2 +0 -0
  477. package/app/public/vendor/fonts/jakarta-var-ext.woff2 +0 -0
  478. package/app/public/vendor/fonts/jakarta-var.woff2 +0 -0
  479. package/app/public/vendor/fonts/lato-400.woff2 +0 -0
  480. package/app/public/vendor/fonts/lato-700.woff2 +0 -0
  481. package/app/public/vendor/fonts/literata-400.woff2 +0 -0
  482. package/app/public/vendor/fonts/literata-700.woff2 +0 -0
  483. package/app/public/vendor/fonts/lora-var-ext.woff2 +0 -0
  484. package/app/public/vendor/fonts/lora-var.woff2 +0 -0
  485. package/app/public/vendor/fonts/merriweather-var-ext.woff2 +0 -0
  486. package/app/public/vendor/fonts/merriweather-var.woff2 +0 -0
  487. package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
  488. package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
  489. package/app/public/vendor/fonts/notosans-var-ext.woff2 +0 -0
  490. package/app/public/vendor/fonts/notosans-var.woff2 +0 -0
  491. package/app/public/vendor/fonts/nunito-var-ext.woff2 +0 -0
  492. package/app/public/vendor/fonts/nunito-var.woff2 +0 -0
  493. package/app/public/vendor/fonts/opendyslexic-400.woff2 +0 -0
  494. package/app/public/vendor/fonts/opensans-400.woff2 +0 -0
  495. package/app/public/vendor/fonts/opensans-700.woff2 +0 -0
  496. package/app/public/vendor/fonts/pinyon-400.woff2 +0 -0
  497. package/app/public/vendor/fonts/playfair-var-ext.woff2 +0 -0
  498. package/app/public/vendor/fonts/playfair-var.woff2 +0 -0
  499. package/app/public/vendor/fonts/pressstart-400.woff2 +0 -0
  500. package/app/public/vendor/fonts/quattro-400.woff2 +0 -0
  501. package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
  502. package/app/public/vendor/fonts/quicksand-var-ext.woff2 +0 -0
  503. package/app/public/vendor/fonts/quicksand-var.woff2 +0 -0
  504. package/app/public/vendor/fonts/robotoflex-var-ext.woff2 +0 -0
  505. package/app/public/vendor/fonts/robotoflex-var.woff2 +0 -0
  506. package/app/public/vendor/fonts/sora-var-ext.woff2 +0 -0
  507. package/app/public/vendor/fonts/sora-var.woff2 +0 -0
  508. package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
  509. package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
  510. package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
  511. package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
  512. package/app/public/vendor/fonts/spacegrotesk-var-ext.woff2 +0 -0
  513. package/app/public/vendor/fonts/spacegrotesk-var.woff2 +0 -0
  514. package/app/public/vendor/fonts/spectral-400-ext.woff2 +0 -0
  515. package/app/public/vendor/fonts/spectral-400.woff2 +0 -0
  516. package/app/public/vendor/fonts/spectral-700-ext.woff2 +0 -0
  517. package/app/public/vendor/fonts/spectral-700.woff2 +0 -0
  518. package/app/public/vendor/fonts/teachers-var-ext.woff2 +0 -0
  519. package/app/public/vendor/fonts/teachers-var.woff2 +0 -0
  520. package/app/public/vendor/fonts/ubuntu-400-ext.woff2 +0 -0
  521. package/app/public/vendor/fonts/ubuntu-400.woff2 +0 -0
  522. package/app/public/vendor/fonts/ubuntu-700-ext.woff2 +0 -0
  523. package/app/public/vendor/fonts/ubuntu-700.woff2 +0 -0
  524. package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
  525. package/dist-pkg/platform/guide-intensity.d.ts +0 -39
  526. package/dist-pkg/platform/guide-intensity.js +0 -71
  527. package/dist-pkg/ui/latch-refusal.d.ts +0 -33
  528. package/dist-pkg/ui/latch-refusal.js +0 -60
@@ -2,7 +2,8 @@
2
2
  import type { Action } from '../core/actions.js';
3
3
  /** The safe item: taking it commands nothing. Same word the gaze cycle uses, and the same job. */
4
4
  export declare const SCAN_CANCEL = "cancel";
5
- export type ScanItem = Action | typeof SCAN_CANCEL;
5
+ /** What a scan offers: the items it was given — positions in play, a menu's steps in a menu — and «cancel» in front. */
6
+ export type ScanItem<T extends string = Action> = T | typeof SCAN_CANCEL;
6
7
  export interface SwitchScanOptions {
7
8
  /** How long each item is offered. 1 s is the gaze cycle's step, which the Dev ran for a day (ADR-0213). */
8
9
  readonly stepMs?: number;
@@ -13,30 +14,46 @@ export declare const SWITCH_SCAN_DEFAULTS: {
13
14
  readonly stepMs: 1000;
14
15
  readonly pulseMs: 400;
15
16
  };
17
+ /**
18
+ * THE ENGINE'S OWN DOORS, and whether each has something behind it (ADR-0218 §3). A door with nothing behind it is not offered:
19
+ * a cycle never stops on a position that does nothing (ADR-0155).
20
+ */
21
+ export interface ScanDoors {
22
+ /** The card SELECT opens is mounted. */
23
+ readonly menus: boolean;
24
+ /** The quick pause START opens has its bar — the menu the scan steps there, and «back» is how it is left. */
25
+ readonly quickPause: boolean;
26
+ }
27
+ /**
28
+ * What the scan offers IN PLAY after «cancel»: the game's named positions, then the doors in the order ADR-0218 §3 names them —
29
+ * the menus (SELECT), then the quick pause (START). Taking a door presses it on the virtual controller, which hands it to the
30
+ * engine as its keys are.
31
+ */
32
+ export declare function playScanList(game: readonly Action[], doors: ScanDoors): readonly Action[];
16
33
  export interface ScanFrame {
17
34
  /** Her switch went down on this frame. Whatever sends it — a key, a touch, a gesture, a word. */
18
35
  readonly press?: boolean;
19
36
  }
20
- export interface ScanOutput {
21
- /** The action being pressed, for `pulseMs` after it was taken. */
22
- readonly pressed: Action | null;
23
- /** The action taken on THIS frame — what a caller turns into a press. */
24
- readonly commanded: Action | null;
37
+ export interface ScanOutput<T extends string = Action> {
38
+ /** The item being pressed, for `pulseMs` after it was taken. */
39
+ readonly pressed: T | null;
40
+ /** The item taken on THIS frame — what a caller turns into a press. */
41
+ readonly commanded: T | null;
25
42
  /** What is being offered right now, and where it sits in the list. Never `null`: something is always showing. */
26
43
  readonly showing: {
27
- readonly item: ScanItem;
44
+ readonly item: ScanItem<T>;
28
45
  readonly index: number;
29
46
  };
30
47
  }
31
- export interface SwitchScan {
32
- (nowMs: number, frame?: ScanFrame): ScanOutput;
48
+ export interface SwitchScan<T extends string = Action> {
49
+ (nowMs: number, frame?: ScanFrame): ScanOutput<T>;
33
50
  }
34
51
  /**
35
- * The scanner. `actions` is what THIS game offers — its declared positions and the engine's own doors — and `cancel` is put in
36
- * front of them.
52
+ * The scanner. `actions` is what is offered now — in play this game's declared positions and the engine's own doors, in a menu
53
+ * that menu's steps — and `cancel` is put in front of them.
37
54
  *
38
55
  * ⚠️ An empty list is not an error: a game that declared nothing leaves a scan of one item, `cancel`, and a press takes nothing.
39
56
  * The alternative — offering the whole controller to a game that reads none of it — is the dead button ADR-0106 §5 refuses, and
40
57
  * here it would cost a child a full pass of fourteen items to reach the one thing that works.
41
58
  */
42
- export declare function createSwitchScan(actions: readonly Action[], options?: SwitchScanOptions): SwitchScan;
59
+ export declare function createSwitchScan<T extends string = Action>(actions: readonly T[], options?: SwitchScanOptions): SwitchScan<T>;
@@ -19,8 +19,21 @@
19
19
  export const SCAN_CANCEL = 'cancel';
20
20
  export const SWITCH_SCAN_DEFAULTS = { stepMs: 1000, pulseMs: 400 };
21
21
  /**
22
- * The scanner. `actions` is what THIS game offers — its declared positions and the engine's own doors — and `cancel` is put in
23
- * front of them.
22
+ * What the scan offers IN PLAY after «cancel»: the game's named positions, then the doors in the order ADR-0218 §3 names them —
23
+ * the menus (SELECT), then the quick pause (START). Taking a door presses it on the virtual controller, which hands it to the
24
+ * engine as its keys are.
25
+ */
26
+ export function playScanList(game, doors) {
27
+ const list = [...game];
28
+ if (doors.menus)
29
+ list.push('select');
30
+ if (doors.quickPause)
31
+ list.push('start');
32
+ return list;
33
+ }
34
+ /**
35
+ * The scanner. `actions` is what is offered now — in play this game's declared positions and the engine's own doors, in a menu
36
+ * that menu's steps — and `cancel` is put in front of them.
24
37
  *
25
38
  * ⚠️ An empty list is not an error: a game that declared nothing leaves a scan of one item, `cancel`, and a press takes nothing.
26
39
  * The alternative — offering the whole controller to a game that reads none of it — is the dead button ADR-0106 §5 refuses, and
@@ -5,9 +5,6 @@ import type { PlayerView } from '../core/entity.js';
5
5
  import type { DomQuery } from '../core/dom-query.js';
6
6
  import type { KeyScheme } from '../core/entity.js';
7
7
  import { type Action } from '../core/actions.js';
8
- export type { DomQuery } from '../core/dom-query.js';
9
- /** action -> list of physical codes. */
10
- export type { KeyScheme } from '../core/entity.js';
11
8
  /** The six input edges touch raises on the player (consumed and cleared by the game's physics). */
12
9
  export type EdgeFlag = 'jumpEdge' | 'runEdge' | 'leftEdge' | 'rightEdge' | 'swapEdge' | 'specialEdge';
13
10
  /** An edge to raise: which player (POSITION in the array) and which flag. */
@@ -29,8 +26,6 @@ export interface TouchBindSnapshot {
29
26
  /** `input/state.ts`'s `keys`: the keys held NOW (every transport's, mixed). */
30
27
  heldKeys: ReadonlySet<string>;
31
28
  }
32
- /** Re-exported: the definition lives in `input/pointer-space`, with the arithmetic that uses it (issue #105). */
33
- export type { RectLike } from './pointer-space.js';
34
29
  /** The d-pad's four physical directions, on or off. */
35
30
  export interface DirSet {
36
31
  left: boolean;
@@ -188,7 +183,9 @@ export interface TouchBindingsCtx {
188
183
  *
189
184
  * 🔴 REQUIRED, and it is where the device switch becomes VISIBLE: touch is the transport the child uses beside the
190
185
  * keyboard, and without this line the automaton answers `teclado` even with the finger on the screen — so the latch
191
- * read would be the keyboard's, on the wrong device.
186
+ * read would be the keyboard's, on the wrong device. 📌 In the root the press has already recorded this edge and resolved
187
+ * touch's latch at the virtual controller's `pressedBy` (ADR-0109 rule 3); a host without that door passes the latched edge
188
+ * of `input/latch-edge` here.
192
189
  */
193
190
  playerEdge: (player: number, source: TransportName) => void;
194
191
  /**
@@ -1,8 +1,6 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  import type { Translate } from '../core/i18n.js';
3
3
  import type { DomQuery } from '../core/dom-query.js';
4
- /** Minimal DOM-selector shape (matches ui/dom.ts's `$`). */
5
- export type { DomQuery } from '../core/dom-query.js';
6
4
  /** Minimal platform/storage.ts shape this module needs. */
7
5
  export interface TouchStore {
8
6
  get(key: string, fallback?: string | null): string | null;
@@ -78,6 +76,22 @@ export interface TouchCtx {
78
76
  * root never handed in, which is what took down every boot in a fake document once this was wired to `createGame`.
79
77
  */
80
78
  win: Pick<Window, 'addEventListener'> | null;
79
+ /**
80
+ * Draws ONE slot's choice by its size (ADR-0130 rule 3): five named positions or fewer are a cycle row, more a dropdown.
81
+ * Injected because the drawing lives in `ui/panel-widgets.mountChoice` and this module is a layer below it (ADR-0173);
82
+ * `createGame` hands it in. ABSENT, each slot stays a hand-built `<select>`, whatever its size — a host that builds its
83
+ * own touch panel keeps the control it always had.
84
+ */
85
+ drawChoice?: (spec: TouchSlotChoice, pick: (action: string) => void) => HTMLElement;
86
+ }
87
+ /** What a slot's choice is drawn from: the slot's name, the game's positions in its words, and the one it carries now. */
88
+ export interface TouchSlotChoice {
89
+ readonly label: string;
90
+ readonly values: readonly {
91
+ readonly value: string;
92
+ readonly label: string;
93
+ }[];
94
+ readonly current: string;
81
95
  }
82
96
  export declare const IPHONE16_LONG_MM = 141.1;
83
97
  export declare const IPHONE16_LONG_PX = 852;
@@ -194,6 +208,7 @@ export interface TouchMarkupSpec {
194
208
  /** The d-pad's drawing: `cruz` (cross) or `analogico` (stick). It comes from the pad's persisted setting (`padDir`). */
195
209
  readonly dpad?: 'cruz' | 'analogico';
196
210
  }
211
+ export declare function buttonName(t: Translate, slotAction: string): string | null;
197
212
  /**
198
213
  * Builds (or reuses) `#touch-controls` and returns it.
199
214
  *
@@ -107,10 +107,31 @@ export function initTouch(ctx) {
107
107
  let padDir = ctx.store.get(KEYS.padDir, 'stick') || 'stick';
108
108
  let _stickTravelPx = 42, _stickDeadPx = 12; // boot values; applyPadPhysical() sets the real ones
109
109
  const touchMap = normalizeTouchMap(ctx.store.getJSON(KEYS.touchmap, null));
110
+ /** A slot's choice landed: store it, and say it in the game's word — never the abstract name. */
111
+ function slotChosen(slot, slotLabel, action) {
112
+ touchMap[slot] = action;
113
+ ctx.store.setJSON(KEYS.touchmap, touchMap);
114
+ // ⚠️ The spoken word is the SAME as the one read: it comes from the list that just built the control, so nothing has
115
+ // to make two tables agree.
116
+ const chosen = ctx.gameActions().find((x) => x.action === action);
117
+ const slotName = slotLabel || t('touch.slot.fallback');
118
+ // ⚠️ WITHOUT THE GAME'S WORD, THE ANNOUNCEMENT DROPS THE POSITION — IT DOES NOT FALL BACK TO THE ID. `action` is the
119
+ // ABSTRACT name (`action3`), and ADR-0074 says it never reaches a person; `7742ac0` already paid for this defect on the
120
+ // remapping screen and the way out is the same: a key of its own that says what matters.
121
+ // 📌 The fallback is reachable because `gameActions()` is a FUNCTION of the cartridge, reread on every choice: in an
122
+ // activity hub the list changes underneath and the control drawn before is orphaned.
123
+ ctx.srSay(chosen
124
+ ? t('sr.touch.slotSet', { slot: slotName, acao: chosen.label })
125
+ : t('sr.touch.slotSetUnnamed', { slot: slotName }));
126
+ }
110
127
  function renderTouchMap() {
111
128
  const el = ctx.$('#touchmap-list');
112
129
  if (!el)
113
130
  return;
131
+ if (ctx.drawChoice) {
132
+ drawSlotChoices(el, ctx.drawChoice);
133
+ return;
134
+ }
114
135
  el.innerHTML = TOUCH_SLOTS.map((s) => `<div class="ctrl-row"><label for="tm-${s.k}">${t(s.lbl)}</label><select id="tm-${s.k}" class="vol" data-slot="${s.k}">` +
115
136
  // ⚠️ THE OPTION IS BORN EMPTY and the `label` goes in just below through `textContent` (issue #106). It is the
116
137
  // game's WORD — `gameActions()` comes from the preset —, and a game lives in another repository (ADR-0083), so
@@ -127,25 +148,41 @@ export function initTouch(ctx) {
127
148
  }
128
149
  el.querySelectorAll('select[data-slot]').forEach((sel) => {
129
150
  sel.addEventListener('change', () => {
130
- const slot = sel.dataset.slot || '';
131
- touchMap[slot] = sel.value;
132
- ctx.store.setJSON(KEYS.touchmap, touchMap);
133
151
  const label = sel.previousElementSibling ? sel.previousElementSibling.textContent : null;
134
- // ⚠️ The spoken word is the SAME as the one read: it comes from the list that just built the `<option>`, so
135
- // nothing has to make two tables agree.
136
- const chosen = ctx.gameActions().find((x) => x.action === sel.value);
137
- const slotName = label || t('touch.slot.fallback');
138
- // ⚠️ WITHOUT THE GAME'S WORD, THE ANNOUNCEMENT DROPS THE POSITION — IT DOES NOT FALL BACK TO THE ID. `sel.value`
139
- // is the ABSTRACT name (`action3`), and ADR-0074 says it never reaches a person; `7742ac0` already paid for
140
- // this defect on the remapping screen and the way out is the same: a key of its own that says what matters.
141
- // 📌 The fallback is reachable because `gameActions()` is a FUNCTION of the cartridge, reread on every
142
- // `change`: in an activity hub the list changes underneath and the `<option>` drawn before is orphaned.
143
- ctx.srSay(chosen
144
- ? t('sr.touch.slotSet', { slot: slotName, acao: chosen.label })
145
- : t('sr.touch.slotSetUnnamed', { slot: slotName }));
152
+ slotChosen(sel.dataset.slot || '', label, sel.value);
146
153
  });
147
154
  });
148
155
  }
156
+ /**
157
+ * THE SLOTS DRAWN BY THEIR SIZE (ADR-0130 rule 3), node by node: each slot is a choice among the game's named positions,
158
+ * so a game naming five or fewer gets cycle rows «◀ Botão 0: Confirmar ▶», and one naming more gets dropdowns. The id
159
+ * (`#tm-<slot>`) and `data-slot` stay on the control in both shapes — they are how the root finds the slots it hides.
160
+ */
161
+ function drawSlotChoices(el, draw) {
162
+ while (el.firstChild)
163
+ el.removeChild(el.firstChild);
164
+ const doc = el.ownerDocument;
165
+ const positions = ctx.gameActions().map(({ action, label }) => ({ value: action, label }));
166
+ for (const s of TOUCH_SLOTS) {
167
+ const slotName = t(s.lbl);
168
+ const control = draw({ label: slotName, values: positions, current: touchMap[s.k] ?? '' }, (action) => slotChosen(s.k, slotName, action));
169
+ control.id = `tm-${s.k}`;
170
+ control.dataset.slot = s.k;
171
+ const row = doc.createElement('div');
172
+ row.className = 'ctrl-row';
173
+ if (control.tagName === 'SELECT') {
174
+ // a dropdown keeps its name beside it; a cycle row already carries it in its own text
175
+ const name = doc.createElement('label');
176
+ name.htmlFor = control.id;
177
+ name.textContent = slotName;
178
+ row.appendChild(name);
179
+ }
180
+ else
181
+ row.classList.add('ctrl-row--passos');
182
+ row.appendChild(control);
183
+ el.appendChild(row);
184
+ }
185
+ }
149
186
  function openTouchCfg() {
150
187
  const ov = ctx.$('#touchcfg');
151
188
  if (!ov)
@@ -310,14 +347,15 @@ export function initTouch(ctx) {
310
347
  }
311
348
  /**
312
349
  * A BUTTON'S NAME, from the position it fires (ADR-0165): the same in every game — 1 to 4, L1/L2/R1/R2, SELECT, START,
313
- * and the four directions by their spoken name. The cartridge's word is the FUNCTION, and it never reaches the face.
350
+ * and the four directions by their spoken name. The cartridge's word is the FUNCTION, and it never reaches the face. The pad
351
+ * wizard asks by these names where the game names no position (`input/pad-wizard`, ADR-0144 erratum of 2026-09-26).
314
352
  */
315
353
  const SLOT_NAME = {
316
354
  action1: '1', action2: '2', action3: '3', action4: '4',
317
355
  leftShoulder: 'L1', leftTrigger: 'L2', rightShoulder: 'R1', rightTrigger: 'R2',
318
356
  select: 'SELECT', start: 'START',
319
357
  };
320
- function buttonName(t, slotAction) {
358
+ export function buttonName(t, slotAction) {
321
359
  if (SLOT_NAME[slotAction])
322
360
  return SLOT_NAME[slotAction];
323
361
  return slotAction === 'up' || slotAction === 'down' || slotAction === 'left' || slotAction === 'right' ? t(`touch.nome.${slotAction}`) : null;
@@ -32,9 +32,9 @@ export declare function isTransportName(v: unknown): v is TransportName;
32
32
  * THE FOUR THAT REQUIRE EXPLICIT ENABLING and, once enabled, rule over all the others (rule 4).
33
33
  *
34
34
  * ⚠️ It is the same list as `ONE_COMMAND_AT_A_TIME` in `input/latch-scope`, and the match is no accident: these
35
- * are the transports of whoever CANNOT HOLD ANYTHING. What ADR-0109 adds is that they do not turn latching on
36
- * only for themselves — they turn it on for the rest, because whoever uses the webcam may also touch the screen,
37
- * and a latch that turns off when the device changes is a trap for exactly that person.
35
+ * are the transports that send one command at a time. What ADR-0109 added — that enabling them turns latching on
36
+ * for the rest — is the model of `latchNow`, which ADR-0113 superseded; since ADR-0249 their own latch starts as
37
+ * the game's `holdsKeys()` and the child may change it.
38
38
  */
39
39
  export declare const NEED_ENABLING: ReadonlySet<TransportName>;
40
40
  /** The transport that turns latching on by itself, with no priority involved (rule 2). */
@@ -78,8 +78,8 @@ export declare const DEFAULT_INPUT_STATE: InputState;
78
78
  * `latch-scope.latchOf` returns `true`, because it reads what they saved.
79
79
  *
80
80
  * ⚠️ AND THE TOUCH CLAUSE FELL TOO: under ADR-0113 touch is a transport like the others — its value is a choice
81
- * and is stored. Only eyes, face, gestures and speech may refuse to turn OFF, and that half lives in
82
- * `latch-scope.latchAlwaysOn`, with a different set from this one and answering a different question.
81
+ * and is stored. Eyes, face, gestures and speech differ only in where their DEFAULT comes from — the game's
82
+ * `holdsKeys()` (ADR-0249, `latch-scope.latchDefaultFromGame`) — and their value is a choice too.
83
83
  *
84
84
  * **The right answer is `latch-scope.latchOf(inputState.inUse, reading)`.** The role left to this module is
85
85
  * what its name says: WHICH transport is in use — which is what feeds that first argument.
@@ -53,9 +53,9 @@ export function isTransportName(v) {
53
53
  * THE FOUR THAT REQUIRE EXPLICIT ENABLING and, once enabled, rule over all the others (rule 4).
54
54
  *
55
55
  * ⚠️ It is the same list as `ONE_COMMAND_AT_A_TIME` in `input/latch-scope`, and the match is no accident: these
56
- * are the transports of whoever CANNOT HOLD ANYTHING. What ADR-0109 adds is that they do not turn latching on
57
- * only for themselves — they turn it on for the rest, because whoever uses the webcam may also touch the screen,
58
- * and a latch that turns off when the device changes is a trap for exactly that person.
56
+ * are the transports that send one command at a time. What ADR-0109 added — that enabling them turns latching on
57
+ * for the rest — is the model of `latchNow`, which ADR-0113 superseded; since ADR-0249 their own latch starts as
58
+ * the game's `holdsKeys()` and the child may change it.
59
59
  */
60
60
  export const NEED_ENABLING = new Set(['olhos', 'rosto', 'gestos', 'fala']);
61
61
  /** The transport that turns latching on by itself, with no priority involved (rule 2). */
@@ -89,8 +89,8 @@ export const DEFAULT_INPUT_STATE = Object.freeze({ inUse: 'teclado', assistedOn:
89
89
  * `latch-scope.latchOf` returns `true`, because it reads what they saved.
90
90
  *
91
91
  * ⚠️ AND THE TOUCH CLAUSE FELL TOO: under ADR-0113 touch is a transport like the others — its value is a choice
92
- * and is stored. Only eyes, face, gestures and speech may refuse to turn OFF, and that half lives in
93
- * `latch-scope.latchAlwaysOn`, with a different set from this one and answering a different question.
92
+ * and is stored. Eyes, face, gestures and speech differ only in where their DEFAULT comes from — the game's
93
+ * `holdsKeys()` (ADR-0249, `latch-scope.latchDefaultFromGame`) — and their value is a choice too.
94
94
  *
95
95
  * **The right answer is `latch-scope.latchOf(inputState.inUse, reading)`.** The role left to this module is
96
96
  * what its name says: WHICH transport is in use — which is what feeds that first argument.
@@ -81,15 +81,6 @@ export interface Transport {
81
81
  }
82
82
  /** Does this transport carry this set of actions? Arithmetic, as ADR-0079 §3 describes it. */
83
83
  export declare function carries(t: Transport, actions: readonly Action[]): boolean;
84
- /**
85
- * Does this transport HOLD as many as the game asks at once? (ADR-0104 §A.)
86
- *
87
- * ⚠️ A TRANSPORT WITH NO DECLARED CEILING ANSWERS YES, and the choice is deliberate: an absent `holds` means "we did
88
- * not measure this", and refusing for lack of a measure would turn ignorance into an accusation — keyboard and pad
89
- * would fail every game for having no number at all. Where there is no decision, the model stays silent; touch is
90
- * the one with a decision, and it alone can fail here.
91
- */
92
- export declare function holds(t: Transport, asked: number): boolean;
93
84
  /**
94
85
  * The AVAILABLE transports that carry this set.
95
86
  *
@@ -91,7 +91,7 @@ export function carries(t, actions) {
91
91
  * would fail every game for having no number at all. Where there is no decision, the model stays silent; touch is
92
92
  * the one with a decision, and it alone can fail here.
93
93
  */
94
- export function holds(t, asked) {
94
+ function holds(t, asked) {
95
95
  return t.holds === undefined || t.holds >= asked;
96
96
  }
97
97
  /**
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- import type { Action } from '../core/actions.js';
2
+ import { type Action } from '../core/actions.js';
3
3
  import type { KeyScheme } from '../core/entity.js';
4
4
  import type { TransportName } from './transport-in-use.js';
5
5
  export interface VirtualCommand {
@@ -30,17 +30,53 @@ export interface VirtualControllerDeps {
30
30
  */
31
31
  readonly menuKey: (code: string, source: TransportName | undefined) => void;
32
32
  readonly deliver: (command: VirtualCommand) => void;
33
+ /**
34
+ * A position the ENGINE answers itself while a menu is open, before it becomes a menu key: the sonar reads the menu in
35
+ * front (ADR-0234, `ui/screen-text.menuSonarPress`). Answers whether it took the press. Absent: every position is a key.
36
+ */
37
+ readonly menuAnswers?: (action: Action, player: number) => boolean;
38
+ /**
39
+ * A SYSTEM position pressed, in play or with a menu open: the engine answers it for that seat as its keys do — `start` the
40
+ * quick pause (again: leaves it), `select` the menus (ADR-0144 §1 and its erratum of 2026-09-26, ADR-0155). Absent: it does
41
+ * nothing.
42
+ *
43
+ * ⚠️ The keyboard does not come here: its key is already in the world, and the engine's own key listeners answer it even for
44
+ * a cartridge with no `onCommand` — the host's keyboard conductor does not press these two, or one key would pause twice.
45
+ */
46
+ readonly systemPress?: (action: Action, player: number) => void;
47
+ /**
48
+ * ONE BUTTON ONLY (ADR-0218 §4): asked FIRST, for every press from every transport that presses here — the eyes, the face,
49
+ * the hands, the voice, the on-screen pad, the gamepad. `true` means one-button scanning took the press as «take the one
50
+ * shown»: the position reaches nothing else — not play, not a menu, not the engine — and no release is owed for it. A press
51
+ * that lands on the scan's «cancel» is taken too, and means nothing. Absent: every press is itself.
52
+ */
53
+ readonly takeShown?: (source: TransportName | undefined) => boolean;
54
+ /**
55
+ * A PRESS FROM A NAMED TRANSPORT, told FIRST — before one button only, a menu or play decides where it goes. This is the one
56
+ * place every position-pressing transport shares, so it is where «the child is using this device» can be heard for all of
57
+ * them (ADR-0109 rule 3), and where the root records that device's edge and resolves its latch before the press reaches the
58
+ * game (ADR-0113, ADR-0249). Not told for a press with no source: a key nobody stamped is nobody's edge — the real keyboard
59
+ * arrives here as `teclado`, read off the event by `input/synthetic-source.sourceOfEvent`. Absent: nothing is told.
60
+ */
61
+ readonly pressedBy?: (source: TransportName, player: number) => void;
33
62
  }
34
63
  export interface VirtualController {
35
64
  /**
36
- * Presses a position. Answers whether it reached PLAY — `false` means a menu took it.
65
+ * Presses a position. Answers whether it reached PLAY — `false` means a menu took it, or it was held back (`toPlay`).
37
66
  *
38
67
  * 🔴 THE ANSWER EXISTS BECAUSE EVERY TRANSPORT NEEDS IT AND EACH WAS GUESSING IT (ADR-0223). The touch pad asked its own
39
68
  * `emMenu()` before deciding what to do, which is the same question this function has just answered — and two answers to
40
69
  * one question is how the two doors came to disagree about what happens with a menu open. A transport that raises an edge,
41
70
  * or hides its tips, or announces something, does it only when the press reached the game; now it is told.
71
+ *
72
+ * `toPlay` false: in play the press belongs to something else — the keyboard knows what has the focus, a field being typed
73
+ * into or the engine's own control being pressed (`input/key-default`) — so it reaches nobody: nothing held, nothing delivered.
74
+ * With a menu open it is the menu's all the same, as every press is (ADR-0111 erratum of 2026-09-26: one press, one action).
75
+ *
76
+ * A system position (`start`, `select`) never reaches play and never becomes a menu key: it is the engine's (ADR-0144 §4), and
77
+ * it goes to `systemPress` — unless, in play, `toPlay` is false, when the press belongs to something else and reaches nobody.
42
78
  */
43
- press(action: Action, source: TransportName | undefined, player?: number): boolean;
79
+ press(action: Action, source: TransportName | undefined, player?: number, toPlay?: boolean): boolean;
44
80
  release(action: Action, source: TransportName | undefined, player?: number): void;
45
81
  }
46
82
  export declare function createVirtualController(d: VirtualControllerDeps): VirtualController;
@@ -4,22 +4,50 @@
4
4
  // The Dev: «a engine lida com o hardware e passa para o jogo o nome virtual do botão, o jogo por sua vez devolve o nome do que é executado
5
5
  // ao apertar cada botão… a engine leva o evento para o jogo». A transport that reads positions (the eyes, and later the face and the
6
6
  // hands) presses and releases a position here, with its source; this decides what that reaches:
7
- // · with a menu open, the position is the menu's key — the way the touch pad already moves menus (ADR-0157), since menus read keys;
7
+ // · with a menu open, the position is the menu's key — the way the touch pad already moves menus (ADR-0157), since menus read keys —
8
+ // unless the engine answers it there itself (`menuAnswers`: the sonar reads the menu, ADR-0234);
8
9
  // · in play, the child's key for that position is held (games that ask what is held keep answering), and the command is delivered to the
9
10
  // cartridge: the position, pressed or released, the source, the seat. The cartridge's map (its `preset`) says what it executes.
10
11
  // A position the child's scheme gives no key is still delivered: the map belongs to the game, not to the keyboard.
12
+ // 🔴 EXCEPT THE TWO SYSTEM POSITIONS, which never reach play (ADR-0144 §4, ADR-0155 §4): `start` is the quick pause and `select`
13
+ // opens the menus, a cartridge may not declare either, so the game has no word for them and nothing to do with them. 📏 Before
14
+ // this, Enter in play opened the quick pause AND the quiz's `onCommand` heard `start`; F opened the card AND it heard `select`.
15
+ // They go to the ENGINE instead (`systemPress`), so START and SELECT open the pause «from any transport» (ADR-0144 §1): the eyes,
16
+ // the face, the hands, the voice and the scan press here and have no key in the world for the engine to hear.
17
+ // 🔴 AND WITH A MENU OPEN TOO, never as a key (ADR-0144 erratum of 2026-09-26). The first key of `start` is whatever the child put
18
+ // first: with `start` remapped to `Enter`, a camera's START on the quick pause's bar was the bar's «confirm» and not the way out.
19
+ // The engine answers the POSITION the same way its key listeners do — START again leaves the quick pause, SELECT goes on to the
20
+ // card, and an open card or panel refuses both.
21
+ // 🔴 AND WITH ONE BUTTON ONLY ON, NONE OF THE ABOVE (ADR-0218 §4): every press here is the child's one switch, and it takes the
22
+ // item the scan shows (`takeShown`, asked before anything else). This is the one place every position-pressing transport shares.
23
+ import { SYSTEM } from '../core/actions.js';
24
+ /** The positions that are the engine's and never the game's (`core/actions.SYSTEM`). */
25
+ const ENGINE_POSITIONS = new Set(SYSTEM);
11
26
  export function createVirtualController(d) {
12
27
  // `${player}:${action}` → the key held for a press the game received (or null when the scheme has none), so the release lets go of the
13
28
  // same key, and only a press the game heard is released to it
14
29
  const held = new Map();
15
30
  return {
16
- press(action, source, player = 0) {
31
+ press(action, source, player = 0, toPlay = true) {
32
+ if (source)
33
+ d.pressedBy?.(source, player);
34
+ if (d.takeShown?.(source))
35
+ return false; // one button only: whatever was pressed, it was the switch (ADR-0218 §4)
36
+ const menu = d.menuOpen();
37
+ // the POSITION, not its first key: a key means what the child bound to it, and `Enter` on a menu is «confirm»
38
+ if (ENGINE_POSITIONS.has(action)) {
39
+ if (menu || toPlay)
40
+ d.systemPress?.(action, player);
41
+ return false;
42
+ }
17
43
  const code = d.scheme(player)[action]?.[0];
18
- if (d.menuOpen()) {
19
- if (code)
44
+ if (menu) {
45
+ if (!d.menuAnswers?.(action, player) && code)
20
46
  d.menuKey(code, source);
21
47
  return false;
22
48
  }
49
+ if (!toPlay)
50
+ return false;
23
51
  if (code)
24
52
  d.holdKey(code, source);
25
53
  held.set(`${player}:${action}`, code ?? null);
@@ -5,7 +5,7 @@ import type { Action } from '../core/actions.js';
5
5
  *
6
6
  * ⚠️ WRITTEN AS THE RECOGNISER'S VOCABULARY SPELLS THEM — lowercase, with their accents (the Dev's words are «ação» and
7
7
  * «Acción»): a grammar word the model does not know is dropped and its position goes mute (measured below). Comparing ignores
8
- * accents, because a heard sentence and a table entry both pass through `wordsOf` before they meet.
8
+ * accents: the reader (`platform/speech-recognition`) matches a heard sentence and a table entry by a key without them.
9
9
  */
10
10
  export type VoiceWords = {
11
11
  readonly [A in Action]?: readonly string[];
@@ -19,25 +19,41 @@ export declare function voiceWordsFor(language: string): VoiceWords;
19
19
  * says something that is not a command: the lab measured free speech being pushed to the nearest word («configurações de
20
20
  * inclusão» → «quatro»). That is the cost of the closed list and the reason the words are short and unlike each other.
21
21
  * ⚠️ `extra` is what the MENU is showing right now (ADR-0194): saying the name of an item activates it, so those words join the
22
- * grammar while that menu is open and leave with it.
22
+ * grammar while that menu is open and leave with it — AS THE LANGUAGE WRITES THEM (§1, «as shown»), accents kept: stripped,
23
+ * «configurações» is not in the model's vocabulary and the name goes mute, the same defect «acao» was.
23
24
  */
24
25
  export declare function voiceGrammar(language: string, extra?: readonly string[]): readonly string[];
26
+ /** What a heard phrase asks for: a position of the controller, or the item of the open menu that has this name (ADR-0194). */
27
+ export type VoiceCommand = {
28
+ readonly kind: 'position';
29
+ readonly action: Action;
30
+ }
31
+ /** `name` is the item's name exactly as it was handed to `items` — the name on screen, to find the item by. */
32
+ | {
33
+ readonly kind: 'item';
34
+ readonly name: string;
35
+ };
25
36
  export interface VoiceCommands {
26
37
  /**
27
- * What the recogniser has heard SO FAR in this utterance, and the position it presses — or `null` when nothing new was said.
38
+ * The names the open menu is showing, as shown (ADR-0194 §2): from now on, saying one is a command — until the next call.
39
+ * An empty list is a menu closed.
40
+ */
41
+ items(names: readonly string[]): void;
42
+ /**
43
+ * What the recogniser has heard SO FAR in this utterance → the commands it completes that were not answered before.
28
44
  * ⚠️ It answers on the PARTIAL and not at the end of the sentence (ADR-0193 erratum, the Dev's choice after running both):
29
- * 0.25–0.45 s against 1.3–1.4 s, which is the difference between a command and a delay a child gives up on.
45
+ * 0.25–0.45 s against 1.3–1.4 s, which is the difference between a command and a delay a child gives up on — except for a
46
+ * name another item's name continues, which waits for `final` (ADR-0194 §3).
30
47
  */
31
- partial(text: string): Action | null;
32
- /** The utterance ended (or the microphone was let go): the next partial starts a new sentence. */
33
- reset(): void;
48
+ partial(text: string): readonly VoiceCommand[];
49
+ /** The utterance ended with this text: what it completes that the partials held back. The next partial starts afresh. */
50
+ final(text: string): readonly VoiceCommand[];
34
51
  }
35
52
  /**
36
- * The rule that turns a growing partial into presses.
53
+ * The Dev's words and the open menu's names, READ BY `platform/speech-recognition.createCommandReader` — the one reader of what
54
+ * was heard (ADR-0194 §2–§3); this adds only what a word MEANS here, the position it presses.
37
55
  *
38
56
  * 🎯 A PARTIAL GROWS, AND ONLY WHAT IS NEW FIRES. «acima» then «acima abaixo» is a child who said two words, and the second
39
- * press must be `down`, not `up` all over again — so the words already answered for are counted, never re-read.
40
- * 📌 The tail is matched LONGEST FIRST because a position may answer to a phrase: «pick up» is one command in English, and
41
- * reading only the last word would make it `null` after having fired nothing.
57
+ * press must be `down`, not `up` all over again — the reader counts what it already answered for in each utterance.
42
58
  */
43
59
  export declare function createVoiceCommands(language: string): VoiceCommands;