@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,276 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// ui/voice-control — PLAYING BY VOICE, PUT TOGETHER (ADR-0189, ADR-0193, ADR-0194, ADR-0204 erratum; issues #184, #190).
|
|
3
|
+
//
|
|
4
|
+
// The four pieces that existed separately, joined: the Dev's vocabulary and the firing rule (`input/voice-map`), the recogniser
|
|
5
|
+
// opened from the delivery (`platform/vosk-runtime`), the microphone that stays open (`platform/voice-listener`), and the
|
|
6
|
+
// presses on the virtual controller with the source `fala` (ADR-0111). The 👄 of the quick bar drives it; what cannot start is
|
|
7
|
+
// SAID, written once in `problems`, and puts the icon back to off — a child must never meet a button that does nothing.
|
|
8
|
+
//
|
|
9
|
+
// 📌 THE GRAMMAR FOLLOWS THE MENU (ADR-0194): saying the name of an item activates it, so the words the open menu is showing
|
|
10
|
+
// join the closed grammar while it is open and leave with it.
|
|
11
|
+
//
|
|
12
|
+
// 🎯 A NAME HEARD IS A CURSOR AND A CONFIRM, NOT A CLICK (ADR-0194 §2): the root's menu navigation puts the cursor on the
|
|
13
|
+
// named item (`pointAt`), and the confirm position is pressed on the virtual controller like any other spoken word — so the
|
|
14
|
+
// item is activated by the same path, with the same spoken feedback, as a child confirming it with the cursor on it. WHEN a
|
|
15
|
+
// name fires is the reader's (`input/voice-map` over `platform/speech-recognition`): at once, unless another item's name
|
|
16
|
+
// continues it («voltar» / «voltar ao jogo»), which waits for the end of the utterance (§3). A LOCKED item's name is heard
|
|
17
|
+
// too and takes the same path: the confirm reaches the item's own press, which says its reason and does nothing (§5, ADR-0161).
|
|
18
|
+
// A name with a word the loaded model lacks cannot be heard at all, and is a line of `problems` (§4).
|
|
19
|
+
// ⚠️ EXCEPT WITH ONE BUTTON ONLY ON (ADR-0218 §4): then every word heard, a name included, is the child's switch and nothing more
|
|
20
|
+
// — one press, which the controller takes as «take the one shown», and no cursor put anywhere first.
|
|
21
|
+
//
|
|
22
|
+
// ⚠️ A SPOKEN COMMAND IS A TAP, NOT A HOLD. The word arrives, the position is pressed and let go — one press, one release.
|
|
23
|
+
// Whether that tap keeps a direction going is the latch's, and on speech the latch starts as the GAME answers `holdsKeys()`
|
|
24
|
+
// (ADR-0249, resolved by the root when the press arrives): a platform game keeps walking on «direita», a quiz moves once on
|
|
25
|
+
// «abaixo», and the child may change either for her voice.
|
|
26
|
+
import { voiceGrammar, createVoiceCommands } from '../input/voice-map.js';
|
|
27
|
+
import { loadVoskRuntime } from '../platform/vosk-runtime.js';
|
|
28
|
+
import { startVoiceListening } from '../platform/voice-listener.js';
|
|
29
|
+
import { spokenText } from '../platform/speech-recognition.js';
|
|
30
|
+
import { MENU_CONFIRM } from './menu-intent.js';
|
|
31
|
+
/** How long a spoken position stays pressed. The same pulse the scan uses: long enough for a game to see a press and a release. */
|
|
32
|
+
export const VOICE_PULSE_MS = 400;
|
|
33
|
+
/** The base of a language tag: `en-US` and `en` are the same model. */
|
|
34
|
+
const baseOf = (tag) => tag.split('-')[0].toLowerCase();
|
|
35
|
+
export function createVoiceControl(d) {
|
|
36
|
+
const { t } = d;
|
|
37
|
+
const loadRuntime = d.loadRuntime ?? loadVoskRuntime;
|
|
38
|
+
const listen = d.listen ?? startVoiceListening;
|
|
39
|
+
const said = new Set();
|
|
40
|
+
let on = false, starting = null;
|
|
41
|
+
let listener = null;
|
|
42
|
+
let commands = null;
|
|
43
|
+
let grammarGiven = '';
|
|
44
|
+
/** The words the model now listening knows, once read (`platform/vosk-vocabulary`); `null` while unknown. */
|
|
45
|
+
let vocabulary = null;
|
|
46
|
+
/** Bumped by every stop, so a vocabulary that arrives for a recogniser already replaced is dropped. */
|
|
47
|
+
let generation = 0;
|
|
48
|
+
/**
|
|
49
|
+
* 🔴 THE LANGUAGE THE LISTENING STARTED IN, read ONCE. The model and the grammar must come from the same reading: `start()` used
|
|
50
|
+
* to read the language again after the model had loaded, and a page booting in English (pt-BR until its stored language
|
|
51
|
+
* applies) opened the Portuguese model with the English grammar — 15 «missing in vocabulary», measured on 2026-09-27.
|
|
52
|
+
*/
|
|
53
|
+
let listeningLanguage = '';
|
|
54
|
+
/** A choice among the game's options borrowing this ear (ADR-0256): what is heard goes to it, and no command is obeyed. */
|
|
55
|
+
let lent = null;
|
|
56
|
+
/** The open menu's names that can enter the grammar. A one-letter name stays out: in a closed grammar every short noise lands on it. */
|
|
57
|
+
const sayableNames = () => d.menuWords().filter((n) => spokenText(n).length > 1);
|
|
58
|
+
/**
|
|
59
|
+
* 🔴 A NAME THE MODEL CANNOT HEAR IS SAID TO THE ADULT (ADR-0194 §4, ADR-0169): Kaldi drops a grammar word its vocabulary lacks,
|
|
60
|
+
* in silence, and the item goes mute for the child — she can still walk to it with the direction words. One line per item and
|
|
61
|
+
* language, naming the words, the cost and the fix. Nothing is said while the vocabulary is unknown: no line beats a false one.
|
|
62
|
+
*/
|
|
63
|
+
const reportUnsayable = (names) => {
|
|
64
|
+
const known = vocabulary;
|
|
65
|
+
if (!known)
|
|
66
|
+
return;
|
|
67
|
+
const language = listeningLanguage;
|
|
68
|
+
for (const name of names) {
|
|
69
|
+
const lacking = [...new Set(spokenText(name).split(' '))].filter((w) => w && !known.has(w));
|
|
70
|
+
const kind = `unsayable:${language}:${name}`;
|
|
71
|
+
if (!lacking.length || said.has(kind))
|
|
72
|
+
continue;
|
|
73
|
+
said.add(kind);
|
|
74
|
+
d.report(`voice control: the menu item "${name}" has ${lacking.length === 1 ? 'a word' : 'words'} the ${language} speech `
|
|
75
|
+
+ `model does not know (${lacking.map((w) => `"${w}"`).join(', ')}) — the child cannot choose this item by saying its name, `
|
|
76
|
+
+ `only by walking to it with the direction words; reword the item's label in the ${language} dictionary with words the `
|
|
77
|
+
+ 'model knows (ADR-0194 §4)');
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
/** The open menu's names, handed to the reader and checked against the model, and the grammar with them. */
|
|
81
|
+
const followMenu = () => {
|
|
82
|
+
const names = sayableNames();
|
|
83
|
+
commands?.items(names);
|
|
84
|
+
reportUnsayable(names);
|
|
85
|
+
return voiceGrammar(listeningLanguage, names);
|
|
86
|
+
};
|
|
87
|
+
const command = (action) => {
|
|
88
|
+
d.controller.press(action, 'fala');
|
|
89
|
+
d.after(() => d.controller.release(action, 'fala'), VOICE_PULSE_MS);
|
|
90
|
+
};
|
|
91
|
+
/*
|
|
92
|
+
* 🔴 ONE WORD HEARD IS ONE ACTION (ADR-0111 errata, ADR-0218 §4). With one button only on, the controller takes every press as
|
|
93
|
+
* «take the one shown», so a word may do nothing BESIDES its press: asked here, first, for every word — a position, a name, any
|
|
94
|
+
* kind a later reader adds. 📏 Before, a name was still pointed at: with the chip on «próximo» the cursor jumped to the named
|
|
95
|
+
* item and then stepped on from it; on «cancelar» the press meant nothing and the cursor had moved anyway.
|
|
96
|
+
*/
|
|
97
|
+
const obey = (heard) => {
|
|
98
|
+
for (const c of heard ?? []) {
|
|
99
|
+
if (d.oneButtonOnly())
|
|
100
|
+
command(c.kind === 'position' ? c.action : MENU_CONFIRM);
|
|
101
|
+
else if (c.kind === 'position')
|
|
102
|
+
command(c.action);
|
|
103
|
+
else if (d.pointAt(c.name))
|
|
104
|
+
command(MENU_CONFIRM);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const stop = () => {
|
|
108
|
+
const going = listener;
|
|
109
|
+
listener = null;
|
|
110
|
+
commands = null;
|
|
111
|
+
lent = null;
|
|
112
|
+
vocabulary = null;
|
|
113
|
+
generation += 1;
|
|
114
|
+
void going?.stop();
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Nothing started: the child hears why, the adult reads it once, and the icon goes back to off. A failure that arrives after
|
|
118
|
+
* the 👄 was turned off (or the root disposed, ADR-0220) has nobody waiting for it and says and writes nothing.
|
|
119
|
+
*/
|
|
120
|
+
const failed = (kind, line, spoken) => {
|
|
121
|
+
if (!on)
|
|
122
|
+
return;
|
|
123
|
+
if (!said.has(kind)) {
|
|
124
|
+
said.add(kind);
|
|
125
|
+
d.report(line);
|
|
126
|
+
}
|
|
127
|
+
d.alert(spoken);
|
|
128
|
+
d.turnOff();
|
|
129
|
+
};
|
|
130
|
+
const start = async () => {
|
|
131
|
+
/*
|
|
132
|
+
* 🔴 THE LOAD IS INSIDE A `try` AND THIS WAS MEASURED, not foreseen: on 2026-09-21 the delivery's bundle turned out to be an
|
|
133
|
+
* ES module and the loader threw. Nothing here caught it, so the rejection died as an unhandled promise and the 👄 STAYED
|
|
134
|
+
* LIT over a microphone that had never opened — the exact defect this module exists to prevent, one layer above where it
|
|
135
|
+
* was being prevented. A failure that has no name is still a failure the child has to be told about.
|
|
136
|
+
*/
|
|
137
|
+
let load;
|
|
138
|
+
const language = d.language();
|
|
139
|
+
try {
|
|
140
|
+
load = await loadRuntime({
|
|
141
|
+
base: d.base, language, hasFile: d.hasFile, loadBundle: d.loadBundle, ...(d.fetch ? { fetch: d.fetch } : {}),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
failed('runtime', `voice control: the recogniser did not open (${e instanceof Error ? e.message : String(e)}) — the child `
|
|
146
|
+
+ 'cannot play by speaking; check that the delivery carries the command files', t('sr.voice.failed'));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (!load.ok) {
|
|
150
|
+
/*
|
|
151
|
+
* 📌 ONE LINE PER LANGUAGE, NAMING THAT LANGUAGE'S FIX (ADR-0225 and its erratum, ADR-0169). The delivery carries every
|
|
152
|
+
* language unless its `--commands` list narrowed it, and the install fetches every one the delivery carries — so a model
|
|
153
|
+
* missing here was left out of the delivery or has not come down yet, and «open it online» alone sends the adult after a
|
|
154
|
+
* download that cannot happen in the first case. The reading's line names its two fixes the same way.
|
|
155
|
+
*/
|
|
156
|
+
const lang = language.split('-')[0].toLowerCase();
|
|
157
|
+
failed(`files:${lang}`, `voice control: ${load.missing.join(', ')} not on this device for ${language} — the child cannot play `
|
|
158
|
+
+ `by speaking in this language; build the delivery with \`npx inclusionist-heavy\` without \`--commands\` (it carries every `
|
|
159
|
+
+ `language) or with \`--commands ${lang}\` in its list, and open the game once online so the install fetches them`, t('sr.voice.needsInternet'));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// the language changed while the model loaded (a page booting before its stored language applies): start again in it
|
|
163
|
+
if (baseOf(d.language()) !== baseOf(language)) {
|
|
164
|
+
await start();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
listeningLanguage = language;
|
|
168
|
+
commands = createVoiceCommands(language);
|
|
169
|
+
const grammar = followMenu();
|
|
170
|
+
grammarGiven = grammar.join('\n');
|
|
171
|
+
try {
|
|
172
|
+
listener = await listen({
|
|
173
|
+
model: load.model,
|
|
174
|
+
grammar,
|
|
175
|
+
getUserMedia: d.getUserMedia,
|
|
176
|
+
createContext: d.createContext,
|
|
177
|
+
onPartial: (text) => { if (lent)
|
|
178
|
+
lent(text, false);
|
|
179
|
+
else
|
|
180
|
+
obey(commands?.partial(text)); },
|
|
181
|
+
onFinal: (text) => { if (lent)
|
|
182
|
+
lent(text, true);
|
|
183
|
+
else
|
|
184
|
+
obey(commands?.final(text)); },
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
failed('microphone', 'voice control: the microphone did not open — the child cannot play by speaking; allow the microphone '
|
|
189
|
+
+ 'for this page, or plug one in', t('sr.voice.noMicrophone'));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
// ⚠️ TURNED OFF WHILE IT WAS STARTING: the microphone opened after the child let go of the icon, and a listener nobody asked
|
|
193
|
+
// for would go on hearing her. The check is here and not only in `apply`, because starting is not instantaneous.
|
|
194
|
+
if (!on) {
|
|
195
|
+
stop();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// a menu that opened or closed while the microphone was opening changed the names after the grammar above was built
|
|
199
|
+
api.refreshGrammar();
|
|
200
|
+
d.say(t('sr.voice.ready'));
|
|
201
|
+
// 📌 THE VOCABULARY IS READ AFTER THE CHILD CAN SPEAK, never before: it is a report for the adult, and reading the model's
|
|
202
|
+
// archive a second time must not delay the first command. It checks the names showing when it arrives and every later menu.
|
|
203
|
+
const mine = generation;
|
|
204
|
+
void load.vocabulary?.().then((words) => {
|
|
205
|
+
if (mine !== generation || !listener)
|
|
206
|
+
return;
|
|
207
|
+
vocabulary = words;
|
|
208
|
+
reportUnsayable(sayableNames());
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
const api = {
|
|
212
|
+
async apply(next) {
|
|
213
|
+
on = next;
|
|
214
|
+
if (!next) {
|
|
215
|
+
stop();
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (listener || starting)
|
|
219
|
+
return;
|
|
220
|
+
starting = start().finally(() => { starting = null; });
|
|
221
|
+
await starting;
|
|
222
|
+
},
|
|
223
|
+
refreshGrammar() {
|
|
224
|
+
// lent to a choice: the options are the grammar until it gives the ear back
|
|
225
|
+
if (!listener || lent)
|
|
226
|
+
return;
|
|
227
|
+
// 📌 A new grammar is a new recogniser (`platform/voice-listener`), and the root asks on every menu change it sees —
|
|
228
|
+
// most of which change no name. Only a grammar that differs is handed on.
|
|
229
|
+
const grammar = followMenu();
|
|
230
|
+
const given = grammar.join('\n');
|
|
231
|
+
if (given === grammarGiven)
|
|
232
|
+
return;
|
|
233
|
+
grammarGiven = given;
|
|
234
|
+
listener.setGrammar(grammar);
|
|
235
|
+
},
|
|
236
|
+
async languageChanged() {
|
|
237
|
+
/*
|
|
238
|
+
* 🔴 THE RECOGNISER STOPS CHOOSING ITS LANGUAGE ONCE (ADR-0225). `start()` reads `d.language()` for the MODEL and for the
|
|
239
|
+
* vocabulary, and it used to read it only at the moment the 👄 was switched on — so a child who changed language while
|
|
240
|
+
* listening went on being heard in the old one.
|
|
241
|
+
* ⚠️ AND THAT IS WORSE THAN STOPPING, which is why this is not cosmetic: the grammar DOES follow, because it is rebuilt
|
|
242
|
+
* whenever a menu opens (ADR-0194). So after a change the new language's words were fed to the old language's model, and
|
|
243
|
+
* a closed grammar answers with the nearest candidate — measured in the lab on 2026-09-14, where «configurações de
|
|
244
|
+
* inclusão» came back as «quatro». A microphone that acts on a word the child did not say is the defect here.
|
|
245
|
+
* 📌 OFF IS ALREADY RIGHT: the next start reads the language then. This only has work to do while it is listening.
|
|
246
|
+
*/
|
|
247
|
+
if (!on)
|
|
248
|
+
return;
|
|
249
|
+
// ⚠️ A START IN FLIGHT IS IN THE OLD LANGUAGE. Letting it finish and replacing it costs one opening; skipping it would
|
|
250
|
+
// leave `starting` to install the old model on top of the new one, which is the race the `if (!on)` in `start` exists for.
|
|
251
|
+
await starting;
|
|
252
|
+
// a start that noticed the change itself is already listening in the new language: nothing to redo
|
|
253
|
+
if (listener && baseOf(listeningLanguage) === baseOf(d.language()))
|
|
254
|
+
return;
|
|
255
|
+
stop();
|
|
256
|
+
await api.apply(true);
|
|
257
|
+
},
|
|
258
|
+
borrow(language, grammar, onHeard) {
|
|
259
|
+
if (!listener || lent || baseOf(language) !== baseOf(listeningLanguage))
|
|
260
|
+
return null;
|
|
261
|
+
const held = listener;
|
|
262
|
+
lent = onHeard;
|
|
263
|
+
held.setGrammar(grammar);
|
|
264
|
+
grammarGiven = '';
|
|
265
|
+
return {
|
|
266
|
+
async stop() {
|
|
267
|
+
if (lent !== onHeard)
|
|
268
|
+
return;
|
|
269
|
+
lent = null;
|
|
270
|
+
api.refreshGrammar(); // the menu's grammar back
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
return api;
|
|
276
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Translator } from '../core/i18n.js';
|
|
3
|
+
import type { DomQuery } from '../core/dom-query.js';
|
|
4
|
+
import { type AudioCatState } from './audio-choices.js';
|
|
5
|
+
export interface TtsPanelEngine {
|
|
6
|
+
id: string;
|
|
7
|
+
speak: (text: string) => void;
|
|
8
|
+
}
|
|
9
|
+
/** Minimal shape of the injected `tts` (platform/tts.ts's createTts() instance) this section drives. */
|
|
10
|
+
export interface TtsPanel {
|
|
11
|
+
getEngineSel: () => string;
|
|
12
|
+
setEngineSel: (v: string) => void;
|
|
13
|
+
getEngine: () => TtsPanelEngine | null;
|
|
14
|
+
getVoiceObj: () => SpeechSynthesisVoice | null;
|
|
15
|
+
setVoiceObj: (v: SpeechSynthesisVoice | null) => void;
|
|
16
|
+
loadTTS: () => void;
|
|
17
|
+
narrate: (text: string) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Does this assembly have a neural engine (the game's Kokoro port, ADR-0198)? Optional, absent reads `true`: a panel test
|
|
20
|
+
* fake written before this field has no opinion on neural engines.
|
|
21
|
+
*/
|
|
22
|
+
neuralAvailable?: boolean;
|
|
23
|
+
/** The voices of the language (ADR-0185). Optional: a panel driven without them offers no «Voz» list and locks nothing. */
|
|
24
|
+
voices?: () => readonly PanelVoice[];
|
|
25
|
+
currentVoice?: () => PanelVoice | null;
|
|
26
|
+
setVoice?: (id: string) => boolean;
|
|
27
|
+
}
|
|
28
|
+
/** A voice as this panel lists it: `webspeech:<name>` for the browser's, `xx_name` for Kokoro's. */
|
|
29
|
+
export interface PanelVoice {
|
|
30
|
+
readonly voice: string;
|
|
31
|
+
readonly engine?: string;
|
|
32
|
+
readonly recommended?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The browser, as four functions.
|
|
36
|
+
*
|
|
37
|
+
* 🔴 A module that reaches `document` or `window` undoes a decision (ADR-0178), and the health ratchet refuses a NEW one that
|
|
38
|
+
* does. These four are what the voice section actually needs from the browser, and naming them is what makes the section
|
|
39
|
+
* testable: hand it a fake `doc`, a list of voices and two no-ops, and every branch below runs without a speech engine.
|
|
40
|
+
*/
|
|
41
|
+
export interface VoicePorts {
|
|
42
|
+
/** Makes one <option> — the only element this section builds. A FUNCTION and not the document: a port read at wiring
|
|
43
|
+
* time would make a panel unmountable where there is no document yet, and the node suite mounts exactly there. */
|
|
44
|
+
readonly newOption: () => HTMLOptionElement;
|
|
45
|
+
/** The system voices, or an empty list where the browser has none or throws. */
|
|
46
|
+
readonly systemVoices: () => readonly SpeechSynthesisVoice[];
|
|
47
|
+
/** Speak the sample through the BROWSER's own synthesiser — the neural engine speaks through `tts` instead. */
|
|
48
|
+
readonly speakSample: (text: string, chosen: SpeechSynthesisVoice | null) => void;
|
|
49
|
+
/** Called again whenever the browser finishes loading its voice list: they arrive late, and often empty first.
|
|
50
|
+
* ⚠️ The parameter is `again` and not `run`, which is a GAME ACTION word this layer does not say (the boundary of 2026-09-06). */
|
|
51
|
+
readonly whenVoicesChange: (again: () => void) => void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* What this section needs from the panel's ctx.
|
|
55
|
+
*
|
|
56
|
+
* ⚠️ The store shape is written here and NOT imported from `ui/settings-audio`, which declares the same two methods: that
|
|
57
|
+
* module imports this one, and importing it back would be the cycle ADR-0173 forbids — for a type as much as for a value.
|
|
58
|
+
*/
|
|
59
|
+
/**
|
|
60
|
+
* THE SETTINGS THIS SECTION READS AND WRITES — the page's settings store, built by the root (ADR-0232 D2c, issue #207): the
|
|
61
|
+
* spoken index (ADR-0044 item 3) and the speech rate (ADR-0183). The names are `core/state`'s, so a root passes the store
|
|
62
|
+
* itself; the reads are LIVE, because the quick bar and a second screen change them too.
|
|
63
|
+
*/
|
|
64
|
+
export interface VoiceSettingsStore {
|
|
65
|
+
readonly menuIndexOn: boolean;
|
|
66
|
+
setMenuIndexOnValue(on: boolean): void;
|
|
67
|
+
readonly speechPpm: number;
|
|
68
|
+
setSpeechPpmValue(ppm: number): void;
|
|
69
|
+
}
|
|
70
|
+
export interface VoiceSettingsCtx {
|
|
71
|
+
/**
|
|
72
|
+
* The root's translator (ADR-0232 D3): its `t`, and the page's language as a BCP-47 tag, which picks the system voices the
|
|
73
|
+
* list offers. A Pick and not a bare `t`, because the voice list reads the language.
|
|
74
|
+
*/
|
|
75
|
+
translator: Pick<Translator, 't' | 'bcp47'>;
|
|
76
|
+
/** The page's settings store (see `VoiceSettingsStore`). REQUIRED: a section reading from nowhere would show the defaults. */
|
|
77
|
+
settings: VoiceSettingsStore;
|
|
78
|
+
$: DomQuery;
|
|
79
|
+
srSay: (msg: string) => void;
|
|
80
|
+
toggleBtn: (btn: HTMLElement, on: boolean) => void;
|
|
81
|
+
store: {
|
|
82
|
+
get(key: string, fallback?: string | null): string | null;
|
|
83
|
+
set(key: string, value: string | number | boolean): boolean;
|
|
84
|
+
};
|
|
85
|
+
tts: TtsPanel;
|
|
86
|
+
getAudioCat: () => Record<string, AudioCatState> | null;
|
|
87
|
+
setCatGain: (k: string) => void;
|
|
88
|
+
}
|
|
89
|
+
export interface VoiceSettings {
|
|
90
|
+
/** Everything the section shows, refreshed from the stored state. Called by the panel's own render. */
|
|
91
|
+
render: () => void;
|
|
92
|
+
/** Just the narration switch, its volume and the chosen engine. Exported because the root reflects it from outside. */
|
|
93
|
+
reflectTts: () => void;
|
|
94
|
+
}
|
|
95
|
+
export declare function createVoiceSettings(ctx: VoiceSettingsCtx, ports: VoicePorts): VoiceSettings;
|