@the-inclusionist/engine 10.0.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/README.md +32 -1
  2. package/app/css/style.css +216 -42
  3. package/app/public/vendor/fonts-licences/NOTICE.txt +166 -0
  4. package/app/public/vendor/fonts-licences/OFL-1.1.txt +86 -0
  5. package/app/public/vendor/fonts.css +11 -1175
  6. package/dist-pkg/boot/create-game.d.ts +84 -33
  7. package/dist-pkg/boot/create-game.js +708 -307
  8. package/dist-pkg/core/a11y-sr.d.ts +1 -1
  9. package/dist-pkg/core/a11y-sr.js +3 -5
  10. package/dist-pkg/core/accommodations.d.ts +26 -8
  11. package/dist-pkg/core/accommodations.js +27 -10
  12. package/dist-pkg/core/actions.d.ts +39 -10
  13. package/dist-pkg/core/actions.js +28 -6
  14. package/dist-pkg/core/contract.d.ts +0 -2
  15. package/dist-pkg/core/contract.js +0 -2
  16. package/dist-pkg/core/i18n.d.ts +36 -71
  17. package/dist-pkg/core/i18n.js +131 -198
  18. package/dist-pkg/core/session-clock.d.ts +23 -0
  19. package/dist-pkg/core/session-clock.js +37 -0
  20. package/dist-pkg/i18n/en.js +44 -49
  21. package/dist-pkg/i18n/es.js +44 -49
  22. package/dist-pkg/i18n/pt.js +49 -54
  23. package/dist-pkg/input/gamepad.d.ts +42 -11
  24. package/dist-pkg/input/gamepad.js +50 -15
  25. package/dist-pkg/input/key-default.d.ts +30 -0
  26. package/dist-pkg/input/key-default.js +60 -0
  27. package/dist-pkg/input/keyboard-runtime.d.ts +0 -4
  28. package/dist-pkg/input/keyboard.d.ts +0 -1
  29. package/dist-pkg/input/keydown.d.ts +5 -11
  30. package/dist-pkg/input/keydown.js +3 -3
  31. package/dist-pkg/input/latch-edge.d.ts +10 -2
  32. package/dist-pkg/input/latch-edge.js +4 -3
  33. package/dist-pkg/input/latch-scope.d.ts +27 -22
  34. package/dist-pkg/input/latch-scope.js +25 -37
  35. package/dist-pkg/input/latch-store.d.ts +9 -12
  36. package/dist-pkg/input/latch-store.js +13 -18
  37. package/dist-pkg/input/latch-sync.d.ts +5 -4
  38. package/dist-pkg/input/latch-sync.js +5 -5
  39. package/dist-pkg/input/pad-reading.js +7 -2
  40. package/dist-pkg/input/pad-wizard.d.ts +4 -1
  41. package/dist-pkg/input/pad-wizard.js +60 -9
  42. package/dist-pkg/input/switch-scan.d.ts +29 -12
  43. package/dist-pkg/input/switch-scan.js +15 -2
  44. package/dist-pkg/input/touch-bindings.d.ts +3 -6
  45. package/dist-pkg/input/touch.d.ts +17 -2
  46. package/dist-pkg/input/touch.js +55 -17
  47. package/dist-pkg/input/transport-in-use.d.ts +5 -5
  48. package/dist-pkg/input/transport-in-use.js +5 -5
  49. package/dist-pkg/input/transports.d.ts +0 -9
  50. package/dist-pkg/input/transports.js +1 -1
  51. package/dist-pkg/input/virtual-controller.d.ts +39 -3
  52. package/dist-pkg/input/virtual-controller.js +32 -4
  53. package/dist-pkg/input/voice-map.d.ts +27 -11
  54. package/dist-pkg/input/voice-map.js +41 -43
  55. package/dist-pkg/platform/audio-ambient.d.ts +0 -1
  56. package/dist-pkg/platform/audio-ambient.js +3 -1
  57. package/dist-pkg/platform/audio-mixer.js +4 -9
  58. package/dist-pkg/platform/audio-sonar.d.ts +8 -94
  59. package/dist-pkg/platform/audio-sonar.js +22 -207
  60. package/dist-pkg/platform/audio.d.ts +10 -1
  61. package/dist-pkg/platform/audio.js +35 -2
  62. package/dist-pkg/platform/choose-by-voice.d.ts +70 -0
  63. package/dist-pkg/platform/choose-by-voice.js +157 -0
  64. package/dist-pkg/platform/font-library.d.ts +77 -0
  65. package/dist-pkg/platform/font-library.js +98 -0
  66. package/dist-pkg/platform/font-library.json +721 -0
  67. package/dist-pkg/platform/heavy-catalogue.d.ts +46 -0
  68. package/dist-pkg/platform/heavy-catalogue.js +47 -14
  69. package/dist-pkg/platform/heavy-mirror.d.ts +3 -9
  70. package/dist-pkg/platform/heavy-mirror.js +14 -17
  71. package/dist-pkg/platform/heavy.d.ts +40 -8
  72. package/dist-pkg/platform/heavy.js +177 -22
  73. package/dist-pkg/platform/interruptible-speech.d.ts +15 -8
  74. package/dist-pkg/platform/interruptible-speech.js +37 -13
  75. package/dist-pkg/platform/listener-scope.js +22 -13
  76. package/dist-pkg/platform/locale-host.d.ts +7 -3
  77. package/dist-pkg/platform/locale-host.js +13 -2
  78. package/dist-pkg/platform/reading-in-worker.d.ts +24 -0
  79. package/dist-pkg/platform/reading-in-worker.js +38 -0
  80. package/dist-pkg/platform/reading-model.d.ts +21 -0
  81. package/dist-pkg/platform/reading-model.js +25 -0
  82. package/dist-pkg/platform/reading-runtime.js +13 -8
  83. package/dist-pkg/platform/reading.d.ts +12 -1
  84. package/dist-pkg/platform/reading.js +9 -1
  85. package/dist-pkg/platform/speech-recognition.d.ts +10 -1
  86. package/dist-pkg/platform/speech-recognition.js +29 -9
  87. package/dist-pkg/platform/speech.d.ts +10 -1
  88. package/dist-pkg/platform/speech.js +24 -13
  89. package/dist-pkg/platform/tts.d.ts +37 -4
  90. package/dist-pkg/platform/tts.js +279 -57
  91. package/dist-pkg/platform/voice-listener.d.ts +6 -2
  92. package/dist-pkg/platform/voice-listener.js +1 -1
  93. package/dist-pkg/platform/voice-plan.d.ts +13 -0
  94. package/dist-pkg/platform/voice-plan.js +57 -2
  95. package/dist-pkg/platform/vosk-runtime.d.ts +25 -0
  96. package/dist-pkg/platform/vosk-runtime.js +59 -1
  97. package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
  98. package/dist-pkg/platform/vosk-vocabulary.js +178 -0
  99. package/dist-pkg/render/crt.d.ts +11 -9
  100. package/dist-pkg/render/crt.js +6 -10
  101. package/dist-pkg/render/cvd-matrices.d.ts +5 -1
  102. package/dist-pkg/render/cvd-matrices.js +5 -1
  103. package/dist-pkg/render/high-contrast.d.ts +1 -2
  104. package/dist-pkg/render/high-contrast.js +5 -1
  105. package/dist-pkg/render/viz-axes.d.ts +9 -0
  106. package/dist-pkg/render/viz-axes.js +15 -2
  107. package/dist-pkg/ui/aac-sets.d.ts +29 -24
  108. package/dist-pkg/ui/aac-sets.js +22 -30
  109. package/dist-pkg/ui/audio-choices.d.ts +10 -5
  110. package/dist-pkg/ui/audio-choices.js +14 -10
  111. package/dist-pkg/ui/camera-control.d.ts +47 -0
  112. package/dist-pkg/ui/camera-control.js +35 -1
  113. package/dist-pkg/ui/declared-words.d.ts +21 -0
  114. package/dist-pkg/ui/declared-words.js +66 -0
  115. package/dist-pkg/ui/drawing-problems.js +4 -3
  116. package/dist-pkg/ui/eye-control.js +17 -17
  117. package/dist-pkg/ui/face-control.js +15 -15
  118. package/dist-pkg/ui/fonts.d.ts +42 -8
  119. package/dist-pkg/ui/fonts.js +58 -24
  120. package/dist-pkg/ui/footer-scroll-driver.d.ts +14 -0
  121. package/dist-pkg/ui/footer-scroll-driver.js +201 -0
  122. package/dist-pkg/ui/footer-scroll.d.ts +38 -0
  123. package/dist-pkg/ui/footer-scroll.js +55 -0
  124. package/dist-pkg/ui/game-options.d.ts +14 -9
  125. package/dist-pkg/ui/game-options.js +41 -21
  126. package/dist-pkg/ui/hand-control.js +15 -15
  127. package/dist-pkg/ui/help-panel.d.ts +19 -8
  128. package/dist-pkg/ui/help-panel.js +15 -5
  129. package/dist-pkg/ui/hud-bands.d.ts +29 -12
  130. package/dist-pkg/ui/hud-bands.js +63 -25
  131. package/dist-pkg/ui/hud-row.d.ts +34 -0
  132. package/dist-pkg/ui/hud-row.js +80 -0
  133. package/dist-pkg/ui/hud.d.ts +0 -3
  134. package/dist-pkg/ui/layout.js +5 -2
  135. package/dist-pkg/ui/libras-avatar-clip.d.ts +30 -0
  136. package/dist-pkg/ui/libras-avatar-clip.js +86 -0
  137. package/dist-pkg/ui/libras-avatar-load.d.ts +52 -0
  138. package/dist-pkg/ui/libras-avatar-load.js +134 -0
  139. package/dist-pkg/ui/libras-avatar-plan.d.ts +102 -0
  140. package/dist-pkg/ui/libras-avatar-plan.js +211 -0
  141. package/dist-pkg/ui/libras-avatar-player.d.ts +28 -0
  142. package/dist-pkg/ui/libras-avatar-player.js +226 -0
  143. package/dist-pkg/ui/libras-avatar-stage.d.ts +37 -0
  144. package/dist-pkg/ui/libras-avatar-stage.js +208 -0
  145. package/dist-pkg/ui/libras-glosses.d.ts +28 -0
  146. package/dist-pkg/ui/libras-glosses.js +161 -0
  147. package/dist-pkg/ui/menu-intent.d.ts +29 -0
  148. package/dist-pkg/ui/menu-intent.js +35 -1
  149. package/dist-pkg/ui/menu-items.d.ts +10 -0
  150. package/dist-pkg/ui/menu-items.js +29 -0
  151. package/dist-pkg/ui/menu-nav.d.ts +40 -4
  152. package/dist-pkg/ui/menu-nav.js +132 -47
  153. package/dist-pkg/ui/panel-widgets.d.ts +34 -0
  154. package/dist-pkg/ui/panel-widgets.js +86 -0
  155. package/dist-pkg/ui/pause-icons.d.ts +30 -14
  156. package/dist-pkg/ui/pause-icons.js +106 -45
  157. package/dist-pkg/ui/scan-overlay.d.ts +3 -3
  158. package/dist-pkg/ui/scan-overlay.js +11 -3
  159. package/dist-pkg/ui/screen-text.d.ts +25 -0
  160. package/dist-pkg/ui/screen-text.js +152 -0
  161. package/dist-pkg/ui/session-clock.d.ts +32 -0
  162. package/dist-pkg/ui/session-clock.js +67 -0
  163. package/dist-pkg/ui/settings-aac.d.ts +3 -1
  164. package/dist-pkg/ui/settings-aac.js +32 -13
  165. package/dist-pkg/ui/settings-audio.d.ts +10 -5
  166. package/dist-pkg/ui/settings-audio.js +101 -35
  167. package/dist-pkg/ui/settings-controls.d.ts +0 -4
  168. package/dist-pkg/ui/settings-mobility.d.ts +3 -6
  169. package/dist-pkg/ui/settings-mobility.js +4 -46
  170. package/dist-pkg/ui/settings-motion.js +2 -2
  171. package/dist-pkg/ui/settings-panel.d.ts +10 -0
  172. package/dist-pkg/ui/settings-panel.js +25 -1
  173. package/dist-pkg/ui/settings-typo.d.ts +5 -6
  174. package/dist-pkg/ui/settings-typo.js +20 -11
  175. package/dist-pkg/ui/settings-visual.js +2 -2
  176. package/dist-pkg/ui/shell.d.ts +1 -3
  177. package/dist-pkg/ui/shell.js +8 -4
  178. package/dist-pkg/ui/title.d.ts +2 -11
  179. package/dist-pkg/ui/title.js +39 -6
  180. package/dist-pkg/ui/top-band.d.ts +5 -3
  181. package/dist-pkg/ui/top-band.js +21 -25
  182. package/dist-pkg/ui/typo-choices.d.ts +3 -3
  183. package/dist-pkg/ui/typo-choices.js +9 -8
  184. package/dist-pkg/ui/vlibras.d.ts +71 -27
  185. package/dist-pkg/ui/vlibras.js +116 -44
  186. package/dist-pkg/ui/voice-control.d.ts +23 -1
  187. package/dist-pkg/ui/voice-control.js +149 -16
  188. package/dist-pkg/ui/voice-settings.d.ts +2 -3
  189. package/dist-pkg/ui/voice-settings.js +53 -3
  190. package/dist-pkg/ui/where-the-child-is.js +2 -2
  191. package/docs/CREDITS.md +122 -10
  192. package/docs/LICENSES.md +36 -7
  193. package/package.json +34 -9
  194. package/scripts/check-cartridge.mjs +78 -0
  195. package/scripts/game-build.d.mts +25 -0
  196. package/scripts/game-build.mjs +144 -0
  197. package/scripts/heavy-into-the-delivery.mjs +284 -40
  198. package/scripts/libras-avatar.json +680 -0
  199. package/scripts/libras-avatar.mjs +246 -0
  200. package/scripts/libras-glosses/gloss.py +95 -0
  201. package/scripts/libras-glosses/pyproject.toml +32 -0
  202. package/scripts/libras-glosses/uv.lock +781 -0
  203. package/scripts/libras-glosses.mjs +351 -0
  204. package/scripts/licences/OFL-1.1.txt +86 -0
  205. package/scripts/licences/UFL-1.0.txt +96 -0
  206. package/scripts/licences/fonts.mjs +389 -0
  207. package/scripts/licences/third-party.mjs +35 -21
  208. package/app/public/vendor/fonts/bitter-var-ext.woff2 +0 -0
  209. package/app/public/vendor/fonts/bitter-var.woff2 +0 -0
  210. package/app/public/vendor/fonts/bodonimoda-var-ext.woff2 +0 -0
  211. package/app/public/vendor/fonts/bodonimoda-var.woff2 +0 -0
  212. package/app/public/vendor/fonts/cat-abril_fatface-400-ext.woff2 +0 -0
  213. package/app/public/vendor/fonts/cat-abril_fatface-400.woff2 +0 -0
  214. package/app/public/vendor/fonts/cat-adlam_display-400-ext.woff2 +0 -0
  215. package/app/public/vendor/fonts/cat-adlam_display-400.woff2 +0 -0
  216. package/app/public/vendor/fonts/cat-agu_display-400-ext.woff2 +0 -0
  217. package/app/public/vendor/fonts/cat-agu_display-400.woff2 +0 -0
  218. package/app/public/vendor/fonts/cat-alfa_slab_one-400-ext.woff2 +0 -0
  219. package/app/public/vendor/fonts/cat-alfa_slab_one-400.woff2 +0 -0
  220. package/app/public/vendor/fonts/cat-are_you_serious-400-ext.woff2 +0 -0
  221. package/app/public/vendor/fonts/cat-are_you_serious-400.woff2 +0 -0
  222. package/app/public/vendor/fonts/cat-asimovian-400-ext.woff2 +0 -0
  223. package/app/public/vendor/fonts/cat-asimovian-400.woff2 +0 -0
  224. package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400-ext.woff2 +0 -0
  225. package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400.woff2 +0 -0
  226. package/app/public/vendor/fonts/cat-bakbak_one-400-ext.woff2 +0 -0
  227. package/app/public/vendor/fonts/cat-bakbak_one-400.woff2 +0 -0
  228. package/app/public/vendor/fonts/cat-bangers-400-ext.woff2 +0 -0
  229. package/app/public/vendor/fonts/cat-bangers-400.woff2 +0 -0
  230. package/app/public/vendor/fonts/cat-barriecito-400-ext.woff2 +0 -0
  231. package/app/public/vendor/fonts/cat-barriecito-400.woff2 +0 -0
  232. package/app/public/vendor/fonts/cat-berkshire_swash-400-ext.woff2 +0 -0
  233. package/app/public/vendor/fonts/cat-berkshire_swash-400.woff2 +0 -0
  234. package/app/public/vendor/fonts/cat-bevan-400-ext.woff2 +0 -0
  235. package/app/public/vendor/fonts/cat-bevan-400.woff2 +0 -0
  236. package/app/public/vendor/fonts/cat-bitcount-400-ext.woff2 +0 -0
  237. package/app/public/vendor/fonts/cat-bitcount-400.woff2 +0 -0
  238. package/app/public/vendor/fonts/cat-bowlby_one_sc-400-ext.woff2 +0 -0
  239. package/app/public/vendor/fonts/cat-bowlby_one_sc-400.woff2 +0 -0
  240. package/app/public/vendor/fonts/cat-bungee_shade-400-ext.woff2 +0 -0
  241. package/app/public/vendor/fonts/cat-bungee_shade-400.woff2 +0 -0
  242. package/app/public/vendor/fonts/cat-charm-400-ext.woff2 +0 -0
  243. package/app/public/vendor/fonts/cat-charm-400.woff2 +0 -0
  244. package/app/public/vendor/fonts/cat-charm-700-ext.woff2 +0 -0
  245. package/app/public/vendor/fonts/cat-charm-700.woff2 +0 -0
  246. package/app/public/vendor/fonts/cat-cherry_bomb_one-400-ext.woff2 +0 -0
  247. package/app/public/vendor/fonts/cat-cherry_bomb_one-400.woff2 +0 -0
  248. package/app/public/vendor/fonts/cat-chokokutai-400-ext.woff2 +0 -0
  249. package/app/public/vendor/fonts/cat-chokokutai-400.woff2 +0 -0
  250. package/app/public/vendor/fonts/cat-chonburi-400-ext.woff2 +0 -0
  251. package/app/public/vendor/fonts/cat-chonburi-400.woff2 +0 -0
  252. package/app/public/vendor/fonts/cat-climate_crisis-400-ext.woff2 +0 -0
  253. package/app/public/vendor/fonts/cat-climate_crisis-400.woff2 +0 -0
  254. package/app/public/vendor/fonts/cat-cookie-400.woff2 +0 -0
  255. package/app/public/vendor/fonts/cat-dela_gothic_one-400-ext.woff2 +0 -0
  256. package/app/public/vendor/fonts/cat-dela_gothic_one-400.woff2 +0 -0
  257. package/app/public/vendor/fonts/cat-fascinate_inline-400-ext.woff2 +0 -0
  258. package/app/public/vendor/fonts/cat-fascinate_inline-400.woff2 +0 -0
  259. package/app/public/vendor/fonts/cat-ga_maamli-400-ext.woff2 +0 -0
  260. package/app/public/vendor/fonts/cat-ga_maamli-400.woff2 +0 -0
  261. package/app/public/vendor/fonts/cat-itim-400-ext.woff2 +0 -0
  262. package/app/public/vendor/fonts/cat-itim-400.woff2 +0 -0
  263. package/app/public/vendor/fonts/cat-jacquard_24-400-ext.woff2 +0 -0
  264. package/app/public/vendor/fonts/cat-jacquard_24-400.woff2 +0 -0
  265. package/app/public/vendor/fonts/cat-kablammo-400-ext.woff2 +0 -0
  266. package/app/public/vendor/fonts/cat-kablammo-400.woff2 +0 -0
  267. package/app/public/vendor/fonts/cat-kalam-400-ext.woff2 +0 -0
  268. package/app/public/vendor/fonts/cat-kalam-400.woff2 +0 -0
  269. package/app/public/vendor/fonts/cat-kalam-700-ext.woff2 +0 -0
  270. package/app/public/vendor/fonts/cat-kalam-700.woff2 +0 -0
  271. package/app/public/vendor/fonts/cat-katibeh-400-ext.woff2 +0 -0
  272. package/app/public/vendor/fonts/cat-katibeh-400.woff2 +0 -0
  273. package/app/public/vendor/fonts/cat-lemonada-400-ext.woff2 +0 -0
  274. package/app/public/vendor/fonts/cat-lemonada-400.woff2 +0 -0
  275. package/app/public/vendor/fonts/cat-lilita_one-400-ext.woff2 +0 -0
  276. package/app/public/vendor/fonts/cat-lilita_one-400.woff2 +0 -0
  277. package/app/public/vendor/fonts/cat-lobster-400-ext.woff2 +0 -0
  278. package/app/public/vendor/fonts/cat-lobster-400.woff2 +0 -0
  279. package/app/public/vendor/fonts/cat-luckiest_guy-400-ext.woff2 +0 -0
  280. package/app/public/vendor/fonts/cat-luckiest_guy-400.woff2 +0 -0
  281. package/app/public/vendor/fonts/cat-marhey-400-ext.woff2 +0 -0
  282. package/app/public/vendor/fonts/cat-marhey-400.woff2 +0 -0
  283. package/app/public/vendor/fonts/cat-modak-400-ext.woff2 +0 -0
  284. package/app/public/vendor/fonts/cat-modak-400.woff2 +0 -0
  285. package/app/public/vendor/fonts/cat-momo_signature-400-ext.woff2 +0 -0
  286. package/app/public/vendor/fonts/cat-momo_signature-400.woff2 +0 -0
  287. package/app/public/vendor/fonts/cat-monofett-400-ext.woff2 +0 -0
  288. package/app/public/vendor/fonts/cat-monofett-400.woff2 +0 -0
  289. package/app/public/vendor/fonts/cat-monomakh-400-ext.woff2 +0 -0
  290. package/app/public/vendor/fonts/cat-monomakh-400.woff2 +0 -0
  291. package/app/public/vendor/fonts/cat-monoton-400-ext.woff2 +0 -0
  292. package/app/public/vendor/fonts/cat-monoton-400.woff2 +0 -0
  293. package/app/public/vendor/fonts/cat-nerko_one-400-ext.woff2 +0 -0
  294. package/app/public/vendor/fonts/cat-nerko_one-400.woff2 +0 -0
  295. package/app/public/vendor/fonts/cat-noto_sans_adlam-400-ext.woff2 +0 -0
  296. package/app/public/vendor/fonts/cat-noto_sans_adlam-400.woff2 +0 -0
  297. package/app/public/vendor/fonts/cat-noto_sans_arabic-400-ext.woff2 +0 -0
  298. package/app/public/vendor/fonts/cat-noto_sans_arabic-400.woff2 +0 -0
  299. package/app/public/vendor/fonts/cat-noto_sans_devanagari-400-ext.woff2 +0 -0
  300. package/app/public/vendor/fonts/cat-noto_sans_devanagari-400.woff2 +0 -0
  301. package/app/public/vendor/fonts/cat-noto_sans_hebrew-400-ext.woff2 +0 -0
  302. package/app/public/vendor/fonts/cat-noto_sans_hebrew-400.woff2 +0 -0
  303. package/app/public/vendor/fonts/cat-noto_sans_jp-400-ext.woff2 +0 -0
  304. package/app/public/vendor/fonts/cat-noto_sans_jp-400.woff2 +0 -0
  305. package/app/public/vendor/fonts/cat-noto_sans_khmer-400-ext.woff2 +0 -0
  306. package/app/public/vendor/fonts/cat-noto_sans_khmer-400.woff2 +0 -0
  307. package/app/public/vendor/fonts/cat-noto_sans_kr-400-ext.woff2 +0 -0
  308. package/app/public/vendor/fonts/cat-noto_sans_kr-400.woff2 +0 -0
  309. package/app/public/vendor/fonts/cat-noto_sans_sc-400-ext.woff2 +0 -0
  310. package/app/public/vendor/fonts/cat-noto_sans_sc-400.woff2 +0 -0
  311. package/app/public/vendor/fonts/cat-noto_sans_thai-400-ext.woff2 +0 -0
  312. package/app/public/vendor/fonts/cat-noto_sans_thai-400.woff2 +0 -0
  313. package/app/public/vendor/fonts/cat-ole-400-ext.woff2 +0 -0
  314. package/app/public/vendor/fonts/cat-ole-400.woff2 +0 -0
  315. package/app/public/vendor/fonts/cat-pacifico-400-ext.woff2 +0 -0
  316. package/app/public/vendor/fonts/cat-pacifico-400.woff2 +0 -0
  317. package/app/public/vendor/fonts/cat-patrick_hand-400-ext.woff2 +0 -0
  318. package/app/public/vendor/fonts/cat-patrick_hand-400.woff2 +0 -0
  319. package/app/public/vendor/fonts/cat-petit_formal_script-400-ext.woff2 +0 -0
  320. package/app/public/vendor/fonts/cat-petit_formal_script-400.woff2 +0 -0
  321. package/app/public/vendor/fonts/cat-pixelify_sans-400-ext.woff2 +0 -0
  322. package/app/public/vendor/fonts/cat-pixelify_sans-400.woff2 +0 -0
  323. package/app/public/vendor/fonts/cat-plaster-400-ext.woff2 +0 -0
  324. package/app/public/vendor/fonts/cat-plaster-400.woff2 +0 -0
  325. package/app/public/vendor/fonts/cat-playwrite_ar_guides-400-0.woff2 +0 -0
  326. package/app/public/vendor/fonts/cat-playwrite_at-400-0.woff2 +0 -0
  327. package/app/public/vendor/fonts/cat-playwrite_at_guides-400-0.woff2 +0 -0
  328. package/app/public/vendor/fonts/cat-playwrite_au_nsw-400-0.woff2 +0 -0
  329. package/app/public/vendor/fonts/cat-playwrite_au_nsw_guides-400-0.woff2 +0 -0
  330. package/app/public/vendor/fonts/cat-playwrite_au_qld-400-0.woff2 +0 -0
  331. package/app/public/vendor/fonts/cat-playwrite_au_qld_guides-400-0.woff2 +0 -0
  332. package/app/public/vendor/fonts/cat-playwrite_au_sa-400-0.woff2 +0 -0
  333. package/app/public/vendor/fonts/cat-playwrite_au_sa_guides-400-0.woff2 +0 -0
  334. package/app/public/vendor/fonts/cat-playwrite_au_tas-400-0.woff2 +0 -0
  335. package/app/public/vendor/fonts/cat-playwrite_au_tas_guides-400-0.woff2 +0 -0
  336. package/app/public/vendor/fonts/cat-playwrite_au_vic-400-0.woff2 +0 -0
  337. package/app/public/vendor/fonts/cat-playwrite_au_vic_guides-400-0.woff2 +0 -0
  338. package/app/public/vendor/fonts/cat-playwrite_be_vlg-400-0.woff2 +0 -0
  339. package/app/public/vendor/fonts/cat-playwrite_be_vlg_guides-400-0.woff2 +0 -0
  340. package/app/public/vendor/fonts/cat-playwrite_be_wal-400-0.woff2 +0 -0
  341. package/app/public/vendor/fonts/cat-playwrite_be_wal_guides-400-0.woff2 +0 -0
  342. package/app/public/vendor/fonts/cat-playwrite_br_guides-400-0.woff2 +0 -0
  343. package/app/public/vendor/fonts/cat-playwrite_ca_guides-400-0.woff2 +0 -0
  344. package/app/public/vendor/fonts/cat-playwrite_cl_guides-400-0.woff2 +0 -0
  345. package/app/public/vendor/fonts/cat-playwrite_co_guides-400-0.woff2 +0 -0
  346. package/app/public/vendor/fonts/cat-playwrite_cu_guides-400-0.woff2 +0 -0
  347. package/app/public/vendor/fonts/cat-playwrite_cz-400-0.woff2 +0 -0
  348. package/app/public/vendor/fonts/cat-playwrite_cz_guides-400-0.woff2 +0 -0
  349. package/app/public/vendor/fonts/cat-playwrite_de_grund-400-0.woff2 +0 -0
  350. package/app/public/vendor/fonts/cat-playwrite_de_grund_guides-400-0.woff2 +0 -0
  351. package/app/public/vendor/fonts/cat-playwrite_de_la-400-0.woff2 +0 -0
  352. package/app/public/vendor/fonts/cat-playwrite_de_la_guides-400-0.woff2 +0 -0
  353. package/app/public/vendor/fonts/cat-playwrite_de_sas-400-0.woff2 +0 -0
  354. package/app/public/vendor/fonts/cat-playwrite_de_sas_guides-400-0.woff2 +0 -0
  355. package/app/public/vendor/fonts/cat-playwrite_de_va-400-0.woff2 +0 -0
  356. package/app/public/vendor/fonts/cat-playwrite_de_va_guides-400-0.woff2 +0 -0
  357. package/app/public/vendor/fonts/cat-playwrite_dk_loopet-400-0.woff2 +0 -0
  358. package/app/public/vendor/fonts/cat-playwrite_dk_loopet_guides-400-0.woff2 +0 -0
  359. package/app/public/vendor/fonts/cat-playwrite_dk_uloopet-400-0.woff2 +0 -0
  360. package/app/public/vendor/fonts/cat-playwrite_dk_uloopet_guides-400-0.woff2 +0 -0
  361. package/app/public/vendor/fonts/cat-playwrite_es_deco_guides-400-0.woff2 +0 -0
  362. package/app/public/vendor/fonts/cat-playwrite_es_guides-400-0.woff2 +0 -0
  363. package/app/public/vendor/fonts/cat-playwrite_fr_moderne-400-0.woff2 +0 -0
  364. package/app/public/vendor/fonts/cat-playwrite_fr_moderne_guides-400-0.woff2 +0 -0
  365. package/app/public/vendor/fonts/cat-playwrite_fr_trad-400-0.woff2 +0 -0
  366. package/app/public/vendor/fonts/cat-playwrite_fr_trad_guides-400-0.woff2 +0 -0
  367. package/app/public/vendor/fonts/cat-playwrite_gb_j_guides-400-0.woff2 +0 -0
  368. package/app/public/vendor/fonts/cat-playwrite_gb_s_guides-400-0.woff2 +0 -0
  369. package/app/public/vendor/fonts/cat-playwrite_hr-400-0.woff2 +0 -0
  370. package/app/public/vendor/fonts/cat-playwrite_hr_guides-400-0.woff2 +0 -0
  371. package/app/public/vendor/fonts/cat-playwrite_hr_lijeva-400-0.woff2 +0 -0
  372. package/app/public/vendor/fonts/cat-playwrite_hr_lijeva_guides-400-0.woff2 +0 -0
  373. package/app/public/vendor/fonts/cat-playwrite_hu-400-0.woff2 +0 -0
  374. package/app/public/vendor/fonts/cat-playwrite_hu_guides-400-0.woff2 +0 -0
  375. package/app/public/vendor/fonts/cat-playwrite_id-400-0.woff2 +0 -0
  376. package/app/public/vendor/fonts/cat-playwrite_id_guides-400-0.woff2 +0 -0
  377. package/app/public/vendor/fonts/cat-playwrite_ie-400-0.woff2 +0 -0
  378. package/app/public/vendor/fonts/cat-playwrite_ie_guides-400-0.woff2 +0 -0
  379. package/app/public/vendor/fonts/cat-playwrite_in-400-0.woff2 +0 -0
  380. package/app/public/vendor/fonts/cat-playwrite_in_guides-400-0.woff2 +0 -0
  381. package/app/public/vendor/fonts/cat-playwrite_is-400-0.woff2 +0 -0
  382. package/app/public/vendor/fonts/cat-playwrite_is_guides-400-0.woff2 +0 -0
  383. package/app/public/vendor/fonts/cat-playwrite_it_moderna-400-0.woff2 +0 -0
  384. package/app/public/vendor/fonts/cat-playwrite_it_moderna_guides-400-0.woff2 +0 -0
  385. package/app/public/vendor/fonts/cat-playwrite_it_trad-400-0.woff2 +0 -0
  386. package/app/public/vendor/fonts/cat-playwrite_it_trad_guides-400-0.woff2 +0 -0
  387. package/app/public/vendor/fonts/cat-playwrite_mx_guides-400-0.woff2 +0 -0
  388. package/app/public/vendor/fonts/cat-playwrite_ng_modern-400-0.woff2 +0 -0
  389. package/app/public/vendor/fonts/cat-playwrite_ng_modern_guides-400-0.woff2 +0 -0
  390. package/app/public/vendor/fonts/cat-playwrite_nl-400-0.woff2 +0 -0
  391. package/app/public/vendor/fonts/cat-playwrite_nl_guides-400-0.woff2 +0 -0
  392. package/app/public/vendor/fonts/cat-playwrite_no-400-0.woff2 +0 -0
  393. package/app/public/vendor/fonts/cat-playwrite_no_guides-400-0.woff2 +0 -0
  394. package/app/public/vendor/fonts/cat-playwrite_nz-400-0.woff2 +0 -0
  395. package/app/public/vendor/fonts/cat-playwrite_nz_basic-400-0.woff2 +0 -0
  396. package/app/public/vendor/fonts/cat-playwrite_nz_basic_guides-400-0.woff2 +0 -0
  397. package/app/public/vendor/fonts/cat-playwrite_nz_guides-400-0.woff2 +0 -0
  398. package/app/public/vendor/fonts/cat-playwrite_pe_guides-400-0.woff2 +0 -0
  399. package/app/public/vendor/fonts/cat-playwrite_pl-400-0.woff2 +0 -0
  400. package/app/public/vendor/fonts/cat-playwrite_pl_guides-400-0.woff2 +0 -0
  401. package/app/public/vendor/fonts/cat-playwrite_pt_guides-400-0.woff2 +0 -0
  402. package/app/public/vendor/fonts/cat-playwrite_ro-400-0.woff2 +0 -0
  403. package/app/public/vendor/fonts/cat-playwrite_ro_guides-400-0.woff2 +0 -0
  404. package/app/public/vendor/fonts/cat-playwrite_sk-400-0.woff2 +0 -0
  405. package/app/public/vendor/fonts/cat-playwrite_sk_guides-400-0.woff2 +0 -0
  406. package/app/public/vendor/fonts/cat-playwrite_tz-400-0.woff2 +0 -0
  407. package/app/public/vendor/fonts/cat-playwrite_tz_guides-400-0.woff2 +0 -0
  408. package/app/public/vendor/fonts/cat-playwrite_us_modern_guides-400-0.woff2 +0 -0
  409. package/app/public/vendor/fonts/cat-playwrite_us_trad_guides-400-0.woff2 +0 -0
  410. package/app/public/vendor/fonts/cat-playwrite_vn-400-0.woff2 +0 -0
  411. package/app/public/vendor/fonts/cat-playwrite_vn_guides-400-0.woff2 +0 -0
  412. package/app/public/vendor/fonts/cat-playwrite_za-400-0.woff2 +0 -0
  413. package/app/public/vendor/fonts/cat-playwrite_za_guides-400-0.woff2 +0 -0
  414. package/app/public/vendor/fonts/cat-potta_one-400-ext.woff2 +0 -0
  415. package/app/public/vendor/fonts/cat-potta_one-400.woff2 +0 -0
  416. package/app/public/vendor/fonts/cat-ranchers-400-ext.woff2 +0 -0
  417. package/app/public/vendor/fonts/cat-ranchers-400.woff2 +0 -0
  418. package/app/public/vendor/fonts/cat-ranga-400-ext.woff2 +0 -0
  419. package/app/public/vendor/fonts/cat-ranga-400.woff2 +0 -0
  420. package/app/public/vendor/fonts/cat-ranga-700-ext.woff2 +0 -0
  421. package/app/public/vendor/fonts/cat-ranga-700.woff2 +0 -0
  422. package/app/public/vendor/fonts/cat-risque-400-ext.woff2 +0 -0
  423. package/app/public/vendor/fonts/cat-risque-400.woff2 +0 -0
  424. package/app/public/vendor/fonts/cat-rowdies-400-ext.woff2 +0 -0
  425. package/app/public/vendor/fonts/cat-rowdies-400.woff2 +0 -0
  426. package/app/public/vendor/fonts/cat-rowdies-700-ext.woff2 +0 -0
  427. package/app/public/vendor/fonts/cat-rowdies-700.woff2 +0 -0
  428. package/app/public/vendor/fonts/cat-ruge_boogie-400-ext.woff2 +0 -0
  429. package/app/public/vendor/fonts/cat-ruge_boogie-400.woff2 +0 -0
  430. package/app/public/vendor/fonts/cat-ruslan_display-400-ext.woff2 +0 -0
  431. package/app/public/vendor/fonts/cat-ruslan_display-400.woff2 +0 -0
  432. package/app/public/vendor/fonts/cat-sacramento-400-ext.woff2 +0 -0
  433. package/app/public/vendor/fonts/cat-sacramento-400.woff2 +0 -0
  434. package/app/public/vendor/fonts/cat-sancreek-400-ext.woff2 +0 -0
  435. package/app/public/vendor/fonts/cat-sancreek-400.woff2 +0 -0
  436. package/app/public/vendor/fonts/cat-sankofa_display-400-ext.woff2 +0 -0
  437. package/app/public/vendor/fonts/cat-sankofa_display-400.woff2 +0 -0
  438. package/app/public/vendor/fonts/cat-sedgwick_ave_display-400-ext.woff2 +0 -0
  439. package/app/public/vendor/fonts/cat-sedgwick_ave_display-400.woff2 +0 -0
  440. package/app/public/vendor/fonts/cat-shantell_sans-400-ext.woff2 +0 -0
  441. package/app/public/vendor/fonts/cat-shantell_sans-400.woff2 +0 -0
  442. package/app/public/vendor/fonts/cat-smokum-400-ext.woff2 +0 -0
  443. package/app/public/vendor/fonts/cat-smokum-400.woff2 +0 -0
  444. package/app/public/vendor/fonts/cat-solitreo-400-ext.woff2 +0 -0
  445. package/app/public/vendor/fonts/cat-solitreo-400.woff2 +0 -0
  446. package/app/public/vendor/fonts/cat-spicy_rice-400-ext.woff2 +0 -0
  447. package/app/public/vendor/fonts/cat-spicy_rice-400.woff2 +0 -0
  448. package/app/public/vendor/fonts/cat-sriracha-400-ext.woff2 +0 -0
  449. package/app/public/vendor/fonts/cat-sriracha-400.woff2 +0 -0
  450. package/app/public/vendor/fonts/cat-srisakdi-400-ext.woff2 +0 -0
  451. package/app/public/vendor/fonts/cat-srisakdi-400.woff2 +0 -0
  452. package/app/public/vendor/fonts/cat-srisakdi-700-ext.woff2 +0 -0
  453. package/app/public/vendor/fonts/cat-srisakdi-700.woff2 +0 -0
  454. package/app/public/vendor/fonts/cat-stix_two_math-400-0.woff2 +0 -0
  455. package/app/public/vendor/fonts/cat-tillana-400-ext.woff2 +0 -0
  456. package/app/public/vendor/fonts/cat-tillana-400.woff2 +0 -0
  457. package/app/public/vendor/fonts/cat-tillana-700-ext.woff2 +0 -0
  458. package/app/public/vendor/fonts/cat-tillana-700.woff2 +0 -0
  459. package/app/public/vendor/fonts/cat-titan_one-400-ext.woff2 +0 -0
  460. package/app/public/vendor/fonts/cat-titan_one-400.woff2 +0 -0
  461. package/app/public/vendor/fonts/cat-yatra_one-400-ext.woff2 +0 -0
  462. package/app/public/vendor/fonts/cat-yatra_one-400.woff2 +0 -0
  463. package/app/public/vendor/fonts/cat-yomogi-400-ext.woff2 +0 -0
  464. package/app/public/vendor/fonts/cat-yomogi-400.woff2 +0 -0
  465. package/app/public/vendor/fonts/dmserifdisplay-400-ext.woff2 +0 -0
  466. package/app/public/vendor/fonts/dmserifdisplay-400.woff2 +0 -0
  467. package/app/public/vendor/fonts/domine-var-ext.woff2 +0 -0
  468. package/app/public/vendor/fonts/domine-var.woff2 +0 -0
  469. package/app/public/vendor/fonts/fondamento-400-ext.woff2 +0 -0
  470. package/app/public/vendor/fonts/fondamento-400.woff2 +0 -0
  471. package/app/public/vendor/fonts/fraunces-var-ext.woff2 +0 -0
  472. package/app/public/vendor/fonts/fraunces-var.woff2 +0 -0
  473. package/app/public/vendor/fonts/fredoka-var-ext.woff2 +0 -0
  474. package/app/public/vendor/fonts/fredoka-var.woff2 +0 -0
  475. package/app/public/vendor/fonts/inter-400.woff2 +0 -0
  476. package/app/public/vendor/fonts/inter-700.woff2 +0 -0
  477. package/app/public/vendor/fonts/jakarta-var-ext.woff2 +0 -0
  478. package/app/public/vendor/fonts/jakarta-var.woff2 +0 -0
  479. package/app/public/vendor/fonts/lato-400.woff2 +0 -0
  480. package/app/public/vendor/fonts/lato-700.woff2 +0 -0
  481. package/app/public/vendor/fonts/literata-400.woff2 +0 -0
  482. package/app/public/vendor/fonts/literata-700.woff2 +0 -0
  483. package/app/public/vendor/fonts/lora-var-ext.woff2 +0 -0
  484. package/app/public/vendor/fonts/lora-var.woff2 +0 -0
  485. package/app/public/vendor/fonts/merriweather-var-ext.woff2 +0 -0
  486. package/app/public/vendor/fonts/merriweather-var.woff2 +0 -0
  487. package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
  488. package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
  489. package/app/public/vendor/fonts/notosans-var-ext.woff2 +0 -0
  490. package/app/public/vendor/fonts/notosans-var.woff2 +0 -0
  491. package/app/public/vendor/fonts/nunito-var-ext.woff2 +0 -0
  492. package/app/public/vendor/fonts/nunito-var.woff2 +0 -0
  493. package/app/public/vendor/fonts/opendyslexic-400.woff2 +0 -0
  494. package/app/public/vendor/fonts/opensans-400.woff2 +0 -0
  495. package/app/public/vendor/fonts/opensans-700.woff2 +0 -0
  496. package/app/public/vendor/fonts/pinyon-400.woff2 +0 -0
  497. package/app/public/vendor/fonts/playfair-var-ext.woff2 +0 -0
  498. package/app/public/vendor/fonts/playfair-var.woff2 +0 -0
  499. package/app/public/vendor/fonts/pressstart-400.woff2 +0 -0
  500. package/app/public/vendor/fonts/quattro-400.woff2 +0 -0
  501. package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
  502. package/app/public/vendor/fonts/quicksand-var-ext.woff2 +0 -0
  503. package/app/public/vendor/fonts/quicksand-var.woff2 +0 -0
  504. package/app/public/vendor/fonts/robotoflex-var-ext.woff2 +0 -0
  505. package/app/public/vendor/fonts/robotoflex-var.woff2 +0 -0
  506. package/app/public/vendor/fonts/sora-var-ext.woff2 +0 -0
  507. package/app/public/vendor/fonts/sora-var.woff2 +0 -0
  508. package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
  509. package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
  510. package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
  511. package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
  512. package/app/public/vendor/fonts/spacegrotesk-var-ext.woff2 +0 -0
  513. package/app/public/vendor/fonts/spacegrotesk-var.woff2 +0 -0
  514. package/app/public/vendor/fonts/spectral-400-ext.woff2 +0 -0
  515. package/app/public/vendor/fonts/spectral-400.woff2 +0 -0
  516. package/app/public/vendor/fonts/spectral-700-ext.woff2 +0 -0
  517. package/app/public/vendor/fonts/spectral-700.woff2 +0 -0
  518. package/app/public/vendor/fonts/teachers-var-ext.woff2 +0 -0
  519. package/app/public/vendor/fonts/teachers-var.woff2 +0 -0
  520. package/app/public/vendor/fonts/ubuntu-400-ext.woff2 +0 -0
  521. package/app/public/vendor/fonts/ubuntu-400.woff2 +0 -0
  522. package/app/public/vendor/fonts/ubuntu-700-ext.woff2 +0 -0
  523. package/app/public/vendor/fonts/ubuntu-700.woff2 +0 -0
  524. package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
  525. package/dist-pkg/platform/guide-intensity.d.ts +0 -39
  526. package/dist-pkg/platform/guide-intensity.js +0 -71
  527. package/dist-pkg/ui/latch-refusal.d.ts +0 -33
  528. package/dist-pkg/ui/latch-refusal.js +0 -60
