@the-inclusionist/engine 9.0.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/README.md +120 -78
  2. package/app/css/style.css +761 -377
  3. package/app/public/vendor/fonts/playwrite-cu.woff2 +0 -0
  4. package/app/public/vendor/fonts/playwrite-es-deco.woff2 +0 -0
  5. package/app/public/vendor/fonts/playwrite-es.woff2 +0 -0
  6. package/app/public/vendor/fonts/playwrite-gb-j.woff2 +0 -0
  7. package/app/public/vendor/fonts/playwrite-gb-s.woff2 +0 -0
  8. package/app/public/vendor/fonts/playwrite-pe.woff2 +0 -0
  9. package/app/public/vendor/fonts/playwrite-pt.woff2 +0 -0
  10. package/app/public/vendor/fonts-licences/NOTICE.txt +166 -0
  11. package/app/public/vendor/fonts-licences/OFL-1.1.txt +86 -0
  12. package/app/public/vendor/fonts.css +36 -84
  13. package/dist-pkg/boot/create-game.d.ts +499 -219
  14. package/dist-pkg/boot/create-game.js +3944 -562
  15. package/dist-pkg/core/a11y-sr.d.ts +25 -3
  16. package/dist-pkg/core/a11y-sr.js +38 -19
  17. package/dist-pkg/core/accessible-label.d.ts +17 -0
  18. package/dist-pkg/core/accessible-label.js +37 -0
  19. package/dist-pkg/core/accommodation-subjects.d.ts +26 -0
  20. package/dist-pkg/core/accommodation-subjects.js +32 -0
  21. package/dist-pkg/core/accommodations.d.ts +125 -0
  22. package/dist-pkg/core/accommodations.js +195 -0
  23. package/dist-pkg/core/actions.d.ts +108 -55
  24. package/dist-pkg/core/actions.js +122 -71
  25. package/dist-pkg/core/calm-mode.d.ts +31 -0
  26. package/dist-pkg/core/calm-mode.js +47 -0
  27. package/dist-pkg/core/camera-cycle.d.ts +15 -0
  28. package/dist-pkg/core/camera-cycle.js +7 -0
  29. package/dist-pkg/core/caption-duration.d.ts +15 -0
  30. package/dist-pkg/core/caption-duration.js +19 -0
  31. package/dist-pkg/core/cartridge-problems.d.ts +34 -0
  32. package/dist-pkg/core/cartridge-problems.js +53 -0
  33. package/dist-pkg/core/constants.d.ts +0 -54
  34. package/dist-pkg/core/constants.js +9 -76
  35. package/dist-pkg/core/contract.d.ts +142 -164
  36. package/dist-pkg/core/contract.js +222 -208
  37. package/dist-pkg/core/dom-query.d.ts +4 -4
  38. package/dist-pkg/core/dom-query.js +12 -20
  39. package/dist-pkg/core/entity.d.ts +62 -77
  40. package/dist-pkg/core/entity.js +18 -32
  41. package/dist-pkg/core/escape-html.d.ts +9 -10
  42. package/dist-pkg/core/escape-html.js +16 -20
  43. package/dist-pkg/core/flash-threshold.d.ts +17 -0
  44. package/dist-pkg/core/flash-threshold.js +113 -0
  45. package/dist-pkg/core/game-speed.d.ts +11 -0
  46. package/dist-pkg/core/game-speed.js +16 -0
  47. package/dist-pkg/core/genres.d.ts +20 -0
  48. package/dist-pkg/core/genres.js +44 -0
  49. package/dist-pkg/core/i18n.d.ts +71 -60
  50. package/dist-pkg/core/i18n.js +186 -200
  51. package/dist-pkg/core/loop.d.ts +17 -6
  52. package/dist-pkg/core/loop.js +26 -26
  53. package/dist-pkg/core/pause-icon-catalogue.d.ts +15 -0
  54. package/dist-pkg/core/pause-icon-catalogue.js +54 -0
  55. package/dist-pkg/core/ring.d.ts +17 -0
  56. package/dist-pkg/core/ring.js +29 -0
  57. package/dist-pkg/core/rng.d.ts +7 -12
  58. package/dist-pkg/core/rng.js +23 -53
  59. package/dist-pkg/core/route.d.ts +26 -26
  60. package/dist-pkg/core/route.js +126 -121
  61. package/dist-pkg/core/scenes.d.ts +37 -40
  62. package/dist-pkg/core/scenes.js +41 -43
  63. package/dist-pkg/core/screens.d.ts +4 -4
  64. package/dist-pkg/core/screens.js +11 -16
  65. package/dist-pkg/core/session-clock.d.ts +23 -0
  66. package/dist-pkg/core/session-clock.js +37 -0
  67. package/dist-pkg/core/setting-defaults.d.ts +61 -0
  68. package/dist-pkg/core/setting-defaults.js +66 -0
  69. package/dist-pkg/core/speech-rate.d.ts +29 -0
  70. package/dist-pkg/core/speech-rate.js +47 -0
  71. package/dist-pkg/core/state.d.ts +118 -118
  72. package/dist-pkg/core/state.js +322 -297
  73. package/dist-pkg/core/visual-cycles.d.ts +30 -0
  74. package/dist-pkg/core/visual-cycles.js +52 -0
  75. package/dist-pkg/core/visual-state.d.ts +13 -0
  76. package/dist-pkg/core/visual-state.js +6 -0
  77. package/dist-pkg/educational/activities-registry.d.ts +1 -1
  78. package/dist-pkg/educational/activities-registry.js +9 -8
  79. package/dist-pkg/educational/adaptive-engine.d.ts +11 -11
  80. package/dist-pkg/educational/adaptive-engine.js +17 -17
  81. package/dist-pkg/educational/segment-bar.d.ts +12 -12
  82. package/dist-pkg/educational/segment-bar.js +9 -9
  83. package/dist-pkg/i18n/en.js +324 -223
  84. package/dist-pkg/i18n/es.js +323 -223
  85. package/dist-pkg/i18n/pt.js +348 -226
  86. package/dist-pkg/input/default-bindings.d.ts +37 -38
  87. package/dist-pkg/input/default-bindings.js +127 -144
  88. package/dist-pkg/input/devices.d.ts +7 -7
  89. package/dist-pkg/input/devices.js +17 -16
  90. package/dist-pkg/input/edges.d.ts +23 -32
  91. package/dist-pkg/input/edges.js +23 -28
  92. package/dist-pkg/input/empathy-filter.d.ts +22 -0
  93. package/dist-pkg/input/empathy-filter.js +34 -0
  94. package/dist-pkg/input/face-map.d.ts +96 -0
  95. package/dist-pkg/input/face-map.js +255 -0
  96. package/dist-pkg/input/face-signals.d.ts +40 -0
  97. package/dist-pkg/input/face-signals.js +48 -0
  98. package/dist-pkg/input/gamepad.d.ts +195 -145
  99. package/dist-pkg/input/gamepad.js +383 -556
  100. package/dist-pkg/input/gaze-cycle.d.ts +64 -0
  101. package/dist-pkg/input/gaze-cycle.js +133 -0
  102. package/dist-pkg/input/gaze-relative.d.ts +68 -0
  103. package/dist-pkg/input/gaze-relative.js +142 -0
  104. package/dist-pkg/input/hand-map.d.ts +28 -0
  105. package/dist-pkg/input/hand-map.js +142 -0
  106. package/dist-pkg/input/input-cooldown.d.ts +17 -0
  107. package/dist-pkg/input/input-cooldown.js +39 -0
  108. package/dist-pkg/input/key-default.d.ts +30 -0
  109. package/dist-pkg/input/key-default.js +60 -0
  110. package/dist-pkg/input/keyboard-runtime.d.ts +15 -21
  111. package/dist-pkg/input/keyboard-runtime.js +23 -27
  112. package/dist-pkg/input/keyboard.d.ts +68 -63
  113. package/dist-pkg/input/keyboard.js +83 -105
  114. package/dist-pkg/input/keydown.d.ts +123 -137
  115. package/dist-pkg/input/keydown.js +284 -289
  116. package/dist-pkg/input/latch-edge.d.ts +33 -21
  117. package/dist-pkg/input/latch-edge.js +34 -35
  118. package/dist-pkg/input/latch-scope.d.ts +51 -50
  119. package/dist-pkg/input/latch-scope.js +61 -82
  120. package/dist-pkg/input/latch-store.d.ts +26 -30
  121. package/dist-pkg/input/latch-store.js +42 -50
  122. package/dist-pkg/input/latch-sync.d.ts +29 -29
  123. package/dist-pkg/input/latch-sync.js +25 -25
  124. package/dist-pkg/input/latch.d.ts +14 -17
  125. package/dist-pkg/input/latch.js +29 -37
  126. package/dist-pkg/input/pad-defaults.d.ts +13 -16
  127. package/dist-pkg/input/pad-defaults.js +21 -28
  128. package/dist-pkg/input/pad-reading.d.ts +76 -0
  129. package/dist-pkg/input/pad-reading.js +169 -0
  130. package/dist-pkg/input/pad-wizard.d.ts +99 -0
  131. package/dist-pkg/input/pad-wizard.js +256 -0
  132. package/dist-pkg/input/pointer-space.d.ts +19 -20
  133. package/dist-pkg/input/pointer-space.js +27 -32
  134. package/dist-pkg/input/pointer.d.ts +39 -40
  135. package/dist-pkg/input/pointer.js +42 -45
  136. package/dist-pkg/input/state.d.ts +101 -89
  137. package/dist-pkg/input/state.js +54 -134
  138. package/dist-pkg/input/switch-scan.d.ts +59 -0
  139. package/dist-pkg/input/switch-scan.js +67 -0
  140. package/dist-pkg/input/synthetic-source.d.ts +42 -0
  141. package/dist-pkg/input/synthetic-source.js +57 -0
  142. package/dist-pkg/input/touch-bindings.d.ts +127 -116
  143. package/dist-pkg/input/touch-bindings.js +158 -173
  144. package/dist-pkg/input/touch.d.ts +147 -72
  145. package/dist-pkg/input/touch.js +362 -126
  146. package/dist-pkg/input/transport-in-use.d.ts +107 -0
  147. package/dist-pkg/input/transport-in-use.js +130 -0
  148. package/dist-pkg/input/transports.d.ts +90 -117
  149. package/dist-pkg/input/transports.js +104 -106
  150. package/dist-pkg/input/virtual-controller.d.ts +82 -0
  151. package/dist-pkg/input/virtual-controller.js +69 -0
  152. package/dist-pkg/input/vocabulary-migration.d.ts +50 -49
  153. package/dist-pkg/input/vocabulary-migration.js +80 -79
  154. package/dist-pkg/input/voice-map.d.ts +59 -0
  155. package/dist-pkg/input/voice-map.js +123 -0
  156. package/dist-pkg/platform/audio-ambient.d.ts +13 -2
  157. package/dist-pkg/platform/audio-ambient.js +14 -14
  158. package/dist-pkg/platform/audio-earcons.d.ts +20 -19
  159. package/dist-pkg/platform/audio-earcons.js +51 -42
  160. package/dist-pkg/platform/audio-jingles.js +9 -10
  161. package/dist-pkg/platform/audio-mixer.d.ts +14 -2
  162. package/dist-pkg/platform/audio-mixer.js +31 -39
  163. package/dist-pkg/platform/audio-sonar.d.ts +49 -152
  164. package/dist-pkg/platform/audio-sonar.js +124 -302
  165. package/dist-pkg/platform/audio.d.ts +62 -19
  166. package/dist-pkg/platform/audio.js +193 -168
  167. package/dist-pkg/platform/choose-by-voice.d.ts +70 -0
  168. package/dist-pkg/platform/choose-by-voice.js +157 -0
  169. package/dist-pkg/platform/flash-sampler.d.ts +19 -0
  170. package/dist-pkg/platform/flash-sampler.js +79 -0
  171. package/dist-pkg/platform/font-library.d.ts +77 -0
  172. package/dist-pkg/platform/font-library.js +98 -0
  173. package/dist-pkg/platform/font-library.json +721 -0
  174. package/dist-pkg/platform/heavy-catalogue.d.ts +77 -0
  175. package/dist-pkg/platform/heavy-catalogue.js +256 -0
  176. package/dist-pkg/platform/heavy-mirror.d.ts +20 -0
  177. package/dist-pkg/platform/heavy-mirror.js +73 -0
  178. package/dist-pkg/platform/heavy.d.ts +136 -0
  179. package/dist-pkg/platform/heavy.js +324 -0
  180. package/dist-pkg/platform/interruptible-speech.d.ts +23 -16
  181. package/dist-pkg/platform/interruptible-speech.js +77 -54
  182. package/dist-pkg/platform/kokoro-port.d.ts +27 -0
  183. package/dist-pkg/platform/kokoro-port.js +50 -0
  184. package/dist-pkg/platform/kokoro-runtime.d.ts +20 -0
  185. package/dist-pkg/platform/kokoro-runtime.js +52 -0
  186. package/dist-pkg/platform/kokoro.d.ts +70 -0
  187. package/dist-pkg/platform/kokoro.js +133 -0
  188. package/dist-pkg/platform/listener-scope.d.ts +12 -0
  189. package/dist-pkg/platform/listener-scope.js +90 -0
  190. package/dist-pkg/platform/locale-host.d.ts +14 -0
  191. package/dist-pkg/platform/locale-host.js +45 -0
  192. package/dist-pkg/platform/microphone.d.ts +51 -0
  193. package/dist-pkg/platform/microphone.js +118 -0
  194. package/dist-pkg/platform/onnx-runtime.d.ts +34 -0
  195. package/dist-pkg/platform/onnx-runtime.js +42 -0
  196. package/dist-pkg/platform/reading-in-worker.d.ts +64 -0
  197. package/dist-pkg/platform/reading-in-worker.js +125 -0
  198. package/dist-pkg/platform/reading-model.d.ts +94 -0
  199. package/dist-pkg/platform/reading-model.js +272 -0
  200. package/dist-pkg/platform/reading-runtime.d.ts +24 -0
  201. package/dist-pkg/platform/reading-runtime.js +164 -0
  202. package/dist-pkg/platform/reading-worker.d.ts +41 -0
  203. package/dist-pkg/platform/reading-worker.js +58 -0
  204. package/dist-pkg/platform/reading.d.ts +80 -0
  205. package/dist-pkg/platform/reading.js +136 -0
  206. package/dist-pkg/platform/speech-recognition.d.ts +60 -0
  207. package/dist-pkg/platform/speech-recognition.js +104 -0
  208. package/dist-pkg/platform/speech.d.ts +23 -1
  209. package/dist-pkg/platform/speech.js +29 -18
  210. package/dist-pkg/platform/storage-keys.d.ts +96 -0
  211. package/dist-pkg/platform/storage-keys.js +106 -0
  212. package/dist-pkg/platform/storage.d.ts +46 -111
  213. package/dist-pkg/platform/storage.js +104 -169
  214. package/dist-pkg/platform/tts.d.ts +85 -39
  215. package/dist-pkg/platform/tts.js +447 -127
  216. package/dist-pkg/platform/vision-loop.d.ts +23 -0
  217. package/dist-pkg/platform/vision-loop.js +56 -0
  218. package/dist-pkg/platform/vision.d.ts +132 -0
  219. package/dist-pkg/platform/vision.js +117 -0
  220. package/dist-pkg/platform/voice-listener.d.ts +40 -0
  221. package/dist-pkg/platform/voice-listener.js +88 -0
  222. package/dist-pkg/platform/voice-plan.d.ts +15 -98
  223. package/dist-pkg/platform/voice-plan.js +56 -143
  224. package/dist-pkg/platform/vosk-runtime.d.ts +96 -0
  225. package/dist-pkg/platform/vosk-runtime.js +151 -0
  226. package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
  227. package/dist-pkg/platform/vosk-vocabulary.js +178 -0
  228. package/dist-pkg/render/canvas.d.ts +13 -7
  229. package/dist-pkg/render/canvas.js +13 -13
  230. package/dist-pkg/render/crt.d.ts +48 -12
  231. package/dist-pkg/render/crt.js +78 -80
  232. package/dist-pkg/render/cvd-matrices.d.ts +22 -18
  233. package/dist-pkg/render/cvd-matrices.js +37 -38
  234. package/dist-pkg/render/hc-role-data.d.ts +7 -7
  235. package/dist-pkg/render/hc-role-data.js +14 -14
  236. package/dist-pkg/render/high-contrast.d.ts +67 -56
  237. package/dist-pkg/render/high-contrast.js +226 -217
  238. package/dist-pkg/render/low-vision-drawing.d.ts +5 -0
  239. package/dist-pkg/render/low-vision-drawing.js +46 -0
  240. package/dist-pkg/render/lq-filter.d.ts +32 -20
  241. package/dist-pkg/render/lq-filter.js +59 -65
  242. package/dist-pkg/render/port.d.ts +86 -88
  243. package/dist-pkg/render/port.js +17 -23
  244. package/dist-pkg/render/screen-pipeline.d.ts +42 -42
  245. package/dist-pkg/render/screen-pipeline.js +80 -87
  246. package/dist-pkg/render/sprite-fx.d.ts +2 -1
  247. package/dist-pkg/render/sprite-fx.js +16 -14
  248. package/dist-pkg/render/viewports.d.ts +20 -15
  249. package/dist-pkg/render/viewports.js +83 -114
  250. package/dist-pkg/render/viz-axes-labels.d.ts +47 -0
  251. package/dist-pkg/render/viz-axes-labels.js +88 -0
  252. package/dist-pkg/render/viz-axes.d.ts +89 -86
  253. package/dist-pkg/render/viz-axes.js +128 -116
  254. package/dist-pkg/render/viz-modes.d.ts +28 -29
  255. package/dist-pkg/render/viz-modes.js +40 -45
  256. package/dist-pkg/render/viz-refusal.d.ts +32 -0
  257. package/dist-pkg/render/viz-refusal.js +57 -0
  258. package/dist-pkg/render/viz-setters.d.ts +104 -66
  259. package/dist-pkg/render/viz-setters.js +182 -191
  260. package/dist-pkg/ui/aac-sets.d.ts +45 -0
  261. package/dist-pkg/ui/aac-sets.js +41 -0
  262. package/dist-pkg/ui/audio-choices.d.ts +68 -0
  263. package/dist-pkg/ui/audio-choices.js +98 -0
  264. package/dist-pkg/ui/audio-rows-that-apply.d.ts +12 -0
  265. package/dist-pkg/ui/audio-rows-that-apply.js +43 -0
  266. package/dist-pkg/ui/camera-control.d.ts +53 -0
  267. package/dist-pkg/ui/camera-control.js +48 -0
  268. package/dist-pkg/ui/changed-mark.d.ts +9 -8
  269. package/dist-pkg/ui/changed-mark.js +22 -53
  270. package/dist-pkg/ui/control-choices.d.ts +37 -0
  271. package/dist-pkg/ui/control-choices.js +84 -0
  272. package/dist-pkg/ui/debug-panel.d.ts +59 -43
  273. package/dist-pkg/ui/debug-panel.js +68 -69
  274. package/dist-pkg/ui/declared-words.d.ts +21 -0
  275. package/dist-pkg/ui/declared-words.js +66 -0
  276. package/dist-pkg/ui/dom.d.ts +10 -14
  277. package/dist-pkg/ui/dom.js +10 -47
  278. package/dist-pkg/ui/drawing-problems.d.ts +25 -0
  279. package/dist-pkg/ui/drawing-problems.js +94 -0
  280. package/dist-pkg/ui/eye-control.d.ts +36 -0
  281. package/dist-pkg/ui/eye-control.js +178 -0
  282. package/dist-pkg/ui/face-control.d.ts +25 -0
  283. package/dist-pkg/ui/face-control.js +183 -0
  284. package/dist-pkg/ui/focus-trap.d.ts +39 -49
  285. package/dist-pkg/ui/focus-trap.js +56 -65
  286. package/dist-pkg/ui/fonts.d.ts +157 -68
  287. package/dist-pkg/ui/fonts.js +305 -115
  288. package/dist-pkg/ui/footer-scroll-driver.d.ts +14 -0
  289. package/dist-pkg/ui/footer-scroll-driver.js +201 -0
  290. package/dist-pkg/ui/footer-scroll.d.ts +38 -0
  291. package/dist-pkg/ui/footer-scroll.js +55 -0
  292. package/dist-pkg/ui/game-options.d.ts +47 -0
  293. package/dist-pkg/ui/game-options.js +158 -0
  294. package/dist-pkg/ui/gaze-overlay.d.ts +64 -0
  295. package/dist-pkg/ui/gaze-overlay.js +165 -0
  296. package/dist-pkg/ui/hand-control.d.ts +25 -0
  297. package/dist-pkg/ui/hand-control.js +143 -0
  298. package/dist-pkg/ui/help-panel.d.ts +87 -0
  299. package/dist-pkg/ui/help-panel.js +242 -0
  300. package/dist-pkg/ui/hud-bands.d.ts +62 -0
  301. package/dist-pkg/ui/hud-bands.js +146 -0
  302. package/dist-pkg/ui/hud-row.d.ts +34 -0
  303. package/dist-pkg/ui/hud-row.js +80 -0
  304. package/dist-pkg/ui/hud.d.ts +73 -73
  305. package/dist-pkg/ui/hud.js +94 -98
  306. package/dist-pkg/ui/item-announcement.d.ts +13 -12
  307. package/dist-pkg/ui/item-announcement.js +25 -26
  308. package/dist-pkg/ui/layout.d.ts +103 -28
  309. package/dist-pkg/ui/layout.js +117 -99
  310. package/dist-pkg/ui/libras-avatar-clip.d.ts +30 -0
  311. package/dist-pkg/ui/libras-avatar-clip.js +86 -0
  312. package/dist-pkg/ui/libras-avatar-load.d.ts +52 -0
  313. package/dist-pkg/ui/libras-avatar-load.js +134 -0
  314. package/dist-pkg/ui/libras-avatar-plan.d.ts +102 -0
  315. package/dist-pkg/ui/libras-avatar-plan.js +211 -0
  316. package/dist-pkg/ui/libras-avatar-player.d.ts +28 -0
  317. package/dist-pkg/ui/libras-avatar-player.js +226 -0
  318. package/dist-pkg/ui/libras-avatar-stage.d.ts +37 -0
  319. package/dist-pkg/ui/libras-avatar-stage.js +208 -0
  320. package/dist-pkg/ui/libras-glosses.d.ts +28 -0
  321. package/dist-pkg/ui/libras-glosses.js +161 -0
  322. package/dist-pkg/ui/locale-flags.d.ts +16 -0
  323. package/dist-pkg/ui/locale-flags.js +30 -0
  324. package/dist-pkg/ui/loop-crash.d.ts +17 -17
  325. package/dist-pkg/ui/loop-crash.js +33 -62
  326. package/dist-pkg/ui/menu-intent.d.ts +61 -0
  327. package/dist-pkg/ui/menu-intent.js +88 -0
  328. package/dist-pkg/ui/menu-items.d.ts +20 -0
  329. package/dist-pkg/ui/menu-items.js +51 -0
  330. package/dist-pkg/ui/menu-nav.d.ts +98 -92
  331. package/dist-pkg/ui/menu-nav.js +398 -286
  332. package/dist-pkg/ui/mobility-choices.d.ts +26 -0
  333. package/dist-pkg/ui/mobility-choices.js +41 -0
  334. package/dist-pkg/ui/motion-choices.d.ts +31 -0
  335. package/dist-pkg/ui/motion-choices.js +68 -0
  336. package/dist-pkg/ui/motion-scene.d.ts +24 -19
  337. package/dist-pkg/ui/motion-scene.js +29 -61
  338. package/dist-pkg/ui/mount-panel.d.ts +81 -0
  339. package/dist-pkg/ui/mount-panel.js +61 -0
  340. package/dist-pkg/ui/panel-shell.d.ts +65 -31
  341. package/dist-pkg/ui/panel-shell.js +92 -66
  342. package/dist-pkg/ui/panel-widgets.d.ts +150 -0
  343. package/dist-pkg/ui/panel-widgets.js +294 -0
  344. package/dist-pkg/ui/pause-buttons.d.ts +35 -0
  345. package/dist-pkg/ui/pause-buttons.js +66 -0
  346. package/dist-pkg/ui/pause-icons.d.ts +261 -347
  347. package/dist-pkg/ui/pause-icons.js +671 -601
  348. package/dist-pkg/ui/pause-markup.d.ts +86 -0
  349. package/dist-pkg/ui/pause-markup.js +125 -0
  350. package/dist-pkg/ui/reach-notice.d.ts +22 -23
  351. package/dist-pkg/ui/reach-notice.js +55 -58
  352. package/dist-pkg/ui/scan-overlay.d.ts +23 -0
  353. package/dist-pkg/ui/scan-overlay.js +50 -0
  354. package/dist-pkg/ui/screen-text.d.ts +25 -0
  355. package/dist-pkg/ui/screen-text.js +152 -0
  356. package/dist-pkg/ui/session-clock.d.ts +32 -0
  357. package/dist-pkg/ui/session-clock.js +67 -0
  358. package/dist-pkg/ui/settings-aac.d.ts +70 -0
  359. package/dist-pkg/ui/settings-aac.js +208 -0
  360. package/dist-pkg/ui/settings-audio.d.ts +97 -114
  361. package/dist-pkg/ui/settings-audio.js +493 -425
  362. package/dist-pkg/ui/settings-controls.d.ts +53 -96
  363. package/dist-pkg/ui/settings-controls.js +143 -215
  364. package/dist-pkg/ui/settings-empathy.d.ts +39 -30
  365. package/dist-pkg/ui/settings-empathy.js +53 -60
  366. package/dist-pkg/ui/settings-mobility.d.ts +192 -0
  367. package/dist-pkg/ui/settings-mobility.js +332 -0
  368. package/dist-pkg/ui/settings-motion.d.ts +91 -70
  369. package/dist-pkg/ui/settings-motion.js +287 -198
  370. package/dist-pkg/ui/settings-panel.d.ts +58 -45
  371. package/dist-pkg/ui/settings-panel.js +189 -94
  372. package/dist-pkg/ui/settings-typo.d.ts +29 -78
  373. package/dist-pkg/ui/settings-typo.js +158 -129
  374. package/dist-pkg/ui/settings-visual.d.ts +29 -87
  375. package/dist-pkg/ui/settings-visual.js +240 -193
  376. package/dist-pkg/ui/shell.d.ts +112 -135
  377. package/dist-pkg/ui/shell.js +148 -217
  378. package/dist-pkg/ui/simulation-list.d.ts +27 -0
  379. package/dist-pkg/ui/simulation-list.js +76 -0
  380. package/dist-pkg/ui/simulation-over-the-world.d.ts +23 -0
  381. package/dist-pkg/ui/simulation-over-the-world.js +131 -0
  382. package/dist-pkg/ui/simulation-refusal.d.ts +5 -31
  383. package/dist-pkg/ui/simulation-refusal.js +8 -56
  384. package/dist-pkg/ui/switchable-control.d.ts +11 -0
  385. package/dist-pkg/ui/switchable-control.js +19 -0
  386. package/dist-pkg/ui/title.d.ts +3 -12
  387. package/dist-pkg/ui/title.js +49 -18
  388. package/dist-pkg/ui/top-band.d.ts +26 -0
  389. package/dist-pkg/ui/top-band.js +96 -0
  390. package/dist-pkg/ui/typo-choices.d.ts +71 -0
  391. package/dist-pkg/ui/typo-choices.js +85 -0
  392. package/dist-pkg/ui/visual-axes-panel.d.ts +11 -47
  393. package/dist-pkg/ui/visual-axes-panel.js +12 -94
  394. package/dist-pkg/ui/visual-choices.d.ts +77 -0
  395. package/dist-pkg/ui/visual-choices.js +107 -0
  396. package/dist-pkg/ui/vlibras.d.ts +77 -10
  397. package/dist-pkg/ui/vlibras.js +130 -81
  398. package/dist-pkg/ui/voice-control.d.ts +68 -0
  399. package/dist-pkg/ui/voice-control.js +276 -0
  400. package/dist-pkg/ui/voice-settings.d.ts +95 -0
  401. package/dist-pkg/ui/voice-settings.js +352 -0
  402. package/dist-pkg/ui/where-the-child-is.d.ts +31 -0
  403. package/dist-pkg/ui/where-the-child-is.js +70 -0
  404. package/docs/CREDITS.md +300 -44
  405. package/docs/LICENSES.md +189 -145
  406. package/package.json +51 -27
  407. package/scripts/check-cartridge.mjs +78 -0
  408. package/scripts/game-build.d.mts +25 -0
  409. package/scripts/game-build.mjs +144 -0
  410. package/scripts/heavy-into-the-delivery.mjs +388 -0
  411. package/scripts/libras-avatar.json +680 -0
  412. package/scripts/libras-avatar.mjs +246 -0
  413. package/scripts/libras-glosses/gloss.py +95 -0
  414. package/scripts/libras-glosses/pyproject.toml +32 -0
  415. package/scripts/libras-glosses/uv.lock +781 -0
  416. package/scripts/libras-glosses.mjs +351 -0
  417. package/scripts/licences/Apache-2.0.txt +176 -0
  418. package/scripts/licences/GPL-3.0.txt +674 -0
  419. package/scripts/licences/MIT.txt +17 -0
  420. package/scripts/licences/OFL-1.1.txt +86 -0
  421. package/scripts/licences/UFL-1.0.txt +96 -0
  422. package/scripts/licences/fonts.mjs +389 -0
  423. package/scripts/licences/third-party.mjs +301 -0
  424. package/scripts/licences/vosk-browser.NOTICE.txt +268 -0
  425. package/app/public/vendor/fonts/comicneue-400.woff2 +0 -0
  426. package/app/public/vendor/fonts/comicneue-700.woff2 +0 -0
  427. package/app/public/vendor/fonts/fondamento-400-ext.woff2 +0 -0
  428. package/app/public/vendor/fonts/fondamento-400.woff2 +0 -0
  429. package/app/public/vendor/fonts/inter-400.woff2 +0 -0
  430. package/app/public/vendor/fonts/inter-700.woff2 +0 -0
  431. package/app/public/vendor/fonts/lato-400.woff2 +0 -0
  432. package/app/public/vendor/fonts/lato-700.woff2 +0 -0
  433. package/app/public/vendor/fonts/literata-400.woff2 +0 -0
  434. package/app/public/vendor/fonts/literata-700.woff2 +0 -0
  435. package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
  436. package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
  437. package/app/public/vendor/fonts/opendyslexic-400.woff2 +0 -0
  438. package/app/public/vendor/fonts/opensans-400.woff2 +0 -0
  439. package/app/public/vendor/fonts/opensans-700.woff2 +0 -0
  440. package/app/public/vendor/fonts/pinyon-400.woff2 +0 -0
  441. package/app/public/vendor/fonts/pressstart-400.woff2 +0 -0
  442. package/app/public/vendor/fonts/quattro-400.woff2 +0 -0
  443. package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
  444. package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
  445. package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
  446. package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
  447. package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
  448. package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
  449. package/dist-pkg/core/anel.d.ts +0 -17
  450. package/dist-pkg/core/anel.js +0 -31
  451. package/dist-pkg/core/collision.d.ts +0 -21
  452. package/dist-pkg/core/collision.js +0 -62
  453. package/dist-pkg/core/layers.d.ts +0 -63
  454. package/dist-pkg/core/layers.js +0 -95
  455. package/dist-pkg/core/letter-grid.d.ts +0 -55
  456. package/dist-pkg/core/letter-grid.js +0 -116
  457. package/dist-pkg/core/password.d.ts +0 -34
  458. package/dist-pkg/core/password.js +0 -205
  459. package/dist-pkg/core/rotulo-acessivel.d.ts +0 -17
  460. package/dist-pkg/core/rotulo-acessivel.js +0 -41
  461. package/dist-pkg/core/run-state.d.ts +0 -115
  462. package/dist-pkg/core/run-state.js +0 -40
  463. package/dist-pkg/core/tiles.d.ts +0 -12
  464. package/dist-pkg/core/tiles.js +0 -61
  465. package/dist-pkg/core/world.d.ts +0 -4
  466. package/dist-pkg/core/world.js +0 -58
  467. package/dist-pkg/input/origem-sintetica.d.ts +0 -44
  468. package/dist-pkg/input/origem-sintetica.js +0 -60
  469. package/dist-pkg/input/transporte-em-uso.d.ts +0 -101
  470. package/dist-pkg/input/transporte-em-uso.js +0 -130
  471. package/dist-pkg/platform/audio-nav.d.ts +0 -51
  472. package/dist-pkg/platform/audio-nav.js +0 -99
  473. package/dist-pkg/platform/guide-intensity.d.ts +0 -40
  474. package/dist-pkg/platform/guide-intensity.js +0 -73
  475. package/dist-pkg/platform/pesados-catalogo.d.ts +0 -14
  476. package/dist-pkg/platform/pesados-catalogo.js +0 -177
  477. package/dist-pkg/platform/pesados.d.ts +0 -31
  478. package/dist-pkg/platform/pesados.js +0 -75
  479. package/dist-pkg/platform/vozes-prontas.d.ts +0 -28
  480. package/dist-pkg/platform/vozes-prontas.js +0 -61
  481. package/dist-pkg/render/camera.d.ts +0 -58
  482. package/dist-pkg/render/camera.js +0 -105
  483. package/dist-pkg/render/cenario-data.d.ts +0 -127
  484. package/dist-pkg/render/cenario-data.js +0 -145
  485. package/dist-pkg/render/city-tex.d.ts +0 -63
  486. package/dist-pkg/render/city-tex.js +0 -228
  487. package/dist-pkg/render/city-tiles.d.ts +0 -11
  488. package/dist-pkg/render/city-tiles.js +0 -140
  489. package/dist-pkg/render/draw.d.ts +0 -149
  490. package/dist-pkg/render/draw.js +0 -231
  491. package/dist-pkg/render/fx.d.ts +0 -63
  492. package/dist-pkg/render/fx.js +0 -123
  493. package/dist-pkg/render/minimap.d.ts +0 -11
  494. package/dist-pkg/render/minimap.js +0 -94
  495. package/dist-pkg/render/parallax.d.ts +0 -85
  496. package/dist-pkg/render/parallax.js +0 -158
  497. package/dist-pkg/render/player-anim.d.ts +0 -71
  498. package/dist-pkg/render/player-anim.js +0 -152
  499. package/dist-pkg/render/recycling-tex.d.ts +0 -48
  500. package/dist-pkg/render/recycling-tex.js +0 -164
  501. package/dist-pkg/render/scene-city.d.ts +0 -77
  502. package/dist-pkg/render/scene-city.js +0 -181
  503. package/dist-pkg/render/scene-parallax.d.ts +0 -72
  504. package/dist-pkg/render/scene-parallax.js +0 -426
  505. package/dist-pkg/render/scene-sky.d.ts +0 -126
  506. package/dist-pkg/render/scene-sky.js +0 -295
  507. package/dist-pkg/render/set-cenario.d.ts +0 -54
  508. package/dist-pkg/render/set-cenario.js +0 -103
  509. package/dist-pkg/render/textures.d.ts +0 -75
  510. package/dist-pkg/render/textures.js +0 -240
  511. package/dist-pkg/render/title-scene.d.ts +0 -46
  512. package/dist-pkg/render/title-scene.js +0 -75
  513. package/dist-pkg/render/weather.d.ts +0 -96
  514. package/dist-pkg/render/weather.js +0 -171
  515. package/dist-pkg/render/wheelchair-sprites.d.ts +0 -32
  516. package/dist-pkg/render/wheelchair-sprites.js +0 -69
  517. package/dist-pkg/render/world-tex.d.ts +0 -18
  518. package/dist-pkg/render/world-tex.js +0 -87
  519. package/dist-pkg/ui/activities-menu.d.ts +0 -258
  520. package/dist-pkg/ui/activities-menu.js +0 -648
  521. package/dist-pkg/ui/caa-sets.d.ts +0 -39
  522. package/dist-pkg/ui/caa-sets.js +0 -65
  523. package/dist-pkg/ui/latch-refusal.d.ts +0 -32
  524. package/dist-pkg/ui/latch-refusal.js +0 -60
  525. package/dist-pkg/ui/map-hub.d.ts +0 -56
  526. package/dist-pkg/ui/map-hub.js +0 -138
  527. package/dist-pkg/ui/settings-caa.d.ts +0 -45
  528. package/dist-pkg/ui/settings-caa.js +0 -137
  529. package/dist-pkg/ui/settings-motor.d.ts +0 -175
  530. package/dist-pkg/ui/settings-motor.js +0 -342
  531. package/dist-pkg/ui/webcam.d.ts +0 -7
  532. package/dist-pkg/ui/webcam.js +0 -93
