@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,128 +1,160 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
- // ui/settings-motion.ts — "Sensibilidade visual" → painel Movimento (#animation overlay): reduce-motion (WCAG
3
- // 2.3.3 + Pause/Stop/Hide 2.2.2) por PERSONAGEM (andar/respirar/gracinhas) e por CENA (parallax/decor/itens/
4
- // partículas), o botão-mestre "Parar/Retomar todas as animações", a seleção de jogador (selAnimPlayer) e a
5
- // estética CRT (scanlines/vinheta/cantos) — que também mora nesta MESMA tela no game.js original (renderMotion
6
- // escreve os dois blocos no mesmo #motion-list), por isso vem junto. Lógica PURA (rótulos, HTML, allMotionFrozen,
7
- // anúncios) separada do DOM. INJETADO via initSettingsMotion(ctx): $ (seletor), srSay, store (persistência),
8
- // frontOverlay/toggleBtn (helpers compartilhados com os painéis irmãos: visual/audio/typo/empathy/controls/
9
- // motor), e rm/saveRM/RM_KEYS/RM_CHAR (estado de movimento reduzido — fica em game.js porque applyCalm(), o
10
- // modo TEA, também os usa; não é exclusivo deste painel). `players`/`numPlayers` (core/state.ts) e CRT/applyCrt
11
- // (render/crt.ts, já extraído) são importados DIRETO — são módulos-folha, não game.js. A API de render/fx.ts
12
- // NÃO é referenciada aqui: renderMotion() nunca leu/escreveu JUICE (só o painel ?debug o faz) — ver nota no
13
- // retorno da extração antes de assumir que falta wiring.
2
+ // ui/settings-motion.ts — the Motion panel (#animation overlay): reduced motion (WCAG 2.3.3 + Pause/Stop/Hide 2.2.2) per
3
+ // CHARACTER (walk/breath/flavour) and per SCENE (parallax/decor/items/particles), the stop/resume-all master button, the
4
+ // player selection and the CRT look (scanlines/vignette/corners), which lives on the SAME screen. What a choice IS lives in
5
+ // ./motion-choices.js. INJECTED via initSettingsMotion(ctx): $ (selector), srSay, store (persistence), matchMedia (the
6
+ // operating system's reduced-motion answer, ADR-0232), frontOverlay/toggleBtn (helpers shared with the sibling panels),
7
+ // the root's CRT (`crt`, ADR-0232 D4), and optionally rm/saveRM/rmKeys/rmChar (reduced-motion state, which a cartridge may
8
+ // share by reference). Only the factory default (`CRT_DEFAULT`, a frozen constant) is imported from render/crt.ts.
14
9
  import { toggleLabel, toggleAria } from './dom.js';
15
- import { CRT, CRT_DEFAULT, applyCrt } from '../render/crt.js';
16
- import { defaultReducedMotion } from '../core/state.js';
10
+ import { CRT_DEFAULT } from '../render/crt.js';
11
+ import { defaultReducedMotion } from '../core/setting-defaults.js';
17
12
  import { markChanged, markMenuChanged } from './changed-mark.js';
18
- import { t } from '../core/i18n.js';
19
- import { CHAVES_DE_CENA, ANIMACOES_DO_PERSONAGEM, lerCenaGuardada, guardarCena } from './motion-scene.js';
20
- /**
21
- * Alvo → CHAVE i18n do rótulo. CHAVES, e não texto, pelo motivo de sempre: uma tabela de `const` com texto
22
- * resolve UMA vez, no import, e fica congelada no idioma do boot.
13
+ import { mountSteps, updateSteps, nextStep, controlRow, labelRow, sectionHeader } from './panel-widgets.js';
14
+ import { SCENE_KEYS, CHARACTER_ANIMATIONS, readStoredScene, storeScene } from './motion-scene.js';
15
+ /*
16
+ * 📌 THE PURE HALF LIVES IN `ui/motion-choices` (ADR-0221), and the SUITE pointed at the seam:
17
+ * `tests/settings-motion.node.test.js` exercises exactly these names, and the node project mounts no document.
23
18
  *
24
- * E é UMA tabela onde eram DUAS. A nota anterior dizia que `walk/breath/flavor` ficavam "redundantes com
25
- * rmChar[].lbl" e que não haviam sido podados "por fidelidade de porte" — havia uma terceira cópia, morta, no
26
- * main.js. Três tabelas dos mesmos rótulos, sem nada ligando as três: mudar um rótulo pedia três edições e
27
- * esquecer uma era silencioso. Agora `rmChar[].lbl` guarda a chave DESTA tabela, e a do main.js foi apagada.
19
+ * ⚠️ NO ALIAS: a re-export would keep alive a published path nothing in here uses — surface with no consumer
20
+ * (issue #204).
21
+ */
22
+ import { RM_LABEL, CRT_LBL, CRT_ROUND_LEVELS, clampSelectedPlayer, allMotionFrozen, motionMasterLabel, sceneMotionAnnouncement, crtToggleAnnouncement, crtLevelLabel, crtRoundAnnouncement, stopResumeAllAnnouncement, } from './motion-choices.js';
23
+ /*
24
+ * 🎯 NO "SOON" MECHANISM: it had no subject — no path let a cartridge supply a coming-soon row, so the only thing
25
+ * keeping it alive would be tests. The `ui.soon` key stays in the three dictionaries, because the no-parentheses label
26
+ * gate still reads it.
28
27
  */