@@ -24,6 +24,52 @@ export declare function readingLanguageOf(id: string): string | null;
24
24
  * models behind it out of the start of every delivery.
25
25
  */
26
26
  export declare function commandsLanguageOf(id: string): string | null;
27
+ /**
28
+ * WHERE THE DELIVERY PUTS THE LIBRAS PLAYER'S FILES (ADR-0234, route B, the engine's interpreter since phase B3): the avatar, its
29
+ * clips, their manifest and the build-time glosses, beside the game's page (`inclusionist-heavy --libras`). Written here, below
30
+ * the player that reads it (`ui/libras-avatar-plan` re-exports it), because the delivery's list of those files names it too.
31
+ *
32
+ * 📌 THERE IS NO CATALOGUE ENTRY FOR IT: the avatar and the clips are this project's own export of LAViD-UFPB's GPL-3.0 sign
33
+ * sources, pinned by sha256 in `scripts/libras-avatar.json`, and each delivery lists what it wrote (`DELIVERY_LISTS`). Nothing
34
+ * closed and nothing patched is served for it.
35
+ */
36
+ export declare const LIBRAS_AVATAR_FOLDER = "libras/avatar/";
37
+ /**
38
+ * THE START OF THE FREE PLAYER'S STAGE CHUNK, under the page: `ui/libras-avatar-stage` and the three.js it carries, which the
39
+ * bundler emits as `assets/libras-avatar-stage-<content hash>.js`. The precache leaves it out on purpose (three.js is only a
40
+ * deaf-mode child's download), so the delivery finds the hashed name after the build and lists it; a NAME's start and not a
41
+ * folder, because the rest of `assets/` belongs to the precache.
42
+ */
43
+ export declare const LIBRAS_AVATAR_STAGE_CHUNK = "assets/libras-avatar-stage-";
44
+ /**
45
+ * A LIST THE DELIVERY WRITES OF ITS OWN FILES, each with its sha256 — for what no catalogue entry can pin because each delivery
46
+ * makes it: the Libras player's avatar, clips and manifest, the glosses of the engine's and the game's texts, and the build's
47
+ * stage chunk (ADR-0234, pillar 8). The device reads the list and keeps each file only if its bytes are the listed ones, in the
48
+ * checked cache, under the file's own address, where the service worker answers the player from offline.
49
+ *
50
+ * ⚠️ WHAT THE LIST PROVES, AND WHAT IT DOES NOT: it comes from the page's own origin, like the page's code, so it is exactly as
51
+ * trusted as the page — it is not a pin. What it guarantees is that what is kept is what this delivery wrote: never a truncated
52
+ * body, a fallback page served for a missing file, or a file of the previous delivery. The avatar's and the clips' hashes in it
53
+ * are the ones `scripts/libras-avatar.json` pins, checked when the delivery wrote them.
54
+ */
55
+ export interface DeliveryList {
56
+ readonly id: string;
57
+ /** Where the delivery writes the list, relative to the page. */
58
+ readonly path: string;
59
+ /**
60
+ * The only places the list may name, relative to the page: a listed file outside them is refused, never kept. Each is a
61
+ * folder (ending in `/`) or, for a file whose name the build hashes, the start of that name (`LIBRAS_AVATAR_STAGE_CHUNK`).
62
+ */
63
+ readonly folders: readonly string[];
64
+ }
65
+ /**
66
+ * The lists a device may read, each asked for with deaf mode (`heavyAtBoot`) — one per delivery step that writes files of its own:
67
+ * · `libras:avatar:delivery`, the Libras player's avatar, clips, manifest and glosses and the stage chunk with three.js, written by
68
+ * `--libras` (ADR-0234, phase B3). A delivery built without it has no such list: a quiet 404, and deaf mode says «signing
69
+ * unavailable» when the sonar is pressed.
70
+ * 📌 THE RULE IS «WHAT THE DELIVERY CARRIES, DEAF MODE KEEPS»: the files are kept whichever interpreter the host lends.
71
+ */
72
+ export declare const DELIVERY_LISTS: readonly DeliveryList[];
27
73
  /**
28
74
  * 📌 Every entry with an address needs its licence group in `scripts/licences/third-party.mjs`: the delivery writes that group's
29
75
  * `LICENSE` and `NOTICE` beside the file, and refuses a file whose licence nobody recorded (ADR-0177).
@@ -52,21 +52,23 @@ const MEDIAPIPE = Object.freeze([
52
52
  * same reason — the engine imports nothing from npm at run time, so a game that never asks for this voice carries none of it, and
53
53
  * the published package stays free of a bundler-only import.
54
54
  *
55
- * · espeak-ng turns a sentence into phonemes, in every language the project speaks. GPL-3.0-or-later, compatible with the engine's
56
- * AGPL-3.0 (LICENSES.md); the source travels beside the mirror (ADR-0203 erratum).
55
+ * · eSpeak NG turns a sentence into phonemes, in every language the project speaks. GPL-3.0-or-later, compatible with the engine's
56
+ * AGPL-3.0 (LICENSES.md). It is the PROJECT'S OWN BUILD (issue #192): the npm build named no source, so the engine compiles it
57
+ * from a pinned commit (`scripts/models/build-espeak-ng.ps1`), and that commit and that recipe travel beside the mirror's copy.
58
+ * Its address is the project's mirror because nothing upstream holds these bytes.
57
59
  * · onnxruntime-web runs Kokoro's graph. The `jsep` pair is what its own threads load, which is why both are here: a worker that
58
60
  * cannot find them answers nothing, and the child hears silence (measured in the quiz demo, #181).
59
61
  *
60
- * ⚠️ sha256 MEASURED on the files the dev dependency already put on the build machine, not taken from a page; the first delivery run
61
- * is what proves jsDelivr serves the same bytes, because it refuses to write anything else.
62
+ * ⚠️ sha256 MEASURED on the files, not taken from a page: onnxruntime-web's on those the dev dependency put on the build machine,
63
+ * which the first delivery run proved jsDelivr serves; eSpeak NG's on two runs of its recipe, which wrote the same bytes.
62
64
  */
