@the-inclusionist/engine 9.0.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/README.md +120 -78
  2. package/app/css/style.css +761 -377
  3. package/app/public/vendor/fonts/playwrite-cu.woff2 +0 -0
  4. package/app/public/vendor/fonts/playwrite-es-deco.woff2 +0 -0
  5. package/app/public/vendor/fonts/playwrite-es.woff2 +0 -0
  6. package/app/public/vendor/fonts/playwrite-gb-j.woff2 +0 -0
  7. package/app/public/vendor/fonts/playwrite-gb-s.woff2 +0 -0
  8. package/app/public/vendor/fonts/playwrite-pe.woff2 +0 -0
  9. package/app/public/vendor/fonts/playwrite-pt.woff2 +0 -0
  10. package/app/public/vendor/fonts-licences/NOTICE.txt +166 -0
  11. package/app/public/vendor/fonts-licences/OFL-1.1.txt +86 -0
  12. package/app/public/vendor/fonts.css +36 -84
  13. package/dist-pkg/boot/create-game.d.ts +499 -219
  14. package/dist-pkg/boot/create-game.js +3944 -562
  15. package/dist-pkg/core/a11y-sr.d.ts +25 -3
  16. package/dist-pkg/core/a11y-sr.js +38 -19
  17. package/dist-pkg/core/accessible-label.d.ts +17 -0
  18. package/dist-pkg/core/accessible-label.js +37 -0
  19. package/dist-pkg/core/accommodation-subjects.d.ts +26 -0
  20. package/dist-pkg/core/accommodation-subjects.js +32 -0
  21. package/dist-pkg/core/accommodations.d.ts +125 -0
  22. package/dist-pkg/core/accommodations.js +195 -0
  23. package/dist-pkg/core/actions.d.ts +108 -55
  24. package/dist-pkg/core/actions.js +122 -71
  25. package/dist-pkg/core/calm-mode.d.ts +31 -0
  26. package/dist-pkg/core/calm-mode.js +47 -0
  27. package/dist-pkg/core/camera-cycle.d.ts +15 -0
  28. package/dist-pkg/core/camera-cycle.js +7 -0
  29. package/dist-pkg/core/caption-duration.d.ts +15 -0
  30. package/dist-pkg/core/caption-duration.js +19 -0
  31. package/dist-pkg/core/cartridge-problems.d.ts +34 -0
  32. package/dist-pkg/core/cartridge-problems.js +53 -0
  33. package/dist-pkg/core/constants.d.ts +0 -54
  34. package/dist-pkg/core/constants.js +9 -76
  35. package/dist-pkg/core/contract.d.ts +142 -164
  36. package/dist-pkg/core/contract.js +222 -208
  37. package/dist-pkg/core/dom-query.d.ts +4 -4
  38. package/dist-pkg/core/dom-query.js +12 -20
  39. package/dist-pkg/core/entity.d.ts +62 -77
  40. package/dist-pkg/core/entity.js +18 -32
  41. package/dist-pkg/core/escape-html.d.ts +9 -10
  42. package/dist-pkg/core/escape-html.js +16 -20
  43. package/dist-pkg/core/flash-threshold.d.ts +17 -0
  44. package/dist-pkg/core/flash-threshold.js +113 -0
  45. package/dist-pkg/core/game-speed.d.ts +11 -0
  46. package/dist-pkg/core/game-speed.js +16 -0
  47. package/dist-pkg/core/genres.d.ts +20 -0
  48. package/dist-pkg/core/genres.js +44 -0
  49. package/dist-pkg/core/i18n.d.ts +71 -60
  50. package/dist-pkg/core/i18n.js +186 -200
  51. package/dist-pkg/core/loop.d.ts +17 -6
  52. package/dist-pkg/core/loop.js +26 -26
  53. package/dist-pkg/core/pause-icon-catalogue.d.ts +15 -0
  54. package/dist-pkg/core/pause-icon-catalogue.js +54 -0
  55. package/dist-pkg/core/ring.d.ts +17 -0
  56. package/dist-pkg/core/ring.js +29 -0
  57. package/dist-pkg/core/rng.d.ts +7 -12
  58. package/dist-pkg/core/rng.js +23 -53
  59. package/dist-pkg/core/route.d.ts +26 -26
  60. package/dist-pkg/core/route.js +126 -121
  61. package/dist-pkg/core/scenes.d.ts +37 -40
  62. package/dist-pkg/core/scenes.js +41 -43
  63. package/dist-pkg/core/screens.d.ts +4 -4
  64. package/dist-pkg/core/screens.js +11 -16
  65. package/dist-pkg/core/session-clock.d.ts +23 -0
  66. package/dist-pkg/core/session-clock.js +37 -0
  67. package/dist-pkg/core/setting-defaults.d.ts +61 -0
  68. package/dist-pkg/core/setting-defaults.js +66 -0
  69. package/dist-pkg/core/speech-rate.d.ts +29 -0
  70. package/dist-pkg/core/speech-rate.js +47 -0
  71. package/dist-pkg/core/state.d.ts +118 -118
  72. package/dist-pkg/core/state.js +322 -297
  73. package/dist-pkg/core/visual-cycles.d.ts +30 -0
  74. package/dist-pkg/core/visual-cycles.js +52 -0
  75. package/dist-pkg/core/visual-state.d.ts +13 -0
  76. package/dist-pkg/core/visual-state.js +6 -0
  77. package/dist-pkg/educational/activities-registry.d.ts +1 -1
  78. package/dist-pkg/educational/activities-registry.js +9 -8
  79. package/dist-pkg/educational/adaptive-engine.d.ts +11 -11
  80. package/dist-pkg/educational/adaptive-engine.js +17 -17
  81. package/dist-pkg/educational/segment-bar.d.ts +12 -12
  82. package/dist-pkg/educational/segment-bar.js +9 -9
  83. package/dist-pkg/i18n/en.js +324 -223
  84. package/dist-pkg/i18n/es.js +323 -223
  85. package/dist-pkg/i18n/pt.js +348 -226
  86. package/dist-pkg/input/default-bindings.d.ts +37 -38
  87. package/dist-pkg/input/default-bindings.js +127 -144
  88. package/dist-pkg/input/devices.d.ts +7 -7
  89. package/dist-pkg/input/devices.js +17 -16
  90. package/dist-pkg/input/edges.d.ts +23 -32
  91. package/dist-pkg/input/edges.js +23 -28
  92. package/dist-pkg/input/empathy-filter.d.ts +22 -0
  93. package/dist-pkg/input/empathy-filter.js +34 -0
  94. package/dist-pkg/input/face-map.d.ts +96 -0
  95. package/dist-pkg/input/face-map.js +255 -0
  96. package/dist-pkg/input/face-signals.d.ts +40 -0
  97. package/dist-pkg/input/face-signals.js +48 -0
  98. package/dist-pkg/input/gamepad.d.ts +195 -145
  99. package/dist-pkg/input/gamepad.js +383 -556
  100. package/dist-pkg/input/gaze-cycle.d.ts +64 -0
  101. package/dist-pkg/input/gaze-cycle.js +133 -0
  102. package/dist-pkg/input/gaze-relative.d.ts +68 -0
  103. package/dist-pkg/input/gaze-relative.js +142 -0
  104. package/dist-pkg/input/hand-map.d.ts +28 -0
  105. package/dist-pkg/input/hand-map.js +142 -0
  106. package/dist-pkg/input/input-cooldown.d.ts +17 -0
  107. package/dist-pkg/input/input-cooldown.js +39 -0
  108. package/dist-pkg/input/key-default.d.ts +30 -0
  109. package/dist-pkg/input/key-default.js +60 -0
  110. package/dist-pkg/input/keyboard-runtime.d.ts +15 -21
  111. package/dist-pkg/input/keyboard-runtime.js +23 -27
  112. package/dist-pkg/input/keyboard.d.ts +68 -63
  113. package/dist-pkg/input/keyboard.js +83 -105
  114. package/dist-pkg/input/keydown.d.ts +123 -137
  115. package/dist-pkg/input/keydown.js +284 -289
  116. package/dist-pkg/input/latch-edge.d.ts +33 -21
  117. package/dist-pkg/input/latch-edge.js +34 -35
  118. package/dist-pkg/input/latch-scope.d.ts +51 -50
  119. package/dist-pkg/input/latch-scope.js +61 -82
  120. package/dist-pkg/input/latch-store.d.ts +26 -30
  121. package/dist-pkg/input/latch-store.js +42 -50
  122. package/dist-pkg/input/latch-sync.d.ts +29 -29
  123. package/dist-pkg/input/latch-sync.js +25 -25
  124. package/dist-pkg/input/latch.d.ts +14 -17
  125. package/dist-pkg/input/latch.js +29 -37
  126. package/dist-pkg/input/pad-defaults.d.ts +13 -16
  127. package/dist-pkg/input/pad-defaults.js +21 -28
  128. package/dist-pkg/input/pad-reading.d.ts +76 -0
  129. package/dist-pkg/input/pad-reading.js +169 -0
  130. package/dist-pkg/input/pad-wizard.d.ts +99 -0
  131. package/dist-pkg/input/pad-wizard.js +256 -0
  132. package/dist-pkg/input/pointer-space.d.ts +19 -20
  133. package/dist-pkg/input/pointer-space.js +27 -32
  134. package/dist-pkg/input/pointer.d.ts +39 -40
  135. package/dist-pkg/input/pointer.js +42 -45
  136. package/dist-pkg/input/state.d.ts +101 -89
  137. package/dist-pkg/input/state.js +54 -134
  138. package/dist-pkg/input/switch-scan.d.ts +59 -0
  139. package/dist-pkg/input/switch-scan.js +67 -0
  140. package/dist-pkg/input/synthetic-source.d.ts +42 -0
  141. package/dist-pkg/input/synthetic-source.js +57 -0
  142. package/dist-pkg/input/touch-bindings.d.ts +127 -116
  143. package/dist-pkg/input/touch-bindings.js +158 -173
  144. package/dist-pkg/input/touch.d.ts +147 -72
  145. package/dist-pkg/input/touch.js +362 -126
  146. package/dist-pkg/input/transport-in-use.d.ts +107 -0
  147. package/dist-pkg/input/transport-in-use.js +130 -0
  148. package/dist-pkg/input/transports.d.ts +90 -117
  149. package/dist-pkg/input/transports.js +104 -106
  150. package/dist-pkg/input/virtual-controller.d.ts +82 -0
  151. package/dist-pkg/input/virtual-controller.js +69 -0
  152. package/dist-pkg/input/vocabulary-migration.d.ts +50 -49
  153. package/dist-pkg/input/vocabulary-migration.js +80 -79
  154. package/dist-pkg/input/voice-map.d.ts +59 -0
  155. package/dist-pkg/input/voice-map.js +123 -0
  156. package/dist-pkg/platform/audio-ambient.d.ts +13 -2
  157. package/dist-pkg/platform/audio-ambient.js +14 -14
  158. package/dist-pkg/platform/audio-earcons.d.ts +20 -19
  159. package/dist-pkg/platform/audio-earcons.js +51 -42
  160. package/dist-pkg/platform/audio-jingles.js +9 -10
  161. package/dist-pkg/platform/audio-mixer.d.ts +14 -2
  162. package/dist-pkg/platform/audio-mixer.js +31 -39
  163. package/dist-pkg/platform/audio-sonar.d.ts +49 -152
  164. package/dist-pkg/platform/audio-sonar.js +124 -302
  165. package/dist-pkg/platform/audio.d.ts +62 -19
  166. package/dist-pkg/platform/audio.js +193 -168
  167. package/dist-pkg/platform/choose-by-voice.d.ts +70 -0
  168. package/dist-pkg/platform/choose-by-voice.js +157 -0
  169. package/dist-pkg/platform/flash-sampler.d.ts +19 -0
  170. package/dist-pkg/platform/flash-sampler.js +79 -0
  171. package/dist-pkg/platform/font-library.d.ts +77 -0
  172. package/dist-pkg/platform/font-library.js +98 -0
  173. package/dist-pkg/platform/font-library.json +721 -0
  174. package/dist-pkg/platform/heavy-catalogue.d.ts +77 -0
  175. package/dist-pkg/platform/heavy-catalogue.js +256 -0
  176. package/dist-pkg/platform/heavy-mirror.d.ts +20 -0
  177. package/dist-pkg/platform/heavy-mirror.js +73 -0
  178. package/dist-pkg/platform/heavy.d.ts +136 -0
  179. package/dist-pkg/platform/heavy.js +324 -0
  180. package/dist-pkg/platform/interruptible-speech.d.ts +23 -16
  181. package/dist-pkg/platform/interruptible-speech.js +77 -54
  182. package/dist-pkg/platform/kokoro-port.d.ts +27 -0
  183. package/dist-pkg/platform/kokoro-port.js +50 -0
  184. package/dist-pkg/platform/kokoro-runtime.d.ts +20 -0
  185. package/dist-pkg/platform/kokoro-runtime.js +52 -0
  186. package/dist-pkg/platform/kokoro.d.ts +70 -0
  187. package/dist-pkg/platform/kokoro.js +133 -0
  188. package/dist-pkg/platform/listener-scope.d.ts +12 -0
  189. package/dist-pkg/platform/listener-scope.js +90 -0
  190. package/dist-pkg/platform/locale-host.d.ts +14 -0
  191. package/dist-pkg/platform/locale-host.js +45 -0
  192. package/dist-pkg/platform/microphone.d.ts +51 -0
  193. package/dist-pkg/platform/microphone.js +118 -0
  194. package/dist-pkg/platform/onnx-runtime.d.ts +34 -0
  195. package/dist-pkg/platform/onnx-runtime.js +42 -0
  196. package/dist-pkg/platform/reading-in-worker.d.ts +64 -0
  197. package/dist-pkg/platform/reading-in-worker.js +125 -0
  198. package/dist-pkg/platform/reading-model.d.ts +94 -0
  199. package/dist-pkg/platform/reading-model.js +272 -0
  200. package/dist-pkg/platform/reading-runtime.d.ts +24 -0
  201. package/dist-pkg/platform/reading-runtime.js +164 -0
  202. package/dist-pkg/platform/reading-worker.d.ts +41 -0
  203. package/dist-pkg/platform/reading-worker.js +58 -0
  204. package/dist-pkg/platform/reading.d.ts +80 -0
  205. package/dist-pkg/platform/reading.js +136 -0
  206. package/dist-pkg/platform/speech-recognition.d.ts +60 -0
  207. package/dist-pkg/platform/speech-recognition.js +104 -0
  208. package/dist-pkg/platform/speech.d.ts +23 -1
  209. package/dist-pkg/platform/speech.js +29 -18
  210. package/dist-pkg/platform/storage-keys.d.ts +96 -0
  211. package/dist-pkg/platform/storage-keys.js +106 -0
  212. package/dist-pkg/platform/storage.d.ts +46 -111
  213. package/dist-pkg/platform/storage.js +104 -169
  214. package/dist-pkg/platform/tts.d.ts +85 -39
  215. package/dist-pkg/platform/tts.js +447 -127
  216. package/dist-pkg/platform/vision-loop.d.ts +23 -0
  217. package/dist-pkg/platform/vision-loop.js +56 -0
  218. package/dist-pkg/platform/vision.d.ts +132 -0
  219. package/dist-pkg/platform/vision.js +117 -0
  220. package/dist-pkg/platform/voice-listener.d.ts +40 -0
  221. package/dist-pkg/platform/voice-listener.js +88 -0
  222. package/dist-pkg/platform/voice-plan.d.ts +15 -98
  223. package/dist-pkg/platform/voice-plan.js +56 -143
  224. package/dist-pkg/platform/vosk-runtime.d.ts +96 -0
  225. package/dist-pkg/platform/vosk-runtime.js +151 -0
  226. package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
  227. package/dist-pkg/platform/vosk-vocabulary.js +178 -0
  228. package/dist-pkg/render/canvas.d.ts +13 -7
  229. package/dist-pkg/render/canvas.js +13 -13
  230. package/dist-pkg/render/crt.d.ts +48 -12
  231. package/dist-pkg/render/crt.js +78 -80
  232. package/dist-pkg/render/cvd-matrices.d.ts +22 -18
  233. package/dist-pkg/render/cvd-matrices.js +37 -38
  234. package/dist-pkg/render/hc-role-data.d.ts +7 -7
  235. package/dist-pkg/render/hc-role-data.js +14 -14
  236. package/dist-pkg/render/high-contrast.d.ts +67 -56
  237. package/dist-pkg/render/high-contrast.js +226 -217
  238. package/dist-pkg/render/low-vision-drawing.d.ts +5 -0
  239. package/dist-pkg/render/low-vision-drawing.js +46 -0
  240. package/dist-pkg/render/lq-filter.d.ts +32 -20
  241. package/dist-pkg/render/lq-filter.js +59 -65
  242. package/dist-pkg/render/port.d.ts +86 -88
  243. package/dist-pkg/render/port.js +17 -23
  244. package/dist-pkg/render/screen-pipeline.d.ts +42 -42
  245. package/dist-pkg/render/screen-pipeline.js +80 -87
  246. package/dist-pkg/render/sprite-fx.d.ts +2 -1
  247. package/dist-pkg/render/sprite-fx.js +16 -14
  248. package/dist-pkg/render/viewports.d.ts +20 -15
  249. package/dist-pkg/render/viewports.js +83 -114
  250. package/dist-pkg/render/viz-axes-labels.d.ts +47 -0
  251. package/dist-pkg/render/viz-axes-labels.js +88 -0
  252. package/dist-pkg/render/viz-axes.d.ts +89 -86
  253. package/dist-pkg/render/viz-axes.js +128 -116
  254. package/dist-pkg/render/viz-modes.d.ts +28 -29
  255. package/dist-pkg/render/viz-modes.js +40 -45
  256. package/dist-pkg/render/viz-refusal.d.ts +32 -0
  257. package/dist-pkg/render/viz-refusal.js +57 -0
  258. package/dist-pkg/render/viz-setters.d.ts +104 -66
  259. package/dist-pkg/render/viz-setters.js +182 -191
  260. package/dist-pkg/ui/aac-sets.d.ts +45 -0
  261. package/dist-pkg/ui/aac-sets.js +41 -0
  262. package/dist-pkg/ui/audio-choices.d.ts +68 -0
  263. package/dist-pkg/ui/audio-choices.js +98 -0
  264. package/dist-pkg/ui/audio-rows-that-apply.d.ts +12 -0
  265. package/dist-pkg/ui/audio-rows-that-apply.js +43 -0
  266. package/dist-pkg/ui/camera-control.d.ts +53 -0
  267. package/dist-pkg/ui/camera-control.js +48 -0
  268. package/dist-pkg/ui/changed-mark.d.ts +9 -8
  269. package/dist-pkg/ui/changed-mark.js +22 -53
  270. package/dist-pkg/ui/control-choices.d.ts +37 -0
  271. package/dist-pkg/ui/control-choices.js +84 -0
  272. package/dist-pkg/ui/debug-panel.d.ts +59 -43
  273. package/dist-pkg/ui/debug-panel.js +68 -69
  274. package/dist-pkg/ui/declared-words.d.ts +21 -0
  275. package/dist-pkg/ui/declared-words.js +66 -0
  276. package/dist-pkg/ui/dom.d.ts +10 -14
  277. package/dist-pkg/ui/dom.js +10 -47
  278. package/dist-pkg/ui/drawing-problems.d.ts +25 -0
  279. package/dist-pkg/ui/drawing-problems.js +94 -0
  280. package/dist-pkg/ui/eye-control.d.ts +36 -0
  281. package/dist-pkg/ui/eye-control.js +178 -0
  282. package/dist-pkg/ui/face-control.d.ts +25 -0
  283. package/dist-pkg/ui/face-control.js +183 -0
  284. package/dist-pkg/ui/focus-trap.d.ts +39 -49
  285. package/dist-pkg/ui/focus-trap.js +56 -65
  286. package/dist-pkg/ui/fonts.d.ts +157 -68
  287. package/dist-pkg/ui/fonts.js +305 -115
  288. package/dist-pkg/ui/footer-scroll-driver.d.ts +14 -0
  289. package/dist-pkg/ui/footer-scroll-driver.js +201 -0
  290. package/dist-pkg/ui/footer-scroll.d.ts +38 -0
  291. package/dist-pkg/ui/footer-scroll.js +55 -0
  292. package/dist-pkg/ui/game-options.d.ts +47 -0
  293. package/dist-pkg/ui/game-options.js +158 -0
  294. package/dist-pkg/ui/gaze-overlay.d.ts +64 -0
  295. package/dist-pkg/ui/gaze-overlay.js +165 -0
  296. package/dist-pkg/ui/hand-control.d.ts +25 -0
  297. package/dist-pkg/ui/hand-control.js +143 -0
  298. package/dist-pkg/ui/help-panel.d.ts +87 -0
  299. package/dist-pkg/ui/help-panel.js +242 -0
  300. package/dist-pkg/ui/hud-bands.d.ts +62 -0
  301. package/dist-pkg/ui/hud-bands.js +146 -0
  302. package/dist-pkg/ui/hud-row.d.ts +34 -0
  303. package/dist-pkg/ui/hud-row.js +80 -0
  304. package/dist-pkg/ui/hud.d.ts +73 -73
  305. package/dist-pkg/ui/hud.js +94 -98
  306. package/dist-pkg/ui/item-announcement.d.ts +13 -12
  307. package/dist-pkg/ui/item-announcement.js +25 -26
  308. package/dist-pkg/ui/layout.d.ts +103 -28
  309. package/dist-pkg/ui/layout.js +117 -99
  310. package/dist-pkg/ui/libras-avatar-clip.d.ts +30 -0
  311. package/dist-pkg/ui/libras-avatar-clip.js +86 -0
  312. package/dist-pkg/ui/libras-avatar-load.d.ts +52 -0
  313. package/dist-pkg/ui/libras-avatar-load.js +134 -0
  314. package/dist-pkg/ui/libras-avatar-plan.d.ts +102 -0
  315. package/dist-pkg/ui/libras-avatar-plan.js +211 -0
  316. package/dist-pkg/ui/libras-avatar-player.d.ts +28 -0
  317. package/dist-pkg/ui/libras-avatar-player.js +226 -0
  318. package/dist-pkg/ui/libras-avatar-stage.d.ts +37 -0
  319. package/dist-pkg/ui/libras-avatar-stage.js +208 -0
  320. package/dist-pkg/ui/libras-glosses.d.ts +28 -0
  321. package/dist-pkg/ui/libras-glosses.js +161 -0
  322. package/dist-pkg/ui/locale-flags.d.ts +16 -0
  323. package/dist-pkg/ui/locale-flags.js +30 -0
  324. package/dist-pkg/ui/loop-crash.d.ts +17 -17
  325. package/dist-pkg/ui/loop-crash.js +33 -62
  326. package/dist-pkg/ui/menu-intent.d.ts +61 -0
  327. package/dist-pkg/ui/menu-intent.js +88 -0
  328. package/dist-pkg/ui/menu-items.d.ts +20 -0
  329. package/dist-pkg/ui/menu-items.js +51 -0
  330. package/dist-pkg/ui/menu-nav.d.ts +98 -92
  331. package/dist-pkg/ui/menu-nav.js +398 -286
  332. package/dist-pkg/ui/mobility-choices.d.ts +26 -0
  333. package/dist-pkg/ui/mobility-choices.js +41 -0
  334. package/dist-pkg/ui/motion-choices.d.ts +31 -0
  335. package/dist-pkg/ui/motion-choices.js +68 -0
  336. package/dist-pkg/ui/motion-scene.d.ts +24 -19
  337. package/dist-pkg/ui/motion-scene.js +29 -61
  338. package/dist-pkg/ui/mount-panel.d.ts +81 -0
  339. package/dist-pkg/ui/mount-panel.js +61 -0
  340. package/dist-pkg/ui/panel-shell.d.ts +65 -31
  341. package/dist-pkg/ui/panel-shell.js +92 -66
  342. package/dist-pkg/ui/panel-widgets.d.ts +150 -0
  343. package/dist-pkg/ui/panel-widgets.js +294 -0
  344. package/dist-pkg/ui/pause-buttons.d.ts +35 -0
  345. package/dist-pkg/ui/pause-buttons.js +66 -0
  346. package/dist-pkg/ui/pause-icons.d.ts +261 -347
  347. package/dist-pkg/ui/pause-icons.js +671 -601
  348. package/dist-pkg/ui/pause-markup.d.ts +86 -0
  349. package/dist-pkg/ui/pause-markup.js +125 -0
  350. package/dist-pkg/ui/reach-notice.d.ts +22 -23
  351. package/dist-pkg/ui/reach-notice.js +55 -58
  352. package/dist-pkg/ui/scan-overlay.d.ts +23 -0
  353. package/dist-pkg/ui/scan-overlay.js +50 -0
  354. package/dist-pkg/ui/screen-text.d.ts +25 -0
  355. package/dist-pkg/ui/screen-text.js +152 -0
  356. package/dist-pkg/ui/session-clock.d.ts +32 -0
  357. package/dist-pkg/ui/session-clock.js +67 -0
  358. package/dist-pkg/ui/settings-aac.d.ts +70 -0
  359. package/dist-pkg/ui/settings-aac.js +208 -0
  360. package/dist-pkg/ui/settings-audio.d.ts +97 -114
  361. package/dist-pkg/ui/settings-audio.js +493 -425
  362. package/dist-pkg/ui/settings-controls.d.ts +53 -96
  363. package/dist-pkg/ui/settings-controls.js +143 -215
  364. package/dist-pkg/ui/settings-empathy.d.ts +39 -30
  365. package/dist-pkg/ui/settings-empathy.js +53 -60
  366. package/dist-pkg/ui/settings-mobility.d.ts +192 -0
  367. package/dist-pkg/ui/settings-mobility.js +332 -0
  368. package/dist-pkg/ui/settings-motion.d.ts +91 -70
  369. package/dist-pkg/ui/settings-motion.js +287 -198
  370. package/dist-pkg/ui/settings-panel.d.ts +58 -45
  371. package/dist-pkg/ui/settings-panel.js +189 -94
  372. package/dist-pkg/ui/settings-typo.d.ts +29 -78
  373. package/dist-pkg/ui/settings-typo.js +158 -129
  374. package/dist-pkg/ui/settings-visual.d.ts +29 -87
  375. package/dist-pkg/ui/settings-visual.js +240 -193
  376. package/dist-pkg/ui/shell.d.ts +112 -135
  377. package/dist-pkg/ui/shell.js +148 -217
  378. package/dist-pkg/ui/simulation-list.d.ts +27 -0
  379. package/dist-pkg/ui/simulation-list.js +76 -0
  380. package/dist-pkg/ui/simulation-over-the-world.d.ts +23 -0
  381. package/dist-pkg/ui/simulation-over-the-world.js +131 -0
  382. package/dist-pkg/ui/simulation-refusal.d.ts +5 -31
  383. package/dist-pkg/ui/simulation-refusal.js +8 -56
  384. package/dist-pkg/ui/switchable-control.d.ts +11 -0
  385. package/dist-pkg/ui/switchable-control.js +19 -0
  386. package/dist-pkg/ui/title.d.ts +3 -12
  387. package/dist-pkg/ui/title.js +49 -18
  388. package/dist-pkg/ui/top-band.d.ts +26 -0
  389. package/dist-pkg/ui/top-band.js +96 -0
  390. package/dist-pkg/ui/typo-choices.d.ts +71 -0
  391. package/dist-pkg/ui/typo-choices.js +85 -0
  392. package/dist-pkg/ui/visual-axes-panel.d.ts +11 -47
  393. package/dist-pkg/ui/visual-axes-panel.js +12 -94
  394. package/dist-pkg/ui/visual-choices.d.ts +77 -0
  395. package/dist-pkg/ui/visual-choices.js +107 -0
  396. package/dist-pkg/ui/vlibras.d.ts +77 -10
  397. package/dist-pkg/ui/vlibras.js +130 -81
  398. package/dist-pkg/ui/voice-control.d.ts +68 -0
  399. package/dist-pkg/ui/voice-control.js +276 -0
  400. package/dist-pkg/ui/voice-settings.d.ts +95 -0
  401. package/dist-pkg/ui/voice-settings.js +352 -0
  402. package/dist-pkg/ui/where-the-child-is.d.ts +31 -0
  403. package/dist-pkg/ui/where-the-child-is.js +70 -0
  404. package/docs/CREDITS.md +300 -44
  405. package/docs/LICENSES.md +189 -145
  406. package/package.json +51 -27
  407. package/scripts/check-cartridge.mjs +78 -0
  408. package/scripts/game-build.d.mts +25 -0
  409. package/scripts/game-build.mjs +144 -0
  410. package/scripts/heavy-into-the-delivery.mjs +388 -0
  411. package/scripts/libras-avatar.json +680 -0
  412. package/scripts/libras-avatar.mjs +246 -0
  413. package/scripts/libras-glosses/gloss.py +95 -0
  414. package/scripts/libras-glosses/pyproject.toml +32 -0
  415. package/scripts/libras-glosses/uv.lock +781 -0
  416. package/scripts/libras-glosses.mjs +351 -0
  417. package/scripts/licences/Apache-2.0.txt +176 -0
  418. package/scripts/licences/GPL-3.0.txt +674 -0
  419. package/scripts/licences/MIT.txt +17 -0
  420. package/scripts/licences/OFL-1.1.txt +86 -0
  421. package/scripts/licences/UFL-1.0.txt +96 -0
  422. package/scripts/licences/fonts.mjs +389 -0
  423. package/scripts/licences/third-party.mjs +301 -0
  424. package/scripts/licences/vosk-browser.NOTICE.txt +268 -0
  425. package/app/public/vendor/fonts/comicneue-400.woff2 +0 -0
  426. package/app/public/vendor/fonts/comicneue-700.woff2 +0 -0
  427. package/app/public/vendor/fonts/fondamento-400-ext.woff2 +0 -0
  428. package/app/public/vendor/fonts/fondamento-400.woff2 +0 -0
  429. package/app/public/vendor/fonts/inter-400.woff2 +0 -0
  430. package/app/public/vendor/fonts/inter-700.woff2 +0 -0
  431. package/app/public/vendor/fonts/lato-400.woff2 +0 -0
  432. package/app/public/vendor/fonts/lato-700.woff2 +0 -0
  433. package/app/public/vendor/fonts/literata-400.woff2 +0 -0
  434. package/app/public/vendor/fonts/literata-700.woff2 +0 -0
  435. package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
  436. package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
  437. package/app/public/vendor/fonts/opendyslexic-400.woff2 +0 -0
  438. package/app/public/vendor/fonts/opensans-400.woff2 +0 -0
  439. package/app/public/vendor/fonts/opensans-700.woff2 +0 -0
  440. package/app/public/vendor/fonts/pinyon-400.woff2 +0 -0
  441. package/app/public/vendor/fonts/pressstart-400.woff2 +0 -0
  442. package/app/public/vendor/fonts/quattro-400.woff2 +0 -0
  443. package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
  444. package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
  445. package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
  446. package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
  447. package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
  448. package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
  449. package/dist-pkg/core/anel.d.ts +0 -17
  450. package/dist-pkg/core/anel.js +0 -31
  451. package/dist-pkg/core/collision.d.ts +0 -21
  452. package/dist-pkg/core/collision.js +0 -62
  453. package/dist-pkg/core/layers.d.ts +0 -63
  454. package/dist-pkg/core/layers.js +0 -95
  455. package/dist-pkg/core/letter-grid.d.ts +0 -55
  456. package/dist-pkg/core/letter-grid.js +0 -116
  457. package/dist-pkg/core/password.d.ts +0 -34
  458. package/dist-pkg/core/password.js +0 -205
  459. package/dist-pkg/core/rotulo-acessivel.d.ts +0 -17
  460. package/dist-pkg/core/rotulo-acessivel.js +0 -41
  461. package/dist-pkg/core/run-state.d.ts +0 -115
  462. package/dist-pkg/core/run-state.js +0 -40
  463. package/dist-pkg/core/tiles.d.ts +0 -12
  464. package/dist-pkg/core/tiles.js +0 -61
  465. package/dist-pkg/core/world.d.ts +0 -4
  466. package/dist-pkg/core/world.js +0 -58
  467. package/dist-pkg/input/origem-sintetica.d.ts +0 -44
  468. package/dist-pkg/input/origem-sintetica.js +0 -60
  469. package/dist-pkg/input/transporte-em-uso.d.ts +0 -101
  470. package/dist-pkg/input/transporte-em-uso.js +0 -130
  471. package/dist-pkg/platform/audio-nav.d.ts +0 -51
  472. package/dist-pkg/platform/audio-nav.js +0 -99
  473. package/dist-pkg/platform/guide-intensity.d.ts +0 -40
  474. package/dist-pkg/platform/guide-intensity.js +0 -73
  475. package/dist-pkg/platform/pesados-catalogo.d.ts +0 -14
  476. package/dist-pkg/platform/pesados-catalogo.js +0 -177
  477. package/dist-pkg/platform/pesados.d.ts +0 -31
  478. package/dist-pkg/platform/pesados.js +0 -75
  479. package/dist-pkg/platform/vozes-prontas.d.ts +0 -28
  480. package/dist-pkg/platform/vozes-prontas.js +0 -61
  481. package/dist-pkg/render/camera.d.ts +0 -58
  482. package/dist-pkg/render/camera.js +0 -105
  483. package/dist-pkg/render/cenario-data.d.ts +0 -127
  484. package/dist-pkg/render/cenario-data.js +0 -145
  485. package/dist-pkg/render/city-tex.d.ts +0 -63
  486. package/dist-pkg/render/city-tex.js +0 -228
  487. package/dist-pkg/render/city-tiles.d.ts +0 -11
  488. package/dist-pkg/render/city-tiles.js +0 -140
  489. package/dist-pkg/render/draw.d.ts +0 -149
  490. package/dist-pkg/render/draw.js +0 -231
  491. package/dist-pkg/render/fx.d.ts +0 -63
  492. package/dist-pkg/render/fx.js +0 -123
  493. package/dist-pkg/render/minimap.d.ts +0 -11
  494. package/dist-pkg/render/minimap.js +0 -94
  495. package/dist-pkg/render/parallax.d.ts +0 -85
  496. package/dist-pkg/render/parallax.js +0 -158
  497. package/dist-pkg/render/player-anim.d.ts +0 -71
  498. package/dist-pkg/render/player-anim.js +0 -152
  499. package/dist-pkg/render/recycling-tex.d.ts +0 -48
  500. package/dist-pkg/render/recycling-tex.js +0 -164
  501. package/dist-pkg/render/scene-city.d.ts +0 -77
  502. package/dist-pkg/render/scene-city.js +0 -181
  503. package/dist-pkg/render/scene-parallax.d.ts +0 -72
  504. package/dist-pkg/render/scene-parallax.js +0 -426
  505. package/dist-pkg/render/scene-sky.d.ts +0 -126
  506. package/dist-pkg/render/scene-sky.js +0 -295
  507. package/dist-pkg/render/set-cenario.d.ts +0 -54
  508. package/dist-pkg/render/set-cenario.js +0 -103
  509. package/dist-pkg/render/textures.d.ts +0 -75
  510. package/dist-pkg/render/textures.js +0 -240
  511. package/dist-pkg/render/title-scene.d.ts +0 -46
  512. package/dist-pkg/render/title-scene.js +0 -75
  513. package/dist-pkg/render/weather.d.ts +0 -96
  514. package/dist-pkg/render/weather.js +0 -171
  515. package/dist-pkg/render/wheelchair-sprites.d.ts +0 -32
  516. package/dist-pkg/render/wheelchair-sprites.js +0 -69
  517. package/dist-pkg/render/world-tex.d.ts +0 -18
  518. package/dist-pkg/render/world-tex.js +0 -87
  519. package/dist-pkg/ui/activities-menu.d.ts +0 -258
  520. package/dist-pkg/ui/activities-menu.js +0 -648
  521. package/dist-pkg/ui/caa-sets.d.ts +0 -39
  522. package/dist-pkg/ui/caa-sets.js +0 -65
  523. package/dist-pkg/ui/latch-refusal.d.ts +0 -32
  524. package/dist-pkg/ui/latch-refusal.js +0 -60
  525. package/dist-pkg/ui/map-hub.d.ts +0 -56
  526. package/dist-pkg/ui/map-hub.js +0 -138
  527. package/dist-pkg/ui/settings-caa.d.ts +0 -45
  528. package/dist-pkg/ui/settings-caa.js +0 -137
  529. package/dist-pkg/ui/settings-motor.d.ts +0 -175
  530. package/dist-pkg/ui/settings-motor.js +0 -342
  531. package/dist-pkg/ui/webcam.d.ts +0 -7
  532. package/dist-pkg/ui/webcam.js +0 -93