29
- export const RM_LABEL = {
30
- parallax: 'rm.parallax', decor: 'rm.decor', items: 'rm.items',
31
- walk: 'rm.walk', breath: 'rm.breath', flavor: 'rm.flavor', particles: 'rm.particles',
32
- };
33
- // Alvos de cena "em breve" (hoje nenhum — os 4 já agem).
34
- export const RM_SOON = new Set([]);
35
- /** Cabeçalho de seção, com a etiqueta "vale para todos os jogadores".
36
- *
37
- * A etiqueta estava escrita à mão em cada `<h3>` e ia ser repetida pela quarta vez quando a seção nova chegou.
38
- * Reunida num ponto só, ela pôde finalmente passar por `t()` — e foi a seção nova que tornou isso urgente: com
39
- * o cabeçalho traduzido ao lado de uma etiqueta em português cru, a mistura aparecia na mesma linha da tela.
40
- * Os títulos das outras três seções continuam crus; é dívida anterior a esta mudança, contada pelo gate. */
41
- const secao = (titulo) => `<h3 class="panel-sub">${titulo} <span class="panel-sub__tag">${t('rm.sec.all')}</span></h3>`;
42
- const CRT_LBL = { scan: 'rm.crt.scan', vig: 'rm.crt.vig', round: 'rm.crt.round' }; // CHAVES i18n (ver RM_LABEL)
43
- const CRT_ROUND_LEVELS = ['desligado', 'pequeno', 'grande'];
44
28
  // ---------------------------------------------------------------------------------------------------------
45
- // Lógica PURA — testável em node, sem `document`.
29
+ // PURE logic — testable in node, no `document`.
46
30
  // ---------------------------------------------------------------------------------------------------------
