@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,41 +1,32 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- // ui/hud.ts — HUD POR TELA + a infraestrutura de TELAS do jogo (Estágio 4). Duas responsabilidades coladas
3
- // desde sempre no game.js: (a) a GRADE de `.player-screen` dentro de `#game-hud` — um contêiner por jogador,
4
- // posicionado em %, que hospeda o HUD, o selo "jogo abandonado", o selo "aperte um botão para entrar"
5
- // (`.vp-wait`), o menu de pausa daquele jogador e (em MP) o overlay de quiz dele; e (b) o CONTEÚDO do HUD —
6
- // o OBJETIVO do jogador e o poder ativo — reescrito a cada frame por updateGameHud().
2
+ // ui/hud.ts — PER-SCREEN HUD + the game's SCREEN infrastructure. Two responsibilities: (a) the GRID of
3
+ // `.player-screen` inside `#game-hud` — one container per player, positioned in %, hosting the HUD, the quit badge, the
4
+ // press-a-button-to-join badge (`.vp-wait`), that player's pause menu and (in multiplayer) their quiz overlay; and (b)
5
+ // the HUD's CONTENT — the player's OBJECTIVE and active power — rewritten every frame by updateGameHud().
7
6
  //
8
- // ========================= O CONTADOR DEIXOU DE SER DE MOEDA (item 19) =========================
9
- // O passo 4 do ADR-0027 matou a DEPENDÊNCIA (`vphudHtml(coinTarget = COIN_TARGET)` virou parâmetro
10
- // obrigatório); o que sobrou era VOCABULÁRIO — o ícone cravado no markup, a classe `vphud-coins`, o campo
11
- // `coins` do view-model. Nome não é seguido pelo compilador e não impede um pacote de se separar, e por isso
12
- // a dívida era menor. Não era nula: ela dizia, em toda tela, que este HUD é de um jogo de plataforma.
7
+ // ========================= THE COUNTER IS NOT A COIN COUNTER =========================
8
+ // The counter receives an `Objective` — field 5 of `core/contract` — and the icon comes in by injection, so the HUD
9
+ // shows what the game declared without knowing whether it is a coin, a word or a sum. And `Objective.name` gives the
10
+ // counter an ACCESSIBLE NAME: without it a blind child would hear "3 / 10", two numbers with no noun — the engine did
11
+ // not know the name of what is collected. Now the game declares it.
13
12
  //
14
- // Agora o contador recebe um `Objective` — campo 5 de `core/contract` — e o ícone entra por injeção. E a
15
- // mudança compra mais do que um nome: com `Objective.name` o contador GANHOU NOME ACESSÍVEL. Até aqui a
16
- // criança cega ouvia o contador como "3 / 10", dois números sem substantivo — não havia o que falar porque a
17
- // engine não sabia o nome do que se junta. Agora sabe, porque o jogo declara.
13
+ // The HUD is OVERLAID DOM (not pixelated: it stays in high definition over the 320×180 canvas) — which is why it lives
14
+ // here and not in render. The pause menu is NOT this module's: `buildScreenPause(i)` comes in by injection, and this
15
+ // module only attaches the result to the right screen and hands the finished panels back through `onScreensBuilt`.
18
16
  //
19
- // O HUD é DOM SOBREPOSTO (não pixela: fica em alta definição sobre o canvas 320×180) — por isso vive aqui e
20
- // não no render. O menu de pausa NÃO é deste módulo: `buildScreenPause(i)` entra por injeção e este módulo só
21
- // anexa o retorno na tela certa e devolve os painéis prontos por `onScreensBuilt` (o game.js guarda `vpPause`
22
- // e o `pauseActor`, que são do slice de pausa/ícones). Ver docs/5-Refactoring/plano-modularizacao-mapa.md.
23
- //
24
- // Sem I/O no import: `document` só aparece DENTRO das funções → o módulo é importável no project node, onde os
25
- // testes exercitam só a metade PURA (screenGrid/screenRect/hudRowView/vphudHtml/waitBadgeHtml).
17
+ // No I/O on import: `document` only appears INSIDE functions → the module is importable in the node project, where the
18
+ // tests exercise only the PURE half (screenGrid/screenRect/hudRowView/vphudHtml/waitBadgeHtml).
26
19
  import { screenGrid } from '../core/screens.js';
27
- import { t } from '../core/i18n.js';
28
20
  // ---------------------------------------------------------------------------------------------
29
- // Lógica PURA (nenhum `document`; testável no project node)
21
+ // PURE logic (no `document`; testable in the node project)
30
22
  // ---------------------------------------------------------------------------------------------
