@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,200 +1,214 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- // core/contract — OS SETE CAMPOS. A interface que o ADR-0030 escolheu como o eixo da engine.
2
+ // core/contract — THE SEVEN FIELDS. The interface ADR-0030 chose as the engine's axis.
3
3
  //
4
- // ⚠️ ESTE FICHEIRO NÃO TINHA IMPORT NENHUM, e o único que ganhou é `import type` — apagado na compilação, logo
5
- // o módulo publicado continua sem dependência de execução. O que entra é o VOCABULÁRIO das catorze posições
6
- // (ADR-0074), e ele tinha de entrar: um campo que fala de mapeamento e escrevesse as suas próprias chaves
7
- // seria a segunda cópia da união que o `core/actions` existe para ser a primeira.
4
+ // ⚠️ Its one import is `import type` — erased at compile time, so the published module keeps no run-time dependency.
5
+ // What comes in is the VOCABULARY of the fourteen positions (ADR-0074), and it had to: a field about mapping that wrote
6
+ // its own keys would be a second copy of the union `core/actions` exists to be the first of.
8
7
  //
9
- // ========================= O QUE ISTO É, E O QUE NÃO É =========================
10
- // Não é um framework nem uma classe-base. É a ÚNICA coisa que a pilha de acessibilidade sabe sobre um jogo.
11
- // O ADR-0027 mediu que as três funções que MAIS pareciam genéricas eram as três mais amarradas à plataforma —
12
- // `roleOf` era uma tabela de tiles, `caneProbe` usava `facing` e `BOX.w`, o sonar definia alvo como "moeda não
13
- // coletada deste jogador". Nenhuma delas estava errada; todas estavam ADIVINHANDO o jogo em vez de perguntar.
8
+ // ========================= WHAT THIS IS, AND WHAT IT IS NOT =========================
9
+ // Not a framework nor a base class. It is the ONLY thing the accessibility stack knows about a game. ADR-0027 measured
10
+ // that the three functions that looked MOST generic were the three most tied to the platformer — the role table was a
11
+ // tile table, the cane probe used facing and a hitbox, the sonar defined a target as "a coin this player has not taken".
12
+ // None was wrong; all were GUESSING the game instead of asking.
14
13
  //
15
- // Estes sete campos são as perguntas. Um jogo que as responda ganha sonar, alto contraste, varredura, leitor de
16
- // tela e Libras sem escrever uma linha deles — que é o produto, e não "mais uma engine 2D" (ADR-0027).
14
+ // These seven fields are the questions. A game that answers them gets sonar, high contrast, scanning, screen reader and
15
+ // Libras without writing a line of them — which is the product, not "one more 2D engine" (ADR-0027).
17
16
  //
18
- // ========================= PURO, E DE PROPÓSITO =========================
19
- // Só TIPOS e funções puras. Zero dependências, zero I/O no import: é módulo-FOLHA, importável dos dois lados da
20
- // fronteira e do project `node`. Um contrato que precisasse de PIXI já teria escolhido o gênero.
17
+ // ========================= PURE, ON PURPOSE =========================
18
+ // Only TYPES and pure functions. No dependencies, no I/O at import: a LEAF module, importable from both sides of the
19
+ // boundary and from the `node` project. A contract that needed PIXI would already have chosen the genre.
21
20
  //
22
- // ========================= COMO SE USA: FATIAS, NÃO O OBJETO GORDO =========================
23
- // Vale aqui a mesma regra de `core/entity`: quem consome declara a FATIA MÍNIMA de que precisa, com `Pick`, em
24
- // vez de receber a declaração inteira. O alto contraste quer `Pick<GameDeclaration, 'roleAt'>` e nada mais; o
25
- // HUD quer `'objective'`. Trocar 23 visões estreitas por uma interface gorda destruiria a testabilidade que o
26
- // projeto tem hoje — todo fixture passaria a inventar campos que o módulo não usa.
21
+ // ========================= HOW IT IS USED: SLICES, NOT THE FAT OBJECT =========================
22
+ // The rule of `core/entity` holds here too: a consumer declares the MINIMAL slice it needs, with `Pick`, instead of
23
+ // receiving the whole declaration. High contrast wants `Pick<GameDeclaration, 'roleAt'>` and nothing else; the HUD wants
24
+ // `'objective'`. A fat interface would destroy the project's testability — every fixture would invent fields the module
25
+ // does not use.
27
26
  //
