@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.
- package/README.md +120 -78
- package/app/css/style.css +761 -377
- package/app/public/vendor/fonts/playwrite-cu.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-es-deco.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-es.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-gb-j.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-gb-s.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-pe.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-pt.woff2 +0 -0
- 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 +36 -84
- package/dist-pkg/boot/create-game.d.ts +499 -219
- package/dist-pkg/boot/create-game.js +3944 -562
- package/dist-pkg/core/a11y-sr.d.ts +25 -3
- package/dist-pkg/core/a11y-sr.js +38 -19
- package/dist-pkg/core/accessible-label.d.ts +17 -0
- package/dist-pkg/core/accessible-label.js +37 -0
- package/dist-pkg/core/accommodation-subjects.d.ts +26 -0
- package/dist-pkg/core/accommodation-subjects.js +32 -0
- package/dist-pkg/core/accommodations.d.ts +125 -0
- package/dist-pkg/core/accommodations.js +195 -0
- package/dist-pkg/core/actions.d.ts +108 -55
- package/dist-pkg/core/actions.js +122 -71
- package/dist-pkg/core/calm-mode.d.ts +31 -0
- package/dist-pkg/core/calm-mode.js +47 -0
- package/dist-pkg/core/camera-cycle.d.ts +15 -0
- package/dist-pkg/core/camera-cycle.js +7 -0
- package/dist-pkg/core/caption-duration.d.ts +15 -0
- package/dist-pkg/core/caption-duration.js +19 -0
- package/dist-pkg/core/cartridge-problems.d.ts +34 -0
- package/dist-pkg/core/cartridge-problems.js +53 -0
- package/dist-pkg/core/constants.d.ts +0 -54
- package/dist-pkg/core/constants.js +9 -76
- package/dist-pkg/core/contract.d.ts +142 -164
- package/dist-pkg/core/contract.js +222 -208
- package/dist-pkg/core/dom-query.d.ts +4 -4
- package/dist-pkg/core/dom-query.js +12 -20
- package/dist-pkg/core/entity.d.ts +62 -77
- package/dist-pkg/core/entity.js +18 -32
- package/dist-pkg/core/escape-html.d.ts +9 -10
- package/dist-pkg/core/escape-html.js +16 -20
- package/dist-pkg/core/flash-threshold.d.ts +17 -0
- package/dist-pkg/core/flash-threshold.js +113 -0
- package/dist-pkg/core/game-speed.d.ts +11 -0
- package/dist-pkg/core/game-speed.js +16 -0
- package/dist-pkg/core/genres.d.ts +20 -0
- package/dist-pkg/core/genres.js +44 -0
- package/dist-pkg/core/i18n.d.ts +71 -60
- package/dist-pkg/core/i18n.js +186 -200
- package/dist-pkg/core/loop.d.ts +17 -6
- package/dist-pkg/core/loop.js +26 -26
- package/dist-pkg/core/pause-icon-catalogue.d.ts +15 -0
- package/dist-pkg/core/pause-icon-catalogue.js +54 -0
- package/dist-pkg/core/ring.d.ts +17 -0
- package/dist-pkg/core/ring.js +29 -0
- package/dist-pkg/core/rng.d.ts +7 -12
- package/dist-pkg/core/rng.js +23 -53
- package/dist-pkg/core/route.d.ts +26 -26
- package/dist-pkg/core/route.js +126 -121
- package/dist-pkg/core/scenes.d.ts +37 -40
- package/dist-pkg/core/scenes.js +41 -43
- package/dist-pkg/core/screens.d.ts +4 -4
- package/dist-pkg/core/screens.js +11 -16
- package/dist-pkg/core/session-clock.d.ts +23 -0
- package/dist-pkg/core/session-clock.js +37 -0
- package/dist-pkg/core/setting-defaults.d.ts +61 -0
- package/dist-pkg/core/setting-defaults.js +66 -0
- package/dist-pkg/core/speech-rate.d.ts +29 -0
- package/dist-pkg/core/speech-rate.js +47 -0
- package/dist-pkg/core/state.d.ts +118 -118
- package/dist-pkg/core/state.js +322 -297
- package/dist-pkg/core/visual-cycles.d.ts +30 -0
- package/dist-pkg/core/visual-cycles.js +52 -0
- package/dist-pkg/core/visual-state.d.ts +13 -0
- package/dist-pkg/core/visual-state.js +6 -0
- package/dist-pkg/educational/activities-registry.d.ts +1 -1
- package/dist-pkg/educational/activities-registry.js +9 -8
- package/dist-pkg/educational/adaptive-engine.d.ts +11 -11
- package/dist-pkg/educational/adaptive-engine.js +17 -17
- package/dist-pkg/educational/segment-bar.d.ts +12 -12
- package/dist-pkg/educational/segment-bar.js +9 -9
- package/dist-pkg/i18n/en.js +324 -223
- package/dist-pkg/i18n/es.js +323 -223
- package/dist-pkg/i18n/pt.js +348 -226
- package/dist-pkg/input/default-bindings.d.ts +37 -38
- package/dist-pkg/input/default-bindings.js +127 -144
- package/dist-pkg/input/devices.d.ts +7 -7
- package/dist-pkg/input/devices.js +17 -16
- package/dist-pkg/input/edges.d.ts +23 -32
- package/dist-pkg/input/edges.js +23 -28
- package/dist-pkg/input/empathy-filter.d.ts +22 -0
- package/dist-pkg/input/empathy-filter.js +34 -0
- package/dist-pkg/input/face-map.d.ts +96 -0
- package/dist-pkg/input/face-map.js +255 -0
- package/dist-pkg/input/face-signals.d.ts +40 -0
- package/dist-pkg/input/face-signals.js +48 -0
- package/dist-pkg/input/gamepad.d.ts +195 -145
- package/dist-pkg/input/gamepad.js +383 -556
- package/dist-pkg/input/gaze-cycle.d.ts +64 -0
- package/dist-pkg/input/gaze-cycle.js +133 -0
- package/dist-pkg/input/gaze-relative.d.ts +68 -0
- package/dist-pkg/input/gaze-relative.js +142 -0
- package/dist-pkg/input/hand-map.d.ts +28 -0
- package/dist-pkg/input/hand-map.js +142 -0
- package/dist-pkg/input/input-cooldown.d.ts +17 -0
- package/dist-pkg/input/input-cooldown.js +39 -0
- 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 +15 -21
- package/dist-pkg/input/keyboard-runtime.js +23 -27
- package/dist-pkg/input/keyboard.d.ts +68 -63
- package/dist-pkg/input/keyboard.js +83 -105
- package/dist-pkg/input/keydown.d.ts +123 -137
- package/dist-pkg/input/keydown.js +284 -289
- package/dist-pkg/input/latch-edge.d.ts +33 -21
- package/dist-pkg/input/latch-edge.js +34 -35
- package/dist-pkg/input/latch-scope.d.ts +51 -50
- package/dist-pkg/input/latch-scope.js +61 -82
- package/dist-pkg/input/latch-store.d.ts +26 -30
- package/dist-pkg/input/latch-store.js +42 -50
- package/dist-pkg/input/latch-sync.d.ts +29 -29
- package/dist-pkg/input/latch-sync.js +25 -25
- package/dist-pkg/input/latch.d.ts +14 -17
- package/dist-pkg/input/latch.js +29 -37
- package/dist-pkg/input/pad-defaults.d.ts +13 -16
- package/dist-pkg/input/pad-defaults.js +21 -28
- package/dist-pkg/input/pad-reading.d.ts +76 -0
- package/dist-pkg/input/pad-reading.js +169 -0
- package/dist-pkg/input/pad-wizard.d.ts +99 -0
- package/dist-pkg/input/pad-wizard.js +256 -0
- package/dist-pkg/input/pointer-space.d.ts +19 -20
- package/dist-pkg/input/pointer-space.js +27 -32
- package/dist-pkg/input/pointer.d.ts +39 -40
- package/dist-pkg/input/pointer.js +42 -45
- package/dist-pkg/input/state.d.ts +101 -89
- package/dist-pkg/input/state.js +54 -134
- package/dist-pkg/input/switch-scan.d.ts +59 -0
- package/dist-pkg/input/switch-scan.js +67 -0
- package/dist-pkg/input/synthetic-source.d.ts +42 -0
- package/dist-pkg/input/synthetic-source.js +57 -0
- package/dist-pkg/input/touch-bindings.d.ts +127 -116
- package/dist-pkg/input/touch-bindings.js +158 -173
- package/dist-pkg/input/touch.d.ts +147 -72
- package/dist-pkg/input/touch.js +362 -126
- package/dist-pkg/input/transport-in-use.d.ts +107 -0
- package/dist-pkg/input/transport-in-use.js +130 -0
- package/dist-pkg/input/transports.d.ts +90 -117
- package/dist-pkg/input/transports.js +104 -106
- package/dist-pkg/input/virtual-controller.d.ts +82 -0
- package/dist-pkg/input/virtual-controller.js +69 -0
- package/dist-pkg/input/vocabulary-migration.d.ts +50 -49
- package/dist-pkg/input/vocabulary-migration.js +80 -79
- package/dist-pkg/input/voice-map.d.ts +59 -0
- package/dist-pkg/input/voice-map.js +123 -0
- package/dist-pkg/platform/audio-ambient.d.ts +13 -2
- package/dist-pkg/platform/audio-ambient.js +14 -14
- package/dist-pkg/platform/audio-earcons.d.ts +20 -19
- package/dist-pkg/platform/audio-earcons.js +51 -42
- package/dist-pkg/platform/audio-jingles.js +9 -10
- package/dist-pkg/platform/audio-mixer.d.ts +14 -2
- package/dist-pkg/platform/audio-mixer.js +31 -39
- package/dist-pkg/platform/audio-sonar.d.ts +49 -152
- package/dist-pkg/platform/audio-sonar.js +124 -302
- package/dist-pkg/platform/audio.d.ts +62 -19
- package/dist-pkg/platform/audio.js +193 -168
- 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/flash-sampler.d.ts +19 -0
- package/dist-pkg/platform/flash-sampler.js +79 -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 +77 -0
- package/dist-pkg/platform/heavy-catalogue.js +256 -0
- package/dist-pkg/platform/heavy-mirror.d.ts +20 -0
- package/dist-pkg/platform/heavy-mirror.js +73 -0
- package/dist-pkg/platform/heavy.d.ts +136 -0
- package/dist-pkg/platform/heavy.js +324 -0
- package/dist-pkg/platform/interruptible-speech.d.ts +23 -16
- package/dist-pkg/platform/interruptible-speech.js +77 -54
- package/dist-pkg/platform/kokoro-port.d.ts +27 -0
- package/dist-pkg/platform/kokoro-port.js +50 -0
- package/dist-pkg/platform/kokoro-runtime.d.ts +20 -0
- package/dist-pkg/platform/kokoro-runtime.js +52 -0
- package/dist-pkg/platform/kokoro.d.ts +70 -0
- package/dist-pkg/platform/kokoro.js +133 -0
- package/dist-pkg/platform/listener-scope.d.ts +12 -0
- package/dist-pkg/platform/listener-scope.js +90 -0
- package/dist-pkg/platform/locale-host.d.ts +14 -0
- package/dist-pkg/platform/locale-host.js +45 -0
- package/dist-pkg/platform/microphone.d.ts +51 -0
- package/dist-pkg/platform/microphone.js +118 -0
- package/dist-pkg/platform/onnx-runtime.d.ts +34 -0
- package/dist-pkg/platform/onnx-runtime.js +42 -0
- package/dist-pkg/platform/reading-in-worker.d.ts +64 -0
- package/dist-pkg/platform/reading-in-worker.js +125 -0
- package/dist-pkg/platform/reading-model.d.ts +94 -0
- package/dist-pkg/platform/reading-model.js +272 -0
- package/dist-pkg/platform/reading-runtime.d.ts +24 -0
- package/dist-pkg/platform/reading-runtime.js +164 -0
- package/dist-pkg/platform/reading-worker.d.ts +41 -0
- package/dist-pkg/platform/reading-worker.js +58 -0
- package/dist-pkg/platform/reading.d.ts +80 -0
- package/dist-pkg/platform/reading.js +136 -0
- package/dist-pkg/platform/speech-recognition.d.ts +60 -0
- package/dist-pkg/platform/speech-recognition.js +104 -0
- package/dist-pkg/platform/speech.d.ts +23 -1
- package/dist-pkg/platform/speech.js +29 -18
- package/dist-pkg/platform/storage-keys.d.ts +96 -0
- package/dist-pkg/platform/storage-keys.js +106 -0
- package/dist-pkg/platform/storage.d.ts +46 -111
- package/dist-pkg/platform/storage.js +104 -169
- package/dist-pkg/platform/tts.d.ts +85 -39
- package/dist-pkg/platform/tts.js +447 -127
- package/dist-pkg/platform/vision-loop.d.ts +23 -0
- package/dist-pkg/platform/vision-loop.js +56 -0
- package/dist-pkg/platform/vision.d.ts +132 -0
- package/dist-pkg/platform/vision.js +117 -0
- package/dist-pkg/platform/voice-listener.d.ts +40 -0
- package/dist-pkg/platform/voice-listener.js +88 -0
- package/dist-pkg/platform/voice-plan.d.ts +15 -98
- package/dist-pkg/platform/voice-plan.js +56 -143
- package/dist-pkg/platform/vosk-runtime.d.ts +96 -0
- package/dist-pkg/platform/vosk-runtime.js +151 -0
- package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
- package/dist-pkg/platform/vosk-vocabulary.js +178 -0
- package/dist-pkg/render/canvas.d.ts +13 -7
- package/dist-pkg/render/canvas.js +13 -13
- package/dist-pkg/render/crt.d.ts +48 -12
- package/dist-pkg/render/crt.js +78 -80
- package/dist-pkg/render/cvd-matrices.d.ts +22 -18
- package/dist-pkg/render/cvd-matrices.js +37 -38
- package/dist-pkg/render/hc-role-data.d.ts +7 -7
- package/dist-pkg/render/hc-role-data.js +14 -14
- package/dist-pkg/render/high-contrast.d.ts +67 -56
- package/dist-pkg/render/high-contrast.js +226 -217
- package/dist-pkg/render/low-vision-drawing.d.ts +5 -0
- package/dist-pkg/render/low-vision-drawing.js +46 -0
- package/dist-pkg/render/lq-filter.d.ts +32 -20
- package/dist-pkg/render/lq-filter.js +59 -65
- package/dist-pkg/render/port.d.ts +86 -88
- package/dist-pkg/render/port.js +17 -23
- package/dist-pkg/render/screen-pipeline.d.ts +42 -42
- package/dist-pkg/render/screen-pipeline.js +80 -87
- package/dist-pkg/render/sprite-fx.d.ts +2 -1
- package/dist-pkg/render/sprite-fx.js +16 -14
- package/dist-pkg/render/viewports.d.ts +20 -15
- package/dist-pkg/render/viewports.js +83 -114
- package/dist-pkg/render/viz-axes-labels.d.ts +47 -0
- package/dist-pkg/render/viz-axes-labels.js +88 -0
- package/dist-pkg/render/viz-axes.d.ts +89 -86
- package/dist-pkg/render/viz-axes.js +128 -116
- package/dist-pkg/render/viz-modes.d.ts +28 -29
- package/dist-pkg/render/viz-modes.js +40 -45
- package/dist-pkg/render/viz-refusal.d.ts +32 -0
- package/dist-pkg/render/viz-refusal.js +57 -0
- package/dist-pkg/render/viz-setters.d.ts +104 -66
- package/dist-pkg/render/viz-setters.js +182 -191
- package/dist-pkg/ui/aac-sets.d.ts +45 -0
- package/dist-pkg/ui/aac-sets.js +41 -0
- package/dist-pkg/ui/audio-choices.d.ts +68 -0
- package/dist-pkg/ui/audio-choices.js +98 -0
- package/dist-pkg/ui/audio-rows-that-apply.d.ts +12 -0
- package/dist-pkg/ui/audio-rows-that-apply.js +43 -0
- package/dist-pkg/ui/camera-control.d.ts +53 -0
- package/dist-pkg/ui/camera-control.js +48 -0
- package/dist-pkg/ui/changed-mark.d.ts +9 -8
- package/dist-pkg/ui/changed-mark.js +22 -53
- package/dist-pkg/ui/control-choices.d.ts +37 -0
- package/dist-pkg/ui/control-choices.js +84 -0
- package/dist-pkg/ui/debug-panel.d.ts +59 -43
- package/dist-pkg/ui/debug-panel.js +68 -69
- package/dist-pkg/ui/declared-words.d.ts +21 -0
- package/dist-pkg/ui/declared-words.js +66 -0
- package/dist-pkg/ui/dom.d.ts +10 -14
- package/dist-pkg/ui/dom.js +10 -47
- package/dist-pkg/ui/drawing-problems.d.ts +25 -0
- package/dist-pkg/ui/drawing-problems.js +94 -0
- package/dist-pkg/ui/eye-control.d.ts +36 -0
- package/dist-pkg/ui/eye-control.js +178 -0
- package/dist-pkg/ui/face-control.d.ts +25 -0
- package/dist-pkg/ui/face-control.js +183 -0
- package/dist-pkg/ui/focus-trap.d.ts +39 -49
- package/dist-pkg/ui/focus-trap.js +56 -65
- package/dist-pkg/ui/fonts.d.ts +157 -68
- package/dist-pkg/ui/fonts.js +305 -115
- 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 +47 -0
- package/dist-pkg/ui/game-options.js +158 -0
- package/dist-pkg/ui/gaze-overlay.d.ts +64 -0
- package/dist-pkg/ui/gaze-overlay.js +165 -0
- package/dist-pkg/ui/hand-control.d.ts +25 -0
- package/dist-pkg/ui/hand-control.js +143 -0
- package/dist-pkg/ui/help-panel.d.ts +87 -0
- package/dist-pkg/ui/help-panel.js +242 -0
- package/dist-pkg/ui/hud-bands.d.ts +62 -0
- package/dist-pkg/ui/hud-bands.js +146 -0
- 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 +73 -73
- package/dist-pkg/ui/hud.js +94 -98
- package/dist-pkg/ui/item-announcement.d.ts +13 -12
- package/dist-pkg/ui/item-announcement.js +25 -26
- package/dist-pkg/ui/layout.d.ts +103 -28
- package/dist-pkg/ui/layout.js +117 -99
- 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/locale-flags.d.ts +16 -0
- package/dist-pkg/ui/locale-flags.js +30 -0
- package/dist-pkg/ui/loop-crash.d.ts +17 -17
- package/dist-pkg/ui/loop-crash.js +33 -62
- package/dist-pkg/ui/menu-intent.d.ts +61 -0
- package/dist-pkg/ui/menu-intent.js +88 -0
- package/dist-pkg/ui/menu-items.d.ts +20 -0
- package/dist-pkg/ui/menu-items.js +51 -0
- package/dist-pkg/ui/menu-nav.d.ts +98 -92
- package/dist-pkg/ui/menu-nav.js +398 -286
- package/dist-pkg/ui/mobility-choices.d.ts +26 -0
- package/dist-pkg/ui/mobility-choices.js +41 -0
- package/dist-pkg/ui/motion-choices.d.ts +31 -0
- package/dist-pkg/ui/motion-choices.js +68 -0
- package/dist-pkg/ui/motion-scene.d.ts +24 -19
- package/dist-pkg/ui/motion-scene.js +29 -61
- package/dist-pkg/ui/mount-panel.d.ts +81 -0
- package/dist-pkg/ui/mount-panel.js +61 -0
- package/dist-pkg/ui/panel-shell.d.ts +65 -31
- package/dist-pkg/ui/panel-shell.js +92 -66
- package/dist-pkg/ui/panel-widgets.d.ts +150 -0
- package/dist-pkg/ui/panel-widgets.js +294 -0
- package/dist-pkg/ui/pause-buttons.d.ts +35 -0
- package/dist-pkg/ui/pause-buttons.js +66 -0
- package/dist-pkg/ui/pause-icons.d.ts +261 -347
- package/dist-pkg/ui/pause-icons.js +671 -601
- package/dist-pkg/ui/pause-markup.d.ts +86 -0
- package/dist-pkg/ui/pause-markup.js +125 -0
- package/dist-pkg/ui/reach-notice.d.ts +22 -23
- package/dist-pkg/ui/reach-notice.js +55 -58
- package/dist-pkg/ui/scan-overlay.d.ts +23 -0
- package/dist-pkg/ui/scan-overlay.js +50 -0
- 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 +70 -0
- package/dist-pkg/ui/settings-aac.js +208 -0
- package/dist-pkg/ui/settings-audio.d.ts +97 -114
- package/dist-pkg/ui/settings-audio.js +493 -425
- package/dist-pkg/ui/settings-controls.d.ts +53 -96
- package/dist-pkg/ui/settings-controls.js +143 -215
- package/dist-pkg/ui/settings-empathy.d.ts +39 -30
- package/dist-pkg/ui/settings-empathy.js +53 -60
- package/dist-pkg/ui/settings-mobility.d.ts +192 -0
- package/dist-pkg/ui/settings-mobility.js +332 -0
- package/dist-pkg/ui/settings-motion.d.ts +91 -70
- package/dist-pkg/ui/settings-motion.js +287 -198
- package/dist-pkg/ui/settings-panel.d.ts +58 -45
- package/dist-pkg/ui/settings-panel.js +189 -94
- package/dist-pkg/ui/settings-typo.d.ts +29 -78
- package/dist-pkg/ui/settings-typo.js +158 -129
- package/dist-pkg/ui/settings-visual.d.ts +29 -87
- package/dist-pkg/ui/settings-visual.js +240 -193
- package/dist-pkg/ui/shell.d.ts +112 -135
- package/dist-pkg/ui/shell.js +148 -217
- package/dist-pkg/ui/simulation-list.d.ts +27 -0
- package/dist-pkg/ui/simulation-list.js +76 -0
- package/dist-pkg/ui/simulation-over-the-world.d.ts +23 -0
- package/dist-pkg/ui/simulation-over-the-world.js +131 -0
- package/dist-pkg/ui/simulation-refusal.d.ts +5 -31
- package/dist-pkg/ui/simulation-refusal.js +8 -56
- package/dist-pkg/ui/switchable-control.d.ts +11 -0
- package/dist-pkg/ui/switchable-control.js +19 -0
- package/dist-pkg/ui/title.d.ts +3 -12
- package/dist-pkg/ui/title.js +49 -18
- package/dist-pkg/ui/top-band.d.ts +26 -0
- package/dist-pkg/ui/top-band.js +96 -0
- package/dist-pkg/ui/typo-choices.d.ts +71 -0
- package/dist-pkg/ui/typo-choices.js +85 -0
- package/dist-pkg/ui/visual-axes-panel.d.ts +11 -47
- package/dist-pkg/ui/visual-axes-panel.js +12 -94
- package/dist-pkg/ui/visual-choices.d.ts +77 -0
- package/dist-pkg/ui/visual-choices.js +107 -0
- package/dist-pkg/ui/vlibras.d.ts +77 -10
- package/dist-pkg/ui/vlibras.js +130 -81
- package/dist-pkg/ui/voice-control.d.ts +68 -0
- package/dist-pkg/ui/voice-control.js +276 -0
- package/dist-pkg/ui/voice-settings.d.ts +95 -0
- package/dist-pkg/ui/voice-settings.js +352 -0
- package/dist-pkg/ui/where-the-child-is.d.ts +31 -0
- package/dist-pkg/ui/where-the-child-is.js +70 -0
- package/docs/CREDITS.md +300 -44
- package/docs/LICENSES.md +189 -145
- package/package.json +51 -27
- 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 +388 -0
- 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/Apache-2.0.txt +176 -0
- package/scripts/licences/GPL-3.0.txt +674 -0
- package/scripts/licences/MIT.txt +17 -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 +301 -0
- package/scripts/licences/vosk-browser.NOTICE.txt +268 -0
- package/app/public/vendor/fonts/comicneue-400.woff2 +0 -0
- package/app/public/vendor/fonts/comicneue-700.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/inter-400.woff2 +0 -0
- package/app/public/vendor/fonts/inter-700.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/newsreader-400.woff2 +0 -0
- package/app/public/vendor/fonts/newsreader-700.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/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/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/ufmag-400.woff2 +0 -0
- package/dist-pkg/core/anel.d.ts +0 -17
- package/dist-pkg/core/anel.js +0 -31
- package/dist-pkg/core/collision.d.ts +0 -21
- package/dist-pkg/core/collision.js +0 -62
- package/dist-pkg/core/layers.d.ts +0 -63
- package/dist-pkg/core/layers.js +0 -95
- package/dist-pkg/core/letter-grid.d.ts +0 -55
- package/dist-pkg/core/letter-grid.js +0 -116
- package/dist-pkg/core/password.d.ts +0 -34
- package/dist-pkg/core/password.js +0 -205
- package/dist-pkg/core/rotulo-acessivel.d.ts +0 -17
- package/dist-pkg/core/rotulo-acessivel.js +0 -41
- package/dist-pkg/core/run-state.d.ts +0 -115
- package/dist-pkg/core/run-state.js +0 -40
- package/dist-pkg/core/tiles.d.ts +0 -12
- package/dist-pkg/core/tiles.js +0 -61
- package/dist-pkg/core/world.d.ts +0 -4
- package/dist-pkg/core/world.js +0 -58
- package/dist-pkg/input/origem-sintetica.d.ts +0 -44
- package/dist-pkg/input/origem-sintetica.js +0 -60
- package/dist-pkg/input/transporte-em-uso.d.ts +0 -101
- package/dist-pkg/input/transporte-em-uso.js +0 -130
- package/dist-pkg/platform/audio-nav.d.ts +0 -51
- package/dist-pkg/platform/audio-nav.js +0 -99
- package/dist-pkg/platform/guide-intensity.d.ts +0 -40
- package/dist-pkg/platform/guide-intensity.js +0 -73
- package/dist-pkg/platform/pesados-catalogo.d.ts +0 -14
- package/dist-pkg/platform/pesados-catalogo.js +0 -177
- package/dist-pkg/platform/pesados.d.ts +0 -31
- package/dist-pkg/platform/pesados.js +0 -75
- package/dist-pkg/platform/vozes-prontas.d.ts +0 -28
- package/dist-pkg/platform/vozes-prontas.js +0 -61
- package/dist-pkg/render/camera.d.ts +0 -58
- package/dist-pkg/render/camera.js +0 -105
- package/dist-pkg/render/cenario-data.d.ts +0 -127
- package/dist-pkg/render/cenario-data.js +0 -145
- package/dist-pkg/render/city-tex.d.ts +0 -63
- package/dist-pkg/render/city-tex.js +0 -228
- package/dist-pkg/render/city-tiles.d.ts +0 -11
- package/dist-pkg/render/city-tiles.js +0 -140
- package/dist-pkg/render/draw.d.ts +0 -149
- package/dist-pkg/render/draw.js +0 -231
- package/dist-pkg/render/fx.d.ts +0 -63
- package/dist-pkg/render/fx.js +0 -123
- package/dist-pkg/render/minimap.d.ts +0 -11
- package/dist-pkg/render/minimap.js +0 -94
- package/dist-pkg/render/parallax.d.ts +0 -85
- package/dist-pkg/render/parallax.js +0 -158
- package/dist-pkg/render/player-anim.d.ts +0 -71
- package/dist-pkg/render/player-anim.js +0 -152
- package/dist-pkg/render/recycling-tex.d.ts +0 -48
- package/dist-pkg/render/recycling-tex.js +0 -164
- package/dist-pkg/render/scene-city.d.ts +0 -77
- package/dist-pkg/render/scene-city.js +0 -181
- package/dist-pkg/render/scene-parallax.d.ts +0 -72
- package/dist-pkg/render/scene-parallax.js +0 -426
- package/dist-pkg/render/scene-sky.d.ts +0 -126
- package/dist-pkg/render/scene-sky.js +0 -295
- package/dist-pkg/render/set-cenario.d.ts +0 -54
- package/dist-pkg/render/set-cenario.js +0 -103
- package/dist-pkg/render/textures.d.ts +0 -75
- package/dist-pkg/render/textures.js +0 -240
- package/dist-pkg/render/title-scene.d.ts +0 -46
- package/dist-pkg/render/title-scene.js +0 -75
- package/dist-pkg/render/weather.d.ts +0 -96
- package/dist-pkg/render/weather.js +0 -171
- package/dist-pkg/render/wheelchair-sprites.d.ts +0 -32
- package/dist-pkg/render/wheelchair-sprites.js +0 -69
- package/dist-pkg/render/world-tex.d.ts +0 -18
- package/dist-pkg/render/world-tex.js +0 -87
- package/dist-pkg/ui/activities-menu.d.ts +0 -258
- package/dist-pkg/ui/activities-menu.js +0 -648
- package/dist-pkg/ui/caa-sets.d.ts +0 -39
- package/dist-pkg/ui/caa-sets.js +0 -65
- package/dist-pkg/ui/latch-refusal.d.ts +0 -32
- package/dist-pkg/ui/latch-refusal.js +0 -60
- package/dist-pkg/ui/map-hub.d.ts +0 -56
- package/dist-pkg/ui/map-hub.js +0 -138
- package/dist-pkg/ui/settings-caa.d.ts +0 -45
- package/dist-pkg/ui/settings-caa.js +0 -137
- package/dist-pkg/ui/settings-motor.d.ts +0 -175
- package/dist-pkg/ui/settings-motor.js +0 -342
- package/dist-pkg/ui/webcam.d.ts +0 -7
- package/dist-pkg/ui/webcam.js +0 -93
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// ui/voice-settings — THE VOICE SECTION of the hearing panel: the narration switch, the engine, the voice, the rate, the
|
|
3
|
+
// spoken index and the sample button (ADR-0221; issue #203).
|
|
4
|
+
//
|
|
5
|
+
// 🔴 WHY IT LEFT `ui/settings-audio`: that module was the third largest in the engine, and half of it was about SPEECH while
|
|
6
|
+
// the other half was about sound categories, the cane, blind mode and the audio outputs. The two halves never needed each
|
|
7
|
+
// other. What binds these seven pieces is one question — «what does the child hear when the engine talks, and what does she
|
|
8
|
+
// change to hear it differently».
|
|
9
|
+
//
|
|
10
|
+
// ⚠️ AND IT RECEIVES THE BROWSER INSTEAD OF REACHING IT, which the ratchet of ADR-0221 step 7d made compulsory rather than
|
|
11
|
+
// tasteful: a module born today that reaches a global is refused, because there the ceiling is ZERO and not a p90. So
|
|
12
|
+
// `document.createElement`, `speechSynthesis.getVoices`, the sample utterance and the `onvoiceschanged` subscription arrive
|
|
13
|
+
// as four ports. What that buys beyond the gate: the whole section can be exercised without a browser's speech engine.
|
|
14
|
+
//
|
|
15
|
+
// 📌 THE SPOKEN INDEX («6 of 10») LIVES HERE and not in a visual panel, by the decision of ADR-0044 item 3: it changes the
|
|
16
|
+
// NARRATION, and whoever turns it off is shortening what she hears at every step. She comes here when what she hears bothers
|
|
17
|
+
// her.
|
|
18
|
+
import { toggleLabel } from './dom.js';
|
|
19
|
+
import { SPEECH_RATES } from '../core/speech-rate.js';
|
|
20
|
+
import { volPercent, voiceEngineOptions, pickVoicesFor, voiceLabel, } from './audio-choices.js';
|
|
21
|
+
/** The name a child sees for a voice: the browser's name, or the name inside a Kokoro identifier — `pf_dora` is «Dora». */
|
|
22
|
+
function voiceName(v) {
|
|
23
|
+
// a browser voice is named by the browser (ADR-0200); Kokoro ids read `xx_name` (`pf_dora`)
|
|
24
|
+
// («Microsoft Maria - Portuguese (Brazil)» is «Microsoft Maria»: the language is already the list's, and no parentheses, ADR-0158)
|
|
25
|
+
if (v.voice.startsWith('webspeech:'))
|
|
26
|
+
return v.voice.slice('webspeech:'.length).replace(/\s*\([^)]*\)/g, '').split(' - ')[0].trim();
|
|
27
|
+
const name = v.voice.split('_')[1] ?? v.voice;
|
|
28
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* What the list SHOWS: Kokoro's two good voices, Heart and Bella, carry a heart (ADR-0198 §3). Only SHOWN: what is said is
|
|
32
|
+
* the name alone (ADR-0159 rule 12, no glyph inside a spoken name).
|
|
33
|
+
*/
|
|
34
|
+
function panelVoiceLabel(v) {
|
|
35
|
+
return (v.recommended ? '❤️ ' : '') + voiceName(v);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The rows a missing voice locks (ADR-0185 §4): narration, its volume and rate, the spoken index, the voice — and the «test voice»
|
|
39
|
+
* button a page may carry, which with no voice of the language would ask the browser for one of another (ADR-0243 §3).
|
|
40
|
+
*/
|
|
41
|
+
const SPEECH_ROWS = ['#opt-tts', '#tts-vol', '#tts-ppm', '#opt-menuindex', '#tts-voz', '#opt-tts-test'];
|
|
42
|
+
export function createVoiceSettings(ctx, ports) {
|
|
43
|
+
const { t, bcp47 } = ctx.translator;
|
|
44
|
+
function reflectTts() {
|
|
45
|
+
const b = ctx.$('#opt-tts');
|
|
46
|
+
const cat = ctx.getAudioCat();
|
|
47
|
+
const on = !!(cat && cat.tts && cat.tts.on);
|
|
48
|
+
if (b) {
|
|
49
|
+
ctx.toggleBtn(b, on);
|
|
50
|
+
b.textContent = toggleLabel(t, on);
|
|
51
|
+
}
|
|
52
|
+
// and its volume: the slider was never drawn from the mixer, so it opened at the range's middle whatever was stored
|
|
53
|
+
const vol = ctx.$('#tts-vol');
|
|
54
|
+
if (vol && cat?.tts)
|
|
55
|
+
vol.value = String(volPercent(cat.tts.vol));
|
|
56
|
+
const e = ctx.$('#tts-engine');
|
|
57
|
+
if (e)
|
|
58
|
+
e.value = ctx.tts.getEngineSel();
|
|
59
|
+
}
|
|
60
|
+
function reflectMenuIndex() {
|
|
61
|
+
const b = ctx.$('#opt-menuindex');
|
|
62
|
+
if (b) {
|
|
63
|
+
ctx.toggleBtn(b, ctx.settings.menuIndexOn);
|
|
64
|
+
b.textContent = toggleLabel(t, ctx.settings.menuIndexOn);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function populateTtsEngines() {
|
|
68
|
+
const sel = ctx.$('#tts-engine');
|
|
69
|
+
if (!sel || sel.dataset.filled)
|
|
70
|
+
return;
|
|
71
|
+
sel.dataset.filled = '1';
|
|
72
|
+
voiceEngineOptions(ctx.tts.neuralAvailable !== false).forEach(([v, l]) => {
|
|
73
|
+
const o = ports.newOption();
|
|
74
|
+
o.value = v;
|
|
75
|
+
o.textContent = t(l);
|
|
76
|
+
sel.appendChild(o);
|
|
77
|
+
});
|
|
78
|
+
sel.value = ctx.tts.getEngineSel();
|
|
79
|
+
}
|
|
80
|
+
function populateTtsVoices() {
|
|
81
|
+
const sel = ctx.$('#tts-voice');
|
|
82
|
+
if (!sel)
|
|
83
|
+
return;
|
|
84
|
+
const list = pickVoicesFor(ports.systemVoices(), bcp47());
|
|
85
|
+
sel.innerHTML = '';
|
|
86
|
+
if (!list.length) {
|
|
87
|
+
const o = ports.newOption();
|
|
88
|
+
o.textContent = t('audio.noSystemVoices');
|
|
89
|
+
sel.appendChild(o);
|
|
90
|
+
ctx.tts.setVoiceObj(null);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
list.forEach((v) => {
|
|
94
|
+
const o = ports.newOption();
|
|
95
|
+
o.value = v.name;
|
|
96
|
+
o.textContent = voiceLabel(v);
|
|
97
|
+
sel.appendChild(o);
|
|
98
|
+
});
|
|
99
|
+
const saved = ctx.store.get('incl_tts_voice', null);
|
|
100
|
+
const pick = list.find((v) => v.name === saved) || list[0];
|
|
101
|
+
sel.value = pick.name;
|
|
102
|
+
ctx.tts.setVoiceObj(pick);
|
|
103
|
+
}
|
|
104
|
+
const noVoice = () => !!ctx.tts.voices && ctx.tts.voices().length === 0;
|
|
105
|
+
/** The lock last drawn on the speech rows; `null` before it is first drawn. Compared when the voices change. */
|
|
106
|
+
let lockDrawn = null;
|
|
107
|
+
/** The speech rate list: each step «N PPM», the stored one selected (ADR-0183 §1, ADR-0196). */
|
|
108
|
+
function renderRate() {
|
|
109
|
+
const sel = ctx.$('#tts-ppm');
|
|
110
|
+
if (!sel)
|
|
111
|
+
return;
|
|
112
|
+
while (sel.firstChild)
|
|
113
|
+
sel.removeChild(sel.firstChild);
|
|
114
|
+
for (const ppm of SPEECH_RATES) {
|
|
115
|
+
const o = ports.newOption();
|
|
116
|
+
o.value = String(ppm);
|
|
117
|
+
o.textContent = t('visual.legenda.ppm', { n: ppm });
|
|
118
|
+
sel.appendChild(o);
|
|
119
|
+
}
|
|
120
|
+
sel.value = String(ctx.settings.speechPpm);
|
|
121
|
+
}
|
|
122
|
+
/** The voices of the language as ids, one per line: what the «Voz» list was last drawn from. */
|
|
123
|
+
const voiceIds = () => (ctx.tts.voices?.() ?? []).map((v) => v.voice).join('\n');
|
|
124
|
+
let listDrawn = null;
|
|
125
|
+
function renderVoiceList() {
|
|
126
|
+
const sel = ctx.$('#tts-voz');
|
|
127
|
+
if (!sel || !ctx.tts.voices)
|
|
128
|
+
return;
|
|
129
|
+
const list = ctx.tts.voices();
|
|
130
|
+
listDrawn = voiceIds();
|
|
131
|
+
sel.replaceChildren(); // options built node by node: no markup sink
|
|
132
|
+
if (!list.length) {
|
|
133
|
+
const o = ports.newOption();
|
|
134
|
+
o.textContent = t('audio.voz.nenhuma');
|
|
135
|
+
sel.appendChild(o);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
for (const v of list) {
|
|
139
|
+
const o = ports.newOption();
|
|
140
|
+
o.value = v.voice;
|
|
141
|
+
o.textContent = panelVoiceLabel(v);
|
|
142
|
+
sel.appendChild(o);
|
|
143
|
+
}
|
|
144
|
+
sel.value = ctx.tts.currentVoice?.()?.voice ?? list[0].voice;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* No voice speaks the language (ADR-0185 §4): the five speech rows are LOCKED with the reason, never hidden (ADR-0161).
|
|
148
|
+
* `aria-disabled` and not `disabled`, so the keyboard still reaches the row and hears why.
|
|
149
|
+
*/
|
|
150
|
+
function lockSpeechRows() {
|
|
151
|
+
const lock = noVoice();
|
|
152
|
+
lockDrawn = lock;
|
|
153
|
+
for (const id of SPEECH_ROWS) {
|
|
154
|
+
const el = ctx.$(id);
|
|
155
|
+
if (!el)
|
|
156
|
+
continue;
|
|
157
|
+
if (lock) {
|
|
158
|
+
el.setAttribute('aria-disabled', 'true');
|
|
159
|
+
el.dataset.motivo = t('audio.semVoz');
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
el.removeAttribute('aria-disabled');
|
|
163
|
+
delete el.dataset.motivo;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/*
|
|
168
|
+
* A LOCKED SPEECH ROW DOES NOTHING AND SAYS WHY (ADR-0185 §4). In the CAPTURE phase on the control itself, so it runs
|
|
169
|
+
* before the row's own listener and stops it; a moved range goes back to the stored volume, a changed list to the voice in
|
|
170
|
+
* use. The footer shows the reason when the row takes focus: the card hears `focusin` after the row's own explanation.
|
|
171
|
+
*/
|
|
172
|
+
/**
|
|
173
|
+
* What a refused control puts back, by row: the moved volume to the stored one, the picked voice and rate to the ones in use.
|
|
174
|
+
* A row not here has nothing to undo (a switch was never flipped). A table, as the other «which row does what» answers here.
|
|
175
|
+
*/
|
|
176
|
+
const UNDO_ON_REFUSAL = {
|
|
177
|
+
'#tts-vol': (el) => { const cat = ctx.getAudioCat(); if (cat?.tts)
|
|
178
|
+
el.value = String(volPercent(cat.tts.vol)); },
|
|
179
|
+
'#tts-voz': () => renderVoiceList(),
|
|
180
|
+
'#tts-ppm': () => renderRate(),
|
|
181
|
+
};
|
|
182
|
+
function refuseWhileLocked() {
|
|
183
|
+
for (const id of SPEECH_ROWS) {
|
|
184
|
+
const el = ctx.$(id);
|
|
185
|
+
if (!el)
|
|
186
|
+
continue;
|
|
187
|
+
const refuse = (e) => {
|
|
188
|
+
if (el.getAttribute('aria-disabled') !== 'true')
|
|
189
|
+
return;
|
|
190
|
+
e.stopImmediatePropagation();
|
|
191
|
+
e.preventDefault();
|
|
192
|
+
UNDO_ON_REFUSAL[id]?.(el);
|
|
193
|
+
ctx.srSay(el.dataset.motivo ?? t('audio.semVoz'));
|
|
194
|
+
};
|
|
195
|
+
for (const kind of ['click', 'input', 'change'])
|
|
196
|
+
el.addEventListener(kind, refuse, true);
|
|
197
|
+
el.closest('.overlay__card')?.addEventListener('focusin', (e) => {
|
|
198
|
+
if (e.target !== el || el.getAttribute('aria-disabled') !== 'true')
|
|
199
|
+
return;
|
|
200
|
+
const footer = el.closest('.overlay__card')?.querySelector('.opt-explain');
|
|
201
|
+
if (footer)
|
|
202
|
+
footer.textContent = el.dataset.motivo ?? '';
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
refuseWhileLocked();
|
|
207
|
+
/**
|
|
208
|
+
* THE SEVEN CONTROLS, wired where the page carries them: the voice list, the rate, the narration switch, the spoken
|
|
209
|
+
* index, and the three the engine never builds but a page may (the engine selector, the system voice, the sample).
|
|
210
|
+
* A page that lacks one simply has that row missing.
|
|
211
|
+
*/
|
|
212
|
+
function wireControls() {
|
|
213
|
+
const voiceSel = ctx.$('#tts-voz');
|
|
214
|
+
if (voiceSel)
|
|
215
|
+
voiceSel.addEventListener('change', () => {
|
|
216
|
+
if (!ctx.tts.setVoice?.(voiceSel.value)) {
|
|
217
|
+
renderVoiceList();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const v = ctx.tts.currentVoice?.();
|
|
221
|
+
if (v)
|
|
222
|
+
ctx.srSay(t('sr.audio.voz', { nome: voiceName(v) }));
|
|
223
|
+
});
|
|
224
|
+
const rateSel = ctx.$('#tts-ppm');
|
|
225
|
+
if (rateSel)
|
|
226
|
+
rateSel.addEventListener('change', () => {
|
|
227
|
+
ctx.settings.setSpeechPpmValue(Number(rateSel.value));
|
|
228
|
+
renderRate();
|
|
229
|
+
ctx.srSay(`${t('audio.ttsPpm')}: ${t('visual.legenda.ppm', { n: ctx.settings.speechPpm })}`);
|
|
230
|
+
});
|
|
231
|
+
const ttsBtn = ctx.$('#opt-tts');
|
|
232
|
+
if (ttsBtn)
|
|
233
|
+
ttsBtn.addEventListener('click', () => {
|
|
234
|
+
const cat = ctx.getAudioCat();
|
|
235
|
+
if (!cat)
|
|
236
|
+
return;
|
|
237
|
+
cat.tts.on = !cat.tts.on;
|
|
238
|
+
ctx.setCatGain('tts');
|
|
239
|
+
reflectTts();
|
|
240
|
+
ctx.srSay(t(cat.tts.on ? 'sr.audio.ttsOn' : 'sr.audio.ttsOff'));
|
|
241
|
+
if (cat.tts.on)
|
|
242
|
+
ctx.tts.narrate(t('sr.audio.ttsOnSpoken'));
|
|
243
|
+
});
|
|
244
|
+
const idxBtn = ctx.$('#opt-menuindex');
|
|
245
|
+
if (idxBtn)
|
|
246
|
+
idxBtn.addEventListener('click', () => {
|
|
247
|
+
ctx.settings.setMenuIndexOnValue(!ctx.settings.menuIndexOn);
|
|
248
|
+
reflectMenuIndex();
|
|
249
|
+
// The announcement of the change carries NO index: it is not an item of any list, and a «1 of 1» here would be noise at
|
|
250
|
+
// exactly the moment the child is judging whether the noise bothers her.
|
|
251
|
+
ctx.srSay(t(ctx.settings.menuIndexOn ? 'sr.menu.indexOn' : 'sr.menu.indexOff'));
|
|
252
|
+
});
|
|
253
|
+
const ttsEngSel = ctx.$('#tts-engine');
|
|
254
|
+
if (ttsEngSel)
|
|
255
|
+
ttsEngSel.addEventListener('change', () => {
|
|
256
|
+
ctx.tts.setEngineSel(ttsEngSel.value);
|
|
257
|
+
ctx.store.set('incl_tts_engine', ttsEngSel.value);
|
|
258
|
+
if (ttsEngSel.value !== 'webspeech')
|
|
259
|
+
ctx.tts.loadTTS();
|
|
260
|
+
const opt = ttsEngSel.options[ttsEngSel.selectedIndex];
|
|
261
|
+
ctx.tts.narrate(t('sr.audio.engineSet', { motor: opt ? opt.text : '' }));
|
|
262
|
+
});
|
|
263
|
+
const ttsVoiceSel = ctx.$('#tts-voice');
|
|
264
|
+
if (ttsVoiceSel)
|
|
265
|
+
ttsVoiceSel.addEventListener('change', () => {
|
|
266
|
+
ctx.tts.setVoiceObj(ports.systemVoices().find((v) => v.name === ttsVoiceSel.value) || null);
|
|
267
|
+
ctx.store.set('incl_tts_voice', ttsVoiceSel.value);
|
|
268
|
+
ctx.tts.narrate(t('sr.audio.voicePicked'));
|
|
269
|
+
});
|
|
270
|
+
const ttsTestBtn = ctx.$('#opt-tts-test');
|
|
271
|
+
if (ttsTestBtn)
|
|
272
|
+
ttsTestBtn.addEventListener('click', () => {
|
|
273
|
+
const sample = t('audio.voiceSample');
|
|
274
|
+
const engine = ctx.tts.getEngine();
|
|
275
|
+
if (ctx.tts.getEngineSel() !== 'webspeech' && engine && engine.speak) {
|
|
276
|
+
try {
|
|
277
|
+
engine.speak(sample);
|
|
278
|
+
}
|
|
279
|
+
catch (e) { /* noop */ } // the neural engine is already loaded
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
ports.speakSample(sample, ctx.tts.getVoiceObj()); // audible fallback (volume 1) + starts the neural download
|
|
283
|
+
if (ctx.tts.getEngineSel() !== 'webspeech')
|
|
284
|
+
ctx.tts.loadTTS();
|
|
285
|
+
}
|
|
286
|
+
ctx.srSay(t('sr.audio.testingVoice'));
|
|
287
|
+
});
|
|
288
|
+
const ttsVolEl = ctx.$('#tts-vol');
|
|
289
|
+
if (ttsVolEl)
|
|
290
|
+
ttsVolEl.addEventListener('input', () => {
|
|
291
|
+
const cat = ctx.getAudioCat();
|
|
292
|
+
if (!cat)
|
|
293
|
+
return;
|
|
294
|
+
cat.tts.vol = (+ttsVolEl.value) / 100;
|
|
295
|
+
cat.tts.on = true;
|
|
296
|
+
ctx.setCatGain('tts');
|
|
297
|
+
reflectTts();
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
wireControls();
|
|
301
|
+
/**
|
|
302
|
+
* A LOCK THAT FLIPS UNDER THE CURSOR IS TOLD, and only there (ADR-0185 erratum 2026-09-26). The footer is written with what
|
|
303
|
+
* focusing the row would show NOW — the reason, or the row's own explanation — because it would otherwise go on saying «no
|
|
304
|
+
* voice» under a row that works. Locking is heard once, through the footer, which is `aria-live`, as when a locked row is
|
|
305
|
+
* focused. Unlocking gets one sentence more: the footer then gives the row's explanation, which does not say the state
|
|
306
|
+
* changed, and whether a removed `aria-disabled` on the focused control is spoken is left to each screen reader.
|
|
307
|
+
*/
|
|
308
|
+
function tellUnderCursor() {
|
|
309
|
+
const el = SPEECH_ROWS.map((id) => ctx.$(id)).find((e) => !!e && e.ownerDocument?.activeElement === e);
|
|
310
|
+
if (!el)
|
|
311
|
+
return;
|
|
312
|
+
const footer = el.closest('.overlay__card')?.querySelector('.opt-explain');
|
|
313
|
+
if (lockDrawn) {
|
|
314
|
+
if (footer)
|
|
315
|
+
footer.textContent = el.dataset.motivo ?? '';
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (footer)
|
|
319
|
+
footer.textContent = el.closest('.ctrl-row')?.dataset.explain || (footer.dataset.idle ?? '');
|
|
320
|
+
ctx.srSay(t('audio.comVoz'));
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* 🔴 THE DEVICE'S VOICES CHANGED (ADR-0185 §4, erratum 2026-09-26): a device may list them a moment after load — empty first,
|
|
324
|
+
* then full — and may lose them. The lock is a fact about those voices, so it is evaluated again here, both ways, IN PLACE:
|
|
325
|
+
* attributes on the same nodes, never a redraw, so the focus stays where the child left it. Only a change is drawn or told:
|
|
326
|
+
* the voice list when its voices differ, the rows and the cursor's row when the lock flips.
|
|
327
|
+
*/
|
|
328
|
+
function voicesChanged() {
|
|
329
|
+
populateTtsVoices();
|
|
330
|
+
if (voiceIds() !== listDrawn)
|
|
331
|
+
renderVoiceList(); // the same voices keep the same options, which the child may be reading
|
|
332
|
+
const before = lockDrawn;
|
|
333
|
+
lockSpeechRows();
|
|
334
|
+
if (lockDrawn !== before)
|
|
335
|
+
tellUnderCursor();
|
|
336
|
+
}
|
|
337
|
+
ports.whenVoicesChange(voicesChanged);
|
|
338
|
+
return {
|
|
339
|
+
render: () => {
|
|
340
|
+
reflectTts();
|
|
341
|
+
// 🔴 THIS ONE WAS MISSING, and only the case for the engine-mounted panel saw it (2026-09-12): the index is born ON, the
|
|
342
|
+
// button was born with no state, and the panel opened saying «off» — the control lying to the screen reader again.
|
|
343
|
+
reflectMenuIndex();
|
|
344
|
+
populateTtsEngines();
|
|
345
|
+
populateTtsVoices();
|
|
346
|
+
renderVoiceList();
|
|
347
|
+
renderRate();
|
|
348
|
+
lockSpeechRows();
|
|
349
|
+
},
|
|
350
|
+
reflectTts,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Translate } from '../core/i18n.js';
|
|
3
|
+
export interface WhereTheChildIsCtx {
|
|
4
|
+
/** Translates in the page's language — the root's translator (ADR-0232 D3). REQUIRED: text built from nowhere is a raw key. */
|
|
5
|
+
t: Translate;
|
|
6
|
+
/** The overlay on top, if any — the same one the focus trap and the menu navigation treat as «the open menu». */
|
|
7
|
+
readonly topVisibleOverlay: () => HTMLElement | null;
|
|
8
|
+
/** The pause card, when it is showing. */
|
|
9
|
+
readonly pauseCard: () => HTMLElement | null;
|
|
10
|
+
/** Who has the focus right now: it decides WHICH item of a panel is named. */
|
|
11
|
+
readonly focused: () => Element | null;
|
|
12
|
+
/**
|
|
13
|
+
* Does this cartridge want «N of M» spoken (ADR-0167)? It is only ever SPOKEN — never drawn — and a cartridge may
|
|
14
|
+
* silence it.
|
|
15
|
+
*/
|
|
16
|
+
readonly withIndex: () => boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Where the child is: a key to compare, and the sentence to say when it changed. */
|
|
19
|
+
export interface Place {
|
|
20
|
+
/** What «did she move?» is decided on. It names the panel or the card's open list, never just «a panel». */
|
|
21
|
+
readonly key: string;
|
|
22
|
+
/** What to say on arriving here — `null` in play, which is announced by the caller in its own words. */
|
|
23
|
+
readonly sentence: string | null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The place, in the order the screen reads: a panel sits over the card, the card sits over the game.
|
|
27
|
+
*
|
|
28
|
+
* 📌 PLAY HAS NO SENTENCE HERE and that is deliberate: «back to the game» is the caller's word for its own world, and
|
|
29
|
+
* this module has no business naming a game it does not know.
|
|
30
|
+
*/
|
|
31
|
+
export declare function whereTheChildIs(ctx: WhereTheChildIsCtx): Place;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// ui/where-the-child-is — WHERE THE CHILD IS NOW, AND WHAT THAT PLACE SAYS (ADR-0159 rule 3; ADR-0221 step 7c).
|
|
3
|
+
//
|
|
4
|
+
// «Opening a menu or panel speaks its title; closing it speaks where the child is back to; entering play is announced.»
|
|
5
|
+
// 📏 Measured in the dist on 2026-09-12, before that rule was built: SELECT opened the card in silence, and a panel
|
|
6
|
+
// opened, closed and went back to the root without a word. A child who plays by ear was moved without being told.
|
|
7
|
+
//
|
|
8
|
+
// WHAT THIS ANSWERS, AND WHY IT IS ONE QUESTION
|
|
9
|
+
// Two things at once, and they belong together: a KEY, which is what «did she move?» is decided on, and the SENTENCE
|
|
10
|
+
// to say when she did. Splitting them would let a caller compare one and speak the other, which is the defect the key
|
|
11
|
+
// exists to prevent — an arrow inside a menu changes no `hidden`, so it must not read as a change of place.
|
|
12
|
+
//
|
|
13
|
+
// WHY IT IS NOT IN THE COMPOSITION ROOT
|
|
14
|
+
// It used to be, and it was the densest function in `boot/create-game` after the root's own body: 19 branches in 24
|
|
15
|
+
// lines. A root holds WIRING (ADR-0221's erratum: its debt is paid when the BRANCHES tend to zero), and «is this a
|
|
16
|
+
// panel, a list of the pause card, or play, and what is its name» is a rule with a reason, not a wire.
|
|
17
|
+
//
|
|
18
|
+
// ⚠️ THE DOM ARRIVES BY QUESTION AND NOT BY GLOBAL: the overlay on top, the open card and the focused element are
|
|
19
|
+
// asked of whoever owns the document. That is what lets a case drive it without a root, and what keeps the module out
|
|
20
|
+
// of the `globalReach` ratchet (ADR-0221 step 7d).
|
|
21
|
+
import { navigableItems } from './menu-items.js';
|
|
22
|
+
import { announceItem } from './item-announcement.js';
|
|
23
|
+
import { controlParts } from './menu-nav.js';
|
|
24
|
+
import { PM_VISIBLE_ITEMS, LIST_DOOR } from './pause-icons.js';
|
|
25
|
+
import { accessibleLabel } from '../core/accessible-label.js';
|
|
26
|
+
/** Title and item joined the way a screen reader reads them: the place first, then where the cursor is in it. */
|
|
27
|
+
const say = (title, item) => [title, item].filter(Boolean).join('. ');
|
|
28
|
+
/** A PANEL: its title, and the item the focus is on — not the first, because the child may have walked into it. */
|
|
29
|
+
function panelPlace(panel, ctx) {
|
|
30
|
+
const title = panel.querySelector('h2')?.textContent?.trim() ?? '';
|
|
31
|
+
const items = navigableItems(panel.querySelector('.overlay__card') ?? panel);
|
|
32
|
+
const focused = items.indexOf(ctx.focused());
|
|
33
|
+
const n = focused >= 0 ? focused : 0;
|
|
34
|
+
const item = items[n] ? announceItem(ctx.t, { ...controlParts(ctx.t, items[n]), position: n + 1, total: items.length }, ctx.withIndex()) : '';
|
|
35
|
+
// ⚠️ THE KEY NAMES WHICH PANEL. Two panels reading as the same place is a child moving from the sound panel to the
|
|
36
|
+
// visual one in silence — and going from one panel straight to another is a real path: «map the keyboard» opens the
|
|
37
|
+
// controls panel on top of the motor one.
|
|
38
|
+
return { key: `painel:${panel.id}`, sentence: say(title, item) };
|
|
39
|
+
}
|
|
40
|
+
/** THE PAUSE CARD: which list of it is showing, named by the item that opens it, and the item under the cursor. */
|
|
41
|
+
function cardPlace(card, ctx) {
|
|
42
|
+
const sub = card.querySelector('.pause-menu:not([hidden])')?.dataset.sub ?? 'raiz';
|
|
43
|
+
// a submenu is named by the item that opens it; the root by the card's title
|
|
44
|
+
const door = LIST_DOOR[sub] ?? null;
|
|
45
|
+
const button = door ? card.querySelector(`.pm-btn[data-act="${door}"]`) : null;
|
|
46
|
+
const title = button ? accessibleLabel(button) : (card.querySelector('h2')?.textContent?.trim() ?? '');
|
|
47
|
+
const items = [...card.querySelectorAll(PM_VISIBLE_ITEMS)];
|
|
48
|
+
// 📌 THE MARKED ITEM AND NOT THE FIRST: coming back from a panel, the cursor is on the row that opened it. Naming
|
|
49
|
+
// the first row would send a child who cannot see the mark looking where she is not.
|
|
50
|
+
const marked = card.querySelector('.pm-sel') ?? items[0];
|
|
51
|
+
const item = marked ? announceItem(ctx.t, { label: accessibleLabel(marked), position: items.indexOf(marked) + 1, total: items.length }, ctx.withIndex()) : '';
|
|
52
|
+
// ⚠️ AND THE KEY CARRIES THE LIST: the root and a submenu are the same card with different rows, so a key that
|
|
53
|
+
// stopped at the card's id would make entering the settings a non-event.
|
|
54
|
+
return { key: `cartao:${card.id}:${sub}`, sentence: say(title, item) };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The place, in the order the screen reads: a panel sits over the card, the card sits over the game.
|
|
58
|
+
*
|
|
59
|
+
* 📌 PLAY HAS NO SENTENCE HERE and that is deliberate: «back to the game» is the caller's word for its own world, and
|
|
60
|
+
* this module has no business naming a game it does not know.
|
|
61
|
+
*/
|
|
62
|
+
export function whereTheChildIs(ctx) {
|
|
63
|
+
const panel = ctx.topVisibleOverlay();
|
|
64
|
+
if (panel)
|
|
65
|
+
return panelPlace(panel, ctx);
|
|
66
|
+
const card = ctx.pauseCard();
|
|
67
|
+
if (card)
|
|
68
|
+
return cardPlace(card, ctx);
|
|
69
|
+
return { key: 'jogo', sentence: null };
|
|
70
|
+
}
|