@@ -0,0 +1,255 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // input/face-map — THE FACE AS A CONTROLLER: THIRTEEN EXPRESSIONS AND THE ACTIONS THEY PRESS (ADR-0210 and its erratum; issue #191).
3
+ //
4
+ // The map is the Dev's, settled in twelve lab rounds (the last clean: every position read, nothing read that was not asked, nothing read in
5
+ // 26 s of «no position»). Each expression is measured as a LEVEL — how far its blendshapes rose from the calibrated rest, 0..1 — and the
6
+ // levels go through the rules those rounds found before a level becomes a press:
7
+ // · exclusions: lips pressed lift the smile, and the mouth pushed to a side projects the lips, so the specific one clears the other; a
8
+ // squeezed eye pulls the brow down, so a squeeze at START's mark clears the frown;
9
+ // · the pucker has its own mark (0.6): a relaxed mouth sits near 0.33;
10
+ // · the crossed look: a look to one side peaking at 0.6, then the other side within 0.8 s and held 300 ms; a turned head cancels it;
11
+ // · START is one eye squeezed at 0.5 for 0.7 s; the mouth expressions hold 300 ms more, because talking moves the mouth in short syllables;
12
+ // · then a level at 0.3 held 300 ms presses, and stays pressed while it holds.
13
+ // ⚠️ The levels are keyed by EXPRESSION, never by action: a number per action is the analogue grammar ADR-0112 refused for input/. The
14
+ // only thing that reaches the action vocabulary is which actions are held.
15
+ /** The Dev's map (ADR-0210 erratum): each expression and the action it presses. SELECT has no expression. */
16
+ export const FACE_MAP = {
17
+ browsUp: 'up', frown: 'down', headLeft: 'left', headRight: 'right', squeeze: 'start',
18
+ pressLips: 'action1', openMouth: 'action2', smile: 'action3', pucker: 'action4',
19
+ lookRightThenLeft: 'leftShoulder', mouthLeft: 'leftTrigger', lookLeftThenRight: 'rightShoulder', mouthRight: 'rightTrigger',
20
+ };
21
+ const EXPRESSIONS = Object.keys(FACE_MAP);
22
+ /** The blendshapes the map reads — a closed list. */
23
+ export const FACE_BLENDSHAPES = [
24
+ 'browInnerUp', 'browOuterUpLeft', 'browOuterUpRight', 'browDownLeft', 'browDownRight',
25
+ 'mouthPressLeft', 'mouthPressRight', 'jawOpen', 'mouthSmileLeft', 'mouthSmileRight', 'mouthUpperUpLeft', 'mouthUpperUpRight',
26
+ 'mouthPucker', 'mouthLeft', 'mouthRight',
27
+ 'eyeLookOutLeft', 'eyeLookInLeft', 'eyeLookOutRight', 'eyeLookInRight', 'eyeBlinkLeft', 'eyeBlinkRight', 'eyeSquintLeft', 'eyeSquintRight',
28
+ ];
29
+ const READ = new Set(FACE_BLENDSHAPES);
30
+ /** The Face Landmarker's categories, keeping the ones the map reads. */
31
+ export function faceScoresFromCategories(categories) {
32
+ return Object.fromEntries((categories ?? []).filter((c) => READ.has(c.categoryName)).map((c) => [c.categoryName, c.score]));
33
+ }
34
+ const rise = (s, rest, n) => {
35
+ const b = rest[n] ?? 0;
36
+ return Math.max(0, ((s[n] ?? 0) - b) / Math.max(1e-6, 1 - b));
37
+ };
38
+ /**
39
+ * The head turned, from the nose tip's offset against the middle of the face's two sides (landmarks 1, 234, 454), in face widths, from the
40
+ * rest. In the camera's unmirrored image the player's left is +x. `FULL_TURN` 0.65 puts the 0.3 mark near 18° (the Dev asked for a less
41
+ * sensitive head; geometry, not measured on a face).
42
+ */
43
+ export const FULL_TURN = 0.65;
44
+ export function headTurn(landmarks, restX = 0) {
45
+ if (!landmarks || landmarks.length < 455)
46
+ return { x: null, left: 0, right: 0 };
47
+ const nose = landmarks[1], a = landmarks[234], b = landmarks[454];
48
+ const width = Math.hypot(b.x - a.x, b.y - a.y) || 1e-6;
49
+ const x = (nose.x - (a.x + b.x) / 2) / width;
50
+ const clamp = (v) => Math.min(1, Math.max(0, v));
51
+ return { x, left: clamp((x - restX) / FULL_TURN), right: clamp((restX - x) / FULL_TURN) };
52
+ }
53
+ /** The raw levels of one frame, from the scores and the head turn, against the rest. */
54
+ export function faceLevels(s, rest, turn) {
55
+ const r = (...names) => Math.max(0, ...names.map((n) => rise(s, rest.scores, n)));
56
+ return {
57
+ browsUp: r('browInnerUp', 'browOuterUpLeft', 'browOuterUpRight'),
58
+ frown: r('browDownLeft', 'browDownRight'),
59
+ headLeft: turn.left, headRight: turn.right,
60
+ // one eye squeezed is enough, the other squeezed or not: the more closed eye, by blink or squint
61
+ squeeze: r('eyeBlinkLeft', 'eyeSquintLeft', 'eyeBlinkRight', 'eyeSquintRight'),
62
+ pressLips: r('mouthPressLeft', 'mouthPressRight'),
63
+ openMouth: r('jawOpen'),
64
+ smile: r('mouthSmileLeft', 'mouthSmileRight', 'mouthUpperUpLeft', 'mouthUpperUpRight'),
65
+ pucker: r('mouthPucker'),
66
+ // a look to the player's left moves the left eye out and the right eye in, and both must rise: the weaker of the pair
67
+ lookRightThenLeft: Math.min(rise(s, rest.scores, 'eyeLookOutLeft'), rise(s, rest.scores, 'eyeLookInRight')),
68
+ lookLeftThenRight: Math.min(rise(s, rest.scores, 'eyeLookOutRight'), rise(s, rest.scores, 'eyeLookInLeft')),
69
+ mouthLeft: r('mouthLeft'), mouthRight: r('mouthRight'),
70
+ };
71
+ }
72
+ /** START's squeeze mark: above the relaxed narrowing (0.30–0.34) and the eye a real frown squeezes (0.36–0.49) in the Dev's runs. */
73
+ export const SQUEEZE_MARK = 0.5;
74
+ const DOMINATES = { pressLips: ['smile'], mouthLeft: ['pucker'], mouthRight: ['pucker'] };
75
+ /** The exclusions: a held specific expression clears the generic one it drags along; a squeeze at START's mark clears the frown. */
76
+ export function resolveFace(levels, mark) {
77
+ const out = { ...levels };
78
+ if ((levels.squeeze ?? 0) >= SQUEEZE_MARK)
79
+ out.frown = 0;
80
+ for (const e of EXPRESSIONS) {
81
+ if ((levels[e] ?? 0) >= mark)
82
+ for (const weak of DOMINATES[e] ?? [])
83
+ out[weak] = 0;
84
+ }
85
+ return out;
86
+ }
87
+ /** The pucker's own mark (0.6): below it, it is not a pucker. */
88
+ export const PUCKER_MARK = 0.6;
89
+ export function ownMarks(levels) {
90
+ return (levels.pucker ?? 0) < PUCKER_MARK ? { ...levels, pucker: 0 } : levels;
91
+ }
92
+ const LOOK_BUTTONS = ['lookRightThenLeft', 'lookLeftThenRight'];
93
+ /** Each button's first half is the other side. */
94
+ const FIRST_SIDE = { lookRightThenLeft: 'lookLeftThenRight', lookLeftThenRight: 'lookRightThenLeft' };
95
+ /**
96
+ * The crossed look. In: the look to each side (in the levels, under the button it ends on). Out: the button levels. A first side counts
97
+ * only if it peaked at `peakMin` and then left the mark; the second must reach `peakMin` within `windowMs` and stay `holdMs`; held, it
98
+ * stays down while the look stays at the mark; a turned head cancels any crossing.
99
+ */
100
+ export function createCrossedLook({ mark, peakMin = 0.6, windowMs = 800, holdMs = 300 }) {
101
+ const side = {
102
+ lookRightThenLeft: { on: false, peak: 0, leftAt: null }, lookLeftThenRight: { on: false, peak: 0, leftAt: null },
103
+ };
104
+ const press = {
105
+ lookRightThenLeft: { start: null, heldSince: null }, lookLeftThenRight: { start: null, heldSince: null },
106
+ };
107
+ /** A side peaks while it is at the mark; leaving after a peak of `peakMin` leaves a first half for the other button. */
108
+ function trackSide(s, v, ms, turned) {
109
+ if (v >= mark) {
110
+ if (!s.on) {
111
+ s.on = true;
112
+ s.peak = 0;
113
+ } // zeroed on arrival, so a weak visit never inherits a strong one's peak
114
+ s.peak = Math.max(s.peak, v);
115
+ }
116
+ else if (s.on) {
117
+ s.on = false;
118
+ if (s.peak >= peakMin)
119
+ s.leftAt = ms;
120
+ }
121
+ if (turned) {
122
+ s.leftAt = null;
123
+ s.peak = 0;
124
+ }
125
+ }
126
+ /** The second side starts a press only if the first left within `windowMs` — and it spends that first half either way. */
127
+ function startOf(ms, before) {
128
+ if (before.leftAt === null)
129
+ return -1;
130
+ const start = ms - before.leftAt <= windowMs ? ms : -1;
131
+ before.leftAt = null;
132
+ return start;
133
+ }
134
+ /** One button's level: held, it stays down while the look stays at the mark; otherwise the second side must reach
135
+ * `peakMin` with the head still, and after `holdMs` the press is held. Letting go clears it whole. */
136
+ function stepPress(st, v, ms, before, turned) {
137
+ if (st.heldSince !== null) {
138
+ if (v >= mark)
139
+ return 1;
140
+ st.heldSince = null;
141
+ st.start = null;
142
+ return 0;
143
+ }
144
+ if (v < peakMin || turned) {
145
+ st.start = null;
146
+ return 0;
147
+ }
148
+ st.start ??= startOf(ms, before);
149
+ if (st.start >= 0 && ms - st.start >= holdMs)
150
+ st.heldSince = st.start;
151
+ return st.start >= 0 ? 1 : 0;
152
+ }
153
+ return (ms, levels) => {
154
+ const out = { ...levels };
155
+ const turned = Math.max(levels.headLeft ?? 0, levels.headRight ?? 0) >= mark;
156
+ // every side is tracked before any button reads one: a button's first half is the OTHER side's exit
157
+ for (const b of LOOK_BUTTONS)
158
+ trackSide(side[b], levels[b] ?? 0, ms, turned);
159
+ for (const b of LOOK_BUTTONS)
160
+ out[b] = stepPress(press[b], levels[b] ?? 0, ms, side[FIRST_SIDE[b]], turned);
161
+ return out;
162
+ };
163
+ }
164
+ /** START's long squeeze: its level passes only after staying at `SQUEEZE_MARK` for `ms` (the usual hold comes on top: about 1 s). */
165
+ export function createLongSqueeze(ms = 700) {
166
+ let since = null;
167
+ return (now, levels) => {
168
+ if ((levels.squeeze ?? 0) < SQUEEZE_MARK) {
169
+ since = null;
170
+ return { ...levels, squeeze: 0 };
171
+ }
172
+ since ??= now;
173
+ return now - since >= ms ? levels : { ...levels, squeeze: 0 };
174
+ };
175
+ }
176
+ /** The mouth expressions, held `ms` longer: talking moves the mouth past the mark in short syllables. */
177
+ const MOUTH_EXPRESSIONS = ['pressLips', 'openMouth', 'smile', 'pucker', 'mouthLeft', 'mouthRight'];
178
+ export function createMouthHold({ mark, ms = 300 }) {
179
+ const since = new Map();
180
+ return (now, levels) => {
181
+ const out = { ...levels };
182
+ for (const e of MOUTH_EXPRESSIONS) {
183
+ if ((levels[e] ?? 0) < mark) {
184
+ since.delete(e);
185
+ continue;
186
+ }
187
+ if (!since.has(e))
188
+ since.set(e, now);
189
+ if (now - since.get(e) < ms)
190
+ out[e] = 0;
191
+ }
192
+ return out;
193
+ };
194
+ }
195
+ /** The whole reader: a frame's scores and landmarks in, the actions held and the ones that just started out. */
196
+ export function createFaceMapReader({ rest, mark = 0.3, holdMs = 300 }) {
197
+ const crossed = createCrossedLook({ mark }), squeeze = createLongSqueeze(), mouth = createMouthHold({ mark });
198
+ const aboveSince = new Map(), held = new Set();
199
+ return (ms, scores, landmarks) => {
200
+ const turn = headTurn(landmarks, rest.headX);
201
+ const levels = mouth(ms, squeeze(ms, crossed(ms, ownMarks(resolveFace(faceLevels(scores, rest, turn), mark)))));
202
+ const started = [];
203
+ for (const e of EXPRESSIONS) {
204
+ if ((levels[e] ?? 0) >= mark) {
205
+ if (!aboveSince.has(e))
206
+ aboveSince.set(e, ms);
207
+ if (!held.has(e) && ms - aboveSince.get(e) >= holdMs) {
208
+ held.add(e);
209
+ started.push(FACE_MAP[e]);
210
+ }
211
+ }
212
+ else {
213
+ aboveSince.delete(e);
214
+ held.delete(e);
215
+ }
216
+ }
217
+ return { held: [...held].map((e) => FACE_MAP[e]), started };
218
+ };
219
+ }
220
+ /**
221
+ * THE FACE'S REST, MEASURED BY ITSELF (the Dev, 2026-09-16: «sozinho, quando o rosto fica parado olhando para o centro da tela por 3 s+»).
222
+ * Frames gather while the face stays still — every blendshape and the nose within `maxSpread` of their median — for `restMs` in a row;
223
+ * any movement restarts the count, so the rest is never taken from a child who is talking, reading or looking around.
224
+ */
225
+ export function createFaceRest({ restMs = 3000, maxSpread = 0.08 } = {}) {
226
+ let since = null;
227
+ const samples = [];
228
+ const median = (xs) => { const a = [...xs].sort((p, q) => p - q); return a[Math.floor(a.length / 2)] ?? 0; };
229
+ return (ms, scores, headX) => {
230
+ since ??= ms;
231
+ samples.push({ scores, headX });
232
+ const moving = [...FACE_BLENDSHAPES.map((n) => samples.map((s) => s.scores[n] ?? 0)), samples.map((s) => s.headX ?? 0)]
233
+ .some((xs) => { const m = median(xs); return xs.some((x) => Math.abs(x - m) > maxSpread); });
234
+ if (moving) {
235
+ samples.length = 0;
236
+ samples.push({ scores, headX });
237
+ since = ms;
238
+ return { rest: null, stillMs: 0 };
239
+ }
240
+ if (ms - since < restMs)
241
+ return { rest: null, stillMs: ms - since };
242
+ return { rest: faceRestFromSamples(samples), stillMs: ms - since };
243
+ };
244
+ }
245
+ /** The rest from a few seconds of samples: each blendshape's median, and the nose's. */
246
+ export function faceRestFromSamples(samples) {
247
+ const median = (xs) => { const a = [...xs].sort((p, q) => p - q); return a.length ? a[Math.floor(a.length / 2)] : 0; };
248
+ const scores = {};
249
+ for (const n of FACE_BLENDSHAPES) {
250
+ const xs = samples.map((s) => s.scores[n]).filter((v) => typeof v === 'number');
251
+ if (xs.length)
252
+ scores[n] = median(xs);
253
+ }
254
+ return { scores, headX: median(samples.map((s) => s.headX).filter((v) => v !== null)) };
255
+ }
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ export interface HeadPose {
3
+ readonly yaw: number;
4
+ readonly pitch: number;
5
+ readonly roll: number;
6
+ /** The face's position in the camera's metric space, in cm: the camera at the origin looking down −z, so a face in front has tz < 0. */
7
+ readonly tx: number;
8
+ readonly ty: number;
9
+ readonly tz: number;
10
+ }
11
+ /** Degrees from the Face Landmarker's 4×4 column-major matrix. Null without one. */
12
+ export declare function headPoseFromMatrix(m: ArrayLike<number> | null | undefined): HeadPose | null;
13
+ /** The blendshapes the eye control reads — a closed list, so a score kept here can never be a number per action (ADR-0112). */
14
+ export declare const EYE_BLENDSHAPES: readonly ["eyeLookInLeft", "eyeLookOutLeft", "eyeLookUpLeft", "eyeLookDownLeft", "eyeLookInRight", "eyeLookOutRight", "eyeLookUpRight", "eyeLookDownRight", "eyeBlinkLeft", "eyeBlinkRight"];
15
+ export type EyeBlendshape = (typeof EYE_BLENDSHAPES)[number];
16
+ /** Scores of the eye blendshapes by name; one the detection did not bring is absent. */
17
+ export type BlendshapeScores = Partial<Readonly<Record<EyeBlendshape, number>>>;
18
+ /** The Face Landmarker gives all 52 blendshapes as `{ categoryName, score }` pairs; this keeps the eye ones, by name. */
19
+ export declare function scoresFromCategories(categories: ReadonlyArray<{
20
+ readonly categoryName: string;
21
+ readonly score: number;
22
+ }> | null | undefined): BlendshapeScores;
23
+ export interface EyeGaze {
24
+ /** Grows as the eye turns towards the PLAYER'S LEFT. */
25
+ readonly h: number;
26
+ /** Grows as the eye turns DOWN. */
27
+ readonly v: number;
28
+ }
29
+ /**
30
+ * Each eye's gaze. `left` and `right` are the subject's own eyes, as MediaPipe names them; the right eye turning to the player's left moves
31
+ * towards the nose (in), the left eye moves out. A missing score reads as zero.
32
+ */
33
+ export declare function eyeGazeFromScores(s: BlendshapeScores | null | undefined): {
34
+ readonly left: EyeGaze;
35
+ readonly right: EyeGaze;
36
+ };
37
+ /** The mark a blink score must reach on BOTH eyes for them to count as closed — START is both eyes closed (ADR-0213 §5). */
38
+ export declare const EYES_CLOSED_MARK = 0.5;
39
+ /** Both eyes closed: the LESS closed of the two reaches the mark, so one eye squeezed shut is not a close. */
40
+ export declare function bothEyesClosed(s: BlendshapeScores | null | undefined, mark?: number): boolean;
@@ -0,0 +1,48 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // input/face-signals — WHAT THE EYE CONTROL READS FROM THE FACE LANDMARKER (ADR-0213; issue #194).
3
+ //
4
+ // Three readings and nothing else: the head pose from the facial transformation matrix, each eye's gaze from the ready-made blendshapes, and
5
+ // whether both eyes are closed. Nothing here knows where the screen is — the eye control measures how far the gaze moves from its own rest
6
+ // (input/gaze-relative), and uses the pose only to notice a head that turns fast.
7
+ //
8
+ // ⚠️ THE SIGN OF PITCH IS NOT MEASURED against a real head. Only the pose's rate of change reaches a command, so the sign does not.
9
+ /** Degrees from the Face Landmarker's 4×4 column-major matrix. Null without one. */
10
+ export function headPoseFromMatrix(m) {
11
+ if (!m || m.length < 16)
12
+ return null;
13
+ const deg = 180 / Math.PI;
14
+ return {
15
+ yaw: Math.atan2(m[8], m[10]) * deg,
16
+ pitch: Math.asin(Math.max(-1, Math.min(1, -m[9]))) * deg,
17
+ roll: Math.atan2(m[1], m[5]) * deg,
18
+ tx: m[12], ty: m[13], tz: m[14],
19
+ };
20
+ }
21
+ /** The blendshapes the eye control reads — a closed list, so a score kept here can never be a number per action (ADR-0112). */
22
+ export const EYE_BLENDSHAPES = [
23
+ 'eyeLookInLeft', 'eyeLookOutLeft', 'eyeLookUpLeft', 'eyeLookDownLeft',
24
+ 'eyeLookInRight', 'eyeLookOutRight', 'eyeLookUpRight', 'eyeLookDownRight',
25
+ 'eyeBlinkLeft', 'eyeBlinkRight',
26
+ ];
27
+ const READ = new Set(EYE_BLENDSHAPES);
28
+ /** The Face Landmarker gives all 52 blendshapes as `{ categoryName, score }` pairs; this keeps the eye ones, by name. */
29
+ export function scoresFromCategories(categories) {
30
+ return Object.fromEntries((categories ?? []).filter((c) => READ.has(c.categoryName)).map((c) => [c.categoryName, c.score]));
31
+ }
32
+ /**
33
+ * Each eye's gaze. `left` and `right` are the subject's own eyes, as MediaPipe names them; the right eye turning to the player's left moves
34
+ * towards the nose (in), the left eye moves out. A missing score reads as zero.
35
+ */
36
+ export function eyeGazeFromScores(s) {
37
+ const q = (n) => s?.[n] ?? 0;
38
+ return {
39
+ left: { h: q('eyeLookOutLeft') - q('eyeLookInLeft'), v: q('eyeLookDownLeft') - q('eyeLookUpLeft') },
40
+ right: { h: q('eyeLookInRight') - q('eyeLookOutRight'), v: q('eyeLookDownRight') - q('eyeLookUpRight') },
41
+ };
42
+ }
43
+ /** The mark a blink score must reach on BOTH eyes for them to count as closed — START is both eyes closed (ADR-0213 §5). */
44
+ export const EYES_CLOSED_MARK = 0.5;
45
+ /** Both eyes closed: the LESS closed of the two reaches the mark, so one eye squeezed shut is not a close. */
46
+ export function bothEyesClosed(s, mark = EYES_CLOSED_MARK) {
47
+ return Math.min(s?.['eyeBlinkLeft'] ?? 0, s?.['eyeBlinkRight'] ?? 0) >= mark;
48
+ }