@@ -1,117 +1,135 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- // ui/layout.ts — ESCALA do jogo (Estágio 4, Tier 1). Trava o #game-region num múltiplo inteiro de PIXELS REAIS
3
- // de 320×180 (por jogador) e reescala as vars de UI escopadas ao canvas. Deps: ui/dom ($), core/screens,
4
- // render/crt (crtScanVars). A contagem de jogadores entra por `initLayout`. fpsTick/configureRender seguem no main.js.
2
+ // ui/layout.ts — the game's SCALE. Locks #game-region to a whole multiple of REAL PIXELS of 320×180 (per player) and
3
+ // rescales the UI variables scoped to the canvas. Deps: core/screens. The pure arithmetic (`stageScale`, `applyScale`,
4
+ // the target floor, the reporters' rules) is exported as functions; `createLayout` is the shell that measures a
5
+ // document it is HANDED and calls `afterScale` (the root's CRT re-anchoring its scanlines) — ADR-0232 D4, issue #207.
5
6
  //
6
- // JÁ NÃO RESERVA ESPAÇO PARA O INTÉRPRETE. Reservava 380px à direita quando o painel do VLibras "abria", e o
7
- // jogo deslocava para a esquerda — decisão revista pelo Dev: o intérprete deve aparecer NA FRENTE da tela
8
- // enquanto um áudio toca, e sumir. E a reserva estava sendo aplicada O TEMPO TODO, porque o detector de
9
- // "aberto" lia um div vazio (ver o cabeçalho de ui/vlibras): o canvas vivia em `left: -136`, fora da tela,
10
- // com ou sem modo pessoa surda. O acoplamento vlibras↔layout desaparece junto.
11
- import { $ } from './dom.js';
7
+ // IT RESERVES NO SPACE FOR THE INTERPRETER: in deaf mode the interpreter appears IN FRONT of the screen when the sonar
8
+ // calls it (ADR-0234, see ui/vlibras), so the layout does not shift the game for it.
12
9
  import { screenBaseSize } from '../core/screens.js';