63
- const ESPEAK = 'https://cdn.jsdelivr.net/npm/espeak-ng@1.0.2';
65
+ const ESPEAK = 'https://lfs-oinclusionista.jrocha.dev.br/espeak-ng-530bf0a';
64
66
  const ORT = 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.27.0';
65
67
  const VOICE_RUNTIME = Object.freeze([
66
- { id: 'voz:runtime:fonemas', url: `${ESPEAK}/dist/espeak-ng.js`, bytes: 178_386,
67
- sha256: '406c6655a6cacf34d84fc69dc4478c81b71518809080ce2d05df1b706d76429d' },
68
- { id: 'voz:runtime:fonemas:wasm', url: `${ESPEAK}/dist/espeak-ng.wasm`, bytes: 18_485_010,
69
- sha256: '10d24bb7e4124e983aa9cd8cd96c52c8ea4b607d81956ec70846684e2827d532' },
68
+ { id: 'voz:runtime:fonemas', url: `${ESPEAK}/espeak-ng.js`, bytes: 70_951,
69
+ sha256: 'd2f7cea5ed29daed420a05271a48e5b7ab5315b1f4b33fa04ea54014c155889e' },
70
+ { id: 'voz:runtime:fonemas:wasm', url: `${ESPEAK}/espeak-ng.wasm`, bytes: 1_493_661,
71
+ sha256: '44e0cc6accb436880d1d52d2dd7b69a72f8f6a8c8f2cdb3dcf00e3914db4eb05' },
70
72
  { id: 'voz:runtime:onnx', url: `${ORT}/dist/ort.webgpu.bundle.min.mjs`, bytes: 113_035,
71
73
  sha256: '3a18c7f261e05d44a15b2eef18a28e5f53c044d5d140bcea6066baf1f09c8b53' },
72
74
  { id: 'voz:runtime:onnx:cola', url: `${ORT}/dist/ort-wasm-simd-threaded.jsep.mjs`, bytes: 46_614,
@@ -84,8 +86,9 @@ const VOICE_RUNTIME = Object.freeze([
84
86
  * exported here from weights that ship no ONNX. The project mirrors them under ADR-0203 — «hospedar na Cloudflare do projeto» —
85
87
  * with the licence of each beside it in `the-inclusionist-lfs`.
86
88
  *
87
- * ⚠️ AND THEY ARE BIG: 378 MiB for pt, 162 for en, 310 for es. Nobody downloads all three — the start asks only for the child's
88
- * language (`heavyAtBoot`), and a game that does not declare `uses: { reading: true }` asks for none of them.
89
+ * ⚠️ AND THEY ARE BIG: 378 MiB for pt, 162 for en, 310 for es — and a device that reads keeps all three, because a child tries
90
+ * the three languages at once (ADR-0225 erratum, the Dev: «Negativo, baixar os três.»). The start asks for the child's language
91
+ * first and then each other whole (`heavyAtBoot`); a game that does not declare `uses: { reading: true }` asks for none of them.
89
92
  *
90
93
  * 📌 The ids are in English while their neighbours are not: what is here stays until the renaming of the whole catalogue (the
91
94
  * English plan, phase 2, a single BREAKING release), and nothing new arrives in Portuguese meanwhile.
@@ -152,9 +155,11 @@ export function readingLanguageOf(id) {
152
155
  * rebuilt from lichess-org/vosk-browser with `-s DYNAMIC_EXECUTION=0` and runs under the policy as it is (`models.md`).
153
156
  * The models are alphacephei's small ones, repacked deterministically as the `.tar.gz` that build loads.
154
157
  *
155
- * ⚠️ ONE MODEL PER LANGUAGE, like the reading: pt 30.9 MiB, en 39.2, es 37.9. The start asks for the child's, and a delivery
156
- * carries the ones it was built with (`inclusionist-heavy --commands pt`). 📌 Unlike the reading, NO GAME DECLARES THIS: a
157
- * child who speaks instead of pressing is using a transport, and a cartridge does not get to deny her one (ADR-0111).
158
+ * ⚠️ ONE MODEL PER LANGUAGE, like the reading: pt 30.9 MiB, en 39.2, es 37.9. A delivery carries the three unless
159
+ * `inclusionist-heavy --commands` narrows it, and the start asks for every language the page can switch to, the child's first
160
+ * (ADR-0225 erratum: a language changed mid-game must find its model), as it does for the reading. 📌 But unlike the reading,
161
+ * NO GAME DECLARES THIS: a child who speaks instead of pressing is using a transport, and a cartridge does not get to deny her
162
+ * one (ADR-0111).
158
163
  *
159
164
  * ⚠️ sha256 MEASURED on the mirror's own files (2026-09-21), each checked against the `SHA256SUMS` its folder publishes.
160
165
  */
@@ -181,6 +186,34 @@ export function commandsLanguageOf(id) {
181
186
  const parts = id.split(':');
182
187
  return parts[0] === 'commands' && parts[1] === 'model' && parts[2] ? parts[2] : null;
183
188
  }
189
+ /**
190
+ * WHERE THE DELIVERY PUTS THE LIBRAS PLAYER'S FILES (ADR-0234, route B, the engine's interpreter since phase B3): the avatar, its
191
+ * clips, their manifest and the build-time glosses, beside the game's page (`inclusionist-heavy --libras`). Written here, below
192
+ * the player that reads it (`ui/libras-avatar-plan` re-exports it), because the delivery's list of those files names it too.
193
+ *
194
+ * 📌 THERE IS NO CATALOGUE ENTRY FOR IT: the avatar and the clips are this project's own export of LAViD-UFPB's GPL-3.0 sign
195
+ * sources, pinned by sha256 in `scripts/libras-avatar.json`, and each delivery lists what it wrote (`DELIVERY_LISTS`). Nothing
196
+ * closed and nothing patched is served for it.
197
+ */
198
+ export const LIBRAS_AVATAR_FOLDER = 'libras/avatar/';
199
+ /**
200
+ * THE START OF THE FREE PLAYER'S STAGE CHUNK, under the page: `ui/libras-avatar-stage` and the three.js it carries, which the
201
+ * bundler emits as `assets/libras-avatar-stage-<content hash>.js`. The precache leaves it out on purpose (three.js is only a
202
+ * deaf-mode child's download), so the delivery finds the hashed name after the build and lists it; a NAME's start and not a
203
+ * folder, because the rest of `assets/` belongs to the precache.
204
+ */
205
+ export const LIBRAS_AVATAR_STAGE_CHUNK = 'assets/libras-avatar-stage-';
206
+ /**
207
+ * The lists a device may read, each asked for with deaf mode (`heavyAtBoot`) — one per delivery step that writes files of its own:
208
+ * · `libras:avatar:delivery`, the Libras player's avatar, clips, manifest and glosses and the stage chunk with three.js, written by
209
+ * `--libras` (ADR-0234, phase B3). A delivery built without it has no such list: a quiet 404, and deaf mode says «signing
210
+ * unavailable» when the sonar is pressed.
211
+ * 📌 THE RULE IS «WHAT THE DELIVERY CARRIES, DEAF MODE KEEPS»: the files are kept whichever interpreter the host lends.
212
+ */
213
+ export const DELIVERY_LISTS = Object.freeze([
214
+ Object.freeze({ id: 'libras:avatar:delivery', path: 'libras/offline-avatar.json',
215
+ folders: Object.freeze([LIBRAS_AVATAR_FOLDER, LIBRAS_AVATAR_STAGE_CHUNK]) }),
216
+ ]);
184
217
  /**
185
218
  * KOKORO (ADR-0186, ADR-0198; the Dev: «Faça»): the fp32 model, its tokenizer vocabulary and a style table per voice of the engine's
186
219
  * languages. The engine loads them itself when a game declares `uses.neuralVoice` (ADR-0216); the phonemizer and the runtime that
@@ -4,15 +4,9 @@ export declare const MIRROR_FOLDERS: ReadonlyArray<readonly [string, string]>;
4
4
  /**
5
5
  * Addresses the project does NOT mirror, each with why — they go on being fetched upstream even when a base is set.
6
6
  *
7
- * 🔴 AND THE ENTRY BELOW CAME BACK THE SAME DAY IT LEFT, which is worth writing rather than hiding. The Dev decided to mirror
8
- * both of the last two third-party addresses («Ok, vamos espelhar»), so this list was emptied — and 📏 measuring the bucket
9
- * after the upload showed `espeak-ng` answering **404** while the three `onnxruntime-web` files answer 200 with exactly the
10
- * catalogued byte counts. Nothing failed: the staging folder is marked «🔴 ON HOLD» and `upload-to-r2.ps1` skips it, because
11
- * espeak-ng is GPL-3.0-or-later and serving the binary obliges publishing the matching SOURCE beside it (ADR-0203 erratum,
12
- * issue #192). Emptying the list without checking what the bucket serves would have pointed every school at a 404.
13
- *
14
- * ⚠️ So it stays upstream until `espeak-ng-1.0.2/source/` exists. The decision to mirror it is unchanged; what is missing is
15
- * the obligation that decision carries, and a mirror is distribution.
7
+ * 📌 EMPTY, and a line here is a written decision, never an omission. The last one was the npm build of eSpeak NG, kept upstream
8
+ * because the project could not name the source it was built from; the engine now pins its own build, whose folder carries that
9
+ * source (issue #192). ⚠️ Before adding a line, check what the bucket serves: the mirror answers 404 for a folder not uploaded.
16
10
  */
17
11
  export declare const NOT_MIRRORED: ReadonlyArray<readonly [string, string]>;
18
12
  /** The path a mirror serves this upstream address under, or `null` when no mirror of this project holds it. */
@@ -29,29 +29,26 @@ export const MIRROR_FOLDERS = [
29
29
  // `vosk-browser` evaluates text as code, so this one was rebuilt with `-s DYNAMIC_EXECUTION=0` to run under the policy.
30
30
  ['https://lfs-oinclusionista.jrocha.dev.br/vosk-browser-dynamic-execution-0', 'vosk-browser-dynamic-execution-0'],
31
31
  ['https://lfs-oinclusionista.jrocha.dev.br/vosk-models', 'vosk-models'],
32
- // The neural voice's phonemizer and the graph runtime it shares with the reading models (issue #192, the Dev on 2026-09-22).
33
- // ⚠️ espeak-ng is GPL-3.0-or-later: the folder must carry the matching SOURCE beside the binary, and `docs/CREDITS.md` says
34
- // where. The version is in the folder name on purpose — a mirror that drops it cannot serve two versions during an upgrade.
35
- ['https://cdn.jsdelivr.net/npm/espeak-ng@1.0.2', 'espeak-ng-1.0.2'],
32
+ // The neural voice's phonemizer, the project's own build of eSpeak NG (issue #192): it has no upstream either, and its folder
33
+ // carries the Corresponding Source the GPL asks for — the pinned commit and the recipe, in `corresponding-source/`. The commit is in the folder
34
+ // name on purpose: a mirror that drops it cannot serve two builds during an upgrade.
35
+ ['https://lfs-oinclusionista.jrocha.dev.br/espeak-ng-530bf0a', 'espeak-ng-530bf0a'],
36
+ // The graph runtime the neural voice shares with the reading models (the Dev on 2026-09-22).
36
37
  ['https://cdn.jsdelivr.net/npm/onnxruntime-web@1.27.0', 'onnxruntime-web-1.27.0'],
38
+ // The font library (ADR-0255): one folder per family under `fonts/`, catalogued in `platform/font-library.json`. It has no
39
+ // upstream either — the library IS the project's copy, and the reserved-name families in it are their authors' originals.
40
+ ['https://lfs-oinclusionista.jrocha.dev.br/fonts', 'fonts'],
41
+ // 📌 The Libras player's avatar and clips are not catalogue files: `--libras` reads them from `<base>/vlibras-avatar-<commit>/`
42
+ // by their own pins (`scripts/libras-avatar.mjs`), so no mapping for them lives here.
37
43
  ];
38
44
  /**
39
45
  * Addresses the project does NOT mirror, each with why — they go on being fetched upstream even when a base is set.
40
46
  *
41
- * 🔴 AND THE ENTRY BELOW CAME BACK THE SAME DAY IT LEFT, which is worth writing rather than hiding. The Dev decided to mirror
42
- * both of the last two third-party addresses («Ok, vamos espelhar»), so this list was emptied — and 📏 measuring the bucket
43
- * after the upload showed `espeak-ng` answering **404** while the three `onnxruntime-web` files answer 200 with exactly the
44
- * catalogued byte counts. Nothing failed: the staging folder is marked «🔴 ON HOLD» and `upload-to-r2.ps1` skips it, because
45
- * espeak-ng is GPL-3.0-or-later and serving the binary obliges publishing the matching SOURCE beside it (ADR-0203 erratum,
46
- * issue #192). Emptying the list without checking what the bucket serves would have pointed every school at a 404.
47
- *
48
- * ⚠️ So it stays upstream until `espeak-ng-1.0.2/source/` exists. The decision to mirror it is unchanged; what is missing is
49
- * the obligation that decision carries, and a mirror is distribution.
47
+ * 📌 EMPTY, and a line here is a written decision, never an omission. The last one was the npm build of eSpeak NG, kept upstream
48
+ * because the project could not name the source it was built from; the engine now pins its own build, whose folder carries that
49
+ * source (issue #192). ⚠️ Before adding a line, check what the bucket serves: the mirror answers 404 for a folder not uploaded.
50
50
  */
51
- export const NOT_MIRRORED = [
52
- ['https://cdn.jsdelivr.net/npm/espeak-ng@1.0.2',
53
- 'GPL: the mirror folder is ON HOLD until the matching source is published beside the build (issue #192)'],
54
- ];
51
+ export const NOT_MIRRORED = [];
55
52
  /** The path a mirror serves this upstream address under, or `null` when no mirror of this project holds it. */
56
53
  export function mirrorPathOf(url) {
57
54
  if (NOT_MIRRORED.some(([prefix]) => url.startsWith(prefix)))
@@ -1,7 +1,6 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  import { CACHE_HEAVY, HEAVY_FILES, type HeavyFile } from './heavy-catalogue.js';
3
3
  export { CACHE_HEAVY, HEAVY_FILES };
4
- export type { HeavyFile };
5
4
  /** What happened to each entry, so the caller can tell a person. */
6
5
  export interface HeavyReport {
7
6
  readonly id: string;
@@ -28,8 +27,16 @@ export interface HeavyOptions {
28
27
  * `crypto.subtle`, which is an insecure context) keeps NOTHING: unverifiable is not verified.
29
28
  */
30
29
  readonly digest: ((payload: ArrayBuffer) => Promise<string>) | null;
31
- /** Only these ids, when given. For a consumer that wants the voices and not the rest. */
30
+ /**
31
+ * Only these ids, when given, and IN THIS ORDER — the download is one at a time, so the order is who waits (`heavyAtBoot`
32
+ * puts everything of the child's language first). For a consumer that wants the voices and not the rest.
33
+ */
32
34
  readonly only?: readonly string[];
35
+ /**
36
+ * Files OUTSIDE the catalogue, kept by the same rules and FIRST: the font library's faces a cartridge declared
37
+ * (`platform/font-library`, ADR-0255) — a few hundred KB the child sees, which should not wait behind 850 MiB of models.
38
+ */
39
+ readonly also?: readonly HeavyFile[];
33
40
  /** The page's address the delivery's `heavy/` folder is resolved against (`document.baseURI`). */
34
41
  readonly base: string;
35
42
  }
@@ -38,21 +45,43 @@ export interface HeavyOptions {
38
45
  *
39
46
  * · The neural voice — its model, its voices AND the runtime that speaks them: without that answer they are 372 MB taken from a
40
47
  * school's link and a child's device for nothing.
41
- * · The reading models: 850 MiB for the three languages, so `reading` is not a yes or no but a LANGUAGE — the child's, known at
42
- * boot. A delivery may carry more than one; a device downloads the one being read in. A game that never listens gets none.
48
+ * · The reading models, one per language (850 MiB for the three): `reading` is a language or a LIST of them, like `commands`, and
49
+ * the root asks for every language the page can switch to, the child's first (ADR-0225 erratum, the Dev: «Negativo, baixar os
50
+ * três. Toda criança vai experimentar as três línguas imediatamente.»). A language the delivery's `--reading` list left out is a
51
+ * quiet 404 here and, when she reads in it, a line of `problems` and a sentence to her. A game that never listens gets none.
43
52
  * · 🔴 THE GRAPH RUNTIME IS NOT THE VOICE'S, and its `voz:` name said otherwise. `platform/onnx-runtime` runs Kokoro AND the
44
53
  * reading models, so a game that only LISTENS needs it: without this line its delivery carried a 378 MiB model and nothing
45
54
  * able to open it, and the first `listen()` asked for a file the build never wrote. Measured on 2026-09-21, building the
46
55
  * very delivery this exists to serve. The PHONEMIZER (`voz:runtime:fonemas`, 18.7 MiB) stays the voice's — nothing else
47
56
  * turns letters into sounds.
48
- * · The command models (issue #184): one per language too, 112 MiB for the three, and the runtime that loads them. Nothing in
57
+ * · The command models (issue #184): one per language too, 108 MiB for the three, and the runtime that loads them. Nothing in
49
58
  * the game decides this — speaking instead of pressing is a way INTO the controller, and a cartridge does not get to close
50
- * one (ADR-0111). What decides is the delivery: `inclusionist-heavy --commands pt` puts Portuguese in it.
59
+ * one (ADR-0111). `commands` is a language or a LIST of them, and the models come in the list's order: the root asks for
60
+ * every language the page can switch to, the child's first, because a language changed mid-game must find its model already
61
+ * kept (ADR-0225 erratum, the Dev: «A entrega leva as três línguas.»). The delivery carries the three unless its
62
+ * `--commands` list narrows it; a language it did not carry is a quiet 404 here and a line of `problems` when she speaks.
63
+ * · The Libras player (ADR-0234): the delivery's list of its avatar, clips, glosses and three.js chunk (34.9 MB in the engine's
64
+ * delivery), only with `libras`: the root asks for it while deaf mode is on, so a device whose child never asks for signing
65
+ * never downloads it. No game declares it either — deaf mode is the person's (ADR-0111) — and a delivery built without
66
+ * `--libras` simply has none, the same quiet 404 as a missing command model. No catalogue file is the player's: it is all the
67
+ * delivery's own, kept by what the delivery carries.
68
+ * The ids are the catalogue's files, then the delivery lists (`DELIVERY_LISTS`), by one rule.
69
+ *
70
+ * 🔴 THE ORDER IS WHO WAITS, because the download is one file at a time (rule 1): a file of a language takes that language's
71
+ * position in the list it was asked by, a file of no language (the runtimes, vision) takes the first, and the sort is stable. So
72
+ * everything of the child's language comes first, then each other language whole — her command model never waits behind 470 MiB
73
+ * of another language's reading.
74
+ * 🔴 AND WITHIN A POSITION, THE WAYS IN COME FIRST (`waitsBehind`): the command models and the camera's reader are how a child
75
+ * who does not press reaches the game at all (ADR-0111), and they have nothing to fall back on; the reading is the game's own
76
+ * listening, with nothing either; the neural voice comes last, because the browser's voice speaks meanwhile (ADR-0200). 📏 In
77
+ * the catalogue's order a 👄 turned on in a fresh install waited behind 336 MiB of neural voice and 378 MiB of reading for a
78
+ * 34 MiB model — seven seconds from a local disk, minutes on a school's link (measured on 2026-09-27).
51
79
  */
52
80
  export declare function heavyAtBoot(declared: {
53
81
  readonly kokoro: boolean;
54
- readonly reading?: string | null;
55
- readonly commands?: string | null;
82
+ readonly reading?: string | readonly string[] | null;
83
+ readonly commands?: string | readonly string[] | null;
84
+ readonly libras?: boolean;
56
85
  }): readonly string[];
57
86
  /**
58
87
  * WHERE THE DELIVERY SERVES A HEAVY FILE (ADR-0177, issue #173): `heavy/<host><path>` beside the page. The child's device
@@ -87,6 +116,9 @@ export declare function deliveryCacheKey(urlOrRequest: string | {
87
116
  * ⚠️ ENTRIES WITHOUT A `url` ARE NOT SKIPPED IN SILENCE — they return `sem-fonte`. It is the difference between "this
88
117
  * subsystem has nowhere to come from yet" and "this subsystem is handled", exactly the distinction ADR-0119 measured as
89
118
  * missing: the engine PROMISED four things and delivered one, with nothing saying so.
119
+ *
120
+ * The files handed in `also` come first (the declared library fonts), then the catalogue's, then the delivery's lists
121
+ * (`DELIVERY_LISTS`), each list ONE report for all its files.
90
122
  */
91
123
  export declare function downloadHeavy(options: HeavyOptions): Promise<HeavyReport[]>;
92
124
  /**
@@ -16,43 +16,95 @@
16
16
  // start over a resource it may not even use today.
17
17
  // 3. **IDEMPOTENT.** What is already in Cache Storage is not fetched again — which is what makes this safe to call on
18
18
  // every start instead of only "on the first", which nobody can detect honestly.
19
- import { CACHE_HEAVY, HEAVY_FILES, readingLanguageOf, commandsLanguageOf } from './heavy-catalogue.js';
19
+ import { CACHE_HEAVY, HEAVY_FILES, DELIVERY_LISTS, readingLanguageOf, commandsLanguageOf, } from './heavy-catalogue.js';
20
20
  export { CACHE_HEAVY, HEAVY_FILES };
21
+ /**
22
+ * Who waits behind whom inside one language's position (`heavyAtBoot`): 0 the ways in (the command models and runtime, the
23
+ * camera's reader), 1 the reading and the graph runtime it opens its models with, 2 the rest — the neural voice, which the
24
+ * browser's voice covers until it lands.
25
+ */
26
+ function waitsBehind(id) {
27
+ if (id.startsWith('commands:') || id.startsWith('visao:'))
28
+ return 0;
29
+ if (id.startsWith('reading:') || id.startsWith('voz:runtime:onnx'))
30
+ return 1;
31
+ return 2;
32
+ }
21
33
  /**
22
34
  * WHAT A GAME'S START FETCHES (ADR-0216 §3): the catalogue, less what this game did not ask for.
23
35
  *
24
36
  * · The neural voice — its model, its voices AND the runtime that speaks them: without that answer they are 372 MB taken from a
25
37
  * school's link and a child's device for nothing.
26
- * · The reading models: 850 MiB for the three languages, so `reading` is not a yes or no but a LANGUAGE — the child's, known at
27
- * boot. A delivery may carry more than one; a device downloads the one being read in. A game that never listens gets none.
38
+ * · The reading models, one per language (850 MiB for the three): `reading` is a language or a LIST of them, like `commands`, and
39
+ * the root asks for every language the page can switch to, the child's first (ADR-0225 erratum, the Dev: «Negativo, baixar os
40
+ * três. Toda criança vai experimentar as três línguas imediatamente.»). A language the delivery's `--reading` list left out is a
41
+ * quiet 404 here and, when she reads in it, a line of `problems` and a sentence to her. A game that never listens gets none.
28
42
  * · 🔴 THE GRAPH RUNTIME IS NOT THE VOICE'S, and its `voz:` name said otherwise. `platform/onnx-runtime` runs Kokoro AND the
29
43
  * reading models, so a game that only LISTENS needs it: without this line its delivery carried a 378 MiB model and nothing
30
44
  * able to open it, and the first `listen()` asked for a file the build never wrote. Measured on 2026-09-21, building the
31
45
  * very delivery this exists to serve. The PHONEMIZER (`voz:runtime:fonemas`, 18.7 MiB) stays the voice's — nothing else
32
46
  * turns letters into sounds.
33
- * · The command models (issue #184): one per language too, 112 MiB for the three, and the runtime that loads them. Nothing in
47
+ * · The command models (issue #184): one per language too, 108 MiB for the three, and the runtime that loads them. Nothing in
34
48
  * the game decides this — speaking instead of pressing is a way INTO the controller, and a cartridge does not get to close
35
- * one (ADR-0111). What decides is the delivery: `inclusionist-heavy --commands pt` puts Portuguese in it.
49
+ * one (ADR-0111). `commands` is a language or a LIST of them, and the models come in the list's order: the root asks for
50
+ * every language the page can switch to, the child's first, because a language changed mid-game must find its model already
51
+ * kept (ADR-0225 erratum, the Dev: «A entrega leva as três línguas.»). The delivery carries the three unless its
52
+ * `--commands` list narrows it; a language it did not carry is a quiet 404 here and a line of `problems` when she speaks.
53
+ * · The Libras player (ADR-0234): the delivery's list of its avatar, clips, glosses and three.js chunk (34.9 MB in the engine's
54
+ * delivery), only with `libras`: the root asks for it while deaf mode is on, so a device whose child never asks for signing
55
+ * never downloads it. No game declares it either — deaf mode is the person's (ADR-0111) — and a delivery built without
56
+ * `--libras` simply has none, the same quiet 404 as a missing command model. No catalogue file is the player's: it is all the
57
+ * delivery's own, kept by what the delivery carries.
58
+ * The ids are the catalogue's files, then the delivery lists (`DELIVERY_LISTS`), by one rule.
59
+ *
60
+ * 🔴 THE ORDER IS WHO WAITS, because the download is one file at a time (rule 1): a file of a language takes that language's
61
+ * position in the list it was asked by, a file of no language (the runtimes, vision) takes the first, and the sort is stable. So
62
+ * everything of the child's language comes first, then each other language whole — her command model never waits behind 470 MiB
63
+ * of another language's reading.
64
+ * 🔴 AND WITHIN A POSITION, THE WAYS IN COME FIRST (`waitsBehind`): the command models and the camera's reader are how a child
65
+ * who does not press reaches the game at all (ADR-0111), and they have nothing to fall back on; the reading is the game's own
66
+ * listening, with nothing either; the neural voice comes last, because the browser's voice speaks meanwhile (ADR-0200). 📏 In
67
+ * the catalogue's order a 👄 turned on in a fresh install waited behind 336 MiB of neural voice and 378 MiB of reading for a
68
+ * 34 MiB model — seven seconds from a local disk, minutes on a school's link (measured on 2026-09-27).
36
69
  */
37
70
  export function heavyAtBoot(declared) {
38
- const reading = declared.reading ? declared.reading.split('-')[0].toLowerCase() : null;
39
- const commands = declared.commands ? declared.commands.split('-')[0].toLowerCase() : null;
40
- return HEAVY_FILES.filter((p) => {
41
- const language = readingLanguageOf(p.id);
71
+ const reading = languagesAsked(declared.reading);
72
+ const commands = languagesAsked(declared.commands);
73
+ const asked = (id) => {
74
+ const language = readingLanguageOf(id);
42
75
  if (language)
43
- return language === reading;
76
+ return reading.includes(language);
44
77
  // 📌 THE COMMAND MODELS ARE A TRANSPORT'S, not a game's: no cartridge declares them, because a child who speaks instead of
45
- // pressing is reaching the controller, and a cartridge does not get to deny her a way in (ADR-0111). The LANGUAGE is still
46
- // asked — 112 MiB for the three — and the runtime comes with whichever one does.
47
- const commanded = commandsLanguageOf(p.id);
78
+ // pressing is reaching the controller, and a cartridge does not get to deny her a way in (ADR-0111). The LANGUAGES are
79
+ // still asked, and the runtime comes with whichever one is.
80
+ const commanded = commandsLanguageOf(id);
48
81
  if (commanded)
49
- return commanded === commands;
50
- if (p.id.startsWith('commands:runtime'))
51
- return !!commands;
52
- if (p.id.startsWith('voz:runtime:onnx'))
53
- return declared.kokoro || !!reading;
54
- return declared.kokoro || !(p.id.startsWith('voz:kokoro:') || p.id.startsWith('voz:runtime:'));
55
- }).map((p) => p.id);
82
+ return commands.includes(commanded);
83
+ if (id.startsWith('commands:runtime'))
84
+ return commands.length > 0;
85
+ if (id.startsWith('libras:'))
86
+ return !!declared.libras;
87
+ if (id.startsWith('voz:runtime:onnx'))
88
+ return declared.kokoro || reading.length > 0;
89
+ return declared.kokoro || !(id.startsWith('voz:kokoro:') || id.startsWith('voz:runtime:'));
90
+ };
91
+ const rank = (id) => {
92
+ const read = readingLanguageOf(id);
93
+ if (read)
94
+ return reading.indexOf(read);
95
+ const spoken = commandsLanguageOf(id);
96
+ return spoken ? commands.indexOf(spoken) : 0;
97
+ };
98
+ return [
99
+ // `Array.prototype.sort` is stable (ES2019): within a position and a kind, the catalogue's order — a runtime before its model
100
+ ...HEAVY_FILES.map((p) => p.id).filter(asked).sort((a, b) => rank(a) - rank(b) || waitsBehind(a) - waitsBehind(b)),
101
+ ...DELIVERY_LISTS.map((l) => l.id).filter(asked),
102
+ ];
103
+ }
104
+ /** The base languages asked — one tag or a list of them — without repeats, in the order asked (`es-MX` asks for `es`). */
105
+ function languagesAsked(asked) {
106
+ const tags = asked == null ? [] : typeof asked === 'string' ? [asked] : asked;
107
+ return [...new Set(tags.filter(Boolean).map((tag) => tag.split('-')[0].toLowerCase()))];
56
108
  }
57
109
  /**
58
110
  * WHERE THE DELIVERY SERVES A HEAVY FILE (ADR-0177, issue #173): `heavy/<host><path>` beside the page. The child's device
@@ -91,20 +143,28 @@ export function deliveryCacheKey(urlOrRequest) {
91
143
  * ⚠️ ENTRIES WITHOUT A `url` ARE NOT SKIPPED IN SILENCE — they return `sem-fonte`. It is the difference between "this
92
144
  * subsystem has nowhere to come from yet" and "this subsystem is handled", exactly the distinction ADR-0119 measured as
93
145
  * missing: the engine PROMISED four things and delivered one, with nothing saying so.
146
+ *
147
+ * The files handed in `also` come first (the declared library fonts), then the catalogue's, then the delivery's lists
148
+ * (`DELIVERY_LISTS`), each list ONE report for all its files.
94
149
  */
95
150
  export async function downloadHeavy(options) {
96
- const targets = options.only ? HEAVY_FILES.filter((p) => options.only.includes(p.id)) : HEAVY_FILES;
151
+ const targets = [...(options.also ?? []), ...(options.only
152
+ ? [...new Set(options.only)].flatMap((id) => HEAVY_FILES.filter((p) => p.id === id))
153
+ : HEAVY_FILES)];
154
+ const lists = DELIVERY_LISTS.filter((l) => !options.only || options.only.includes(l.id));
97
155
  const out = [];
98
156
  const record = (r) => { out.push(r); options.onProgress?.(r); };
99
157
  const { cacheStorage, fetch: fetchFile, digest, base } = options;
100
158
  if (!cacheStorage || !fetchFile) {
101
- for (const p of targets)
159
+ for (const p of [...targets, ...lists])
102
160
  record({ id: p.id, outcome: 'falhou', error: 'sem Cache Storage ou sem fetch' });
103
161
  return out;
104
162
  }
105
163
  const tools = { cache: await cacheStorage.open(CACHE_HEAVY), fetchFile, digest, base };
106
164
  for (const p of targets)
107
165
  record(await fetchOne(p, tools));
166
+ for (const l of lists)
167
+ record(await keepListed(l, tools));
108
168
  return out;
109
169
  }
110
170
  /** One file's fate: already kept, fetched from the delivery and checked, or refused — always with the reason. */
@@ -142,6 +202,101 @@ async function keepIfChecked(p, url, resp, t) {
142
202
  await t.cache.put(url, new Response(body, { status: resp.status, statusText: resp.statusText, headers: resp.headers }));
143
203
  return { id: p.id, outcome: 'baixado', bytes: p.bytes };
144
204
  }
205
+ /** The header a file kept from a delivery's list carries its listed sha256 in: how a later start knows it is kept, and current. */
206
+ const LISTED_SHA256 = 'x-inclusionist-sha256';
207
+ /**
208
+ * The files a delivery's list names, or a THROW saying why the list is refused whole: a list with no `files`, an entry without a
209
+ * path or a sha256, or one whose address falls outside the list's folders (a `..`, another origin, a query) — the list may only
210
+ * put the player's own files in the checked cache, never the game's page nor anything a route outside those folders serves.
211
+ */
212
+ function listedFiles(data, l, base) {
213
+ const files = data?.files;
214
+ if (!Array.isArray(files))
215
+ throw new Error('its `files` is missing');
216
+ const folders = l.folders.map((folder) => new URL(folder, base).href);
217
+ return files.map((f) => {
218
+ const { path, sha256 } = (f ?? {});
219
+ if (typeof path !== 'string' || typeof sha256 !== 'string' || !/^[0-9a-f]{64}$/.test(sha256)) {
220
+ throw new Error(`a listed file is malformed: ${JSON.stringify(f)}`);
221
+ }
222
+ const at = new URL(path, base);
223
+ const url = at.href;
224
+ if (at.search || at.hash || !folders.some((folder) => url.startsWith(folder) && url.length > folder.length)) {
225
+ throw new Error(`it names ${path}, outside ${l.folders.join(' and ')}`);
226
+ }
227
+ return { path, url, sha256 };
228
+ });
229
+ }
230
+ /**
231
+ * A DELIVERY'S LIST, KEPT FILE BY FILE (ADR-0234, pillar 8): the list is read from the page's origin, and each file it names is
232
+ * fetched from there, CHECKED against its listed sha256, and kept under its own address, where the service worker answers it
233
+ * offline. A file already kept with that sha256 is not fetched again; a body that is not the listed one is never kept, and the
234
+ * report names it. One report for the list: `baixado` with the bytes fetched, `ja-tinha`, or `falhou` with the files refused.
235
+ */
236
+ async function keepListed(l, t) {
237
+ const failed = (error) => ({ id: l.id, outcome: 'falhou', error });
238
+ const digest = t.digest;
239
+ if (!digest)
240
+ return failed('this host cannot compute a sha256 (crypto.subtle needs a secure context)');
241
+ const files = await readList(l, t);
242
+ if (typeof files === 'string')
243
+ return failed(files);
244
+ const refused = [];
245
+ let bytes = 0;
246
+ let fetched = 0;
247
+ for (const f of files) {
248
+ const kept = await keepListedFile(f, t, digest);
249
+ if (typeof kept === 'string')
250
+ refused.push(`${f.path}: ${kept}`);
251
+ else if (kept !== null) {
252
+ bytes += kept;
253
+ fetched += 1;
254
+ }
255
+ }
256
+ if (!refused.length)
257
+ return fetched ? { id: l.id, outcome: 'baixado', bytes } : { id: l.id, outcome: 'ja-tinha' };
258
+ const more = refused.length > 5 ? `; and ${refused.length - 5} more` : '';
259
+ return failed(`${refused.length} of ${files.length} files of ${l.path} not kept: ${refused.slice(0, 5).join('; ')}${more}`);
260
+ }
261
+ /** The list's files, or why it is refused whole (not there, not JSON, or naming what it may not). */
262
+ async function readList(l, t) {
263
+ try {
264
+ // never an old copy of the list: it is what says which files are current
265
+ const resp = await t.fetchFile(new URL(l.path, t.base).href, { cache: 'no-store' });
266
+ if (!resp.ok)
267
+ return `HTTP ${resp.status} — ${l.path}`;
268
+ return listedFiles(await resp.json(), l, t.base);
269
+ }
270
+ catch (e) {
271
+ return `the list ${l.path} is refused: ${e instanceof Error ? e.message : String(e)}`;
272
+ }
273
+ }
274
+ /** One listed file: `null` when it is already kept with its listed hash, the bytes kept, or why it was not kept. */
275
+ async function keepListedFile(f, t, digest) {
276
+ try {
277
+ if ((await t.cache.match(f.url))?.headers.get(LISTED_SHA256) === f.sha256)
278
+ return null;
279
+ /*
280
+ * 📌 THE LISTED HASH GOES IN THE QUERY: the service worker answers these folders from this cache by their address, so a file
281
+ * the list CHANGED would be answered with the copy it replaces. Another address reaches the delivery, and the old copy stays
282
+ * kept until the new one is checked — offline a child keeps the player she had.
283
+ */
284
+ const resp = await t.fetchFile(`${f.url}?sha256=${f.sha256}`);
285
+ if (!resp.ok)
286
+ return `HTTP ${resp.status}`;
287
+ const body = await resp.arrayBuffer();
288
+ const got = await digest(body);
289
+ if (got !== f.sha256)
290
+ return `sha256 mismatch: expected ${f.sha256}, got ${got} — not kept`;
291
+ const headers = new Headers(resp.headers);
292
+ headers.set(LISTED_SHA256, f.sha256);
293
+ await t.cache.put(f.url, new Response(body, { status: resp.status, statusText: resp.statusText, headers }));
294
+ return body.byteLength;
295
+ }
296
+ catch (e) {
297
+ return e instanceof Error ? e.message : String(e);
298
+ }
299
+ }
145
300
  /**
146
301
  * THE SHA-256 OF A BODY AS LOWERCASE HEX, by the `crypto.subtle` it is handed (issue #168) — or `null` when there is none,
147
302
  * which is a host outside a secure context: the answer `HeavyOptions.digest` reads as «cannot hash, so keep nothing».
@@ -1,19 +1,26 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- /** What the caller provides. Nothing here knows the neural engine, Web Audio or the browser. */
3
- export interface SpeechEngine<Audio, Fonte> {
4
- /** Text → audio. ASYNCHRONOUS on purpose: it is where neural synthesis spends its time. */
5
- synthesize(text: string): Promise<Audio>;
2
+ /**
3
+ * What the caller provides. Nothing here knows the neural engine, Web Audio or the browser. `Request` is what one utterance
4
+ * asks for: a text by default, or a text with the voice that reads it (ADR-0243 §2).
5
+ */
6
+ export interface SpeechEngine<Audio, Fonte, Request = string> {
7
+ /** Request → audio. ASYNCHRONOUS on purpose: it is where neural synthesis spends its time. */
8
+ synthesize(request: Request): Promise<Audio>;
6
9
  /** Starts playing and returns the source, so it can be stopped. `null` = it could not play right now. */
7
10
  play(audio: Audio, onEnded: () => void): Fonte | null;
8
11
  /** Silences the source. Called with what `play` returned, and never with `null`. */
9
12
  stop(playing: Fonte): void;
10
13
  }
11
- export interface InterruptibleSpeech {
12
- /** Speaks `text`, SILENCING at once whatever is speaking. It does not queue: the latest request is the one that counts. */
13
- speak(text: string): void;
14
+ export interface InterruptibleSpeech<Request = string> {
15
+ /**
16
+ * Speaks `request`, SILENCING at once whatever is speaking. It does not queue: the latest request is the one that counts.
17
+ * `finished` is called ONCE, when this utterance is over for any reason — it ended, it was silenced or overtaken, or it could
18
+ * not be synthesised or played — so a caller speaking parts in order (ADR-0243 §1) knows when to go on, and never waits forever.
19
+ */
20
+ speak(request: Request, finished?: () => void): void;
14
21
  /** Silences and forgets. Used when a menu closes or narration is switched off. */
15
22
  silence(): void;
16
23
  /** Is anything playing? For tests and debugging only — the policy does not depend on it. */
17
24
  speaking(): boolean;
18
25
  }
19
- export declare function createInterruptibleSpeech<Audio, Fonte>(engine: SpeechEngine<Audio, Fonte>): InterruptibleSpeech;
26
+ export declare function createInterruptibleSpeech<Audio, Fonte, Request = string>(engine: SpeechEngine<Audio, Fonte, Request>): InterruptibleSpeech<Request>;