47
- /** selAnimPlayer nunca aponta pra fora do nº de telas atual. */
48
- export function clampSelectedPlayer(selected, total) {
49
- return selected >= total ? 0 : selected;
50
- }
51
- /** Uma linha de switch "Animado/Congelado" (usada tanto para o personagem quanto para a cena). */
52
- export function motionRowHtml(label, frozen, attr, soon) {
53
- const on = !frozen;
54
- const soonTag = soon ? ' <em style="opacity:.7">(em breve)</em>' : '';
55
- const cls = 'mode-btn switch' + (on ? ' is-on' : '');
56
- const btnText = on ? '▶ Animado' : '❄ Congelado';
57
- const state = on ? 'animação ligada' : 'animação congelada';
58
- return `<div class="ctrl-row"><span>${label}${soonTag}</span><button class="${cls}" ${attr} type="button" aria-pressed="${on}" aria-label="${label}: ${state}">${btnText}</button></div>`;
59
- }
60
- /** Linhas "Personagem" (por jogador selecionado). */
61
- export function buildCharRowsHtml(rmChar, player) {
62
- return rmChar.map((c) => motionRowHtml(t(c.lbl), !!(player && player[c.prop]), `data-rmc="${c.prop}"`, false)).join('');
63
- }
64
- /** Linhas "Cena" (globais, valem para todos os jogadores). */
65
- export function buildSceneRowsHtml(rmKeys, rm, labels, soon) {
66
- return rmKeys.map((k) => motionRowHtml(t(labels[k]), !!rm[k], `data-rm="${k}"`, soon.has(k))).join('');
67
- }
68
- /** Toggle liga/desliga da estética CRT (scanlines/vinheta). */
69
- export function crtToggleRowHtml(label, key, on) {
70
- const cls = 'mode-btn switch' + (on ? ' is-on' : '');
71
- return `<div class="ctrl-row"><span>${label}</span><button class="${cls}" data-crt-tgl="${key}" type="button" aria-pressed="${on}" aria-label="${toggleAria(label, on)}">${toggleLabel(on)}</button></div>`;
72
- }
73
- /** Cantos CRT: 3 níveis (0=quadrado · 1=pequeno · 2=grande). */
74
- export function crtRoundRowHtml(label, round) {
75
- const opt = (v, text) => `<option value="${v}"${round === v ? ' selected' : ''}>${text}</option>`;
76
- return `<div class="ctrl-row"><span>${label}</span><select class="vol" data-crt="round" aria-label="${label}">${opt(0, 'Desligado (quadrado)')}${opt(1, 'Pequeno')}${opt(2, 'Grande')}</select></div>`;
77
- }
78
- /** true quando TUDO (cena + personagem selecionado) já está com movimento reduzido LIGADO, isto é,
79
- * congelado — nome fiel ao `rm[k]`/`player[prop]` que representam "reduzido", não "animado". Controla
80
- * se o botão-mestre oferece "Retomar" (true) ou "Parar" (false) — mesma variável `allOn` do game.js
81
- * original, aqui renomeada por clareza (o valor/comportamento não muda). */
82
- export function allMotionFrozen(rmKeys, rm, rmChar, player) {
83
- return rmKeys.every((k) => rm[k]) && rmChar.every((c) => !!(player && player[c.prop]));
84
- }
85
- /** allFrozen=true (tudo já congelado) → oferece "Retomar"; caso contrário → oferece "Parar". */
86
- export function motionMasterLabel(allFrozen) {
87
- return allFrozen ? '▶ Retomar todas as animações' : '⏸ Parar todas as animações';
88
- }
89
- /** `label` chega JÁ TRADUZIDO; o que era concatenação (' congelado.') virou moldura com `{alvo}` — é o que
90
- * permite a uma língua pôr o estado ANTES do alvo, coisa que uma concatenação não deixa. */
91
- export function sceneMotionAnnouncement(label, frozen) {
92
- return t(frozen ? 'sr.rm.frozen' : 'sr.rm.animated', { alvo: label });
93
- }
94
- export function crtToggleAnnouncement(label, on) {
95
- return t(on ? 'sr.crt.on' : 'sr.crt.off', { efeito: label });
96
- }
97
- export function crtLevelLabel(level) {
98
- return CRT_ROUND_LEVELS[level];
31
+ /**
32
+ * The NAME of each part of this inside, which is what mounting reconciles by.
33
+ *
34
+ * 📌 A key and not a position: the character rows appear and disappear with the cartridge (ADR-0153), so mounting has to
35
+ * know WHICH row is which to relabel the one that stayed and remove the one that lost its subject.
36
+ */
37
+ const partOfChar = (prop) => `char:${prop}`;
38
+ const partOfScene = (key) => `scene:${key}`;
39
+ const partOfCrt = (key) => `crt:${key}`;
40
+ /**
41
+ * Mounts this panel's inside and reconciles it afterwards — creates what is missing, rewrites what stayed, removes what
42
+ * lost its subject. It NEVER moves a node that already exists.
43
+ *
44
+ * 🔴 Rebuilding costs the child their place: with the cursor on the rounded corners, a click on the neighbouring row
45
+ * would destroy the control and drop focus on `<body>`. ⚠️ And moving also blurs, which is why this function INSERTS at
46
+ * the right position instead of appending and reordering: a node that changes parent is removed and re-added, and the
47
+ * browser takes its focus away on removal.
48
+ */
49
+ function mountMotionInside(ctx, list, spec) {
50
+ reconcile(list, motionParts(ctx, spec));
99
51
  }
100
- export function crtRoundAnnouncement(label, level) {
101
- return t('sr.crt.round', { efeito: label, nivel: crtLevelLabel(level) });
52
+ /**
53
+ * What this inside HAS, in order — a different question from how the document gets there.
54
+ *
55
+ * ⚠️ Separate from `reconcile` so each stays under McCabe's ceiling of 10 (ADR-0221): each is a sentence with a name.
56
+ */
57
+ function motionParts(ctx, spec) {
58
+ const sectionPart = (key, title, tag, rows) => (rows === 0 ? null : {
59
+ key,
60
+ build: () => sectionHeader(ctx, title, tag, rows) ?? ctx.create('h3'),
61
+ write: (el) => {
62
+ el.textContent = title + ' ';
63
+ const mark = ctx.create('span');
64
+ mark.className = 'panel-sub__tag';
65
+ mark.textContent = tag;
66
+ el.appendChild(mark);
67
+ },
68
+ });
69
+ const switchPart = (key, id, label, mark) => ({
70
+ key,
71
+ build: () => {
72
+ const { row: newRow, control: switchButton } = controlRow(ctx, { id, label: label, ariaLabel: label });
73
+ switchButton.setAttribute(mark[0], mark[1]);
74
+ return newRow;
75
+ },
76
+ // ⚠️ ONLY THE WORDS. The state (class, `aria-pressed`, the button's text) is written by the panel's reflect, which
77
+ // knows the value — writing it here would give two answers to the same question.
78
+ write: (el) => labelRow(el, { id, label: label, ariaLabel: label }),
79
+ });
80
+ const parts = [];
81
+ const charHeader = sectionPart('sec:char', spec.charTitle ?? '', spec.charTag, spec.charTitle ? spec.charRows.length : 0);
82
+ if (charHeader)
83
+ parts.push(charHeader);
84
+ for (const r of spec.charRows)
85
+ parts.push(switchPart(partOfChar(r.prop), `motion-char-${r.prop}`, r.label, ['data-rmc', r.prop]));
86
+ const sceneHeader = sectionPart('sec:scene', spec.sceneTitle, spec.allTag, spec.sceneRows.length);
87
+ if (sceneHeader)
88
+ parts.push(sceneHeader);
89
+ for (const r of spec.sceneRows)
90
+ parts.push(switchPart(partOfScene(r.key), `motion-scene-${r.key}`, r.label, ['data-rm', r.key]));
91
+ const crtHeader = sectionPart('sec:crt', spec.crtTitle, spec.allTag, spec.crtToggles.length + 1);
92
+ if (crtHeader)
93
+ parts.push(crtHeader);
94
+ for (const r of spec.crtToggles)
95
+ parts.push(switchPart(partOfCrt(r.key), `crt-${r.key}`, r.label, ['data-crt-tgl', r.key]));
96
+ parts.push({
97
+ key: partOfCrt('round'),
98
+ build: () => {
99
+ // ⚠️ NO SEPARATE LABEL (ADR-0130 errata): the steps control writes «◀ Cantos arredondados: pequeno ▶» across the
100
+ // whole row, and a label beside it would say the name twice.
101
+ const row = ctx.create('div');
102
+ row.className = 'ctrl-row ctrl-row--passos';
103
+ const steps = mountSteps(ctx, spec.roundSpec());
104
+ steps.setAttribute('data-crt', 'round');
105
+ row.appendChild(steps);
106
+ return row;
107
+ },
108
+ write: (el) => {
109
+ const steps = el.querySelector('[data-passos]');
110
+ if (steps)
111
+ updateSteps(steps, spec.roundSpec());
112
+ },
113
+ });
114
+ return parts;
102
115
  }
103
- /** `nowFrozen` = o NOVO valor de rm[k]/player[prop] aplicado pelo botão-mestre (true = acabou de congelar
104
- * tudo; false = acabou de descongelar/retomar tudo) — mesma variável `v` do game.js original. */
105
- export function stopResumeAllAnnouncement(nowFrozen) {
106
- return t(nowFrozen ? 'sr.rm.allStopped' : 'sr.rm.allResumed');
116
+ /**
117
+ * The document brought in line with the list: creates what is missing AT THE RIGHT POSITION, rewrites what stayed,
118
+ * removes what is no longer asked for.
119
+ *
120
+ * ⚠️ IT NEVER MOVES A NODE THAT ALREADY EXISTS, and not for thrift: a node that changes parent is removed and re-added,
121
+ * and the browser takes its focus away on removal — the defect building nodes exists to avoid, through another door.
122
+ */
123
+ function reconcile(list, parts) {
124
+ let previous = null;
125
+ for (const part of parts) {
126
+ let el = list.querySelector(`[data-motion-part="${part.key}"]`);
127
+ if (!el) {
128
+ el = part.build();
129
+ el.dataset.motionPart = part.key;
130
+ list.insertBefore(el, previous ? previous.nextSibling : list.firstChild);
131
+ }
132
+ part.write(el);
133
+ previous = el;
134
+ }
135
+ const keep = new Set(parts.map((p) => p.key));
136
+ for (const el of [...list.querySelectorAll('[data-motion-part]')]) {
137
+ if (!keep.has(el.dataset.motionPart ?? ''))
138
+ el.remove();
139
+ }
107
140
  }
108
- // ---------------------------------------------------------------------------------------------------------
109
- // Estado do módulo — equivalente a `let selAnimPlayer=0` + `animationOpen=false` do game.js.
110
- // ---------------------------------------------------------------------------------------------------------
111
- let selectedPlayer = 0;
112
- export function getSelectedPlayer() { return selectedPlayer; }
113
- /** Chamado de fora (ex.: o atalho "anim" do menu de pausa) antes de open(). */
114
- export function setSelectedPlayer(i) { selectedPlayer = i; }
115
141
  export function initSettingsMotion(ctx) {
142
+ const { t } = ctx;
143
+ const crtCfg = ctx.crt.cfg;
144
+ const applyCrt = () => { ctx.crt.apply(); };
145
+ /** The selected player: THIS panel's, in its closure (ADR-0232 D4) — a module `let` was shared by every root's panel. */
146
+ let selectedPlayer = 0;
116
147
  /*
117
- * ⚠️ RESOLVIDAS UMA VEZ, NO ARRANQUE, e não a cada uso. O `rm` é mutado in-place e partilhado por
118
- * REFERÊNCIA com quem desenha a cena; resolvê-lo a cada leitura criaria um objecto novo por chamada, o
119
- * interruptor deixaria de alcançar o desenho, e não haveria erro nenhum — o menu diria «reduzido» e a cena
120
- * continuaria a mexer-se.
148
+ * ⚠️ RESOLVED ONCE, AT BOOT, not on every use. `rm` is mutated in place and shared by REFERENCE with whoever draws
149
+ * the scene; resolving it on every read would create a new object per call, the switch would stop reaching the
150
+ * drawing, and there would be no error at all — the menu would say reduced and the scene would keep moving.
121
151
  */
122
- const rm = ctx.rm ?? lerCenaGuardada();
123
- const rmKeys = ctx.rmKeys ?? CHAVES_DE_CENA;
124
- const rmChar = ctx.rmChar ?? ANIMACOES_DO_PERSONAGEM;
125
- const saveRM = ctx.saveRM ?? (() => guardarCena(rm));
152
+ const rm = ctx.rm ?? readStoredScene(ctx.store, defaultReducedMotion(ctx.matchMedia));
153
+ const rmKeys = ctx.rmKeys ?? SCENE_KEYS;
154
+ const allCharAnimations = ctx.rmChar ?? CHARACTER_ANIMATIONS;
155
+ /** The character targets that HAVE A SUBJECT in this game — read on every use, because the cartridge changes on `mount()`. */
156
+ const rmChar = () => (ctx.hasCharacter?.() === false ? [] : allCharAnimations);
157
+ const saveRM = ctx.saveRM ?? (() => storeScene(ctx.store, rm));
126
158
  function reflectMotionBtn() {
127
159
  const b = ctx.$('#opt-animation');
128
160
  if (b)
@@ -134,119 +166,172 @@ export function initSettingsMotion(ctx) {
134
166
  if (!m)
135
167
  return;
136
168
  const player = ctx.getPlayers()[selectedPlayer];
137
- const allFrozen = allMotionFrozen(rmKeys, rm, rmChar, player);
138
- m.textContent = motionMasterLabel(allFrozen);
169
+ const allFrozen = allMotionFrozen(rmKeys, rm, rmChar(), player);
170
+ m.textContent = motionMasterLabel(t, allFrozen);
139
171
  ctx.toggleBtn(m, allFrozen);
140
172
  }
173
+ const kitCtx = (list) => ({
174
+ find: (sel) => ctx.$(sel),
175
+ create: (tag) => list.ownerDocument.createElement(tag),
176
+ });
177
+ const roundSpec = () => ({ label: t(CRT_LBL.round), values: [0, 1, 2].map((level) => crtLevelLabel(t, level)), current: crtCfg.round });
178
+ /** Each switch's STATE — what the kit does not write, because the panel knows the value. */
179
+ function reflectSwitches(el) {
180
+ const player = ctx.getPlayers()[selectedPlayer];
181
+ const writeSwitch = (sel, on, name) => {
182
+ const b = el.querySelector(sel);
183
+ if (!b)
184
+ return;
185
+ ctx.toggleBtn(b, on);
186
+ b.textContent = toggleLabel(t, on);
187
+ b.setAttribute('aria-label', toggleAria(t, name, on));
188
+ };
189
+ // ⚠️ "Animated" is the OPPOSITE of `rm`/`player[prop]`, which store "reduced motion". The faithful name is in
190
+ // `allMotionFrozen`, and the inversion lives here, in one place.
191
+ for (const c of rmChar())
192
+ writeSwitch(`[data-rmc="${c.prop}"]`, !(player && player[c.prop]), t(c.lbl));
193
+ for (const k of rmKeys)
194
+ writeSwitch(`[data-rm="${k}"]`, !rm[k], t(RM_LABEL[k]));
195
+ writeSwitch('[data-crt-tgl="scan"]', !!crtCfg.scan, t(CRT_LBL.scan));
196
+ writeSwitch('[data-crt-tgl="vig"]', !!crtCfg.vig, t(CRT_LBL.vig));
197
+ }
198
+ /** The listeners, ONCE and by delegation: the character rows come and go with the cartridge (ADR-0153), and wiring
199
+ * button by button on every render would pile one listener per pass onto each button that survived. */
200
+ let wired = false;
201
+ function wireOnce(el) {
202
+ if (wired)
203
+ return;
204
+ wired = true;
205
+ el.addEventListener('click', (ev) => {
206
+ const b = ev.target?.closest('button');
207
+ if (!b || !el.contains(b))
208
+ return;
209
+ const crt = b.dataset.crtTgl;
210
+ if (crt) {
211
+ crtCfg[crt] = crtCfg[crt] ? 0 : 1;
212
+ applyCrt();
213
+ reflectSwitches(el);
214
+ refreshMarks();
215
+ ctx.srSay(crtToggleAnnouncement(t, t(CRT_LBL[crt]), !!crtCfg[crt]));
216
+ return;
217
+ }
218
+ const prop = b.dataset.rmc;
219
+ if (prop) {
220
+ const p = ctx.getPlayers()[selectedPlayer];
221
+ p[prop] = !p[prop];
222
+ ctx.store.setBool('incl_' + prop + '_p' + selectedPlayer, !!p[prop]);
223
+ render();
224
+ return;
225
+ }
226
+ const k = b.dataset.rm;
227
+ if (!k)
228
+ return;
229
+ rm[k] = !rm[k];
230
+ saveRM();
231
+ render();
232
+ updateMotionMaster();
233
+ ctx.srSay(sceneMotionAnnouncement(t, t(RM_LABEL[k]), rm[k]));
234
+ });
235
+ el.addEventListener('passo', (ev) => {
236
+ const stepper = ev.target?.closest('[data-crt="round"]');
237
+ if (!stepper)
238
+ return;
239
+ const next = nextStep(crtCfg.round, CRT_ROUND_LEVELS.length, ev.detail);
240
+ // ⚠️ AT THE END NOTHING IS ANNOUNCED: repeating the largest level to someone already there would sound like a step.
241
+ if (next === crtCfg.round)
242
+ return;
243
+ crtCfg.round = next;
244
+ applyCrt();
245
+ updateSteps(stepper, roundSpec());
246
+ refreshMarks();
247
+ ctx.srSay(crtRoundAnnouncement(t, t(CRT_LBL.round), crtCfg.round));
248
+ });
249
+ }
141
250
  function render() {
142
251
  const el = ctx.$('#motion-list');
143
252
  if (!el)
144
253
  return;
145
254
  selectedPlayer = clampSelectedPlayer(selectedPlayer, ctx.getNumPlayers());
146
- // E3: sem abas — cada jogador edita só o seu. BUG preservado VERBATIM do game.js (não corrigido, ver
147
- // retorno da extração): innerHTML='' roda ANTES do querySelectorAll, então o forEach abaixo nunca acha
148
- // botões — este bloco de wiring é código morto tanto aqui quanto no original.
255
+ // No tabs — each player edits only their own. The strip stays hidden and empty.
149
256
  const tabs = ctx.$('#animation-players');
150
257
  if (tabs) {
151
258
  tabs.hidden = true;
152
- tabs.innerHTML = '';
153
- tabs.querySelectorAll('button[data-ap]').forEach((b) => b.addEventListener('click', () => {
154
- selectedPlayer = Number(b.dataset.ap);
155
- render();
156
- // A prosa volta para o rodapé depois de as linhas serem reconstruídas (CLAUDE.md §4, #109).
157
- ctx.fillExplain?.(ctx.$('#animation .overlay__card'));
158
- }));
259
+ tabs.textContent = '';
159
260
  }
160
- const player = ctx.getPlayers()[selectedPlayer];
161
- const charRows = buildCharRowsHtml(rmChar, player);
162
- const sceneRows = buildSceneRowsHtml(rmKeys, rm, RM_LABEL, RM_SOON);
163
- const crtRows = crtToggleRowHtml(t(CRT_LBL.scan), 'scan', !!CRT.scan) + crtToggleRowHtml(t(CRT_LBL.vig), 'vig', !!CRT.vig) + crtRoundRowHtml(t(CRT_LBL.round), CRT.round);
164
- el.innerHTML =
165
- `<h3 class="panel-sub">Personagem${ctx.getNumPlayers() > 1 ? ' · Jogador ' + (selectedPlayer + 1) : ''} <span class="panel-sub__tag">por jogador</span></h3>${charRows}` +
166
- `${secao('Cena')}${sceneRows}` +
167
- `${secao('Estética CRT')}${crtRows}`;
168
- el.querySelectorAll('button[data-crt-tgl]').forEach((b) => b.addEventListener('click', () => {
169
- const k = b.dataset.crtTgl;
170
- CRT[k] = CRT[k] ? 0 : 1;
171
- applyCrt();
172
- render();
173
- ctx.srSay(crtToggleAnnouncement(t(CRT_LBL[k]), !!CRT[k]));
174
- }));
175
- el.querySelectorAll('select[data-crt]').forEach((s) => s.addEventListener('change', () => {
176
- const key = s.dataset.crt;
177
- CRT[key] = +s.value;
178
- applyCrt();
179
- ctx.srSay(crtRoundAnnouncement(t(CRT_LBL[key]), CRT[key]));
180
- }));
181
- el.querySelectorAll('button[data-rmc]').forEach((b) => b.addEventListener('click', () => {
182
- const prop = b.dataset.rmc;
183
- const p = ctx.getPlayers()[selectedPlayer];
184
- p[prop] = !p[prop];
185
- ctx.store.setBool('incl_' + prop + '_p' + selectedPlayer, !!p[prop]);
186
- render();
187
- }));
188
- el.querySelectorAll('button[data-rm]').forEach((b) => b.addEventListener('click', () => {
189
- const k = b.dataset.rm;
190
- rm[k] = !rm[k];
191
- saveRM();
192
- render();
193
- updateMotionMaster();
194
- ctx.srSay(sceneMotionAnnouncement(t(RM_LABEL[k]), rm[k]));
195
- }));
261
+ mountMotionInside(kitCtx(el), el, {
262
+ // ⚠️ THE SEAT SUFFIX is a key, and reuses the card's `pause.cardSeat`: it is the SAME sentence for the SAME person,
263
+ // and two keys would be two places for it to drift between languages.
264
+ charTitle: rmChar().length
265
+ ? (ctx.characterLabel?.() ?? 'Personagem') + (ctx.getNumPlayers() > 1 ? t('pause.cardSeat', { n: selectedPlayer + 1 }) : '')
266
+ : null,
267
+ // 📌 Three section labels are still raw and are in this module's raw-prose ledger — fixing them in passing would
268
+ // mix two decisions in one commit.
269
+ charTag: 'por jogador',
270
+ charRows: rmChar().map((c) => ({ prop: c.prop, label: t(c.lbl) })),
271
+ sceneTitle: 'Cena',
272
+ sceneRows: rmKeys.map((k) => ({ key: k, label: t(RM_LABEL[k]) })),
273
+ crtTitle: 'Estética CRT',
274
+ allTag: t('rm.sec.all'),
275
+ crtToggles: [{ key: 'scan', label: t(CRT_LBL.scan) }, { key: 'vig', label: t(CRT_LBL.vig) }],
276
+ roundSpec,
277
+ });
278
+ reflectSwitches(el);
279
+ wireOnce(el);
196
280
  updateMotionMaster();
197
281
  refreshMarks();
282
+ // The prose goes back to the footer after the rows change (CLAUDE.md §4, #109).
283
+ ctx.fillExplain?.(ctx.$('#animation .overlay__card'));
198
284
  }
199
285
  /**
200
- * A marca de "saiu do padrão" (ADR-0029), contra o padrão CALCULADO — não contra `false`.
286
+ * The left-the-default mark (ADR-0029), against the COMPUTED default — not against `false`.
201
287
  *
202
- * Numa máquina cujo dono pediu menos movimento, o padrão das cinco linhas de animação é CONGELADO. Marcar
203
- * contra `false` acusaria "alterado" em cinco linhas que a criança nunca tocou, e mandaria justamente ela
204
- * desfazer a preferência do próprio sistema. Uma marca errada é pior que marca nenhuma, e aqui ela erraria
205
- * na direção mais cara.
288
+ * On a machine whose owner asked for less motion, the animation rows' default is FROZEN. Marking against `false` would
289
+ * accuse "changed" on rows the child never touched, and send exactly them to undo their own system's preference. A
290
+ * wrong mark is worse than no mark, and here it would err in the costliest direction.
206
291
  */
207
292
  function refreshMarks() {
208
- const padraoRm = defaultReducedMotion();
293
+ const reducedByDefault = defaultReducedMotion(ctx.matchMedia);
209
294
  const el = ctx.$('#motion-list');
210
295
  const player = ctx.getPlayers()[selectedPlayer];
211
- const mudou = [];
212
- const marcar = (sel, changed) => {
213
- mudou.push(changed);
214
- markChanged(el?.querySelector(sel)?.closest('.ctrl-row') ?? null, changed);
296
+ const changedFlags = [];
297
+ const markRow = (sel, changed) => {
298
+ changedFlags.push(changed);
299
+ markChanged(t, el?.querySelector(sel)?.closest('.ctrl-row') ?? null, changed);
215
300
  };
216
- for (const c of rmChar)
217
- marcar(`[data-rmc="${c.prop}"]`, !!(player && player[c.prop]) !== padraoRm);
301
+ for (const c of rmChar())
302
+ markRow(`[data-rmc="${c.prop}"]`, !!(player && player[c.prop]) !== reducedByDefault);
218
303
  for (const k of rmKeys)
219
- marcar(`[data-rm="${k}"]`, !!rm[k] !== padraoRm);
220
- marcar('[data-crt-tgl="scan"]', !!CRT.scan !== !!CRT_DEFAULT.scan);
221
- marcar('[data-crt-tgl="vig"]', !!CRT.vig !== !!CRT_DEFAULT.vig);
222
- marcar('[data-crt="round"]', CRT.round !== CRT_DEFAULT.round);
223
- markMenuChanged(ctx.$('[data-act="anim"]'), mudou);
304
+ markRow(`[data-rm="${k}"]`, !!rm[k] !== reducedByDefault);
305
+ markRow('[data-crt-tgl="scan"]', !!crtCfg.scan !== !!CRT_DEFAULT.scan);
306
+ markRow('[data-crt-tgl="vig"]', !!crtCfg.vig !== !!CRT_DEFAULT.vig);
307
+ markRow('[data-crt="round"]', crtCfg.round !== CRT_DEFAULT.round);
308
+ markMenuChanged(t, ctx.$('[data-act="anim"]'), changedFlags);
224
309
  }
225
- // ---- restaurar os padrões DESTE menu (ADR-0028) ----
310
+ // ---- reset THIS menu's defaults (ADR-0028) ----
226
311
  //
227
- // O único dos sete cujo padrão NÃO é uma constante: o das cinco linhas de animação é o que o sistema
228
- // operacional pede (`prefers-reduced-motion`). Devolver `false` aqui RELIGARIA a animação na tela de quem
229
- // já pediu menos movimento — o reset faria sozinho o que a WCAG 2.3.3 existe para impedir. Por isso ele
230
- // chama `defaultReducedMotion()` e não escreve o valor à mão.
312
+ // The only menu whose default is NOT a constant: the animation rows' default is what the operating system asks for
313
+ // (`prefers-reduced-motion`). Returning `false` here would TURN ANIMATION BACK ON for whoever already asked for less
314
+ // motion — the reset alone would do what WCAG 2.3.3 exists to prevent. That is why it calls `defaultReducedMotion`
315
+ // and does not write the value by hand.
231
316
  //
232
- // O escopo é TODOS os jogadores, como no menu motor: o painel edita um por vez, mas o reset é do menu, e
233
- // deixar o jogador 2 congelado porque a aba aberta era a do jogador 1 daria dois estados com um nome só.
317
+ // The scope is ALL players, as in the mobility menu: the panel edits one at a time, but the reset belongs to the menu,
318
+ // and leaving player 2 frozen because the open tab was player 1's would give two states one name.
234
319
  const resetBtn = ctx.$('#animation-reset');
235
320
  if (resetBtn)
236
321
  resetBtn.addEventListener('click', () => {
237
- const padraoRm = defaultReducedMotion();
322
+ const reducedByDefault = defaultReducedMotion(ctx.matchMedia);
238
323
  for (const k of rmKeys)
239
- rm[k] = padraoRm;
324
+ rm[k] = reducedByDefault;
240
325
  saveRM();
241
326
  ctx.getPlayers().forEach((p, i) => {
242
- for (const c of rmChar) {
243
- p[c.prop] = padraoRm;
244
- ctx.store.setBool('incl_' + c.prop + '_p' + i, padraoRm);
327
+ for (const c of rmChar()) {
328
+ p[c.prop] = reducedByDefault;
329
+ ctx.store.setBool('incl_' + c.prop + '_p' + i, reducedByDefault);
245
330
  }
246
331
  });
247
- CRT.scan = CRT_DEFAULT.scan;
248
- CRT.vig = CRT_DEFAULT.vig;
249
- CRT.round = CRT_DEFAULT.round;
332
+ crtCfg.scan = CRT_DEFAULT.scan;
333
+ crtCfg.vig = CRT_DEFAULT.vig;
334
+ crtCfg.round = CRT_DEFAULT.round;
250
335
  applyCrt();
251
336
  render();
252
337
  ctx.srSay(t('sr.motion.reset'));
@@ -271,25 +356,29 @@ export function initSettingsMotion(ctx) {
271
356
  return;
272
357
  const b = ctx.$('#opt-animation');
273
358
  if (b)
274
- b.focus(); // recuo: este id nao existe no documento hoje (gancho de uma barra futura)
359
+ b.focus(); // fallback: this id does not exist in the document today (a hook for a future bar)
275
360
  }
276
361
  const master = ctx.$('#motion-master');
277
362
  if (master)
278
363
  master.addEventListener('click', () => {
279
364
  const player = ctx.getPlayers()[selectedPlayer];
280
- const allFrozen = allMotionFrozen(rmKeys, rm, rmChar, player);
365
+ const allFrozen = allMotionFrozen(rmKeys, rm, rmChar(), player);
281
366
  const next = !allFrozen;
282
367
  for (const k of rmKeys)
283
368
  rm[k] = next;
284
369
  saveRM();
285
370
  if (player)
286
- for (const c of rmChar) {
371
+ for (const c of rmChar()) {
287
372
  player[c.prop] = next;
288
373
  ctx.store.setBool('incl_' + c.prop + '_p' + selectedPlayer, next);
289
374
  }
290
375
  render();
291
- ctx.srSay(stopResumeAllAnnouncement(next));
376
+ ctx.srSay(stopResumeAllAnnouncement(t, next));
292
377
  });
293
- reflectMotionBtn(); // estado inicial (ex.: prefers-reduced-motion liga por padrão)
294
- return { render, open, close };
378
+ reflectMotionBtn(); // initial state (e.g. prefers-reduced-motion switches it on by default)
379
+ return {
380
+ render, open, close,
381
+ selectedPlayer: () => selectedPlayer,
382
+ setSelectedPlayer: (i) => { selectedPlayer = i; },
383
+ };
295
384
  }