13
- import { crtScanVars } from '../render/crt.js';
14
10
  /**
15
- * A RÉGUA DO ALVO DE TOQUE, INDEXADA PELA ALTURA DO VIEWPORT (ADR-0095, decisão do Dev).
11
+ * THE TOUCH TARGET FLOOR, in CSS px, for a CSS scale factor `k` (ADR-0163).
16
12
  *
17
- * ⚠️ O ALVO DEIXOU DE SER UM NÚMERO E PASSOU A SER UMA FUNÇÃO DA TELA, e o motivo é um custo que o gate de
18
- * `pausa-44px` já tinha MEDIDO e deixado por resolver: a 640×360 o cartão de pausa não cabe e a lista ROLA.
19
- * Remedido em 06/09, porque o cartão mudou desde então: 391 px de conteúdo para 349 visíveis, ou seja 42 px
20
- * de excesso (o comentário antigo dizia 413/353). Um alvo de 44 px que exige rolagem para ser alcançado
21
- * pode custar mais dedo do que um de 24 px que está à vista.
22
- *
23
- * Os três degraus são os do Dev, e os dois extremos são as duas normas — não números de gosto:
13
+ * 🔴 IT WAS A RULER BY VIEWPORT HEIGHT (ADR-0095: 24 px under 540, 34 under 720, 44 above), because a 640×360 pause
14
+ * card with 44 px items scrolled. ADR-0163 made the resolution the engine's — never under 640×360 — and the Dev set the
15
+ * target — «44px é o correto, eu errei quando disse 42px» — so the floor is 44 px at the minimum (k = 2) and
16
+ * grows with the scale, like the text; there is no smaller screen left to shrink for.
17
+ */
18
+ export function minimumTarget(k) {
19
+ return 22 * (Number.isFinite(k) && k > 2 ? k : 2);
20
+ }
21
+ /**
22
+ * WHAT A CARTRIDGE DRAWS UNDER THE FLOOR (ADR-0163 rule 4): text under 8·k px (16 at 640×360) and targets whose SMALLER
23
+ * side is under 22·k px (44 at 640×360). The engine's own nodes are not the cartridge's to answer for, and a node with no
24
+ * area is not drawn. Half a pixel of slack absorbs subpixel layout.
25
+ */
26
+ export function belowFloor(nodes, k) {
27
+ const ratio = minimumTarget(k) / 22;
28
+ const smallText = [];
29
+ const smallTargets = [];
30
+ for (const n of nodes) {
31
+ if (n.daEngine)
32
+ continue;
33
+ if (n.fontPx !== null && n.fontPx > 0 && n.fontPx < 8 * ratio - 0.5)
34
+ smallText.push(n.name);
35
+ if (n.target && n.target.w > 0 && n.target.h > 0 && Math.min(n.target.w, n.target.h) < minimumTarget(k) - 0.5)
36
+ smallTargets.push(n.name);
37
+ }
38
+ return { text: smallText, targets: smallTargets };
39
+ }
40
+ export function barIntruders(barBox, nodes) {
41
+ // A bar with no area reserves nothing — and accusing against a zero rectangle would accuse everyone.
42
+ if (!barBox || barBox.w <= 0 || barBox.h <= 0)
43
+ return [];
44
+ // ⚠️ THE ZERO-AREA GUARD DOES WORK: the strict inequalities exclude a node that is DEGENERATE AT THE BOUNDARY, not one
45
+ // in general — a zero-width stripe crossing the bar passes all four comparisons. 📌 Containers of zero height or width
46
+ // are common in generated markup, and accusing them would be pure noise — which is how a consumer learns to ignore
47
+ // the line.
48
+ return nodes
49
+ .filter((n) => !n.isBar && n.box.w > 0 && n.box.h > 0)
50
+ .filter((n) => n.box.x < barBox.x + barBox.w && barBox.x < n.box.x + n.box.w
51
+ && n.box.y < barBox.y + barBox.h && barBox.y < n.box.y + n.box.h)
52
+ .map((n) => n.name);
53
+ }
54
+ /**
55
+ * THE SHELL THAT GIVES THE AVAILABLE SPACE — by id OR by class, and both forms count the same.
24
56
  *
25
- * altura ≥ 720 44 px WCAG 2.2 · 2.5.5 Target Size (Enhanced) — AAA
26
- * altura ≥ 540 34 px o degrau do meio
27
- * altura < 540 24 px WCAG 2.2 · 2.5.8 Target Size (Minimum) — AA
57
+ * ⚠️ BY ID ONLY, a host with `<div class="stage-wrap">` (the quiz) got no scale at all: `layout()` returned early and
58
+ * nothing reported anything — a silent `return` is indistinguishable from "there was nothing to do".
28
59
  *
29
- * ⚠️ ISTO É «MARCAR HONESTAMENTE ONDE SÓ DÁ AA», que é regra escrita do projeto — e não uma renúncia
30
- * silenciosa. O que se perde em 360 está registrado com número no ADR-0095: a 96 px/pol, 24 CSS px são
31
- * 6,4 mm, abaixo do alvo de polegar de 9,6 mm que o painel de toque deste jogo cita. É por isso que o
32
- * ESPAÇAMENTO entre alvos passa a ser o que protege o dedo onde o tamanho não pode — a mesma saída que a
33
- * própria 2.5.8 dá na sua exceção de spacing.
60
+ * The consumer is not wrong to use the class: a document can have several screens, and an id is unique. Accepting both
61
+ * is what makes the engine consumable by whoever did not copy its markup.
34
62
  */