31
- /** Grade de telas: 1 → 1×1, 2 → 2×1, 3-4 → 2×2 (a 3ª tela é centralizada na linha de baixo). */
32
- // A grade agora mora em core/screens (folha, sem dependências), porque o layout e o CRT precisam da MESMA
33
- // conta e não têm o que fazer importando de um módulo de HUD. Reexportada aqui sob o nome de sempre.
23
+ /** Screen grid: 1 → 1×1, 2 → 2×1, 3-4 → 2×2 (the 3rd screen is centred on the bottom row). */
24
+ // The grid lives in core/screens (a leaf, no dependencies), because the layout and the CRT need the SAME arithmetic and
25
+ // have no business importing from a HUD module. Re-exported here under its usual name.
34
26
  export { screenGrid } from '../core/screens.js';
35
27
  /**
36
- * Posição/tamanho da tela `i` numa grade de `n` jogadores. Verbatim de screenRect(i) — que lia `numPlayers`
37
- * global; aqui `n` é parâmetro (mesma conta, testável sem estado). Caso especial preservado: com 3 telas, a
38
- * terceira é centralizada na linha de baixo, para casar com o posicionamento do render (configureRender).
28
+ * Position/size of screen `i` in a grid of `n` players; `n` is a parameter, so it is testable without state. Special
29
+ * case: with 3 screens, the third is centred on the bottom row, to match the renderer's positioning.
39
30
  */