28
- // ========================= O QUE TEM EVIDÊNCIA E O QUE AINDA NÃO TEM =========================
29
- // Cinco campos nasceram de um consumidor REAL que hoje adivinha (marcados abaixo com "hoje quem adivinha").
30
- // DOIS não têm consumidor no código ainda — `tick` e `Announcement` — e estão aqui porque o ADR-0027 os nomeia
31
- // como o que decide varredura e WCAG 2.2.1. Estão marcados. Enquanto nenhum módulo os ler, são hipótese, e o
32
- // ADR-0030 registra que "o contrato basta" só vira resultado quando DOIS presets existirem.
33
- /** A dimensão que a topologia declara. `hotspots` não tem espaço, logo não tem dimensão. */
34
- export function dimension(t) { return t.kind === 'hotspots' ? 0 : t.size.length; }
35
- /** O eixo `i` de um ponto, para quem percorre dimensões em vez de as nomear. */
36
- function eixo(s, i) { return i === 0 ? s.x : i === 1 ? s.y : (s.z ?? 0); }
37
- /* ===================== CONFORMIDADE ===================== */
38
- /**
39
- * Uma declaração é bem-formada? Devolve a lista de problemas — VAZIA quer dizer conforme.
40
- *
41
- * Existe porque um preset é uma promessa, e promessa sem verificação é comentário. O ADR-0030 diz que um
42
- * pacote de gênero "ou satisfaz os sete campos ou não satisfaz"; isto é o "ou não".
43
- *
44
- * Confere FORMA, não verdade: que a topologia tenha medida positiva, que as funções existam, que o objetivo
45
- * não peça um alvo impossível. Não tem como conferir se `roleAt` devolve o papel CERTO — isso é o teste do
46
- * preset, não deste módulo.
47
- */
48
- export function conformanceProblems(d) {
49
- const p = [];
50
- if (!d)
51
- return ['declaration missing'];
52
- // ⚠️ DUAS FALHAS DIFERENTES, E ELAS PRECISAM DE DUAS MENSAGENS. `topology` ausente é um campo que ninguém
53
- // escreveu; `topology` que não é função é o campo escrito à moda antiga — um VALOR, que passava no
54
- // TypeScript de quem não recompilou e morreria em produção com "topology is not a function". Dizer só
55
- // "ausente" mandaria o autor procurar um campo que está lá, à vista.
56
- const t = typeof d.topology === 'function' ? d.topology() : undefined;
27
+ // ========================= EVIDENCE =========================
28
+ // Each field was born from a REAL consumer that used to guess, and ADR-0030 records that "the contract is enough" only
29
+ // becomes a result when TWO presets exist.
30
+ /** Axis `i` of a point, for whoever walks dimensions instead of naming them. */
31
+ function axis(s, i) { return i === 0 ? s.x : i === 1 ? s.y : (s.z ?? 0); }
32
+ function topologyProblems(d) {
33
+ // ⚠️ TWO DIFFERENT FAILURES, AND THEY NEED TWO MESSAGES. A missing `topology` is a field nobody wrote; a `topology`
34
+ // that is not a function is the field written the old way — a VALUE, which passed the TypeScript of whoever had not
35
+ // recompiled and would die in production with "topology is not a function". Saying only "missing" would send the
36
+ // author looking for a field that is right there.
37
+ // Each answer excludes the others, so each one returns: the order is the rule, and the space is asked for only once it
38
+ // is known to be a function.
57
39
  if (d.topology === undefined || d.topology === null)
58
- p.push('topology: missing');
59
- else if (typeof d.topology !== 'function')
60
- p.push('topology: must be a FUNCTION (it was a value until ADR-0084)');
61
- else if (!t)
62
- p.push('topology: the function returned nothing');
63
- else if (t.kind === 'grid' || t.kind === 'continuous') {
64
- // ⚠️ A DIMENSÃO É `size.length`, e é por isso que ela é conferida ANTES de tudo: um `size` vazio ou de
65
- // quatro entradas não é uma medida ruim, é um espaço que `Spot` não sabe representar — e o erro apareceria
66
- // longe daqui, como um eixo simplesmente ignorado.
67
- if (!Array.isArray(t.size) || t.size.length < 2 || t.size.length > 3) {
68
- p.push('topology.size: must be [w, h] or [w, h, d] - dimension is 2 or 3, and it is size.length');
69
- }
70
- else if (!t.size.every((n) => n > 0)) {
71
- p.push('topology.size: every extent must be positive');
72
- }
73
- // `move` é o que decide a métrica. Ausente, a distância seria adivinhada — e adivinhar Chebyshev num
74
- // quebra-cabeça deslizante sub-relata até 2×, que foi o achado §3 do ADR-0080.
75
- if (t.move !== 'orthogonal' && t.move !== 'diagonal' && t.move !== 'free') {
76
- p.push('topology.move: must be "orthogonal" (L1), "diagonal" (L8/Chebyshev) or "free" (L2) - it is the metric the sonar counts in');
77
- }
78
- // `frame` é em que PALAVRAS a direção é dita. Sem ele a engine escolheria pela criança, e num jogo de
79
- // plataforma escolheria mal: norte e sul não querem dizer nada numa vista lateral.
80
- if (t.frame !== 'compass' && t.frame !== 'clock') {
81
- p.push('topology.frame: must be "compass" (board, top-down, map, 3D) or "clock" (2D side view)');
82
- }
83
- // `unit` é o que dá MÉTRICA a um espaço contínuo: sem ela, "a dois passos" não tem como ser dito.
84
- if (t.kind === 'continuous' && !(t.unit > 0)) {
85
- p.push('topology.continuous: unit must be positive (it is the metric the narration counts in)');
86
- }
40
+ return ['topology: missing'];
41
+ if (typeof d.topology !== 'function')
42
+ return ['topology: must be a FUNCTION (it was a value until ADR-0084)'];
43
+ const t = d.topology();
44
+ if (!t)
45
+ return ['topology: the function returned nothing'];
46
+ if (t.kind === 'grid' || t.kind === 'continuous')
47
+ return [...sizeProblems(t), ...metricProblems(t), ...frameProblems(t)];
48
+ if (t.kind === 'hotspots')
49
+ return hotspotProblems(t);
50
+ return ['topology: unknown kind'];
51
+ }
52
+ // ⚠️ THE DIMENSION IS `size.length`, which is why it is checked BEFORE anything: an empty or four-entry `size` is not a
53
+ // bad measurement, it is a space `Spot` cannot represent — and the error would show far from here, as an axis simply
54
+ // ignored.
55
+ function sizeProblems(t) {
56
+ if (!Array.isArray(t.size) || t.size.length < 2 || t.size.length > 3) {
57
+ return ['topology.size: must be [w, h] or [w, h, d] - dimension is 2 or 3, and it is size.length'];
87
58
  }
88
- else if (t.kind === 'hotspots') {
89
- if (!t.order?.length)
90
- p.push('topology.hotspots: order is empty - there is nowhere to navigate');
91
- else if (new Set(t.order).size !== t.order.length)
92
- p.push('topology.hotspots: order has a repeated id');
59
+ return !t.size.every((n) => n > 0) ? ['topology.size: every extent must be positive'] : [];
60
+ }
61
+ function metricProblems(t) {
62
+ const p = [];
63
+ // `move` decides the metric. Absent, distance would be guessed — and guessing Chebyshev in a sliding puzzle
64
+ // under-reports up to 2×, finding §3 of ADR-0080.
65
+ if (t.move !== 'orthogonal' && t.move !== 'diagonal' && t.move !== 'free') {
66
+ p.push('topology.move: must be "orthogonal" (L1), "diagonal" (L8/Chebyshev) or "free" (L2) - it is the metric the sonar counts in');
93
67
  }
94
- else
95
- p.push('topology: unknown kind');
96
- // ⚠️ TRÊS FALHAS DISTINTAS, e a terceira é a que este campo existe para tornar impossível: um jogo cujo
97
- // mundo NÃO foi declarado. Antes deste campo, esquecer e escolher «não tenho espaço» produziam o mesmo
98
- // silêncio — e o silêncio era resolvido pela engine a adivinhar que o mundo é a canvas.
99
- if (d.world === undefined || d.world === null) {
100
- p.push('world: missing - declare the element that IS the game, or {kind:"none"} if it has no space');
68
+ // `unit` is what gives a continuous space a METRIC: without it, "two steps away" cannot be said.
69
+ if (t.kind === 'continuous' && !(t.unit > 0)) {
70
+ p.push('topology.continuous: unit must be positive (it is the metric the narration counts in)');
101
71
  }
102
- else if (typeof d.world !== 'function') {
103
- p.push('world: must be a FUNCTION');
72
+ return p;
73
+ }
74
+ // `frame` is in what WORDS a direction is said. Without it the engine would choose for the child, and in a platformer it
75
+ // would choose badly: north and south mean nothing in a side view.
76
+ function frameProblems(t) {
77
+ return t.frame !== 'compass' && t.frame !== 'clock'
78
+ ? ['topology.frame: must be "compass" (board, top-down, map, 3D) or "clock" (2D side view)']
79
+ : [];
80
+ }
81
+ function hotspotProblems(t) {
82
+ if (!t.order?.length)
83
+ return ['topology.hotspots: order is empty - there is nowhere to navigate'];
84
+ return new Set(t.order).size !== t.order.length ? ['topology.hotspots: order has a repeated id'] : [];
85
+ }
86
+ function worldProblems(d) {
87
+ // ⚠️ THREE DISTINCT FAILURES, and the third is the one this field exists to make impossible: a game whose world was
88
+ // NOT declared. Before this field, forgetting and choosing "I have no space" produced the same silence — and the
89
+ // silence was resolved by the engine guessing that the world is the canvas.
90
+ if (d.world === undefined || d.world === null) {
91
+ return ['world: missing - declare the element that IS the game, or {kind:"none"} if it has no space'];
104
92
  }
105
- else {
106
- const w = d.world();
107
- if (!w)
108
- p.push('world: the function returned nothing');
109
- else if (w.kind === 'element') {
110
- if (!w.selector || !w.selector.trim())
111
- p.push('world: kind "element" needs a non-empty selector');
112
- }
113
- else if (w.kind !== 'none')
114
- p.push('world: unknown kind');
93
+ if (typeof d.world !== 'function')
94
+ return ['world: must be a FUNCTION'];
95
+ const w = d.world();
96
+ if (!w)
97
+ return ['world: the function returned nothing'];
98
+ if (w.kind === 'element') {
99
+ return !w.selector || !w.selector.trim() ? ['world: kind "element" needs a non-empty selector'] : [];
115
100
  }
116
- // ⚠️ A MENSAGEM NOMEIA A SAÍDA, como as outras quatro fazem. Um jogo que não declara isto não recebe um
117
- // padrão — recebe uma frase que diz o que perguntar a si próprio, porque a resposta é do jogo e de mais
118
- // ninguém. (ADR-0104 §A.)
101
+ return w.kind !== 'none' ? ['world: unknown kind'] : [];
102
+ }
103
+ function holdsAtOnceProblems(d) {
104
+ // ⚠️ THE MESSAGE NAMES THE WAY OUT, like the others do. A game that does not declare this gets no default — it gets a
105
+ // sentence saying what to ask itself, because the answer is the game's and nobody else's. (ADR-0104 §A.)
119
106
  if (typeof d.holdsAtOnce !== 'function') {
120
- // ⚠️ A MENSAGEM NÃO NOMEIA GÊNERO, e o gate de fronteira cobrou-o: a primeira escrita dizia «run+walk+jump
121
- // is 3, a quiz is 1» e o `engine-boundary` reprovou a palavra «quiz» em linha de CÓDIGO da engine. Ele
122
- // tinha razão, e a frase ficou melhor: descreve a FORMA da pergunta, que serve aos 300 jogos, em vez de
123
- // dois exemplos que servem a dois.
124
- p.push('holdsAtOnce: missing - declare how many positions are held AT ONCE (three if three fingers must press together, one if commands arrive one at a time)');
125
- }
126
- else {
127
- const n = d.holdsAtOnce();
128
- if (!Number.isInteger(n) || n < 1) {
129
- // Zero não é «não usa controle»: um jogo que não segura posição nenhuma não é jogável, e devolver zero
130
- // faria a aritmética do alcance passar por vacuidade — o mesmo defeito que o `reachable` recusa.
131
- p.push('holdsAtOnce: must be an integer >= 1 - a game that holds nothing cannot be played');
132
- }
133
- }
134
- // ⚠️ E ESTA É A OUTRA PERGUNTA, que o número acima parecia responder e não responde (ADR-0115). A mensagem
135
- // diz o que a ausência CUSTA, e não só o que falta: sem ela, um jogo que nada segura oferece um controle de
136
- // acessibilidade que não faz nada, e um que segura tudo pode não o oferecer a quem depende dele.
137
- if (typeof d.seguraTeclas !== 'function') {
138
- p.push('seguraTeclas: missing - declare whether any key is HELD in this game (latching is offered only where something can be held, and a game that holds nothing must not show a control that does nothing)');
107
+ // ⚠️ THE MESSAGE NAMES NO GENRE, and the boundary gate insisted: a first wording used a quiz as the example and the
108
+ // gate refused the word in a line of engine CODE. It was right, and the sentence got better: it describes the SHAPE
109
+ // of the question, which serves every game, instead of two examples that serve two.
110
+ return ['holdsAtOnce: missing - declare how many positions are held AT ONCE (three if three fingers must press together, one if commands arrive one at a time)'];
139
111
  }
140
- else if (typeof d.seguraTeclas() !== 'boolean') {
141
- // Um valor não-booleano seria truthy e ofereceria a alternância a toda a gente — o mesmo defeito
142
- // silencioso que o `needsPointer` recusa logo abaixo, e pela mesma razão.
143
- p.push('seguraTeclas: must return a boolean - a non-boolean is truthy and would offer latching in a game where nothing is held');
144
- }
145
- // ⚠️ OPCIONAL, MAS NÃO IMPUNE. Ausente é a resposta `false` e não é problema — ver a nota no campo. O que
146
- // se recusa é declará-lo MAL: um `needsPointer: true` (valor em vez de função) seria sempre verdadeiro por
147
- // ser um objecto, e um que devolvesse `'sim'` também. Nos dois casos o jogo julgaria ter declarado, o
148
- // alcance leria uma coisa diferente do que ele quis dizer, e ninguém saberia — que é o defeito silencioso
149
- // que esta função inteira existe para não deixar acontecer.
150
- if (d.needsPointer !== undefined) {
151
- if (typeof d.needsPointer !== 'function') {
152
- // ⚠️ MENSAGENS SEM A PALAVRA `as`, e o motivo merece uma linha porque volta a morder: o detector de prosa
153
- // pt-BR do `engine-i18n` casa palavras funcionais isoladas, e `as` é artigo plural em português. Uma
154
- // mensagem INGLESA que diga «declare it as …» é contada como texto cru e faz o tecto do módulo subir.
155
- // O cabeçalho daquele gate já admite a aproximação («senão 'mode' casa 'de'»); reescrever a frase custa
156
- // nada e afrouxar o detector custaria a razão de ele existir.
157
- p.push('needsPointer: must be a function - write `needsPointer: () => true`, because a game may draw in one phase and not in another');
158
- }
159
- else if (typeof d.needsPointer() !== 'boolean') {
160
- p.push('needsPointer: must return a boolean - a non-boolean would be truthy and refuse devices this game can actually use');
161
- }
162
- }
163
- // ⚠️ E O MESMO PARA O MAPEAMENTO, com uma razão própria: aqui um valor em vez de uma função não seria um
164
- // erro barulhento, seria um mapeamento SILENCIOSAMENTE ignorado — a fábrica da engine ficava, e a criança
165
- // jogava com um teclado que o autor do jogo julga ter mudado. E devolver algo que não é objecto nem `null`
166
- // atravessaria o `Object.assign` sem escrever nada, que é a mesma ausência com outra roupa.
167
- if (d.mapeamentoDoTeclado !== undefined) {
168
- if (typeof d.mapeamentoDoTeclado !== 'function') {
169
- p.push('mapeamentoDoTeclado: must be a function - write `mapeamentoDoTeclado: (jogadores, assento) => ({ action1: ["KeyQ"] })`, because the keyboard of two players is not the keyboard of one');
170
- }
171
- else {
172
- const m = d.mapeamentoDoTeclado(1, 0);
173
- if (m !== null && (typeof m !== 'object' || Array.isArray(m))) {
174
- p.push('mapeamentoDoTeclado: must return an object or null - anything else is merged into nothing, and this game keeps the engine factory while its author believes otherwise');
175
- }
176
- }
112
+ const n = d.holdsAtOnce();
113
+ // Zero is not "uses no controls": a game that holds no position cannot be played, and returning zero would pass the
114
+ // reach arithmetic vacuously — the same defect `reachable` refuses.
115
+ return !Number.isInteger(n) || n < 1
116
+ ? ['holdsAtOnce: must be an integer >= 1 - a game that holds nothing cannot be played']
117
+ : [];
118
+ }
119
+ function latchingProblems(d) {
120
+ // ⚠️ AND THIS IS THE OTHER QUESTION, which the number above seemed to answer and does not (ADR-0115). The message says
121
+ // what the absence COSTS, not only what is missing: without it a game that holds nothing offers an accessibility
122
+ // control that does nothing, and one that holds everything may not offer it to whoever depends on it.
123
+ if (typeof d.holdsKeys !== 'function') {
124
+ return ['holdsKeys: missing - declare whether any key is HELD in this game (latching is offered only where something can be held, and a game that holds nothing must not show a control that does nothing)'];
177
125
  }
178
- if (d.mapeamentoDoPad !== undefined) {
179
- if (typeof d.mapeamentoDoPad !== 'function') {
180
- p.push('mapeamentoDoPad: must be a function - write `mapeamentoDoPad: (jogadores, assento) => ({ action1: 3 })`, because two seats may want different arrangements');
181
- }
182
- else {
183
- const m = d.mapeamentoDoPad(1, 0);
184
- if (m !== null && (typeof m !== 'object' || Array.isArray(m))) {
185
- p.push('mapeamentoDoPad: must return an object or null - anything else is merged into nothing, and this game keeps the engine factory while its author believes otherwise');
186
- }
187
- }
126
+ // A non-boolean would be truthy and offer the toggle to everyone — the same silent defect `needsPointer` refuses just
127
+ // below, for the same reason.
128
+ return typeof d.holdsKeys() !== 'boolean'
129
+ ? ['holdsKeys: must return a boolean - a non-boolean is truthy and would offer latching in a game where nothing is held']
130
+ : [];
131
+ }
132
+ function pointerProblems(d) {
133
+ // ⚠️ OPTIONAL, BUT NOT UNCHECKED. Absent is the answer `false` and no problem — see the note on the field. What is
134
+ // refused is declaring it WRONG: `needsPointer: true` (a value instead of a function) would always be truthy for
135
+ // being an object, and one returning a string too. Either way the game would believe it had declared, the reach would
136
+ // read something other than what it meant, and nobody would know — the silent defect this whole function exists to
137
+ // prevent.
138
+ if (d.needsPointer === undefined)
139
+ return [];
140
+ if (typeof d.needsPointer !== 'function') {
141
+ // ⚠️ MESSAGES WITHOUT THE WORD `as`, worth a line because it bites again: the raw-prose detector of `engine-i18n`
142
+ // matches isolated function words, and `as` is a plural article in Portuguese. An ENGLISH message saying
143
+ // "declare it as …" is counted as raw text and raises the module's ceiling. Rewording costs nothing; loosening the
144
+ // detector would cost the reason it exists.
145
+ return ['needsPointer: must be a function - write `needsPointer: () => true`, because a game may draw in one phase and not in another'];
188
146
  }
189
- if (d.tick !== 'player' && d.tick !== 'clock')
190
- p.push('tick: must be "player" or "clock"');
191
- for (const f of ['roleAt', 'nameAt', 'focusOf', 'objectiveOf', 'targetsOf']) {
192
- if (typeof d[f] !== 'function')
193
- p.push(`${f}: missing`);
147
+ return typeof d.needsPointer() !== 'boolean'
148
+ ? ['needsPointer: must return a boolean - a non-boolean would be truthy and refuse devices this game can actually use']
149
+ : [];
150
+ }
151
+ /**
152
+ * A MAPPING DECLARED BY THE GAME, for the keyboard or the pad.
153
+ *
154
+ * 🔴 IT WAS THE SAME CHECK WRITTEN TWICE, and the two copies were not equally guarded: the keyboard's two decisions had
155
+ * cases and the pad's two were BLIND — asymmetric coverage is how a duplicate announces itself, because one copy gets
156
+ * attention and the other is assumed.
157
+ *
158
+ * ⚠️ Here a value instead of a function would not be a loud error, it would be a mapping SILENTLY ignored — the engine's
159
+ * factory would stay, and the child would play with controls the game's author believes they changed. And returning
160
+ * something that is neither an object nor `null` would pass through `Object.assign` writing nothing, the same absence in
161
+ * other clothes.
162
+ */
163
+ function mappingProblems(field, declared, example, because) {
164
+ if (declared === undefined)
165
+ return [];
166
+ if (typeof declared !== 'function') {
167
+ return [`${field}: must be a function - write \`${field}: ${example}\`, because ${because}`];
194
168
  }
195
- return p;
169
+ // The names of THIS annotation are mine and were born in English; the field's own (`players`, `seat`) became
170
+ // English with phase 7 of the English plan (ADR-0230).
171
+ const m = declared(1, 0);
172
+ return m !== null && (typeof m !== 'object' || Array.isArray(m))
173
+ ? [`${field}: must return an object or null - anything else is merged into nothing, and this game keeps the engine factory while its author believes otherwise`]
174
+ : [];
175
+ }
176
+ const keyboardMappingProblems = (d) => mappingProblems('keyboardMapping', d.keyboardMapping, '(players, seat) => ({ action1: ["KeyQ"] })', 'the keyboard of two players is not the keyboard of one');
177
+ const padMappingProblems = (d) => mappingProblems('padMapping', d.padMapping, '(players, seat) => ({ action1: 3 })', 'two seats may want different arrangements');
178
+ const tickProblems = (d) => (d.tick !== 'player' && d.tick !== 'clock' ? ['tick: must be "player" or "clock"'] : []);
179
+ /** The five questions the engine asks the world. Each absent one is ONE problem, and the message says WHICH is missing. */
180
+ const READERS = ['roleAt', 'nameAt', 'focusOf', 'objectiveOf', 'targetsOf'];
181
+ const readerProblems = (d) => READERS.filter((f) => typeof d[f] !== 'function').map((f) => `${f}: missing`);
182
+ /**
183
+ * 📌 THIS TABLE'S ORDER IS THE ORDER OF THE MESSAGES, and it matters to the reader: an author writing a preset gets the
184
+ * problems in the order the fields appear in the contract, not in the order this file grew.
185
+ */
186
+ const FIELD_CHECKS = [
187
+ topologyProblems,
188
+ worldProblems,
189
+ holdsAtOnceProblems,
190
+ latchingProblems,
191
+ pointerProblems,
192
+ keyboardMappingProblems,
193
+ padMappingProblems,
194
+ tickProblems,
195
+ readerProblems,
196
+ ];
197
+ /**
198
+ * Is a declaration well formed? Returns the list of problems — EMPTY means conformant.
199
+ *
200
+ * It exists because a preset is a promise, and a promise without a check is a comment. ADR-0030 says a genre package
201
+ * "either satisfies the seven fields or does not"; this is the "does not".
202
+ *
203
+ * It checks SHAPE, not truth: that the topology has a positive measure, that the functions exist. It cannot check
204
+ * whether `roleAt` returns the RIGHT role — that is the preset's own test, not this module's.
205
+ */
206
+ export function conformanceProblems(d) {
207
+ if (!d)
208
+ return ['declaration missing'];
209
+ return FIELD_CHECKS.flatMap((check) => check(d));
196
210
  }
197
- /** Um nome falável bem-formado? Texto vazio é o defeito silencioso: o leitor de tela simplesmente cala. */
211
+ /** Is a speakable name well formed? Empty text is the silent defect: the screen reader simply goes quiet. */
198
212
  export function speakableProblems(s) {
199
213
  if (!s)
200
214
  return ['name missing'];
@@ -208,32 +222,32 @@ export function speakableProblems(s) {
208
222
  return p;
209
223
  }
210
224
  /**
211
- * Distância entre dois pontos NA MÉTRICA declarada — a que o jogo declarou em `move`, e em quantas dimensões
212
- * ele declarou em `size`. É o que o sonar precisa e antes calculava em pixels.
225
+ * The distance between two spots IN THE DECLARED METRIC — the one the game declared in `move`, over as many dimensions
226
+ * as it declared in `size`. It is what the sonar needs and used to compute in pixels.
213
227
  *
214
- * ⚠️ A GRADE ERA SEMPRE CHEBYSHEV, e isso custava até 2× de erro num quebra-cabeça deslizante. As três regras
215
- * não são gosto: são o que "um passo" significa em cada jogo, e o sonar fala em passos.
228
+ * ⚠️ THE GRID WAS ALWAYS CHEBYSHEV, which cost up to 2× error in a sliding puzzle. The three rules are not taste: they
229
+ * are what "one step" means in each game, and the sonar speaks in steps.
216
230
  */
217
231
  export function distance(t, a, b) {
218
- // Lista: a distância é quantos itens separam um do outro. Não há eixo, logo não há regra de movimento.
232
+ // A list: the distance is how many items lie between. There is no axis, so there is no movement rule.
219
233
  if (t.kind === 'hotspots')
220
234
  return Math.abs(a.x - b.x);
221
235
  const d = [];
222
236
  for (let i = 0; i < t.size.length; i++)
223
- d.push(Math.abs(eixo(a, i) - eixo(b, i)));
224
- const bruta = t.move === 'orthogonal' ? d.reduce((s, v) => s + v, 0) // L¹: cada eixo custa por si
225
- : t.move === 'diagonal' ? Math.max(...d) // L∞: a diagonal custa um passo
226
- : Math.hypot(...d); // L²: a reta entre os dois
227
- // Contínuo: dividida pela unidade — o resultado é "quantos passos", não "quantos pixels".
228
- return t.kind === 'continuous' ? bruta / t.unit : bruta;
237
+ d.push(Math.abs(axis(a, i) - axis(b, i)));
238
+ const rawDistance = t.move === 'orthogonal' ? d.reduce((s, v) => s + v, 0) // L¹: each axis costs on its own
239
+ : t.move === 'diagonal' ? Math.max(...d) // L∞: a diagonal costs one step
240
+ : Math.hypot(...d); // L²: the straight line between them
241
+ // Continuous: divided by the unit — the result is "how many steps", not "how many pixels".
242
+ return t.kind === 'continuous' ? rawDistance / t.unit : rawDistance;
229
243
  }
230
244
  /**
231
- * PARA ONDE FICA `to` VISTO DE `from`, já nas palavras que a topologia declarou.
245
+ * WHERE `to` LIES AS SEEN FROM `from`, already in the words the topology declared.
232
246
  *
233
- * ⚠️ DOIS EIXOS COM CONVENÇÕES DIFERENTES, e o silêncio sobre isto seria o defeito. `y` CRESCE PARA BAIXO —
234
- * é a coordenada da tela, herdada da canvas e de todo o código que já existe, não uma escolha desta função.
235
- * `z` CRESCE PARA CIMA, e essa é escolha: nada a força, e num espaço de três dimensões «zênite» só pode
236
- * querer dizer o lado para onde a criança olharia levantando a cabeça. Um jogo 3D tem de saber os dois.
247
+ * ⚠️ TWO AXES WITH DIFFERENT CONVENTIONS, and silence about it would be the defect. `y` GROWS DOWNWARD — the screen's
248
+ * coordinate, inherited from the canvas and all existing code, not a choice of this function. `z` GROWS UPWARD, and
249
+ * that is a choice: nothing forces it, and in three dimensions "zenith" can only mean the side the child would look at
250
+ * by raising their head. A 3D game has to know both.
237
251
  */
238
252
  export function bearing(t, from, to) {
239
253
  if (t.kind === 'hotspots')
@@ -241,22 +255,22 @@ export function bearing(t, from, to) {
241
255
  const dx = to.x - from.x;
242
256
  const dy = to.y - from.y;
243
257
  const dz = t.size.length > 2 ? (to.z ?? 0) - (from.z ?? 0) : 0;
244
- const plano = Math.hypot(dx, dy);
245
- // O eixo vertical do ESPAÇO ganha quando domina o plano — e ganha em palavras próprias, porque `up`/`down`
246
- // já são AÇÕES em `core/actions`. Ver o comentário de `Heading`.
247
- if (Math.abs(dz) > plano)
258
+ const plane = Math.hypot(dx, dy);
259
+ // SPACE's vertical axis wins when it dominates the plane — and wins in words of its own, because `up`/`down` are
260
+ // already ACTIONS in `core/actions`. See the comment on `Heading`.
261
+ if (Math.abs(dz) > plane)
248
262
  return { kind: 'compass', heading: dz > 0 ? 'zenith' : 'nadir' };
249
- if (plano === 0)
250
- return { kind: 'none' }; // mesmo lugar: não há direção que dizer, e inventar uma seria mentir
251
- // `-dy` porque o norte é para CIMA e `y` cresce para baixo. Sem esta troca a rosa sai invertida, e o teste
252
- // que a apanharia é o único que precisa de existir aqui.
253
- const ang = Math.atan2(-dy, dx); // 0 = leste, cresce no sentido anti-horário
263
+ if (plane === 0)
264
+ return { kind: 'none' }; // the same place: there is no direction to say, and inventing one would lie
265
+ // `-dy` because north is UP and `y` grows downward. Without this swap the rose comes out inverted, and the test that
266
+ // would catch it is the only one that needs to exist here.
267
+ const ang = Math.atan2(-dy, dx); // 0 = east, growing anticlockwise
254
268
  if (t.frame === 'clock') {
255
- // 12 horas é para CIMA e os ponteiros andam no sentido horário — daí `90 - graus`, e não `graus`.
256
- const horario = ((90 - (ang * 180) / Math.PI) % 360 + 360) % 360;
257
- const h = Math.round(horario / 30) % 12;
269
+ // 12 o'clock is UP and the hands move clockwise — hence `90 - degrees`, not `degrees`.
270
+ const clockwiseDegrees = ((90 - (ang * 180) / Math.PI) % 360 + 360) % 360;
271
+ const h = Math.round(clockwiseDegrees / 30) % 12;
258
272
  return { kind: 'clock', hour: h === 0 ? 12 : h };
259
273
  }
260
- const ROSA = ['e', 'ne', 'n', 'nw', 'w', 'sw', 's', 'se'];
261
- return { kind: 'compass', heading: ROSA[(Math.round(ang / (Math.PI / 4)) % 8 + 8) % 8] };
274
+ const COMPASS_ROSE = ['e', 'ne', 'n', 'nw', 'w', 'sw', 's', 'se'];
275
+ return { kind: 'compass', heading: COMPASS_ROSE[(Math.round(ang / (Math.PI / 4)) % 8 + 8) % 8] };
262
276
  }
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  /**
3
- * `document.querySelector`, na forma em que os módulos o recebem por INJEÇÃO — nunca importando `document`.
3
+ * `document.querySelector`, in the shape modules receive it by INJECTION — never importing `document`.
4
4
  *
5
- * O padrão é `HTMLElement` e não `Element` porque é o que os chamadores usam: `.hidden`, `.textContent`,
6
- * `.dataset`, `.focus()`. Quem precisa de outra coisa instancia — há um `$<SVGElement>` na árvore, e é por
7
- * causa dele que a RESTRIÇÃO continua sendo `Element`.
5
+ * The default is `HTMLElement` and not `Element` because that is what callers use: `.hidden`, `.textContent`,
6
+ * `.dataset`, `.focus()`. Whoever needs something else instantiates it — there is a `$<SVGElement>` in the tree, and
7
+ * it is why the CONSTRAINT stays `Element`.
8
8
  */
9
9
  export type DomQuery = <T extends Element = HTMLElement>(sel: string) => T | null;
@@ -1,25 +1,17 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- // core/dom-query — O SELETOR DE DOM INJETADO, declarado UMA VEZ.
2
+ // core/dom-query — THE INJECTED DOM SELECTOR, declared ONCE.
3
3
  //
4
- // ========================= POR QUE ESTE ARQUIVO EXISTE =========================
5
- // A mesma declaração de `DomQuery` — uma seta genérica sobre `Element`, devolvendo `T | null` — estava
6
- // escrita em DEZESSEIS módulos: `game/coin-spawning`, `game/quiz`, `input/gamepad`, `input/keydown`,
7
- // `input/touch`, `input/touch-bindings`, `ui/activities-menu`, `ui/hud`, `ui/map-hub`, `ui/menu-nav`,
8
- // `ui/settings-audio`, `ui/settings-controls`, `ui/settings-motor`, `ui/settings-typo`, `ui/shell` e
9
- // `ui/title`.
4
+ // ========================= WHY THIS FILE EXISTS =========================
5
+ // The same `DomQuery` declaration — a generic arrow over `Element`, returning `T | null` — was written in SIXTEEN
6
+ // modules: ADR-0039's defect one step up (there a FIELD described twice, here a TYPE described sixteen times).
10
7
  //
11
- // Dezesseis cópias de uma verdade, que é o defeito do ADR-0039 um degrau acima: lá era um CAMPO descrito
12
- // duas vezes, aqui é um TIPO descrito dezesseis.
8
+ // And, as copies do, they diverged. One declared it NON-generic. A generic function assigned to a non-generic
9
+ // signature is instantiated at its CONSTRAINT, not its default: the real `$`, `<T extends Element = HTMLElement>`,
10
+ // became `Element` — and `Element` has no `hidden`. Two type errors came from it, and neither mentioned a selector.
13
11
  //
14
- // E, como sempre acontece com cópia, elas divergiram. O `game/session` declarava a sua NÃO-genérica,
15
- // devolvendo um `SessionEl` estrutural. Uma função genérica atribuída a uma assinatura não-genérica é
16
- // instanciada pela RESTRIÇÃO e não pelo padrão: o `$` real, que é `<T extends Element = HTMLElement>`,
17
- // virava `Element` — e `Element` não tem `hidden`. Dois erros de tipo no `main.ts` nasciam daí, e nenhum
18
- // deles falava de seletor.
19
- //
20
- // ========================= POR QUE EM `core/` =========================
21
- // Porque é a camada que todos podem importar sem inverter nada — `game/`, `input/`, `render/` e `ui/`. E
22
- // não custa dependência nenhuma: o arquivo é SÓ TIPO, `import type` é apagado na compilação, e `Element` é
23
- // global de `lib.dom`, ligado no tsconfig. Nada aqui roda, então a propriedade de `core/` ser testável sem
24
- // navegador continua intacta.
12
+ // ========================= WHY IN `core/` =========================
13
+ // Because it is the layer everyone may import without inverting anything — `input/`, `render/` and `ui/` (ADR-0173).
14
+ // And it costs no dependency: `Element` is a `lib.dom` global, and a type is erased at build.
15
+ // 📌 It holds only the TYPE. The two global queries that lived here (`$`, `$$` over `globalThis.document`) left in
16
+ // ADR-0232 D4: every module now queries the document it is GIVEN, and the root builds its `$` over the host's.
25
17
  export {};