35
- export const REGUA_DE_ALVO = Object.freeze([
36
- { altura: 720, alvo: 44 },
37
- { altura: 540, alvo: 34 },
38
- { altura: 0, alvo: 24 },
39
- ]);
63
+ function findStageWrap(doc) {
64
+ return doc.querySelector('#stage-wrap') ?? doc.querySelector('.stage-wrap');
65
+ }
40
66
  /**
41
- * O menor alvo de toque aceitável num viewport desta altura, em CSS px.
67
+ * ADR-0001 AS A PURE FUNCTION — so the engine can apply it to every cartridge (ADR-0163) and a test can pin it.
42
68
  *
43
- * ⚠️ NUNCA DEVOLVE MENOS DE 24: abaixo disso não é «AA num aparelho pequeno», é furar o piso da WCAG. Uma
44
- * tela mais baixa que 360 não compra o direito de encolher mais — compra o direito de mostrar menos itens.
69
+ * Integer multiple of 320×180 (per the screen grid) in REAL pixels; up to 5 logical px of crop per side when that buys one
70
+ * more step (the `−10`: `base·kDev − avail·dpr ≤ 10·kDev`). Never under 2 CSS px per logical pixel — 640×360 CSS, text 16 px,
71
+ * targets 44 px: where the whole multiple gives less (a fractional display scale on the minimum window) the scale is exactly
72
+ * 2 CSS px, whole in real pixels or not, because WCAG 2.2 AA decides (ADR-0179).
45
73
  */
