@the-inclusionist/engine 10.0.0 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -1
- package/app/css/style.css +216 -42
- package/app/public/vendor/fonts-licences/NOTICE.txt +166 -0
- package/app/public/vendor/fonts-licences/OFL-1.1.txt +86 -0
- package/app/public/vendor/fonts.css +11 -1175
- package/dist-pkg/boot/create-game.d.ts +84 -33
- package/dist-pkg/boot/create-game.js +708 -307
- package/dist-pkg/core/a11y-sr.d.ts +1 -1
- package/dist-pkg/core/a11y-sr.js +3 -5
- package/dist-pkg/core/accommodations.d.ts +26 -8
- package/dist-pkg/core/accommodations.js +27 -10
- package/dist-pkg/core/actions.d.ts +39 -10
- package/dist-pkg/core/actions.js +28 -6
- package/dist-pkg/core/contract.d.ts +0 -2
- package/dist-pkg/core/contract.js +0 -2
- package/dist-pkg/core/i18n.d.ts +36 -71
- package/dist-pkg/core/i18n.js +131 -198
- package/dist-pkg/core/session-clock.d.ts +23 -0
- package/dist-pkg/core/session-clock.js +37 -0
- package/dist-pkg/i18n/en.js +44 -49
- package/dist-pkg/i18n/es.js +44 -49
- package/dist-pkg/i18n/pt.js +49 -54
- package/dist-pkg/input/gamepad.d.ts +42 -11
- package/dist-pkg/input/gamepad.js +50 -15
- package/dist-pkg/input/key-default.d.ts +30 -0
- package/dist-pkg/input/key-default.js +60 -0
- package/dist-pkg/input/keyboard-runtime.d.ts +0 -4
- package/dist-pkg/input/keyboard.d.ts +0 -1
- package/dist-pkg/input/keydown.d.ts +5 -11
- package/dist-pkg/input/keydown.js +3 -3
- package/dist-pkg/input/latch-edge.d.ts +10 -2
- package/dist-pkg/input/latch-edge.js +4 -3
- package/dist-pkg/input/latch-scope.d.ts +27 -22
- package/dist-pkg/input/latch-scope.js +25 -37
- package/dist-pkg/input/latch-store.d.ts +9 -12
- package/dist-pkg/input/latch-store.js +13 -18
- package/dist-pkg/input/latch-sync.d.ts +5 -4
- package/dist-pkg/input/latch-sync.js +5 -5
- package/dist-pkg/input/pad-reading.js +7 -2
- package/dist-pkg/input/pad-wizard.d.ts +4 -1
- package/dist-pkg/input/pad-wizard.js +60 -9
- package/dist-pkg/input/switch-scan.d.ts +29 -12
- package/dist-pkg/input/switch-scan.js +15 -2
- package/dist-pkg/input/touch-bindings.d.ts +3 -6
- package/dist-pkg/input/touch.d.ts +17 -2
- package/dist-pkg/input/touch.js +55 -17
- package/dist-pkg/input/transport-in-use.d.ts +5 -5
- package/dist-pkg/input/transport-in-use.js +5 -5
- package/dist-pkg/input/transports.d.ts +0 -9
- package/dist-pkg/input/transports.js +1 -1
- package/dist-pkg/input/virtual-controller.d.ts +39 -3
- package/dist-pkg/input/virtual-controller.js +32 -4
- package/dist-pkg/input/voice-map.d.ts +27 -11
- package/dist-pkg/input/voice-map.js +41 -43
- package/dist-pkg/platform/audio-ambient.d.ts +0 -1
- package/dist-pkg/platform/audio-ambient.js +3 -1
- package/dist-pkg/platform/audio-mixer.js +4 -9
- package/dist-pkg/platform/audio-sonar.d.ts +8 -94
- package/dist-pkg/platform/audio-sonar.js +22 -207
- package/dist-pkg/platform/audio.d.ts +10 -1
- package/dist-pkg/platform/audio.js +35 -2
- package/dist-pkg/platform/choose-by-voice.d.ts +70 -0
- package/dist-pkg/platform/choose-by-voice.js +157 -0
- package/dist-pkg/platform/font-library.d.ts +77 -0
- package/dist-pkg/platform/font-library.js +98 -0
- package/dist-pkg/platform/font-library.json +721 -0
- package/dist-pkg/platform/heavy-catalogue.d.ts +46 -0
- package/dist-pkg/platform/heavy-catalogue.js +47 -14
- package/dist-pkg/platform/heavy-mirror.d.ts +3 -9
- package/dist-pkg/platform/heavy-mirror.js +14 -17
- package/dist-pkg/platform/heavy.d.ts +40 -8
- package/dist-pkg/platform/heavy.js +177 -22
- package/dist-pkg/platform/interruptible-speech.d.ts +15 -8
- package/dist-pkg/platform/interruptible-speech.js +37 -13
- package/dist-pkg/platform/listener-scope.js +22 -13
- package/dist-pkg/platform/locale-host.d.ts +7 -3
- package/dist-pkg/platform/locale-host.js +13 -2
- package/dist-pkg/platform/reading-in-worker.d.ts +24 -0
- package/dist-pkg/platform/reading-in-worker.js +38 -0
- package/dist-pkg/platform/reading-model.d.ts +21 -0
- package/dist-pkg/platform/reading-model.js +25 -0
- package/dist-pkg/platform/reading-runtime.js +13 -8
- package/dist-pkg/platform/reading.d.ts +12 -1
- package/dist-pkg/platform/reading.js +9 -1
- package/dist-pkg/platform/speech-recognition.d.ts +10 -1
- package/dist-pkg/platform/speech-recognition.js +29 -9
- package/dist-pkg/platform/speech.d.ts +10 -1
- package/dist-pkg/platform/speech.js +24 -13
- package/dist-pkg/platform/tts.d.ts +37 -4
- package/dist-pkg/platform/tts.js +279 -57
- package/dist-pkg/platform/voice-listener.d.ts +6 -2
- package/dist-pkg/platform/voice-listener.js +1 -1
- package/dist-pkg/platform/voice-plan.d.ts +13 -0
- package/dist-pkg/platform/voice-plan.js +57 -2
- package/dist-pkg/platform/vosk-runtime.d.ts +25 -0
- package/dist-pkg/platform/vosk-runtime.js +59 -1
- package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
- package/dist-pkg/platform/vosk-vocabulary.js +178 -0
- package/dist-pkg/render/crt.d.ts +11 -9
- package/dist-pkg/render/crt.js +6 -10
- package/dist-pkg/render/cvd-matrices.d.ts +5 -1
- package/dist-pkg/render/cvd-matrices.js +5 -1
- package/dist-pkg/render/high-contrast.d.ts +1 -2
- package/dist-pkg/render/high-contrast.js +5 -1
- package/dist-pkg/render/viz-axes.d.ts +9 -0
- package/dist-pkg/render/viz-axes.js +15 -2
- package/dist-pkg/ui/aac-sets.d.ts +29 -24
- package/dist-pkg/ui/aac-sets.js +22 -30
- package/dist-pkg/ui/audio-choices.d.ts +10 -5
- package/dist-pkg/ui/audio-choices.js +14 -10
- package/dist-pkg/ui/camera-control.d.ts +47 -0
- package/dist-pkg/ui/camera-control.js +35 -1
- package/dist-pkg/ui/declared-words.d.ts +21 -0
- package/dist-pkg/ui/declared-words.js +66 -0
- package/dist-pkg/ui/drawing-problems.js +4 -3
- package/dist-pkg/ui/eye-control.js +17 -17
- package/dist-pkg/ui/face-control.js +15 -15
- package/dist-pkg/ui/fonts.d.ts +42 -8
- package/dist-pkg/ui/fonts.js +58 -24
- package/dist-pkg/ui/footer-scroll-driver.d.ts +14 -0
- package/dist-pkg/ui/footer-scroll-driver.js +201 -0
- package/dist-pkg/ui/footer-scroll.d.ts +38 -0
- package/dist-pkg/ui/footer-scroll.js +55 -0
- package/dist-pkg/ui/game-options.d.ts +14 -9
- package/dist-pkg/ui/game-options.js +41 -21
- package/dist-pkg/ui/hand-control.js +15 -15
- package/dist-pkg/ui/help-panel.d.ts +19 -8
- package/dist-pkg/ui/help-panel.js +15 -5
- package/dist-pkg/ui/hud-bands.d.ts +29 -12
- package/dist-pkg/ui/hud-bands.js +63 -25
- package/dist-pkg/ui/hud-row.d.ts +34 -0
- package/dist-pkg/ui/hud-row.js +80 -0
- package/dist-pkg/ui/hud.d.ts +0 -3
- package/dist-pkg/ui/layout.js +5 -2
- package/dist-pkg/ui/libras-avatar-clip.d.ts +30 -0
- package/dist-pkg/ui/libras-avatar-clip.js +86 -0
- package/dist-pkg/ui/libras-avatar-load.d.ts +52 -0
- package/dist-pkg/ui/libras-avatar-load.js +134 -0
- package/dist-pkg/ui/libras-avatar-plan.d.ts +102 -0
- package/dist-pkg/ui/libras-avatar-plan.js +211 -0
- package/dist-pkg/ui/libras-avatar-player.d.ts +28 -0
- package/dist-pkg/ui/libras-avatar-player.js +226 -0
- package/dist-pkg/ui/libras-avatar-stage.d.ts +37 -0
- package/dist-pkg/ui/libras-avatar-stage.js +208 -0
- package/dist-pkg/ui/libras-glosses.d.ts +28 -0
- package/dist-pkg/ui/libras-glosses.js +161 -0
- package/dist-pkg/ui/menu-intent.d.ts +29 -0
- package/dist-pkg/ui/menu-intent.js +35 -1
- package/dist-pkg/ui/menu-items.d.ts +10 -0
- package/dist-pkg/ui/menu-items.js +29 -0
- package/dist-pkg/ui/menu-nav.d.ts +40 -4
- package/dist-pkg/ui/menu-nav.js +132 -47
- package/dist-pkg/ui/panel-widgets.d.ts +34 -0
- package/dist-pkg/ui/panel-widgets.js +86 -0
- package/dist-pkg/ui/pause-icons.d.ts +30 -14
- package/dist-pkg/ui/pause-icons.js +106 -45
- package/dist-pkg/ui/scan-overlay.d.ts +3 -3
- package/dist-pkg/ui/scan-overlay.js +11 -3
- package/dist-pkg/ui/screen-text.d.ts +25 -0
- package/dist-pkg/ui/screen-text.js +152 -0
- package/dist-pkg/ui/session-clock.d.ts +32 -0
- package/dist-pkg/ui/session-clock.js +67 -0
- package/dist-pkg/ui/settings-aac.d.ts +3 -1
- package/dist-pkg/ui/settings-aac.js +32 -13
- package/dist-pkg/ui/settings-audio.d.ts +10 -5
- package/dist-pkg/ui/settings-audio.js +101 -35
- package/dist-pkg/ui/settings-controls.d.ts +0 -4
- package/dist-pkg/ui/settings-mobility.d.ts +3 -6
- package/dist-pkg/ui/settings-mobility.js +4 -46
- package/dist-pkg/ui/settings-motion.js +2 -2
- package/dist-pkg/ui/settings-panel.d.ts +10 -0
- package/dist-pkg/ui/settings-panel.js +25 -1
- package/dist-pkg/ui/settings-typo.d.ts +5 -6
- package/dist-pkg/ui/settings-typo.js +20 -11
- package/dist-pkg/ui/settings-visual.js +2 -2
- package/dist-pkg/ui/shell.d.ts +1 -3
- package/dist-pkg/ui/shell.js +8 -4
- package/dist-pkg/ui/title.d.ts +2 -11
- package/dist-pkg/ui/title.js +39 -6
- package/dist-pkg/ui/top-band.d.ts +5 -3
- package/dist-pkg/ui/top-band.js +21 -25
- package/dist-pkg/ui/typo-choices.d.ts +3 -3
- package/dist-pkg/ui/typo-choices.js +9 -8
- package/dist-pkg/ui/vlibras.d.ts +71 -27
- package/dist-pkg/ui/vlibras.js +116 -44
- package/dist-pkg/ui/voice-control.d.ts +23 -1
- package/dist-pkg/ui/voice-control.js +149 -16
- package/dist-pkg/ui/voice-settings.d.ts +2 -3
- package/dist-pkg/ui/voice-settings.js +53 -3
- package/dist-pkg/ui/where-the-child-is.js +2 -2
- package/docs/CREDITS.md +122 -10
- package/docs/LICENSES.md +36 -7
- package/package.json +34 -9
- package/scripts/check-cartridge.mjs +78 -0
- package/scripts/game-build.d.mts +25 -0
- package/scripts/game-build.mjs +144 -0
- package/scripts/heavy-into-the-delivery.mjs +284 -40
- package/scripts/libras-avatar.json +680 -0
- package/scripts/libras-avatar.mjs +246 -0
- package/scripts/libras-glosses/gloss.py +95 -0
- package/scripts/libras-glosses/pyproject.toml +32 -0
- package/scripts/libras-glosses/uv.lock +781 -0
- package/scripts/libras-glosses.mjs +351 -0
- package/scripts/licences/OFL-1.1.txt +86 -0
- package/scripts/licences/UFL-1.0.txt +96 -0
- package/scripts/licences/fonts.mjs +389 -0
- package/scripts/licences/third-party.mjs +35 -21
- package/app/public/vendor/fonts/bitter-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/bitter-var.woff2 +0 -0
- package/app/public/vendor/fonts/bodonimoda-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/bodonimoda-var.woff2 +0 -0
- package/app/public/vendor/fonts/cat-abril_fatface-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-abril_fatface-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-adlam_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-adlam_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-agu_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-agu_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-alfa_slab_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-alfa_slab_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-are_you_serious-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-are_you_serious-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-asimovian-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-asimovian-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bakbak_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bakbak_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bangers-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bangers-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-barriecito-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-barriecito-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-berkshire_swash-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-berkshire_swash-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bevan-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bevan-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bitcount-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bitcount-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bowlby_one_sc-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bowlby_one_sc-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bungee_shade-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bungee_shade-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-charm-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-charm-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-charm-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-charm-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-cherry_bomb_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-cherry_bomb_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-chokokutai-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-chokokutai-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-chonburi-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-chonburi-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-climate_crisis-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-climate_crisis-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-cookie-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-dela_gothic_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-dela_gothic_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-fascinate_inline-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-fascinate_inline-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ga_maamli-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ga_maamli-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-itim-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-itim-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-jacquard_24-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-jacquard_24-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kablammo-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kablammo-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kalam-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kalam-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kalam-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kalam-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-katibeh-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-katibeh-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lemonada-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lemonada-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lilita_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lilita_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lobster-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lobster-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-luckiest_guy-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-luckiest_guy-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-marhey-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-marhey-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-modak-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-modak-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-momo_signature-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-momo_signature-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monofett-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monofett-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monomakh-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monomakh-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monoton-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monoton-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-nerko_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-nerko_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_adlam-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_adlam-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_arabic-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_arabic-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_devanagari-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_devanagari-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_hebrew-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_hebrew-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_jp-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_jp-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_khmer-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_khmer-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_kr-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_kr-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_sc-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_sc-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_thai-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_thai-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ole-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ole-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-pacifico-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-pacifico-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-patrick_hand-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-patrick_hand-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-petit_formal_script-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-petit_formal_script-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-pixelify_sans-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-pixelify_sans-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-plaster-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-plaster-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ar_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_at-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_at_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_nsw-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_nsw_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_qld-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_qld_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_sa-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_sa_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_tas-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_tas_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_vic-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_vic_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_be_vlg-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_be_vlg_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_be_wal-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_be_wal_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_br_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ca_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_cl_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_co_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_cu_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_cz-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_cz_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_grund-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_grund_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_la-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_la_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_sas-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_sas_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_va-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_va_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_dk_loopet-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_dk_loopet_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_dk_uloopet-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_dk_uloopet_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_es_deco_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_es_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_fr_moderne-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_fr_moderne_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_fr_trad-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_fr_trad_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_gb_j_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_gb_s_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hr-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hr_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hr_lijeva-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hr_lijeva_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hu-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hu_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_id-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_id_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ie-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ie_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_in-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_in_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_is-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_is_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_it_moderna-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_it_moderna_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_it_trad-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_it_trad_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_mx_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ng_modern-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ng_modern_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nl-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nl_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_no-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_no_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nz-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nz_basic-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nz_basic_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nz_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_pe_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_pl-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_pl_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_pt_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ro-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ro_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_sk-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_sk_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_tz-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_tz_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_us_modern_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_us_trad_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_vn-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_vn_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_za-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_za_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-potta_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-potta_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranchers-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranchers-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranga-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranga-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranga-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranga-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-risque-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-risque-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-rowdies-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-rowdies-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-rowdies-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-rowdies-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ruge_boogie-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ruge_boogie-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ruslan_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ruslan_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sacramento-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sacramento-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sancreek-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sancreek-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sankofa_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sankofa_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sedgwick_ave_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sedgwick_ave_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-shantell_sans-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-shantell_sans-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-smokum-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-smokum-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-solitreo-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-solitreo-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-spicy_rice-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-spicy_rice-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sriracha-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sriracha-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-srisakdi-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-srisakdi-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-srisakdi-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-srisakdi-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-stix_two_math-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-tillana-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-tillana-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-tillana-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-tillana-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-titan_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-titan_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-yatra_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-yatra_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-yomogi-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-yomogi-400.woff2 +0 -0
- package/app/public/vendor/fonts/dmserifdisplay-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/dmserifdisplay-400.woff2 +0 -0
- package/app/public/vendor/fonts/domine-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/domine-var.woff2 +0 -0
- package/app/public/vendor/fonts/fondamento-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/fondamento-400.woff2 +0 -0
- package/app/public/vendor/fonts/fraunces-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/fraunces-var.woff2 +0 -0
- package/app/public/vendor/fonts/fredoka-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/fredoka-var.woff2 +0 -0
- package/app/public/vendor/fonts/inter-400.woff2 +0 -0
- package/app/public/vendor/fonts/inter-700.woff2 +0 -0
- package/app/public/vendor/fonts/jakarta-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/jakarta-var.woff2 +0 -0
- package/app/public/vendor/fonts/lato-400.woff2 +0 -0
- package/app/public/vendor/fonts/lato-700.woff2 +0 -0
- package/app/public/vendor/fonts/literata-400.woff2 +0 -0
- package/app/public/vendor/fonts/literata-700.woff2 +0 -0
- package/app/public/vendor/fonts/lora-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/lora-var.woff2 +0 -0
- package/app/public/vendor/fonts/merriweather-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/merriweather-var.woff2 +0 -0
- package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
- package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
- package/app/public/vendor/fonts/notosans-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/notosans-var.woff2 +0 -0
- package/app/public/vendor/fonts/nunito-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/nunito-var.woff2 +0 -0
- package/app/public/vendor/fonts/opendyslexic-400.woff2 +0 -0
- package/app/public/vendor/fonts/opensans-400.woff2 +0 -0
- package/app/public/vendor/fonts/opensans-700.woff2 +0 -0
- package/app/public/vendor/fonts/pinyon-400.woff2 +0 -0
- package/app/public/vendor/fonts/playfair-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/playfair-var.woff2 +0 -0
- package/app/public/vendor/fonts/pressstart-400.woff2 +0 -0
- package/app/public/vendor/fonts/quattro-400.woff2 +0 -0
- package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
- package/app/public/vendor/fonts/quicksand-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/quicksand-var.woff2 +0 -0
- package/app/public/vendor/fonts/robotoflex-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/robotoflex-var.woff2 +0 -0
- package/app/public/vendor/fonts/sora-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/sora-var.woff2 +0 -0
- package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
- package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
- package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
- package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
- package/app/public/vendor/fonts/spacegrotesk-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/spacegrotesk-var.woff2 +0 -0
- package/app/public/vendor/fonts/spectral-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/spectral-400.woff2 +0 -0
- package/app/public/vendor/fonts/spectral-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/spectral-700.woff2 +0 -0
- package/app/public/vendor/fonts/teachers-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/teachers-var.woff2 +0 -0
- package/app/public/vendor/fonts/ubuntu-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/ubuntu-400.woff2 +0 -0
- package/app/public/vendor/fonts/ubuntu-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/ubuntu-700.woff2 +0 -0
- package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
- package/dist-pkg/platform/guide-intensity.d.ts +0 -39
- package/dist-pkg/platform/guide-intensity.js +0 -71
- package/dist-pkg/ui/latch-refusal.d.ts +0 -33
- package/dist-pkg/ui/latch-refusal.js +0 -60
|
@@ -25,7 +25,7 @@ export declare function inputModeOf(s: {
|
|
|
25
25
|
readonly toggleMove?: boolean;
|
|
26
26
|
readonly switchScan?: boolean;
|
|
27
27
|
}): InputMode;
|
|
28
|
-
export declare function nextInputMode(m: InputMode, holdsKeys: boolean
|
|
28
|
+
export declare function nextInputMode(m: InputMode, holdsKeys: boolean): InputMode;
|
|
29
29
|
import type { Store } from '../platform/storage.js';
|
|
30
30
|
/**
|
|
31
31
|
* Hover and focus on a bar's icons write its NAME in the bar's `.pause-icons-cap` and ask for its EXPLANATION.
|
|
@@ -88,15 +88,6 @@ export interface IconStateSnapshot {
|
|
|
88
88
|
locale?: string;
|
|
89
89
|
/** False disables the blind/TTS icons: those need an audio output nobody else is listening to. */
|
|
90
90
|
privateOutput: boolean;
|
|
91
|
-
/**
|
|
92
|
-
* Does the device in use REQUIRE the latch? (ADR-0113 clause 3.) With the eyes, the face, gestures and speech the latch
|
|
93
|
-
* is what makes the input work, so there is no choice to offer: the ☝️ cycle then skips `standard` (see
|
|
94
|
-
* `inputModeOrder`).
|
|
95
|
-
*
|
|
96
|
-
* OPTIONAL because adding a required member to a published snapshot is a breaking change (the shape gate,
|
|
97
|
-
* `tests/public-surface-shrinks-by-declaration`, fails on it). Absent means «nobody told me», which degrades to «not required».
|
|
98
|
-
*/
|
|
99
|
-
latchRequired?: boolean;
|
|
100
91
|
/** No voice speaks the current language (ADR-0185): the narration icon is locked. Absent reads as a voice. */
|
|
101
92
|
noVoice?: boolean;
|
|
102
93
|
}
|
|
@@ -136,8 +127,8 @@ export interface ActionableIcons {
|
|
|
136
127
|
* DOES THIS GAME HOLD ANY KEY? — `GameDeclaration.holdsKeys`, the field of ADR-0115.
|
|
137
128
|
*
|
|
138
129
|
* The latch exists for whoever cannot keep a key pressed; in a game where nothing is held it has nothing to hold, and a
|
|
139
|
-
* control that does nothing teaches a child that the setting she depends on is broken.
|
|
140
|
-
*
|
|
130
|
+
* control that does nothing teaches a child that the setting she depends on is broken. On eyes, face, gestures and
|
|
131
|
+
* speech it is also the latch's default (ADR-0249) — read by the root at every command, not here.
|
|
141
132
|
*
|
|
142
133
|
* A FUNCTION, not a value (as in ADR-0084): an answer read once goes stale silently, and with one `createGame` serving
|
|
143
134
|
* several cartridges (ADR-0142) the icon would describe the game that booted first.
|
|
@@ -188,6 +179,11 @@ export declare function rootThatActs(rootEl: readonly PauseMenuButton[], options
|
|
|
188
179
|
* counted in «N de M» (a locked one is not hidden — it is reached, and says why).
|
|
189
180
|
*/
|
|
190
181
|
export declare const PM_VISIBLE_ITEMS = ".pause-menu:not([hidden]) .pm-btn:not([hidden])";
|
|
182
|
+
/**
|
|
183
|
+
* The other direction of the same table: the item of the root that opens each list. It is where «back» puts the cursor
|
|
184
|
+
* (ADR-0130 rule 1), and the name a list is announced by (`ui/where-the-child-is`). The root has no door.
|
|
185
|
+
*/
|
|
186
|
+
export declare const LIST_DOOR: Readonly<Record<PauseSub, string | null>>;
|
|
191
187
|
/**
|
|
192
188
|
* Switches the visible list of ONE pause card, and puts the cursor on the FIRST item of the list that came in.
|
|
193
189
|
*
|
|
@@ -195,6 +191,23 @@ export declare const PM_VISIBLE_ITEMS = ".pause-menu:not([hidden]) .pm-btn:not([
|
|
|
195
191
|
* access to the button tables. Every list already exists in the markup, so the switch is DOM only.
|
|
196
192
|
*/
|
|
197
193
|
export declare function showPauseOptions(sp: HTMLElement, sub: PauseSub): HTMLElement | null;
|
|
194
|
+
/**
|
|
195
|
+
* PUTS THE CARD'S CURSOR ON `el` — the one place every move of it goes through, whatever moved it: the arrows and the pad
|
|
196
|
+
* (`ui/menu-nav`), a finger, a held press, a door between lists, «back». The card selects by class, not by browser focus,
|
|
197
|
+
* so nothing scrolls it by itself: an item past the visible part of a long list would be marked where the child cannot see
|
|
198
|
+
* it. So the list is scrolled HERE, inside the card, until the item is wholly in view (issue #134, `keepInView`).
|
|
199
|
+
*/
|
|
200
|
+
export declare function markPauseItem(sp: HTMLElement, el: HTMLElement | null | undefined): void;
|
|
201
|
+
/**
|
|
202
|
+
* «BACK» FROM A LIST OF THE CARD: the root comes in with the cursor on THE ITEM THAT OPENED the list being left, not on
|
|
203
|
+
* the root's first item (ADR-0130 rule 1). A child who went into «Opções», looked, and came back is where she was; landing
|
|
204
|
+
* on «Voltar» would send her walking the root again to find her place, and a child who cannot see the mark would not even
|
|
205
|
+
* know she had been moved.
|
|
206
|
+
*
|
|
207
|
+
* Opening the card is another question and keeps `showPauseOptions(sp, 'raiz')`: a card opens on item 1 (ADR-0158).
|
|
208
|
+
* A door that is gone or hidden leaves the cursor on the first item, which is all there is to return to.
|
|
209
|
+
*/
|
|
210
|
+
export declare function backToRoot(sp: HTMLElement): HTMLElement | null;
|
|
198
211
|
/**
|
|
199
212
|
* WHAT AN INTENT MEANS INSIDE THE `accessibility` MODE (ADR-0044 item 7).
|
|
200
213
|
*
|
|
@@ -230,7 +243,7 @@ export interface PauseIconsCtx {
|
|
|
230
243
|
getPlayers: () => readonly unknown[];
|
|
231
244
|
/** aria-live "polite" — every successful toggle announces its NEW state. */
|
|
232
245
|
srSay: (text: string) => void;
|
|
233
|
-
/** aria-live "assertive" — the refusals (a shared audio output,
|
|
246
|
+
/** aria-live "assertive" — the refusals (a shared audio output, no voice for the language). */
|
|
234
247
|
srAlert: (text: string) => void;
|
|
235
248
|
/**
|
|
236
249
|
* Called after EVERY exit from the bar mode, with the screen and whether it was silent. Absent, nothing happens. It lets
|
|
@@ -277,7 +290,10 @@ export interface PauseIconsCtx {
|
|
|
277
290
|
setCatGain: (k: string) => void;
|
|
278
291
|
/** Repaints the TTS row of the auditory panel after the icon changes it. */
|
|
279
292
|
reflectTtsPanel: () => void;
|
|
280
|
-
/**
|
|
293
|
+
/**
|
|
294
|
+
* Whether the TTS icon also calls `reflectTtsPanel`. `createGame` passes `false`: it repaints the panel from the mixer's
|
|
295
|
+
* `onCatChange`, which hears this icon's write like any other (ADR-0247). A host without that listener passes `true`.
|
|
296
|
+
*/
|
|
281
297
|
reflectTtsPanelEnabled: boolean;
|
|
282
298
|
isLibrasOn: () => boolean;
|
|
283
299
|
toggleLibras: () => void;
|
|
@@ -43,6 +43,7 @@ import { quickBarMarkup, screenPauseMarkup, } from './pause-markup.js';
|
|
|
43
43
|
import { PAUSE_ICONS, pauseIcon } from '../core/pause-icon-catalogue.js';
|
|
44
44
|
import { nextTheme, nextCorrection, hasHighContrast, DEFAULT_VISUAL, } from '../render/viz-axes.js';
|
|
45
45
|
import { announceItem } from './item-announcement.js';
|
|
46
|
+
import { keepInView } from './menu-items.js';
|
|
46
47
|
import { accessibleLabel } from '../core/accessible-label.js';
|
|
47
48
|
import { stepInRing } from '../core/ring.js'; // from the LEAF, not from ui/menu-nav: see the note there
|
|
48
49
|
// A LIVE BINDING (ESM): the index can be turned off in the menu, and the value here follows without a subscription.
|
|
@@ -64,22 +65,18 @@ export function inputModeOf(s) {
|
|
|
64
65
|
return s.switchScan ? 'scan' : s.toggleMove ? 'sticky' : 'standard';
|
|
65
66
|
}
|
|
66
67
|
/**
|
|
67
|
-
* The next position.
|
|
68
|
-
* would happen (ADR-0155), and a word that promised what this game cannot do would teach a
|
|
69
|
-
* (ADR-0106 §5)
|
|
68
|
+
* The next position. A GAME THAT HOLDS NO KEY has nothing for the latch to hold, so the icon offers standard and one button:
|
|
69
|
+
* a cycle never stops where nothing would happen (ADR-0155), and a word that promised what this game cannot do would teach a
|
|
70
|
+
* child that her setting is broken (ADR-0106 §5).
|
|
70
71
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* `standard` is unreachable there. 🔴 That used to grey the whole icon out, and with three positions that would have cost a
|
|
74
|
-
* child playing with her eyes the one-button scan as well — the lock is the latch's, not the scan's.
|
|
72
|
+
* 📌 THE DEVICE TAKES NOTHING AWAY (ADR-0249): on eyes, face, gestures and speech the latch starts as the game answers
|
|
73
|
+
* `holdsKeys()`, and the child may turn it on or off like on any other device — so all three positions are offered there too.
|
|
75
74
|
*/
|
|
76
|
-
function inputModeOrder(holdsKeys
|
|
77
|
-
|
|
78
|
-
return ['standard', 'scan'];
|
|
79
|
-
return latchRequired ? ['sticky', 'scan'] : ['standard', 'sticky', 'scan'];
|
|
75
|
+
function inputModeOrder(holdsKeys) {
|
|
76
|
+
return holdsKeys ? ['standard', 'sticky', 'scan'] : ['standard', 'scan'];
|
|
80
77
|
}
|
|
81
|
-
export function nextInputMode(m, holdsKeys
|
|
82
|
-
const order = inputModeOrder(holdsKeys
|
|
78
|
+
export function nextInputMode(m, holdsKeys) {
|
|
79
|
+
const order = inputModeOrder(holdsKeys);
|
|
83
80
|
const i = order.indexOf(m);
|
|
84
81
|
return order[(i < 0 ? 0 : i + 1) % order.length];
|
|
85
82
|
}
|
|
@@ -88,8 +85,8 @@ export function nextInputMode(m, holdsKeys, latchRequired = false) {
|
|
|
88
85
|
import { nextGameSpeed } from '../core/game-speed.js';
|
|
89
86
|
import { KEYS } from '../platform/storage-keys.js';
|
|
90
87
|
import { setMoveLatch } from './settings-mobility.js';
|
|
91
|
-
import { latchRefusal } from './latch-refusal.js';
|
|
92
88
|
import { PM_BTNS, PM_OPTIONS_BTNS, PM_GAME_BTNS } from './pause-buttons.js';
|
|
89
|
+
import { aacMenuLocked } from './aac-sets.js';
|
|
93
90
|
import { SCENE_KEYS, CHARACTER_ANIMATIONS, readStoredScene, storeScene } from './motion-scene.js';
|
|
94
91
|
/**
|
|
95
92
|
* Hover and focus on a bar's icons write its NAME in the bar's `.pause-icons-cap` and ask for its EXPLANATION.
|
|
@@ -187,9 +184,8 @@ const ICON_VISUAL = Object.freeze({
|
|
|
187
184
|
tts: (s) => ({ on: s.ttsOn, dis: !s.privateOutput || !!s.noVoice }),
|
|
188
185
|
libras: (s) => ({ on: s.librasOn }),
|
|
189
186
|
tea: (s) => ({ on: s.calmMode === 2, calm: s.calmMode === 1 }),
|
|
190
|
-
// ⚠️ AND IT IS NEVER GREYED OUT
|
|
191
|
-
//
|
|
192
|
-
// would take the one-button scan away from the child playing with their eyes, who is the likeliest to need it.
|
|
187
|
+
// ⚠️ AND IT IS NEVER GREYED OUT: every device may be in any of its positions (ADR-0249), and what a game cannot hold the
|
|
188
|
+
// CYCLE tells by not offering it — greying the icon would take the one-button scan away with it.
|
|
193
189
|
altmove: (s) => ({ on: inputModeOf(s) !== 'standard' }),
|
|
194
190
|
contrast: (s) => ({ on: hasHighContrast(s.visual) }),
|
|
195
191
|
velocidade: (s) => ({ on: (s.speed ?? 1) < 1 }),
|
|
@@ -252,17 +248,25 @@ const ENGINE_ITEMS = new Set(['options', 'opcoesdojogo', 'pmback', 'acessibilida
|
|
|
252
248
|
* «Número de jogadores»: the GAME decides how many (ADR-0147) — and one general reason for the rest. Resolved at every
|
|
253
249
|
* refresh, so it follows the language of the moment the card opens.
|
|
254
250
|
*/
|
|
255
|
-
const OWN_REASONS = new Set(['ajuda', 'addplayer', 'opcoesdojogo']);
|
|
251
|
+
const OWN_REASONS = new Set(['ajuda', 'addplayer', 'opcoesdojogo', 'caa']);
|
|
256
252
|
function itemReason(t, act) {
|
|
257
253
|
return t(OWN_REASONS.has(act) ? `pause.motivo.${act}` : 'pause.motivo');
|
|
258
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* A door the ENGINE keeps locked whatever the game hands over. Today one: `caa`, the AAC menu, disabled until a
|
|
257
|
+
* pictogram set is licensed (ADR-0233 erratum). Its reason is only «menu disabled» — no licence explanation reaches the
|
|
258
|
+
* child — and a game's own `caa` action does not unlock it.
|
|
259
|
+
*/
|
|
260
|
+
function lockedByEngine(act) {
|
|
261
|
+
return act === 'caa' && aacMenuLocked();
|
|
262
|
+
}
|
|
259
263
|
/**
|
|
260
264
|
* THE MENU ITEMS THIS GAME CAN ACTUALLY ACTIVATE. The others are not hidden: they stay on the card, LOCKED with their
|
|
261
265
|
* reason said (ADR-0161) — an item that does nothing when pressed, and says nothing, reads to a screen-reader user as an
|
|
262
266
|
* item that does not exist.
|
|
263
267
|
*/
|
|
264
268
|
function itemsThatAct(buttons, acts) {
|
|
265
|
-
return buttons.filter((b) => ENGINE_ITEMS.has(b.act) || typeof acts[b.act] === 'function');
|
|
269
|
+
return buttons.filter((b) => !lockedByEngine(b.act) && (ENGINE_ITEMS.has(b.act) || typeof acts[b.act] === 'function'));
|
|
266
270
|
}
|
|
267
271
|
/**
|
|
268
272
|
* THE ROOT LIST, with one more rule: `options` is a DOOR, and a door to an empty room acts no more than a dead button.
|
|
@@ -299,6 +303,11 @@ export const PM_VISIBLE_ITEMS = '.pause-menu:not([hidden]) .pm-btn:not([hidden])
|
|
|
299
303
|
* row, not one more branch.
|
|
300
304
|
*/
|
|
301
305
|
const DOOR_TO_LIST = Object.freeze({ options: 'opcoes', opcoesdojogo: 'jogo', pmback: 'raiz' });
|
|
306
|
+
/**
|
|
307
|
+
* The other direction of the same table: the item of the root that opens each list. It is where «back» puts the cursor
|
|
308
|
+
* (ADR-0130 rule 1), and the name a list is announced by (`ui/where-the-child-is`). The root has no door.
|
|
309
|
+
*/
|
|
310
|
+
export const LIST_DOOR = Object.freeze({ raiz: null, opcoes: 'options', jogo: 'opcoesdojogo' });
|
|
302
311
|
/**
|
|
303
312
|
* Switches the visible list of ONE pause card, and puts the cursor on the FIRST item of the list that came in.
|
|
304
313
|
*
|
|
@@ -308,11 +317,42 @@ const DOOR_TO_LIST = Object.freeze({ options: 'opcoes', opcoesdojogo: 'jogo', pm
|
|
|
308
317
|
export function showPauseOptions(sp, sub) {
|
|
309
318
|
sp.querySelectorAll('.pause-menu').forEach((m) => { m.hidden = m.dataset.sub !== sub; });
|
|
310
319
|
const first = sp.querySelector(PM_VISIBLE_ITEMS);
|
|
311
|
-
sp.querySelectorAll('.
|
|
312
|
-
|
|
313
|
-
first.classList.add('pm-sel');
|
|
320
|
+
sp.querySelectorAll('.pi-sel').forEach((b) => b.classList.remove('pi-sel'));
|
|
321
|
+
markPauseItem(sp, first);
|
|
314
322
|
return first;
|
|
315
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* PUTS THE CARD'S CURSOR ON `el` — the one place every move of it goes through, whatever moved it: the arrows and the pad
|
|
326
|
+
* (`ui/menu-nav`), a finger, a held press, a door between lists, «back». The card selects by class, not by browser focus,
|
|
327
|
+
* so nothing scrolls it by itself: an item past the visible part of a long list would be marked where the child cannot see
|
|
328
|
+
* it. So the list is scrolled HERE, inside the card, until the item is wholly in view (issue #134, `keepInView`).
|
|
329
|
+
*/
|
|
330
|
+
export function markPauseItem(sp, el) {
|
|
331
|
+
if (!el)
|
|
332
|
+
return;
|
|
333
|
+
sp.querySelectorAll('.pm-sel').forEach((b) => b.classList.remove('pm-sel'));
|
|
334
|
+
el.classList.add('pm-sel');
|
|
335
|
+
keepInView(el);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* «BACK» FROM A LIST OF THE CARD: the root comes in with the cursor on THE ITEM THAT OPENED the list being left, not on
|
|
339
|
+
* the root's first item (ADR-0130 rule 1). A child who went into «Opções», looked, and came back is where she was; landing
|
|
340
|
+
* on «Voltar» would send her walking the root again to find her place, and a child who cannot see the mark would not even
|
|
341
|
+
* know she had been moved.
|
|
342
|
+
*
|
|
343
|
+
* Opening the card is another question and keeps `showPauseOptions(sp, 'raiz')`: a card opens on item 1 (ADR-0158).
|
|
344
|
+
* A door that is gone or hidden leaves the cursor on the first item, which is all there is to return to.
|
|
345
|
+
*/
|
|
346
|
+
export function backToRoot(sp) {
|
|
347
|
+
const left = sp.querySelector('.pause-menu:not([hidden])')?.dataset.sub;
|
|
348
|
+
const first = showPauseOptions(sp, 'raiz');
|
|
349
|
+
const door = left ? LIST_DOOR[left] : null;
|
|
350
|
+
const opener = door ? [...sp.querySelectorAll(PM_VISIBLE_ITEMS)].find((b) => b.dataset.act === door) : undefined;
|
|
351
|
+
if (!opener || opener === first)
|
|
352
|
+
return first;
|
|
353
|
+
markPauseItem(sp, opener);
|
|
354
|
+
return opener;
|
|
355
|
+
}
|
|
316
356
|
export function barAction(k, hasStart) {
|
|
317
357
|
if (hasStart || k.no)
|
|
318
358
|
return 'sair';
|
|
@@ -395,8 +435,6 @@ export function initPauseIcons(ctx) {
|
|
|
395
435
|
const setPauseActor = (i) => { if (ctx.setPauseActor)
|
|
396
436
|
ctx.setPauseActor(i); };
|
|
397
437
|
function hasPrivateOutput(i) { return hasPrivateOutputIn(P(), ctx.getNumPlayers(), i); }
|
|
398
|
-
/** The latch refusal for this player now, or `null`. Recomputed: the device in use changes. */
|
|
399
|
-
function refusalNow(i) { return ctx.transportInUse ? latchRefusal(ctx.transportInUse(i)) : null; }
|
|
400
438
|
function iconState(i) {
|
|
401
439
|
const p = P()[i] || {};
|
|
402
440
|
const cat = ctx.getAudioCat();
|
|
@@ -415,7 +453,6 @@ export function initPauseIcons(ctx) {
|
|
|
415
453
|
camera: ctx.settings.cameraControl,
|
|
416
454
|
locale: ctx.translator.locale(),
|
|
417
455
|
privateOutput: hasPrivateOutput(i),
|
|
418
|
-
latchRequired: refusalNow(i) !== null,
|
|
419
456
|
noVoice: !!ctx.noVoice?.(),
|
|
420
457
|
};
|
|
421
458
|
}
|
|
@@ -478,21 +515,15 @@ export function initPauseIcons(ctx) {
|
|
|
478
515
|
altmove: (i) => {
|
|
479
516
|
// verbatim: `players[i].toggleMove` with no `||{}` guard (unlike contrast/cvd below).
|
|
480
517
|
const latched = !!P()[i].toggleMove;
|
|
481
|
-
const next = nextInputMode(inputModeOf({ toggleMove: latched, switchScan: ctx.settings.switchScan }), ctx.holdsKeys()
|
|
518
|
+
const next = nextInputMode(inputModeOf({ toggleMove: latched, switchScan: ctx.settings.switchScan }), ctx.holdsKeys());
|
|
482
519
|
ctx.settings.setSwitchScanValue(next === 'scan');
|
|
483
520
|
// 📌 ENTERING THE SCAN LEAVES THE LATCH WHERE SHE PUT IT — the scan wins in `inputModeOf`, so the position shown is never
|
|
484
521
|
// ambiguous and coming back out returns her to the choice she had made. Leaving it writes the position she walked to.
|
|
485
522
|
// ⚠️ And the latch writer ANNOUNCES BY ITSELF, so it is called only where it changes something: otherwise the child would
|
|
486
523
|
// hear «não precisa segurar, desligado» when what ended was the scan.
|
|
524
|
+
// 📌 On every device, eyes and voice included (ADR-0249): the write goes under the transport in use, and that stored
|
|
525
|
+
// choice is what wins over the game's default the next time that transport presses.
|
|
487
526
|
if (next !== 'scan' && latched !== (next === 'sticky')) {
|
|
488
|
-
// ⚠️ THE REFUSAL, over the WRITE, which is the only thing it ever meant. The cycle above already skips `standard` on a
|
|
489
|
-
// device that always latches, so this should be unreachable — and it stays because `iconAct` is exported and the two
|
|
490
|
-
// rules could drift apart, which is the same reason the guards below give for not being belt and braces.
|
|
491
|
-
const refusal = refusalNow(i);
|
|
492
|
-
if (refusal) {
|
|
493
|
-
ctx.srAlert(t(refusal.key));
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
527
|
setToggleMove(i, next === 'sticky');
|
|
497
528
|
return;
|
|
498
529
|
}
|
|
@@ -523,18 +554,26 @@ export function initPauseIcons(ctx) {
|
|
|
523
554
|
if (face)
|
|
524
555
|
ctx.srSay(t('sr.typo.font', { fam: face }));
|
|
525
556
|
},
|
|
526
|
-
|
|
557
|
+
/*
|
|
558
|
+
* PLAYING THROUGH THE WEBCAM (ADR-0215) and BY SPEAKING (ADR-0189, issue #184): each writes the child's answer, one stored key.
|
|
559
|
+
*
|
|
560
|
+
* 🔴 A POSITION THAT STARTS A CONTROL IS ANNOUNCED BY THE CONTROL, NOT HERE. At this line nothing has started: the control
|
|
561
|
+
* starts after the write, asynchronously, and answers either way — «Pronto: já pode jogar…» when it is really on, or the
|
|
562
|
+
* reason assertively when it cannot start (and the answer goes back to off). Saying the position here told the child
|
|
563
|
+
* «Comando de voz: ligado» over a button that read «desligado», on every press where the microphone or the runtime failed.
|
|
564
|
+
* Off is true the moment it is written, so off is still said here.
|
|
565
|
+
*/
|
|
527
566
|
camera: () => {
|
|
528
567
|
const v = nextCameraControl(ctx.settings.cameraControl);
|
|
529
568
|
ctx.settings.setCameraControlValue(v);
|
|
530
|
-
|
|
569
|
+
if (v === 'off')
|
|
570
|
+
ctx.srSay(t('sr.icon.camera', { v: t('state.off') }));
|
|
531
571
|
},
|
|
532
|
-
// PLAYING BY SPEAKING (ADR-0189, issue #184): on or off, one stored key. What cannot start puts it back to off and says why,
|
|
533
|
-
// which is the control's own job (`ui/voice-control`) — this only writes the child's answer.
|
|
534
572
|
voice: () => {
|
|
535
573
|
const v = !ctx.settings.voiceControl;
|
|
536
574
|
ctx.settings.setVoiceControlValue(v);
|
|
537
|
-
|
|
575
|
+
if (!v)
|
|
576
|
+
ctx.srSay(t('sr.icon.voice', { v: t('state.off') }));
|
|
538
577
|
},
|
|
539
578
|
// THE LANGUAGE (the Dev, 2026-09-16): the next flag; `setLocale` stores it and every surface redraws on `i18n:change`. Said in the NEW
|
|
540
579
|
// language, once it has loaded.
|
|
@@ -566,9 +605,7 @@ export function initPauseIcons(ctx) {
|
|
|
566
605
|
ctx.srAlert(t('sr.icon.needsPrivateOutput'));
|
|
567
606
|
return;
|
|
568
607
|
}
|
|
569
|
-
// No
|
|
570
|
-
// lock «one button only» away from the child playing with their eyes. The lock lives in the CYCLE, which skips
|
|
571
|
-
// `standard` on that device, and the refusal lives inside the action, over the latch write only.
|
|
608
|
+
// No refusal for `altmove` (ADR-0249): no device locks the latch, and what a game cannot hold the CYCLE leaves out.
|
|
572
609
|
const act = ICON_ACTS[k];
|
|
573
610
|
if (act)
|
|
574
611
|
act(i);
|
|
@@ -614,6 +651,25 @@ export function initPauseIcons(ctx) {
|
|
|
614
651
|
// corrects it. 📌 Measured in a browser back when a guard skipped some of them: five icons in English and three still in
|
|
615
652
|
// Portuguese, on the same bar.
|
|
616
653
|
b.setAttribute('aria-label', computeIconLabel(t, k, st));
|
|
654
|
+
refreshCursorCaption(b);
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* THE NAME UNDER THE ROW FOLLOWS THE LABEL OF THE ICON UNDER THE CURSOR (ADR-0159 rule 10, ADR-0167). The caption is the
|
|
658
|
+
* visible half of what the cursor says, and the reflection is how a state changed ELSEWHERE reaches the icon — the 🦯, 📷
|
|
659
|
+
* and 👄 through the root's `stateOn`, the 🗣 through the mixer's `onCatChange` (ADR-0247). Written only on a move or a press,
|
|
660
|
+
* the caption kept the state the child had left while the label spoke the new one.
|
|
661
|
+
*
|
|
662
|
+
* Only the CURSOR's icon (`.pi-sel`, which lives only on the bars `getA11yBars` hands over): another icon's name under the
|
|
663
|
+
* row would move the cursor's only visible mark. And only when the text CHANGED: the per-screen bar's caption is a live
|
|
664
|
+
* region, and the same words rewritten are said again.
|
|
665
|
+
*/
|
|
666
|
+
function refreshCursorCaption(b) {
|
|
667
|
+
if (!b.classList.contains('pi-sel'))
|
|
668
|
+
return;
|
|
669
|
+
const cap = ctx.getA11yBars().find((bar) => bar.contains(b))?.querySelector('.pause-icons-cap');
|
|
670
|
+
const text = accessibleLabel(b); // name and state only: «N de M» is spoken, never written (ADR-0167)
|
|
671
|
+
if (cap && cap.textContent !== text)
|
|
672
|
+
cap.textContent = text;
|
|
617
673
|
}
|
|
618
674
|
function reflectIconsIn(root, i) {
|
|
619
675
|
if (!root)
|
|
@@ -694,11 +750,12 @@ export function initPauseIcons(ctx) {
|
|
|
694
750
|
* with it (ADR-0044 item 3) and says how many items the new list has.
|
|
695
751
|
*/
|
|
696
752
|
function announceList(sp, sub) {
|
|
697
|
-
|
|
698
|
-
|
|
753
|
+
// «back» lands on the door that opened the list being left (ADR-0130 rule 1); any other door, on the first item
|
|
754
|
+
const cursor = sub === 'raiz' ? backToRoot(sp) : showPauseOptions(sp, sub);
|
|
755
|
+
if (!cursor)
|
|
699
756
|
return;
|
|
700
757
|
const items = [...sp.querySelectorAll(PM_VISIBLE_ITEMS)];
|
|
701
|
-
ctx.srSay(announceItem(t, { label:
|
|
758
|
+
ctx.srSay(announceItem(t, { label: cursor.textContent || '', position: items.indexOf(cursor) + 1, total: items.length }, ctx.settings.menuIndexOn));
|
|
702
759
|
}
|
|
703
760
|
/* ===================== THE `accessibility` MODE (ADR-0044 item 7) ===================== */
|
|
704
761
|
/**
|
|
@@ -824,6 +881,10 @@ export function initPauseIcons(ctx) {
|
|
|
824
881
|
}
|
|
825
882
|
/** One item of screen `i`'s pause card pressed — a locked one, a door between its lists, the quick bar, or an action. */
|
|
826
883
|
function pressPauseItem(i, sp, b) {
|
|
884
|
+
// 🔴 THE CURSOR GOES WHERE THE CHILD PRESSED (ADR-0130 rule 1). A finger or a mouse opens a panel without walking the
|
|
885
|
+
// arrows, and the mark stayed on the item the arrows had last reached — so «back» from the panel returned her to an
|
|
886
|
+
// item she never chose. The keyboard's press is already on its item; this is the pointer's half.
|
|
887
|
+
markPauseItem(sp, b);
|
|
827
888
|
// LOCKED (ADR-0161): pressing it SAYS the reason and does nothing — neither door nor action.
|
|
828
889
|
if (b.getAttribute('aria-disabled') === 'true') {
|
|
829
890
|
const reason = b.dataset.motivo ?? '';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
2
|
import type { Action } from '../core/actions.js';
|
|
3
|
-
import {
|
|
4
|
-
/** What the chip reads for one item. Pure: the
|
|
5
|
-
export declare function scanItemText(item:
|
|
3
|
+
import type { Translate } from '../core/i18n.js';
|
|
4
|
+
/** What the chip reads for one item. Pure: the engine's word where the item is the engine's, else the game's own word. */
|
|
5
|
+
export declare function scanItemText(item: string, label: (a: Action) => string | null, t: Translate): string;
|
|
6
6
|
export interface ScanOverlay {
|
|
7
7
|
/**
|
|
8
8
|
* Puts the item on screen, and answers whether the words CHANGED. The same item twice does not rewrite the node — a live
|
|
@@ -9,9 +9,17 @@
|
|
|
9
9
|
// «Confirmar» or «Dizer a resposta», never `action2` (ADR-0074). A position the game did not name is not offered at all — the
|
|
10
10
|
// list is built from the named ones — because a scan that stopped on a word nobody wrote would cost the child a full pass.
|
|
11
11
|
import { SCAN_CANCEL } from '../input/switch-scan.js';
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
/** The ENGINE's words, by dictionary key — the wording is an interface choice (interface log 2026-09-26). */
|
|
13
|
+
const ENGINE_WORDS = new Map([
|
|
14
|
+
[SCAN_CANCEL, 'scan.nothing'],
|
|
15
|
+
['select', 'scan.door.menus'], ['start', 'scan.door.pause'],
|
|
16
|
+
['next', 'scan.menu.next'], ['confirm', 'scan.menu.confirm'], ['back', 'scan.menu.back'], ['previous', 'scan.menu.previous'],
|
|
17
|
+
['increase', 'scan.menu.increase'], ['decrease', 'scan.menu.decrease'],
|
|
18
|
+
]);
|
|
19
|
+
/** What the chip reads for one item. Pure: the engine's word where the item is the engine's, else the game's own word. */
|
|
20
|
+
export function scanItemText(item, label, t) {
|
|
21
|
+
const key = ENGINE_WORDS.get(item);
|
|
22
|
+
return key ? t(key) : (label(item) ?? '');
|
|
15
23
|
}
|
|
16
24
|
/**
|
|
17
25
|
* Mounts the chip inside the game's region, under the quick bar's band.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Action } from '../core/actions.js';
|
|
3
|
+
import type { WorldScope } from '../core/contract.js';
|
|
4
|
+
/** What the reader is built over. Both are read at every call: a `mount()` swaps the cartridge, a panel opens. */
|
|
5
|
+
export interface ScreenTextCtx {
|
|
6
|
+
/** The root's document. */
|
|
7
|
+
readonly doc: Document;
|
|
8
|
+
/** The world the mounted game declares (`GameDeclaration.world`). */
|
|
9
|
+
readonly world: () => WorldScope;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* WHAT IS ON THE SCREEN NOW, as the sonar reads it — `''` when there is nothing the engine can read: no world, an empty one,
|
|
13
|
+
* or a world drawn on a canvas.
|
|
14
|
+
*/
|
|
15
|
+
export declare function screenText(ctx: ScreenTextCtx): string;
|
|
16
|
+
/**
|
|
17
|
+
* The `problems` line for a world the sonar cannot read — none, or one (ADR-0169: the subject, the child's cost, the fix).
|
|
18
|
+
* Measured at every read of `problems`: a canvas is often drawn after the boot.
|
|
19
|
+
*/
|
|
20
|
+
export declare function unreadableWorldProblems(ctx: ScreenTextCtx): string[];
|
|
21
|
+
/**
|
|
22
|
+
* A press made WITH A MENU OPEN: the menu sonar's position reads what is in front (`read`) and takes the press. Any other
|
|
23
|
+
* position is left to the menus — answers whether this one was taken.
|
|
24
|
+
*/
|
|
25
|
+
export declare function menuSonarPress(action: Action, ctx: ScreenTextCtx, read: (text: string) => void): boolean;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* THE SONAR'S POSITION WHILE A MENU IS OPEN. In play the position is the game's (its `preset`); with a menu open the positions
|
|
4
|
+
* are the engine's, and there R1 reads the menu — the Dev's default for the sonar («Tecla padrão para o sonar deve ser R1»).
|
|
5
|
+
*/
|
|
6
|
+
const MENU_SONAR = 'rightShoulder';
|
|
7
|
+
/** The engine's chrome the child did not ask about (see the header). */
|
|
8
|
+
const NOT_ASKED_ABOUT = [
|
|
9
|
+
'.pause-icons', '.screen-a11y', '.rodape-da-tela', '.scan-now', '#touch-controls', '.touch', '.sr-only',
|
|
10
|
+
'.gaze-overlay', '.face-overlay', '.hand-overlay', '.hud-row-clock',
|
|
11
|
+
].join(', ');
|
|
12
|
+
/** What is open in front of the world. */
|
|
13
|
+
const DIALOG = '[role="dialog"], [role="alertdialog"], [aria-modal="true"]';
|
|
14
|
+
/** Elements whose content is not words on the screen (a `<select>` shows its chosen option only — see `spokenAs`). */
|
|
15
|
+
const NOT_WORDS = /^(script|style|template|noscript|svg|canvas|video|audio|iframe|object|option|optgroup)$/i;
|
|
16
|
+
/** A line that already ends a sentence is not given a full stop. */
|
|
17
|
+
const ENDS_A_SENTENCE = /[.!?…:;]$/u;
|
|
18
|
+
/**
|
|
19
|
+
* Is this one element drawn for the eye, and meant for everyone? Its ancestors are asked by whoever walks down to it.
|
|
20
|
+
* 📌 The RENDERING decides, not the `hidden` attribute: `hidden` hides by `display: none`, which is read here, and a stylesheet
|
|
21
|
+
* that shows a `[hidden]` element puts it on the screen.
|
|
22
|
+
*/
|
|
23
|
+
function isShown(el) {
|
|
24
|
+
if (el.hasAttribute('inert') || el.getAttribute('aria-hidden') === 'true')
|
|
25
|
+
return false;
|
|
26
|
+
const style = el.ownerDocument?.defaultView?.getComputedStyle(el);
|
|
27
|
+
return !style || (style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0');
|
|
28
|
+
}
|
|
29
|
+
/** Is it drawn, with every ancestor drawn too? For an element found by a query rather than walked down to. */
|
|
30
|
+
function isOnScreen(el) {
|
|
31
|
+
for (let node = el; node; node = node.parentElement)
|
|
32
|
+
if (!isShown(node))
|
|
33
|
+
return false;
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Can this node be walked and asked? A host double may hand elements without the DOM's questions; then there is nothing the
|
|
38
|
+
* engine can read, and it says nothing rather than throwing into the sonar (a capability of the environment, ADR-0169).
|
|
39
|
+
*/
|
|
40
|
+
function canBeRead(el) {
|
|
41
|
+
return !!el && typeof el.matches === 'function' && typeof el.querySelectorAll === 'function' && typeof el.hasAttribute === 'function';
|
|
42
|
+
}
|
|
43
|
+
/** The dialog in front, or `null`: the one holding the focus, else the last one open in the document. */
|
|
44
|
+
function dialogInFront(doc) {
|
|
45
|
+
if (typeof doc.querySelectorAll !== 'function')
|
|
46
|
+
return null;
|
|
47
|
+
const open = [...doc.querySelectorAll(DIALOG)].filter((d) => canBeRead(d) && isOnScreen(d) && !d.matches(NOT_ASKED_ABOUT));
|
|
48
|
+
const focused = doc.activeElement;
|
|
49
|
+
return open.find((d) => !!focused && d.contains(focused)) ?? open[open.length - 1] ?? null;
|
|
50
|
+
}
|
|
51
|
+
/** The world's element, or `null` when the game declared none, its selector matches nothing, or it cannot be read. */
|
|
52
|
+
function worldElement(ctx) {
|
|
53
|
+
const scope = ctx.world();
|
|
54
|
+
const el = scope.kind === 'element' && typeof ctx.doc.querySelector === 'function' ? ctx.doc.querySelector(scope.selector) : null;
|
|
55
|
+
return canBeRead(el) ? el : null;
|
|
56
|
+
}
|
|
57
|
+
/** Does the world draw on a canvas the engine did not put there? Then its words are pixels. */
|
|
58
|
+
function drawsOnCanvas(world) {
|
|
59
|
+
const canvases = world.matches('canvas') ? [world] : [...world.querySelectorAll('canvas')];
|
|
60
|
+
return canvases.some((c) => !c.closest(NOT_ASKED_ABOUT) && isOnScreen(c));
|
|
61
|
+
}
|
|
62
|
+
/** The words an element stands for instead of its children, or `null` to read its children. */
|
|
63
|
+
function spokenAs(el) {
|
|
64
|
+
if (el.getAttribute('role') === 'img')
|
|
65
|
+
return el.getAttribute('aria-label') ?? '';
|
|
66
|
+
if (el.localName === 'img')
|
|
67
|
+
return el.getAttribute('alt') ?? '';
|
|
68
|
+
if (el.localName === 'select')
|
|
69
|
+
return el.selectedOptions[0]?.textContent ?? '';
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
/** Does the element start a line of its own? Everything that is not inline does — a button, a heading, a row. */
|
|
73
|
+
function breaksTheLine(el) {
|
|
74
|
+
const display = el.ownerDocument?.defaultView?.getComputedStyle(el).display ?? 'block';
|
|
75
|
+
return el.localName === 'br' || (display !== 'inline' && display !== 'contents');
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The text under `root`, in DOM order, one line per block. Lines are joined as sentences, so the voice pauses between the
|
|
79
|
+
* statement and each option and the interpreter receives them apart.
|
|
80
|
+
*/
|
|
81
|
+
function textOf(root) {
|
|
82
|
+
const lines = [];
|
|
83
|
+
let line = '';
|
|
84
|
+
const endLine = () => {
|
|
85
|
+
const words = line.replace(/\s+/gu, ' ').trim();
|
|
86
|
+
if (words)
|
|
87
|
+
lines.push(words);
|
|
88
|
+
line = '';
|
|
89
|
+
};
|
|
90
|
+
const readChildren = (el) => {
|
|
91
|
+
for (const child of el.childNodes ?? []) {
|
|
92
|
+
if (child.nodeType === 3)
|
|
93
|
+
line += child.textContent ?? '';
|
|
94
|
+
else if (child.nodeType === 1)
|
|
95
|
+
visit(child);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const visit = (el) => {
|
|
99
|
+
if (!isShown(el) || el.matches(NOT_ASKED_ABOUT) || NOT_WORDS.test(el.localName))
|
|
100
|
+
return;
|
|
101
|
+
const own = breaksTheLine(el);
|
|
102
|
+
if (own)
|
|
103
|
+
endLine();
|
|
104
|
+
const said = spokenAs(el);
|
|
105
|
+
if (said === null)
|
|
106
|
+
readChildren(el);
|
|
107
|
+
else
|
|
108
|
+
line += ` ${said} `;
|
|
109
|
+
if (own)
|
|
110
|
+
endLine();
|
|
111
|
+
};
|
|
112
|
+
visit(root);
|
|
113
|
+
endLine();
|
|
114
|
+
return lines.map((l) => (ENDS_A_SENTENCE.test(l) ? l : `${l}.`)).join(' ');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* WHAT IS ON THE SCREEN NOW, as the sonar reads it — `''` when there is nothing the engine can read: no world, an empty one,
|
|
118
|
+
* or a world drawn on a canvas.
|
|
119
|
+
*/
|
|
120
|
+
export function screenText(ctx) {
|
|
121
|
+
const front = dialogInFront(ctx.doc);
|
|
122
|
+
if (front)
|
|
123
|
+
return textOf(front);
|
|
124
|
+
const world = worldElement(ctx);
|
|
125
|
+
return world && !drawsOnCanvas(world) ? textOf(world) : '';
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The `problems` line for a world the sonar cannot read — none, or one (ADR-0169: the subject, the child's cost, the fix).
|
|
129
|
+
* Measured at every read of `problems`: a canvas is often drawn after the boot.
|
|
130
|
+
*/
|
|
131
|
+
export function unreadableWorldProblems(ctx) {
|
|
132
|
+
const world = worldElement(ctx);
|
|
133
|
+
if (!world || !drawsOnCanvas(world))
|
|
134
|
+
return [];
|
|
135
|
+
return ['the sonar cannot read this game\'s screen: its world draws on a <canvas>, whose words are pixels to the engine, so '
|
|
136
|
+
+ 'a child who presses the sonar hears only the nearest target\'s name and side instead of what is written on screen — '
|
|
137
|
+
+ 'and in deaf mode the interpreter signs that, not the screen (ADR-0234). Write the words the child must read as text '
|
|
138
|
+
+ 'in the page, inside the world; a contract field for a game to hand the engine its screen\'s text is a decision the '
|
|
139
|
+
+ 'Dev has not taken'];
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* A press made WITH A MENU OPEN: the menu sonar's position reads what is in front (`read`) and takes the press. Any other
|
|
143
|
+
* position is left to the menus — answers whether this one was taken.
|
|
144
|
+
*/
|
|
145
|
+
export function menuSonarPress(action, ctx, read) {
|
|
146
|
+
if (action !== MENU_SONAR)
|
|
147
|
+
return false;
|
|
148
|
+
const text = screenText(ctx);
|
|
149
|
+
if (text)
|
|
150
|
+
read(text);
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Translate } from '../core/i18n.js';
|
|
3
|
+
/**
|
|
4
|
+
* What the clock needs, all lent by the root. The three host ports are REQUIRED and may carry `undefined` — a host without
|
|
5
|
+
* them is answered here, not with a branch in the root (ADR-0232 erratum of 2026-09-25): with no clock or no tick there is no
|
|
6
|
+
* session to measure, and nothing is mounted, silently, as a capability of the environment (ADR-0169).
|
|
7
|
+
*/
|
|
8
|
+
export interface SessionClockCtx {
|
|
9
|
+
readonly doc: Document;
|
|
10
|
+
/** Where the clock goes: the HUD row's centre cell. Absent, or a node that takes no children, and nothing is mounted. */
|
|
11
|
+
readonly slot: HTMLElement | null;
|
|
12
|
+
readonly t: Translate;
|
|
13
|
+
/** The host's `performance`, milliseconds and monotonic. The session starts at the mount. */
|
|
14
|
+
readonly performance: {
|
|
15
|
+
now(): number;
|
|
16
|
+
} | undefined;
|
|
17
|
+
readonly setInterval: ((fn: () => void, ms: number) => number) | undefined;
|
|
18
|
+
readonly clearInterval: ((handle: number) => void) | undefined;
|
|
19
|
+
/** The polite announcer: said once, when the hour runs out. */
|
|
20
|
+
readonly announce: (text: string) => void;
|
|
21
|
+
/** Called after every redraw, so the root can measure the row again when the clock's size changed. */
|
|
22
|
+
readonly drawn: () => void;
|
|
23
|
+
}
|
|
24
|
+
export interface SessionClockMounted {
|
|
25
|
+
readonly el: HTMLElement;
|
|
26
|
+
/** Reads the time again and redraws what changed (the tick calls it; a language change too). */
|
|
27
|
+
refresh(): void;
|
|
28
|
+
/** Stops the tick and takes the clock off the page. */
|
|
29
|
+
remove(): void;
|
|
30
|
+
}
|
|
31
|
+
/** Mounts the clock in its slot, draws it now, and redraws it every second until `remove()`; `null` where it cannot. */
|
|
32
|
+
export declare function mountSessionClock(ctx: SessionClockCtx): SessionClockMounted | null;
|