40
31
  export function screenRect(i, n) {
41
32
  const { cols, rows } = screenGrid(n);
@@ -45,83 +36,88 @@ export function screenRect(i, n) {
45
36
  colFrac = (1 - 1 / cols) / 2;
46
37
  return { L: (colFrac * 100) + '%', T: (row / rows * 100) + '%', W: (100 / cols) + '%', H: (100 / rows) + '%' };
47
38
  }
48
- /** Quantas telas o HUD monta: ao menos uma, mesmo antes de `players[]` existir no boot. Verbatim (Math.max(1,…)). */
39
+ /** How many screens the HUD mounts: at least one, even before `players[]` exists at boot. */
49
40
  export function screenCount(n) { return Math.max(1, n); }
50
- /** O texto que o leitor de tela ouve no contador. A MOLDURA é a chave; o NOME do objetivo atravessa por
51
- * parâmetro — a regra do pilar 3 (ADR-0010), a mesma que o currículo segue. */
52
- export const contadorLabel = (o) => t('hud.contador', { have: String(o.have), need: String(o.need), nome: o.name.text });
41
+ /** The text a screen reader hears on the counter. The FRAME is the key; the objective's NAME passes through as a
42
+ * parameter — pillar 3's rule (ADR-0010), the same the curriculum follows. */
43
+ export const counterLabel = (t, o) => t('hud.contador', { have: String(o.have), need: String(o.need), nome: o.name.text });
53
44
  /**
54
- * Markup do contador (objetivo na 1ª coluna, poder na 2ª).
45
+ * The counter's markup (objective in the 1st column, power in the 2nd).
55
46
  *
56
- * O objetivo entra INTEIRO — nome, quanto tem, quanto precisa — em vez de só o alvo numérico, e o ícone entra
57
- * por injeção. É o que tira o desenho da moeda de dentro da engine: o HUD mostra o que o jogo declarou
58
- * (campo 5 do contrato), sem saber se é moeda, palavra ou conta.
47
+ * The objective comes in WHOLE — name, how much you have, how much you need — and the icon by injection: the HUD shows
48
+ * what the game declared (field 5 of the contract), without knowing whether it is a coin, a word or a sum.
59
49
  *
60
- * O `aria-label` é a parte que não é renomeação: sem o nome do objetivo não havia o que dizer, e o contador
61
- * era mudo para quem não vê a tela.
50
+ * The accessible name is set separately (`applyCounterLabel`), because the objective's name is outside data.
62
51
  */
63
- export function vphudHtml(objetivo, icone) {
64
- return '<span class="vphud-obj"><b class="vphud-ico">' + icone
65
- + '</b> <b class="vphud-n">' + numero(objetivo.have) + '</b> / ' + numero(objetivo.need)
52
+ export function vphudHtml(objective, icon) {
53
+ return '<span class="vphud-obj"><b class="vphud-ico">' + icon
54
+ + '</b> <b class="vphud-n">' + finiteOrZero(objective.have) + '</b> / ' + finiteOrZero(objective.need)
66
55
  + '</span><span class="vphud-power"><b class="vphud-ico">✨</b> <span class="vphud-pw">—</span></span>';
67
56
  }
68
57
  /**
69
- * PÕE O NOME DECLARADO PELO JOGO NO RÓTULO DO LEITOR DE TELA — por atributo, nunca por markup (issue #106).
58
+ * PUTS THE NAME THE GAME DECLARED INTO THE SCREEN READER'S LABEL — by attribute, never by markup (issue #106).
70
59
  *
71
- * ⚠️ ESTE É UM VETOR QUE A AUDITORIA DE 2026-08-26 NÃO TINHA COMO CONHECER, e vale dizer por quê: ela varreu
72
- * por FONTE DE DADO e concluiu, com razão para a época, que nada de fora chegava a markup. Depois disso o
73
- * contrato passou a existir (ADR-0030) e os jogos passaram a viver em REPOSITÓRIOS SEPARADOS, consumindo a
74
- * engine como pacote (ADR-0083). O `name.text` do objetivo é texto de um jogo que esta árvore não revê.
60
+ * ⚠️ The games live in SEPARATE REPOSITORIES and consume the engine as a package (ADR-0083), so the objective's
61
+ * `name.text` is text from a game this tree does not review.
75
62
  *
76
- * ⚠️ E ELE ENTRAVA NUM ATRIBUTO, que é o pior contexto dos dois: dentro de um elemento uma aspa é inofensiva,
77
- * dentro de `aria-label="…"` ela FECHA o atributo e o que vem a seguir vira atributo — um `onmouseover` sem
78
- * precisar de uma única tag.
63
+ * ⚠️ AND IT GOES INTO AN ATTRIBUTE, the worse of the two contexts: inside an element a quote is harmless; inside
64
+ * `aria-label="…"` it CLOSES the attribute and what follows becomes an attribute — an `onmouseover` without a single
65
+ * tag.
79
66
  *
80
- * `setAttribute` escapa por construção, e é por isso que a resposta é «construir nós» e não «escapar à mão»:
81
- * um escape esquecido não deixa rasto; um `setAttribute` esquecido tira o rótulo, e há caso a prendê-lo.
67
+ * `setAttribute` escapes by construction, which is why the answer is building nodes and not escaping by hand: a
68
+ * forgotten escape leaves no trace; a forgotten `setAttribute` removes the label, and a case holds it.
82
69
  */
83
- export function aplicarRotuloDoContador(vphud, objetivo) {
84
- vphud?.querySelector('.vphud-obj')?.setAttribute('aria-label', contadorLabel(objetivo));
70
+ export function applyCounterLabel(t, vphud, objective) {
71
+ vphud?.querySelector('.vphud-obj')?.setAttribute('aria-label', counterLabel(t, objective));
85
72
  }
86
73
  /**
87
- * Um número do jogo, coagido.
74
+ * A number from the game, coerced.
88
75
  *
89
- * ⚠️ `Objective.have` É `number` NO TIPO E O TIPO NÃO ATRAVESSA A FRONTEIRA DO PACOTE: um jogo em JavaScript
90
- * puro, ou compilado de outra árvore, devolve o que quiser. Colar isso num template literal é a mesma
91
- * categoria de defeito que o nome — só que mais fácil de esquecer, porque «é um número» está escrito no tipo.
92
- * Um não-número vira `0`, que é falso mas inofensivo; deixar passar seria falso E perigoso.
76
+ * ⚠️ `Objective.have` IS `number` IN THE TYPE AND THE TYPE DOES NOT CROSS THE PACKAGE BOUNDARY: a game in plain
77
+ * JavaScript, or compiled from another tree, returns whatever it likes. Pasting that into a template literal is the
78
+ * same category of defect as the name — only easier to forget, because "it is a number" is written in the type. A
79
+ * non-number becomes `0`, which is false but harmless; letting it through would be false AND dangerous.
93
80
  */
94
- function numero(v) {
81
+ function finiteOrZero(v) {
95
82
  return Number.isFinite(v) ? v : 0;
96
83
  }
97
- /** Markup do selo "aperte um botão para entrar" (tela criada em jogo, ainda sem dono). `i` é o índice 0-based. */
98
- export function waitBadgeHtml(i) {
99
- return '<div class="vphud-quit vp-wait">Jogador ' + (i + 1)
100
- + ': aperte um botão do SEU teclado ou de um controle livre para entrar</div>';
84
+ /**
85
+ * The markup of the press-a-button-to-join badge (a screen created mid-game, still with no owner). `i` is 0-based.
86
+ *
87
+ * 🔴 FROM THE DICTIONARY, never raw text: it is the only sentence that tells the child who just got a screen HOW to join,
88
+ * and the badge is their whole screen at that instant, not a corner detail.
89
+ *
90
+ * 📌 ITS OWN KEY and not the existing `sr.player.pressToJoin`, although the two look alike: the screen reader's says to
91
+ * press a button, this one says WHICH — your own keyboard or a free controller —, because whoever reads it is looking
92
+ * at a screen with other people around and needs to know it is not just any keyboard. Merging them would erase that
93
+ * half of one of the two.
94
+ */
95
+ export function waitBadgeHtml(t, i) {
96
+ return '<div class="vphud-quit vp-wait">' + t('hud.waitBadge', { n: i + 1 }) + '</div>';
101
97
  }
102
98
  /**
103
- * Estado do HUD de um jogador. Verbatim do corpo de updateGameHud(), só que como valor.
104
- * `powerShort` é o POWER_SHORT do game.js (injetado — a mesma FUNÇÃO que game/coin-spawning.ts já recebe).
105
- * Função e não tabela: o texto depende do idioma ATUAL, e uma tabela lida no boot ficaria congelada nele.
99
+ * One player's HUD state, as a value. `powerShort` is injected by the host (the same function other game modules
100
+ * receive). A function and not a table: the text depends on the CURRENT language, and a table read at boot would stay
101
+ * frozen in it.
106
102
  */
107
- export function hudRowView(p, powerShort, objetivo) {
103
+ export function hudRowView(t, p, powerShort, objective) {
108
104
  return {
109
- have: String(objetivo.have),
110
- label: contadorLabel(objetivo),
111
- // O `|| '—'` FICA, mesmo com o resolvedor já tratando desconhecido. Não é redundância: é a garantia de
112
- // que o campo do poder NUNCA aparece em branco no HUD, e ela não pode depender de todo consumidor futuro
113
- // lembrar de tratar o caso. Um teste meu ia perdê-la nesta mudança e reprovou por isso.
105
+ have: String(objective.have),
106
+ label: counterLabel(t, objective),
107
+ // The `|| '—'` STAYS, even with the resolver already handling unknowns. It is not redundancy: it guarantees the
108
+ // power field NEVER appears blank on the HUD, and that cannot depend on every future consumer remembering the case.
114
109
  power: powerShort(p.activePower) || '—',
115
110
  quitHidden: !p.quit,
116
111
  visibility: p.quit ? 'hidden' : 'visible',
117
112
  };
118
113
  }
119
114
  export function initHud(ctx) {
115
+ const { t } = ctx;
120
116
  let gameHudEl = null;
121
117
  let vpHudDom = [];
122
118
  let vpQuitDom = [];
123
119
  let vpScreens = [];
124
- /** A sub-camada de EXPERIÊNCIA de cada tela — o que a empatia atrapalha. Ver `buildGameHud`. */
120
+ /** Each screen's EXPERIENCE sub-layer — what empathy gets in the way of. See `buildGameHud`. */
125
121
  let vpExpDom = [];
126
122
  function buildGameHud() {
127
123
  if (!gameHudEl)
@@ -136,44 +132,46 @@ export function initHud(ctx) {
136
132
  const panes = [];
137
133
  const bars = [];
138
134
  const n = ctx.getNumPlayers();
135
+ // the screens are made by the document the hud is drawn in — the host's own, never the global (ADR-0221 step 7d)
136
+ const doc = gameHudEl.ownerDocument;
139
137
  for (let i = 0; i < screenCount(n); i++) {
140
138
  const r = screenRect(i, n);
141
- const scr = document.createElement('div');
139
+ const scr = doc.createElement('div');
142
140
  scr.className = 'player-screen';
143
141
  scr.dataset.player = String(i);
144
142
  scr.style.left = r.L;
145
143
  scr.style.top = r.T;
146
144
  scr.style.width = r.W;
147
145
  scr.style.height = r.H;
148
- // A TELA TEM DUAS SUB-CAMADAS, e a divisão é de PAPEL (issue #82, decisão do Dev):
146
+ // THE SCREEN HAS TWO SUB-LAYERS, divided by ROLE (issue #82, the Dev's decision):
149
147
  //
150
- // · EXPERIÊNCIA (`.screen-exp`) — HUD, selo de abandono e a atividade pedagógica do multi-tela. O
151
- // modo de EMPATIA precisa atrapalhar aqui: é o prejuízo que a pessoa tem de sentir.
152
- // · CONTROLE (o painel de pausa, irmão) — nunca é atingido por empatia. Simulação não é
153
- // acessibilidade: é criar dificuldade onde a facilidade não existe. O que existe para DAR ACESSO
154
- // — pausa, legenda, controle de toque — não pode ser degradado por ela.
148
+ // · EXPERIENCE (`.screen-exp`) — HUD, quit badge and the multi-screen learning activity. EMPATHY mode has to get
149
+ // in the way here: it is the harm the person has to feel.
150
+ // · CONTROL (the pause panel, a sibling) — never touched by empathy. Simulation is not accessibility: it creates
151
+ // difficulty where ease does not exist. What exists to GIVE ACCESS — pause, captions, touch controls — cannot
152
+ // be degraded by it.
155
153
  //
156
- // Elas são IRMÃS e não pai/filho porque `filter` de CSS desce para os descendentes e um filho não
157
- // consegue cancelá-lo: com a pausa dentro da experiência, não haveria como isentá-la.
158
- const exp = document.createElement('div');
154
+ // They are SIBLINGS and not parent/child because a CSS `filter` descends to descendants and a child cannot cancel
155
+ // it: with the pause inside the experience, there would be no way to exempt it.
156
+ const exp = doc.createElement('div');
159
157
  exp.className = 'screen-exp';
160
158
  scr.appendChild(exp);
161
159
  vpExpDom.push(exp);
162
- const d = document.createElement('div');
160
+ const d = doc.createElement('div');
163
161
  d.className = 'vphud';
164
162
  d.innerHTML = vphudHtml(ctx.hudObjective(i), ctx.hudIcon);
165
- aplicarRotuloDoContador(d, ctx.hudObjective(i)); // #106: o nome vem do JOGO — atributo, nunca markup
163
+ applyCounterLabel(t, d, ctx.hudObjective(i)); // #106: the name comes from the GAME — attribute, never markup
166
164
  exp.appendChild(d);
167
165
  vpHudDom.push(d);
168
- const q = document.createElement('div');
166
+ const q = doc.createElement('div');
169
167
  q.className = 'vphud-quit';
170
168
  q.hidden = true;
171
169
  q.textContent = 'Jogo abandonado';
172
170
  exp.appendChild(q);
173
171
  vpQuitDom.push(q);
174
- // A BARRA RÁPIDA entra entre a experiência e a pausa, e é IRMÃ das duas. Não vai DENTRO da
175
- // `.screen-exp` porque `filter` de CSS desce para os descendentes e um filho não consegue cancelá-lo:
176
- // ali dentro, o modo empatia degradaria justamente o que existe para dar acesso.
172
+ // THE QUICK BAR goes between the experience and the pause, as a SIBLING of both. Not INSIDE `.screen-exp`, because
173
+ // a CSS `filter` descends to descendants and a child cannot cancel it: in there, empathy mode would degrade exactly
174
+ // what exists to give access.
177
175
  const bar = ctx.buildQuickBar(i);
178
176
  scr.appendChild(bar);
179
177
  bars.push(bar);
@@ -183,9 +181,7 @@ export function initHud(ctx) {
183
181
  gameHudEl.appendChild(scr);
184
182
  vpScreens.push(scr);
185
183
  }
186
- // O original terminava com `vpPause` preenchido e dois efeitos DEFENSIVOS (applyLetra/renderPauseLegend em
187
- // try/catch, porque no 1º build do init LETRA/PAD_DESIGNS ainda estão em TDZ). Ambos são de OUTROS slices →
188
- // saem por este gancho, com o try/catch preservado no game.js. Ver "chamada defensiva" no relatório.
184
+ // What depends on the finished panels belongs to other modules, so it leaves through these hooks.
189
185
  ctx.onBarsBuilt?.(bars);
190
186
  ctx.onScreensBuilt?.(panes);
191
187
  }
@@ -195,12 +191,12 @@ export function initHud(ctx) {
195
191
  if (!p)
196
192
  continue;
197
193
  const d = vpHudDom[i];
198
- const v = hudRowView(p, ctx.powerShort, ctx.hudObjective(i));
194
+ const v = hudRowView(t, p, ctx.powerShort, ctx.hudObjective(i));
199
195
  const n = d.querySelector('.vphud-n');
200
196
  if (n)
201
197
  n.textContent = v.have;
202
- // O rótulo acessível acompanha o número. Escrevê-lo só na montagem deixaria o leitor de tela repetindo
203
- // "0 de 10" a partida inteira — pior do que não ter rótulo, porque soa como informação.
198
+ // The accessible label follows the number. Writing it only at mount would leave the screen reader repeating
199
+ // "0 of 10" the whole match — worse than no label, because it sounds like information.
204
200
  const obj = d.querySelector('.vphud-obj');
205
201
  if (obj)
206
202
  obj.setAttribute('aria-label', v.label);
@@ -210,14 +206,14 @@ export function initHud(ctx) {
210
206
  if (vpQuitDom[i])
211
207
  vpQuitDom[i].hidden = v.quitHidden;
212
208
  if (d)
213
- d.style.visibility = v.visibility; // jogador que saiu: tela preta "jogo abandonado"
209
+ d.style.visibility = v.visibility; // a player who left: black screen with the quit badge
214
210
  }
215
211
  }
216
212
  const getScreen = (i) => vpScreens[i] ?? null;
217
213
  function showWaitingBadge(i) {
218
214
  const scr = vpScreens[i];
219
215
  if (scr && !scr.querySelector('.vp-wait'))
220
- scr.insertAdjacentHTML('beforeend', waitBadgeHtml(i));
216
+ scr.insertAdjacentHTML('beforeend', waitBadgeHtml(t, i));
221
217
  }
222
218
  function clearWaitingBadge(i) {
223
219
  const scr = vpScreens[i];
@@ -1,19 +1,20 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ import type { Translate } from '../core/i18n.js';
2
3
  export interface ItemDeMenu {
3
- /** O que o item é. Espaço em branco de markup é normalizado aqui. */
4
- rotulo: string;
5
- /** O valor ou estado: "ativado", "38%", a palavra de exemplo do minijogo. Opcional. */
6
- estado?: string;
7
- /** Posição na lista, contada a partir de 1 — é o número que a criança ouve, não o índice do array. */
8
- posicao: number;
9
- /** Quantos itens a lista tem. */
4
+ /** What the item is. Markup whitespace is normalised here. */
5
+ label: string;
6
+ /** The value or state: "on", "38%", the game's example word. Optional. */
7
+ state?: string;
8
+ /** Position in the list, counted from 1 — the number the child hears, not the array index. */
9
+ position: number;
10
+ /** How many items the list has. */
10
11
  total: number;
11
12
  }
12
13
  /**
13
- * A frase que o item narra.
14
+ * The sentence the item narrates.
14
15
  *
15
- * A posição fora de faixa NÃO é anunciada, e é decisão, não guarda defensivo: um item filtrado por
16
- * visibilidade sai da lista e deixa o índice de quem sobrou fora dela. "0 de 7" ensina uma geografia falsa
17
- * do menu, e a criança confia nela — número errado é pior que número nenhum.
16
+ * An out-of-range position is NOT announced, and that is a decision, not a defensive guard: an item filtered out
17
+ * by visibility leaves the list and can leave the index of the ones that remain out of range. "0 of 7" teaches a
18
+ * false geography of the menu, and the child trusts it — a wrong number is worse than no number.
18
19
  */
19
- export declare function anunciarItem(item: ItemDeMenu, comIndice: boolean): string;
20
+ export declare function announceItem(t: Translate, item: ItemDeMenu, withIndex: boolean): string;
@@ -1,36 +1,35 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- // ui/item-announcement — COMO UM ITEM DE MENU SE ANUNCIA (ADR-0044, item 3).
2
+ // ui/item-announcement — HOW A MENU ITEM ANNOUNCES ITSELF (ADR-0044, item 3; ADR-0167).
3
3
  //
4
- // A XAG 106 descreve a frase inteira — "Gamma, slider, 38%, 6 of 9" — e este módulo monta a parte que o jogo
5
- // controla: RÓTULO, ESTADO e ÍNDICE, nessa ordem, com o índice no FIM.
4
+ // XAG 106 describes the whole sentence — "Gamma, slider, 38%, 6 of 9" — and this module builds the part the game
5
+ // controls: LABEL, STATE and INDEX, in that order, with the index at the END.
6
6
  //
7
- // POR QUE O ÍNDICE VAI NO FIM. Quem varre um menu por escuta interrompe assim que reconhece o item — é o que
8
- // a narração interrompível do item 2 passou a permitir. Com o número na frente, a contagem seria a única
9
- // parte que SEMPRE daria tempo de ouvir, e o rótulo, a única que interessa, a que nunca chegaria.
7
+ // WHY THE INDEX GOES LAST. Whoever scans a menu by ear interrupts as soon as they recognise the item — which the
8
+ // interruptible narration allows. With the number first, the count would be the one part there is ALWAYS time to
9
+ // hear, and the label, the only part that matters, the one that never arrives.
10
10
  //
11
- // POR QUE ELE PODE SER DESLIGADO. Para quem já sabe o menu de cor, o número vira ruído em toda passagem. A
12
- // XAG pede a opção explicitamente, e o princípio é o mesmo do resto do projeto: acessibilidade que não se
13
- // pode desligar é imposição, não ajuste.
11
+ // WHY IT CAN BE TURNED OFF. For someone who knows the menu by heart, the number is noise on every pass. XAG asks
12
+ // for the option explicitly, and the principle is the one the whole project follows: accessibility that cannot be
13
+ // turned off is an imposition, not a setting.
14
14
  //
15
- // ESTE MÓDULO NÃO TOCA O DOM. Quem chama separa as partes (o rótulo do botão, o sub-rótulo, o estado do
16
- // alternador) e recebe uma frase. É o que permite que a regra seja a MESMA na abertura, na pausa e nas
17
- // atividades sem que cada tela reinvente a pontuação.
18
- import { t } from '../core/i18n.js';
19
- /** Espaço em branco de markup (quebras de linha, indentação) vira UM espaço; pontas somem. */
20
- const enxuto = (s) => (s || '').replace(/\s+/g, ' ').trim();
15
+ // THIS MODULE DOES NOT TOUCH THE DOM. The caller separates the parts (the button's label, the sub-label, the
16
+ // toggle's state) and gets a sentence back. That is what keeps the rule the SAME on every screen, without each
17
+ // one reinventing the punctuation.
18
+ /** Markup whitespace (line breaks, indentation) becomes ONE space; the ends are trimmed. */
19
+ const tidy = (s) => (s || '').replace(/\s+/g, ' ').trim();
21
20
  /**
22
- * A frase que o item narra.
21
+ * The sentence the item narrates.
23
22
  *
24
- * A posição fora de faixa NÃO é anunciada, e é decisão, não guarda defensivo: um item filtrado por
25
- * visibilidade sai da lista e deixa o índice de quem sobrou fora dela. "0 de 7" ensina uma geografia falsa
26
- * do menu, e a criança confia nela — número errado é pior que número nenhum.
23
+ * An out-of-range position is NOT announced, and that is a decision, not a defensive guard: an item filtered out
24
+ * by visibility leaves the list and can leave the index of the ones that remain out of range. "0 of 7" teaches a
25
+ * false geography of the menu, and the child trusts it — a wrong number is worse than no number.
27
26
  */
28
- export function anunciarItem(item, comIndice) {
29
- const valeIndice = comIndice && item.total >= 1 && item.posicao >= 1 && item.posicao <= item.total;
30
- const partes = [
31
- enxuto(item.rotulo),
32
- enxuto(item.estado),
33
- valeIndice ? t('sr.menu.index', { n: item.posicao, m: item.total }) : '',
27
+ export function announceItem(t, item, withIndex) {
28
+ const indexApplies = withIndex && item.total >= 1 && item.position >= 1 && item.position <= item.total;
29
+ const parts = [
30
+ tidy(item.label),
31
+ tidy(item.state),
32
+ indexApplies ? t('sr.menu.index', { n: item.position, m: item.total }) : '',
34
33
  ];
35
- return partes.filter(Boolean).join(', ');
34
+ return parts.filter(Boolean).join(', ');
36
35
  }
@@ -1,38 +1,113 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  /**
3
- * A RÉGUA DO ALVO DE TOQUE, INDEXADA PELA ALTURA DO VIEWPORT (ADR-0095, decisão do Dev).
3
+ * THE TOUCH TARGET FLOOR, in CSS px, for a CSS scale factor `k` (ADR-0163).
4
4
  *
5
- * ⚠️ 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
6
- * `pausa-44px` já tinha MEDIDO e deixado por resolver: a 640×360 o cartão de pausa não cabe e a lista ROLA.
7
- * 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
8
- * de excesso (o comentário antigo dizia 413/353). Um alvo de 44 px que exige rolagem para ser alcançado
9
- * pode custar mais dedo do que um de 24 px que está à vista.
5
+ * 🔴 IT WAS A RULER BY VIEWPORT HEIGHT (ADR-0095: 24 px under 540, 34 under 720, 44 above), because a 640×360 pause
6
+ * card with 44 px items scrolled. ADR-0163 made the resolution the engine's — never under 640×360 — and the Dev set the
7
+ * target — «44px é o correto, eu errei quando disse 42px» — so the floor is 44 px at the minimum (k = 2) and
8
+ * grows with the scale, like the text; there is no smaller screen left to shrink for.
9
+ */
10
+ export declare function minimumTarget(k: number): number;
11
+ /** One node inside the region, as measured by whoever calls: its computed font size if it holds text, its box if it is a target. */
12
+ export interface NodeMeasure {
13
+ readonly name: string;
14
+ readonly daEngine: boolean;
15
+ readonly fontPx: number | null;
16
+ readonly target: {
17
+ readonly w: number;
18
+ readonly h: number;
19
+ } | null;
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 declare function belowFloor(nodes: readonly NodeMeasure[], k: number): {
27
+ text: string[];
28
+ targets: string[];
29
+ };
30
+ /**
31
+ * THE GAME'S NODES THAT INVADE THE ACCESSIBILITY BAR'S RECTANGLE (ADR-0148 §3).
32
+ *
33
+ * 🔴 The bar is `position:absolute` INSIDE `#game-region`, so a game can draw right over it — a question title on top
34
+ * of the buttons, and the child looking for blind mode finds text over them.
35
+ *
36
+ * ⚠️ AND NOTHING FAILS. No error, no type, no console: just a row of covered buttons — and whoever depends on it most is
37
+ * precisely whoever cannot see it is covered.
10
38
  *
11
- * Os três degraus são os do Dev, e os dois extremos são as duas normas — não números de gosto:
39
+ * 📌 PURE AND WITH THE BOXES INJECTED, so the gate can drive it with no browser. Whoever calls measures; what this
40
+ * function decides is what COUNTS as an invasion, which is the part people get wrong.
12
41
  *
13
- * altura ≥ 720 44 px WCAG 2.2 · 2.5.5 Target Size (Enhanced) — AAA
14
- * altura ≥ 540 34 px o degrau do meio
15
- * altura < 540 24 px WCAG 2.2 · 2.5.8 Target Size (Minimum) — AA
42
+ * ⚠️ IT IGNORES THE BAR'S OWN DESCENDANTS: its buttons intersect it by definition, and counting them would make the gate
43
+ * accuse always — the defect ADR-0106 §2 calls drowning what can be fixed.
44
+ */
45
+ export interface NamedBox {
46
+ readonly name: string;
47
+ readonly box: Box;
48
+ readonly isBar: boolean;
49
+ }
50
+ export interface Box {
51
+ readonly x: number;
52
+ readonly y: number;
53
+ readonly w: number;
54
+ readonly h: number;
55
+ }
56
+ export declare function barIntruders(barBox: Box | null, nodes: readonly NamedBox[]): string[];
57
+ /** The document a layout measures — only the lookup it uses. */
58
+ export type LayoutDoc = Pick<Document, 'querySelector'>;
59
+ /**
60
+ * The scale ADR-0001 gives a stage: the factor in REAL pixels (whole, except at the floor — ADR-0179), the CSS factor, and
61
+ * the region's CSS size.
62
+ */
63
+ export interface Scale {
64
+ readonly kDev: number;
65
+ readonly k: number;
66
+ readonly width: number;
67
+ readonly height: number;
68
+ }
69
+ /**
70
+ * ADR-0001 AS A PURE FUNCTION — so the engine can apply it to every cartridge (ADR-0163) and a test can pin it.
16
71
  *
17
- * ⚠️ ISTO É «MARCAR HONESTAMENTE ONDE SÓ DÁ AA», que é regra escrita do projeto — e não uma renúncia
18
- * silenciosa. O que se perde em 360 está registrado com número no ADR-0095: a 96 px/pol, 24 CSS px são
19
- * 6,4 mm, abaixo do alvo de polegar de 9,6 mm que o painel de toque deste jogo cita. É por isso que o
20
- * ESPAÇAMENTO entre alvos passa a ser o que protege o dedo onde o tamanho não pode — a mesma saída que a
21
- * própria 2.5.8 dá na sua exceção de spacing.
72
+ * 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
73
+ * more step (the `−10`: `base·kDev − avail·dpr ≤ 10·kDev`). Never under 2 CSS px per logical pixel — 640×360 CSS, text 16 px,
74
+ * targets 44 px: where the whole multiple gives less (a fractional display scale on the minimum window) the scale is exactly
75
+ * 2 CSS px, whole in real pixels or not, because WCAG 2.2 AA decides (ADR-0179).
22
76
  */
23
- export declare const REGUA_DE_ALVO: readonly {
24
- readonly altura: number;
25
- readonly alvo: number;
26
- }[];
77
+ export declare function stageScale(availW: number, availH: number, dpr: number, baseW: number, baseH: number): Scale;
27
78
  /**
28
- * O menor alvo de toque aceitável num viewport desta altura, em CSS px.
79
+ * Writes a scale onto the game region: its size, and the UI variables that grow with it.
29
80
  *
30
- * ⚠️ NUNCA DEVOLVE MENOS DE 24: abaixo disso não é «AA num aparelho pequeno», é furar o piso da WCAG. Uma
31
- * tela mais baixa que 360 não compra o direito de encolher mais — compra o direito de mostrar menos itens.
81
+ * ⚠️ HOST-INJECTED (the region is passed in): `createGame` serves documents that
82
+ * are not the global one — the fault the root's finding 15 names about reaching `document` from under the injection.
83
+ */
84
+ export declare function applyScale(region: HTMLElement, e: Scale): void;
85
+ export interface LayoutCtx {
86
+ /** The document holding the stage shell and `#game-region` — passed, never the global one (ADR-0232). */
87
+ doc: LayoutDoc;
88
+ /** The window, for its pixel ratio only: the scale is locked to whole REAL pixels. */
89
+ win: Pick<Window, 'devicePixelRatio'>;
90
+ /**
91
+ * THE PLAYER COUNT, as the GETTER of the round the game owns (ADR-0038): the screen grid sets the base size. A number
92
+ * would freeze the count at the first layout.
93
+ */
94
+ numPlayers: () => number;
95
+ /**
96
+ * CALLED AFTER EVERY SCALE — the root's CRT re-anchoring its scanlines to real pixels (`engine.crt.scanVars`).
97
+ * REQUIRED: the layout used to call the page's one CRT by import, and a game that forgets this would get scanlines
98
+ * spaced for the previous scale, with no error. A game with no CRT passes `() => {}` and says so.
99
+ */
100
+ afterScale: () => void;
101
+ /** Logs the scale to the console (`?debug=true`). Optional: absent, nothing is logged. */
102
+ debug?: () => boolean;
103
+ }
104
+ /** A game's stage scaler. */
105
+ export interface Layout {
106
+ /** Measures the shell, scales `#game-region` and calls `afterScale`. Call it at boot and on every `resize`. */
107
+ layout(): void;
108
+ }
109
+ /**
110
+ * Builds a stage scaler over the document and window it is handed. It keeps nothing between calls: every `layout()`
111
+ * measures again, reads the player count again, and writes onto the region.
32
112
  */
33
- export declare function alvoMinimoDeToque(alturaCss: number): number;
34
- /** Liga a contagem de jogadores. Chamado uma vez pela raiz, antes do primeiro `layout()`. */
35
- export declare function initLayout(deps: {
36
- numJogadores: () => number;
37
- }): void;
38
- export declare function layout(): void;
113
+ export declare function createLayout(ctx: LayoutCtx): Layout;