46
- export function alvoMinimoDeToque(alturaCss) {
47
- const h = Number.isFinite(alturaCss) ? alturaCss : 0;
48
- for (const degrau of REGUA_DE_ALVO)
49
- if (h >= degrau.altura)
50
- return degrau.alvo;
51
- return 24;
74
+ export function stageScale(availW, availH, dpr, baseW, baseH) {
75
+ const MIN_K = 2;
76
+ const integerK = Math.floor(Math.min(availW * dpr / (baseW - 10), availH * dpr / (baseH - 10)));
77
+ const kDev = integerK / dpr >= MIN_K ? integerK : MIN_K * dpr;
78
+ const k = kDev / dpr;
79
+ return { kDev, k, width: baseW * k, height: baseH * k };
52
80
  }
53
- // A CONTAGEM DE JOGADORES entra por injeção desde 2026-08-26. Era `numPlayers`, um `let` de `core/state`
54
- // importado como binding vivo — e um `let` de módulo é compartilhado por qualquer segundo jogo que a
55
- // mesma página carregue (D13 do `demos`, ADR-0038). O que entra aqui é o GETTER da rodada que a raiz
56
- // possui; o `let` que sobra guarda a função, não o número.
57
- let _numJogadores = () => 1;
58
- /** Liga a contagem de jogadores. Chamado uma vez pela raiz, antes do primeiro `layout()`. */
59
- export function initLayout(deps) { _numJogadores = deps.numJogadores; }
60
81
  /**
61
- * A CASCA QUE DÁ O ESPAÇO DISPONÍVEL — por id OU por classe, e as duas formas valem o mesmo.
62
- *
63
- * ⚠️ ERA SÓ `#stage-wrap`, E ISSO DEIXOU A ENGINE SEM ESCALA NO PRÓPRIO HOST. O `app/index.html` do jogo
64
- * trazia `<div id="stage-wrap">`; quando o cartucho saiu (issue #111) sobrou o `app/quiz.html`, que tem
65
- * `<div class="stage-wrap">`. A procura por id falhava, `layout()` fazia early-return, e **nada reportava
66
- * nada**: um `return` silencioso é indistinguível de «não havia o que fazer». O comentário do próprio
67
- * `quiz.html` dizia «mesmo id que ui/layout escala» — quem o escreveu acreditava que corria.
82
+ * Writes a scale onto the game region: its size, and the UI variables that grow with it.
68
83
  *
69
- * O consumidor não erra ao usar a classe: um documento pode ter várias telas, e um id é único. Aceitar as
70
- * duas é o que torna a engine consumível por quem não copiou o markup dela.
84
+ * ⚠️ HOST-INJECTED (the region is passed in): `createGame` serves documents that
85
+ * are not the global one — the fault the root's finding 15 names about reaching `document` from under the injection.
71
86
  */
72
- function cascaDoPalco() {
73
- return $('#stage-wrap') ?? $('.stage-wrap');
87
+ export function applyScale(region, e) {
88
+ region.style.width = e.width + 'px';
89
+ region.style.height = e.height + 'px';
90
+ region.style.setProperty('--hud-fs', Math.max(9, Math.round(180 * e.k * 0.052)) + 'px');
91
+ region.style.setProperty('--ui-fs', (8 * e.k) + 'px'); // LOGICAL base 8px × k (16px at k=2)
92
+ // One ruler (plan phase 5b): `--tap` is the name three sibling games read, `--alvo-min` the engine's (ADR-0163); both come
93
+ // from `minimumTarget`, so a display scale that gives k under 2 (Windows 110%) no longer drops `--tap` under 44 px.
94
+ region.style.setProperty('--tap', minimumTarget(e.k) + 'px');
95
+ region.style.setProperty('--alvo-min', minimumTarget(e.k) + 'px'); // 44 px at 640×360, growing with k (ADR-0163)
96
+ // THE EDGE MARGIN (interface log 2026-09-26): 4 logical px between the region's edge and every text and button but the quick
97
+ // bar's — 8 px at 640×360, growing with k like the text. The stylesheet reads it; the quick bar keeps the edge (ADR-0180).
98
+ region.style.setProperty('--margem-borda', (4 * e.k) + 'px');
74
99
  }
75
- export function layout() {
76
- const wrap = cascaDoPalco();
77
- if (!wrap)
78
- return;
79
- wrap.style.paddingRight = '0px';
80
- const availW = wrap.clientWidth || 320;
81
- const availH = wrap.clientHeight || 180;
82
- // E11: a grade de telas define a base (1=320×180, 2=640×180, 3-4=640×360)
83
- const n = _numJogadores();
84
- // (`screenGrid(n)` SAIU em 2026-08-26: `cols`/`rows` eram desestruturados e nunca lidos — a escala sai de
85
- // `screenBaseSize`, logo abaixo. Era uma chamada paga a cada `layout()` por nada. `noUnusedLocals` achou.)
86
- const { w: baseW, h: baseH } = screenBaseSize(n);
87
- // Piso k=2: CADA viewport tem no mínimo 640×360. Assim 2×2 = 1280×720 cabe num Chromebook do governo (1366×768).
88
- const MIN_K = 2;
89
- // ADR-001 (CORRIGIDO 2026-07-04): ESCALA travada em PIXELS REAIS INTEIROS. Cada pixel de arte = kDev pixels
90
- // FÍSICOS (inteiro) → scanlines SEMPRE regulares e arte uniforme em QUALQUER dpr. Tolera ≤5px lógicos de corte
91
- // por lado (o −10): base·kDev − avail·dpr ≤ 10·kDev ⇒ kDev ≤ avail·dpr/(base−10). (José escolheu inteiro-REAL.)
92
- const dpr = window.devicePixelRatio || 1;
93
- const kDev = Math.max(Math.round(MIN_K * dpr), Math.floor(Math.min(availW * dpr / (baseW - 10), availH * dpr / (baseH - 10))));
94
- const k = kDev / dpr; // fator LÓGICO/CSS (kDev = fator em pixels REAIS, inteiro)
95
- // ESCALA das vars de UI é ESCOPADA ao #game-region: só a UI DENTRO do canvas (menus/HUD/pausa/quiz) escala com o
96
- // k. Fora do canvas (barra de topo, painel de debug) herda o :root → texto SEMPRE 16px, toque 44px (José).
97
- const gr = $('#game-region');
98
- if (gr) {
99
- gr.style.width = (baseW * k) + 'px';
100
- gr.style.height = (baseH * k) + 'px';
101
- gr.style.setProperty('--hud-fs', Math.max(9, Math.round(180 * k * 0.052)) + 'px');
102
- gr.style.setProperty('--ui-fs', (8 * k) + 'px'); // base LÓGICA 8px × k (16px em k=2)
103
- gr.style.setProperty('--tap', (22 * k) + 'px'); // toque 22px × k (44px em k=2, piso WCAG)
104
- // ⚠️ O PISO DA RÉGUA (ADR-0095), e ele é OUTRA COISA que o `--tap`. O `--tap` é o tamanho PREFERIDO e
105
- // cresce com a escala do canvas; `--alvo-min` é o CHÃO por altura de tela — 24 px abaixo de 540, 34 a
106
- // partir de 540, 44 a partir de 720. Um botão isolado usa o preferido; um item de LISTA, que tem de
107
- // caber inteiro na tela, usa o chão.
108
- //
109
- // ⚠️ A ALTURA É A DO ESPAÇO DISPONÍVEL, e não a da sub-tela de um jogador: o dedo toca o aparelho, não
110
- // o viewport lógico. Em quatro telas divididas cada uma tem 180 px de alto, e encolher o alvo por causa
111
- // disso seria ler o número errado — o aparelho continua o mesmo.
112
- gr.style.setProperty('--alvo-min', alvoMinimoDeToque(availH) + 'px');
100
+ /**
101
+ * Builds a stage scaler over the document and window it is handed. It keeps nothing between calls: every `layout()`
102
+ * measures again, reads the player count again, and writes onto the region.
103
+ */
104
+ export function createLayout(ctx) {
105
+ function layout() {
106
+ const wrap = findStageWrap(ctx.doc);
107
+ if (!wrap)
108
+ return;
109
+ wrap.style.paddingRight = '0px';
110
+ const availW = wrap.clientWidth || 320;
111
+ const availH = wrap.clientHeight || 180;
112
+ // The screen grid sets the base (1=320×180, 2=640×180, 3-4=640×360).
113
+ const n = ctx.numPlayers();
114
+ const { w: baseW, h: baseH } = screenBaseSize(n);
115
+ // Floor k=2: EACH viewport is at least 640×360, so 2×2 = 1280×720 fits a government Chromebook (1366×768).
116
+ // ADR-0001: SCALE locked to WHOLE REAL PIXELS. Each art pixel = kDev PHYSICAL pixels (whole) → scanlines ALWAYS regular
117
+ // and uniform art at ANY dpr. Tolerates ≤5 logical px of crop per side (the −10): base·kDev − avail·dpr ≤ 10·kDev ⇒
118
+ // kDev ≤ avail·dpr/(base−10). (The Dev chose whole REAL pixels.) The arithmetic lives in `stageScale` (ADR-0163), so the
119
+ // engine applies it to every cartridge.
120
+ const dpr = ctx.win.devicePixelRatio || 1;
121
+ const ratio = stageScale(availW, availH, dpr, baseW, baseH);
122
+ const { kDev, k } = ratio;
123
+ // The UI variables' SCALE is SCOPED to #game-region: only the UI INSIDE the canvas (menus/HUD/pause/quiz) scales with
124
+ // k. Outside the canvas (top bar, debug panel) it inherits :root → text ALWAYS 16px, touch 44px (the Dev).
125
+ const gr = ctx.doc.querySelector('#game-region');
126
+ if (gr) {
127
+ // `--tap` is the PREFERRED size (22·k) and `--alvo-min` the FLOOR (22·k, 44 px at 640×360 — ADR-0163), written in `applyScale`.
128
+ applyScale(gr, ratio);
129
+ }
130
+ ctx.afterScale(); // scanlines realign when the scale k changes
131
+ if (ctx.debug?.())
132
+ console.info(`[escala] kDev=${kDev}× px REAIS (canvas físico ${baseW * kDev}×${baseH * kDev} = múltiplo INTEIRO de ${baseW}×${baseH}); CSS ${Math.round(baseW * k)}×${Math.round(baseH * k)} (k=${k.toFixed(3)}, dpr=${dpr})`);
113
133
  }
114
- crtScanVars(); // scanlines re-alinham quando a escala k muda
115
- if (/[?&]debug=true/.test(location.search))
116
- console.info(`[escala] kDev=${kDev}× px REAIS (canvas físico ${baseW * kDev}×${baseH * kDev} = múltiplo INTEIRO de ${baseW}×${baseH}); CSS ${Math.round(baseW * k)}×${Math.round(baseH * k)} (k=${k.toFixed(3)}, dpr=${dpr})`);
134
+ return { layout };
117
135
  }
@@ -0,0 +1,30 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ /** One track of a three.js AnimationClip JSON, as the export writes it. */
3
+ export interface TrackJson {
4
+ readonly name: string;
5
+ readonly type: string;
6
+ readonly times: readonly number[];
7
+ readonly values: readonly number[];
8
+ readonly interpolation?: number;
9
+ }
10
+ /** A three.js AnimationClip JSON (`AnimationClip.parse`), as the export writes it. */
11
+ export interface ClipJson {
12
+ readonly name: string;
13
+ readonly duration: number;
14
+ readonly tracks: readonly TrackJson[];
15
+ }
16
+ /** A track's value at `time`, as three.js interpolates it: held before the first key and after the last. */
17
+ export declare function valueAt(track: TrackJson, time: number): number[];
18
+ /**
19
+ * The clip from `from` seconds on, its times shifted to start at zero: each track keeps its value AT `from` as its first key,
20
+ * then its later keys. A track whose keys all lie before `from` holds its last value. `from` of zero is the clip itself.
21
+ */
22
+ export declare function clipFrom(clip: ClipJson, from: number): ClipJson;
23
+ /**
24
+ * The face's tracks, bound to every mesh that carries the morph targets. The export names a morph track after the head's NODE
25
+ * (`cabecaModifAlisson.morphTargetInfluences[Sorriso]`), and three.js loads a node whose mesh has two primitives as a GROUP of
26
+ * two meshes, each with its own copy of the targets — a track on the group moves neither. `meshesOf(node)` answers the meshes
27
+ * a track on that node must reach (by the names three.js binds, e.g. their uuids), or `null` where the node is itself the mesh;
28
+ * the track is written once for each.
29
+ */
30
+ export declare function bindFaceTracks(clip: ClipJson, meshesOf: (node: string) => readonly string[] | null): ClipJson;
@@ -0,0 +1,86 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // ui/libras-avatar-clip — A SIGN CLIP, BEFORE three.js READS IT (ADR-0234, route B, phase B2). Pure: no three.js, no DOM.
3
+ //
4
+ // The B1 export hands each sign over as three.js AnimationClip JSON (`scripts/libras-export.mjs`), and two things about it are
5
+ // answered here, on the JSON, where node can hold them (`tests/libras-avatar-plan.node.test.js`): a clip whose sign starts
6
+ // later than the clip does — FALA, whose export starts at a stray keyframe — is played from its sign (`clipFrom`), and the
7
+ // face's tracks, named after the head's node, are written for each mesh three.js loads the head as (`bindFaceTracks`).
8
+ // `ui/libras-avatar-stage` parses what comes out.
9
+ /** three.js `InterpolateDiscrete`: the export marks a STEP track with it. */
10
+ const DISCRETE = 2300;
11
+ function slerp(a, b, u) {
12
+ let dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
13
+ const bb = dot < 0 ? b.map((x) => -x) : [...b];
14
+ dot = Math.abs(dot);
15
+ if (dot > 0.9995) {
16
+ const q = a.map((x, c) => x + (bb[c] - x) * u);
17
+ const l = Math.hypot(...q);
18
+ return q.map((x) => x / l);
19
+ }
20
+ const th = Math.acos(dot);
21
+ const s = Math.sin(th);
22
+ return a.map((x, c) => (Math.sin((1 - u) * th) * x + Math.sin(u * th) * bb[c]) / s);
23
+ }
24
+ /** A track's value at `time`, as three.js interpolates it: held before the first key and after the last. */
25
+ export function valueAt(track, time) {
26
+ const { times, values } = track;
27
+ const width = values.length / times.length;
28
+ const key = (i) => values.slice(i * width, i * width + width);
29
+ const last = times.length - 1;
30
+ if (time <= times[0] || last === 0)
31
+ return key(0);
32
+ if (time >= times[last])
33
+ return key(last);
34
+ let i = 0;
35
+ while (times[i + 1] <= time)
36
+ i += 1;
37
+ if (time === times[i] || track.interpolation === DISCRETE)
38
+ return key(i);
39
+ const u = (time - times[i]) / (times[i + 1] - times[i]);
40
+ const a = key(i);
41
+ const b = key(i + 1);
42
+ return track.type === 'quaternion' ? slerp(a, b, u) : a.map((x, c) => x + (b[c] - x) * u);
43
+ }
44
+ /**
45
+ * The clip from `from` seconds on, its times shifted to start at zero: each track keeps its value AT `from` as its first key,
46
+ * then its later keys. A track whose keys all lie before `from` holds its last value. `from` of zero is the clip itself.
47
+ */
48
+ export function clipFrom(clip, from) {
49
+ if (!(from > 0))
50
+ return clip;
51
+ const tracks = clip.tracks.map((t) => {
52
+ const times = [0];
53
+ const values = [...valueAt(t, from)];
54
+ const width = t.values.length / t.times.length;
55
+ t.times.forEach((time, i) => {
56
+ if (time <= from)
57
+ return;
58
+ times.push(time - from);
59
+ values.push(...t.values.slice(i * width, i * width + width));
60
+ });
61
+ return { ...t, times, values };
62
+ });
63
+ return { name: clip.name, duration: Math.max(0, clip.duration - from), tracks };
64
+ }
65
+ const MORPH_TRACK = /^(.+)\.morphTargetInfluences\[(.+)\]$/u;
66
+ /**
67
+ * The face's tracks, bound to every mesh that carries the morph targets. The export names a morph track after the head's NODE
68
+ * (`cabecaModifAlisson.morphTargetInfluences[Sorriso]`), and three.js loads a node whose mesh has two primitives as a GROUP of
69
+ * two meshes, each with its own copy of the targets — a track on the group moves neither. `meshesOf(node)` answers the meshes
70
+ * a track on that node must reach (by the names three.js binds, e.g. their uuids), or `null` where the node is itself the mesh;
71
+ * the track is written once for each.
72
+ */
73
+ export function bindFaceTracks(clip, meshesOf) {
74
+ const tracks = [];
75
+ for (const t of clip.tracks) {
76
+ const m = MORPH_TRACK.exec(t.name);
77
+ const meshes = m ? meshesOf(m[1]) : null;
78
+ if (!m || !meshes) {
79
+ tracks.push(t);
80
+ continue;
81
+ }
82
+ for (const mesh of meshes)
83
+ tracks.push({ ...t, name: `${mesh}.morphTargetInfluences[${m[2]}]` });
84
+ }
85
+ return { ...clip, tracks };
86
+ }
@@ -0,0 +1,52 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import { type AvatarManifest } from './libras-avatar-plan.js';
3
+ import type { AvatarStage } from './libras-avatar-stage.js';
4
+ /** The host's `fetch`, lent unbound — and called bare, never as a method of what carries it. */
5
+ export type FetchFile = ((url: string) => Promise<Response>) | undefined;
6
+ /**
7
+ * Why a delivery with no avatar cannot sign, and the fix (ADR-0169): the reason `NO_INTERPRETER` gives, word for word — the
8
+ * root's interpreter answers a delivery built without `--libras` exactly as a root with no player would.
9
+ */
10
+ export declare const NOT_SHIPPED = "a Libras player is not installed in this delivery \u2014 build it with `inclusionist-heavy <folder> --libras`";
11
+ /** Why a request that waited across a `hide()` or the root's end was not signed. */
12
+ export declare const RELEASED = "the interpreter was taken off the screen before it signed";
13
+ /** Where the delivery's files are: the avatar's folder, its manifest, and the glosses `--libras` writes beside them. */
14
+ export interface AvatarPlace {
15
+ readonly folder: string;
16
+ readonly manifest: string;
17
+ readonly glosses: string;
18
+ }
19
+ /** The addresses under `base`, or `null` where it resolves nothing — a host whose document has no address finds no avatar. */
20
+ export declare function avatarPlace(base: string, folder?: string): AvatarPlace | null;
21
+ /** The delivery's manifest, or `null` for a delivery that did not ship the avatar. */
22
+ export declare const readManifest: (fetchFile: FetchFile, place: AvatarPlace) => Promise<AvatarManifest | null>;
23
+ /** The canvas the avatar is drawn on: the bottom right, in front of the screen, watched and never operated. */
24
+ export declare function avatarCanvas(doc: Document, title: string): HTMLCanvasElement;
25
+ export interface AvatarOpening {
26
+ readonly fetchFile: FetchFile;
27
+ /** The avatar's address, from the manifest. */
28
+ readonly avatarUrl: string;
29
+ readonly loadStage: (canvas: HTMLCanvasElement, avatar: ArrayBuffer) => Promise<AvatarStage>;
30
+ readonly timeoutMs: number;
31
+ readonly win: Pick<Window, 'setTimeout' | 'clearTimeout'>;
32
+ }
33
+ /** A stage, or why there is none. */
34
+ export type Opened = {
35
+ readonly stage: AvatarStage;
36
+ } | {
37
+ readonly reason: string;
38
+ };
39
+ /**
40
+ * Builds the stage on `canvas` from the delivery's avatar: the stage, or why not — an avatar the delivery cannot give, a device
41
+ * that cannot draw it, a load past `timeoutMs`. `wanted()` is asked when the stage arrives: false, and it is released at once.
42
+ * `cancel()` answers «released» now and clears the timer, so nothing of a released root outlives it.
43
+ */
44
+ export declare function openAvatar(canvas: HTMLCanvasElement, o: AvatarOpening, wanted: () => boolean): {
45
+ readonly done: Promise<Opened>;
46
+ readonly cancel: () => void;
47
+ };
48
+ /**
49
+ * Makes each clip of `names` playable on `stage`, fetching the ones it has not got — once each, remembered in `ready` — and
50
+ * answers the names whose file could not be read or prepared.
51
+ */
52
+ export declare function prepareClips(stage: AvatarStage, names: readonly string[], manifest: AvatarManifest, place: AvatarPlace, fetchFile: FetchFile, ready: Map<string, Promise<boolean>>): Promise<string[]>;
@@ -0,0 +1,134 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // ui/libras-avatar-load — WHAT THE DELIVERY SHIPPED FOR THE FREE PLAYER, AND OPENING IT (ADR-0234, route B, phase B2).
3
+ //
4
+ // The half of `ui/libras-avatar-player` that talks to the delivery: where its files are, whether it shipped the avatar at all
5
+ // (its manifest, which only `inclusionist-heavy --libras` writes), the canvas the avatar is drawn on, the stage built on it from
6
+ // the avatar's bytes — within a time, or not at all — and the clips, each fetched and prepared once. Every answer is a value,
7
+ // never a throw: a delivery without the avatar, a device without WebGL and a clip that cannot be read are reasons, which the
8
+ // player hands to deaf mode and deaf mode to `problems` (ADR-0169).
9
+ import { LIBRAS_GLOSSES_FILE } from './libras-glosses.js';
10
+ import { LIBRAS_NOT_INSTALLED } from './vlibras.js';
11
+ import { LIBRAS_AVATAR_FOLDER, LIBRAS_AVATAR_MANIFEST, avatarManifestOf } from './libras-avatar-plan.js';
12
+ /**
13
+ * Why a delivery with no avatar cannot sign, and the fix (ADR-0169): the reason `NO_INTERPRETER` gives, word for word — the
14
+ * root's interpreter answers a delivery built without `--libras` exactly as a root with no player would.
15
+ */
16
+ export const NOT_SHIPPED = LIBRAS_NOT_INSTALLED;
17
+ /** Why a request that waited across a `hide()` or the root's end was not signed. */
18
+ export const RELEASED = 'the interpreter was taken off the screen before it signed';
19
+ /** The addresses under `base`, or `null` where it resolves nothing — a host whose document has no address finds no avatar. */
20
+ export function avatarPlace(base, folder = LIBRAS_AVATAR_FOLDER) {
21
+ try {
22
+ const at = new URL(folder, base);
23
+ return { folder: at.href, manifest: new URL(LIBRAS_AVATAR_MANIFEST, at).href, glosses: new URL(LIBRAS_GLOSSES_FILE, at).href };
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ /** A JSON file of the delivery, or `null` — no fetch, no file, not JSON. */
30
+ async function readJson(fetchFile, url) {
31
+ if (!fetchFile)
32
+ return null;
33
+ try {
34
+ const resp = await fetchFile(url);
35
+ return resp.ok ? await resp.json() : null;
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ /** The delivery's manifest, or `null` for a delivery that did not ship the avatar. */
42
+ export const readManifest = async (fetchFile, place) => avatarManifestOf(await readJson(fetchFile, place.manifest));
43
+ /** The canvas the avatar is drawn on: the bottom right, in front of the screen, watched and never operated. */
44
+ export function avatarCanvas(doc, title) {
45
+ const canvas = doc.createElement('canvas');
46
+ canvas.setAttribute('role', 'img');
47
+ canvas.setAttribute('aria-label', title);
48
+ canvas.tabIndex = -1; // the keyboard stays with the game
49
+ canvas.hidden = true;
50
+ Object.assign(canvas.style, {
51
+ position: 'fixed', right: '0', bottom: '0', width: 'max(25vw, 200px)', height: 'max(50vh, 200px)', border: '0',
52
+ background: 'transparent', pointerEvents: 'none', zIndex: '2147483000',
53
+ });
54
+ doc.body.append(canvas);
55
+ return canvas;
56
+ }
57
+ const reasonOf = (failure) => (failure instanceof Error ? failure.message : String(failure));
58
+ async function build(canvas, o, wanted) {
59
+ const { fetchFile } = o; // called bare, as `FetchFile` says
60
+ if (!fetchFile)
61
+ return { reason: NOT_SHIPPED };
62
+ try {
63
+ const resp = await fetchFile(o.avatarUrl);
64
+ if (!resp.ok) {
65
+ return { reason: `the Libras avatar could not be read from the delivery (HTTP ${resp.status}) — build it again with `
66
+ + '`inclusionist-heavy <folder> --libras`' };
67
+ }
68
+ const stage = await o.loadStage(canvas, await resp.arrayBuffer());
69
+ if (!wanted()) {
70
+ stage.dispose();
71
+ return { reason: RELEASED };
72
+ } // given up on or released meanwhile: nothing is kept
73
+ return { stage };
74
+ }
75
+ catch (failure) {
76
+ return { reason: `the Libras avatar cannot be drawn here: ${reasonOf(failure)}` };
77
+ }
78
+ }
79
+ /**
80
+ * Builds the stage on `canvas` from the delivery's avatar: the stage, or why not — an avatar the delivery cannot give, a device
81
+ * that cannot draw it, a load past `timeoutMs`. `wanted()` is asked when the stage arrives: false, and it is released at once.
82
+ * `cancel()` answers «released» now and clears the timer, so nothing of a released root outlives it.
83
+ */
84
+ export function openAvatar(canvas, o, wanted) {
85
+ let answer = () => { };
86
+ const stopped = new Promise((resolve) => { answer = resolve; });
87
+ const timer = o.win.setTimeout(() => {
88
+ answer({ reason: `the Libras avatar did not load within ${Math.round(o.timeoutMs / 1000)} s` });
89
+ }, o.timeoutMs);
90
+ const done = Promise.race([build(canvas, o, wanted), stopped]).then((r) => { o.win.clearTimeout(timer); return r; });
91
+ return { done, cancel: () => { o.win.clearTimeout(timer); answer({ reason: RELEASED }); } };
92
+ }
93
+ const isClipJson = (data) => {
94
+ const c = data;
95
+ return !!c && typeof c.duration === 'number' && Array.isArray(c.tracks);
96
+ };
97
+ /**
98
+ * A clip's address under the avatar's folder, SPELLED AS A URL SPELLS ITS NAME — which is the address the delivery's list keeps it
99
+ * under offline (`libras/offline-avatar.json`, ADR-0234 phase B3). Escaping the name first (`&` as `%26`, as `encodeURIComponent`
100
+ * does) asks another address, which the server answers online and the checked cache never holds: PRIMEIRO&ORDINAL and
101
+ * SEGUNDO&ORDINAL went unsigned offline. 📌 No clip name carries `%`, `#`, `?` or `\`, which a URL reads as something other than
102
+ * a name — `tests/libras-avatar-delivery.node.test.js` holds that over the pins.
103
+ */
104
+ const clipAddress = (file, folder) => new URL(file, folder).href;
105
+ /**
106
+ * Makes each clip of `names` playable on `stage`, fetching the ones it has not got — once each, remembered in `ready` — and
107
+ * answers the names whose file could not be read or prepared.
108
+ */
109
+ export async function prepareClips(stage, names, manifest, place, fetchFile, ready) {
110
+ const one = async (name) => {
111
+ const w = manifest.clips.get(name);
112
+ if (!w)
113
+ return false;
114
+ const json = await readJson(fetchFile, clipAddress(w.file, place.folder));
115
+ if (!isClipJson(json))
116
+ return false;
117
+ try {
118
+ stage.prepare(name, json, w.from);
119
+ return true;
120
+ }
121
+ catch {
122
+ return false;
123
+ }
124
+ };
125
+ const read = await Promise.all(names.map((name) => {
126
+ let loading = ready.get(name);
127
+ if (!loading) {
128
+ loading = one(name);
129
+ ready.set(name, loading);
130
+ }
131
+ return loading;
132
+ }));
133
+ return names.filter((_, i) => !read[i]);
134
+ }