@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,152 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* THE SONAR'S POSITION WHILE A MENU IS OPEN. In play the position is the game's (its `preset`); with a menu open the positions
|
|
4
|
+
* are the engine's, and there R1 reads the menu — the Dev's default for the sonar («Tecla padrão para o sonar deve ser R1»).
|
|
5
|
+
*/
|
|
6
|
+
const MENU_SONAR = 'rightShoulder';
|
|
7
|
+
/** The engine's chrome the child did not ask about (see the header). */
|
|
8
|
+
const NOT_ASKED_ABOUT = [
|
|
9
|
+
'.pause-icons', '.screen-a11y', '.rodape-da-tela', '.scan-now', '#touch-controls', '.touch', '.sr-only',
|
|
10
|
+
'.gaze-overlay', '.face-overlay', '.hand-overlay', '.hud-row-clock',
|
|
11
|
+
].join(', ');
|
|
12
|
+
/** What is open in front of the world. */
|
|
13
|
+
const DIALOG = '[role="dialog"], [role="alertdialog"], [aria-modal="true"]';
|
|
14
|
+
/** Elements whose content is not words on the screen (a `<select>` shows its chosen option only — see `spokenAs`). */
|
|
15
|
+
const NOT_WORDS = /^(script|style|template|noscript|svg|canvas|video|audio|iframe|object|option|optgroup)$/i;
|
|
16
|
+
/** A line that already ends a sentence is not given a full stop. */
|
|
17
|
+
const ENDS_A_SENTENCE = /[.!?…:;]$/u;
|
|
18
|
+
/**
|
|
19
|
+
* Is this one element drawn for the eye, and meant for everyone? Its ancestors are asked by whoever walks down to it.
|
|
20
|
+
* 📌 The RENDERING decides, not the `hidden` attribute: `hidden` hides by `display: none`, which is read here, and a stylesheet
|
|
21
|
+
* that shows a `[hidden]` element puts it on the screen.
|
|
22
|
+
*/
|
|
23
|
+
function isShown(el) {
|
|
24
|
+
if (el.hasAttribute('inert') || el.getAttribute('aria-hidden') === 'true')
|
|
25
|
+
return false;
|
|
26
|
+
const style = el.ownerDocument?.defaultView?.getComputedStyle(el);
|
|
27
|
+
return !style || (style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0');
|
|
28
|
+
}
|
|
29
|
+
/** Is it drawn, with every ancestor drawn too? For an element found by a query rather than walked down to. */
|
|
30
|
+
function isOnScreen(el) {
|
|
31
|
+
for (let node = el; node; node = node.parentElement)
|
|
32
|
+
if (!isShown(node))
|
|
33
|
+
return false;
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Can this node be walked and asked? A host double may hand elements without the DOM's questions; then there is nothing the
|
|
38
|
+
* engine can read, and it says nothing rather than throwing into the sonar (a capability of the environment, ADR-0169).
|
|
39
|
+
*/
|
|
40
|
+
function canBeRead(el) {
|
|
41
|
+
return !!el && typeof el.matches === 'function' && typeof el.querySelectorAll === 'function' && typeof el.hasAttribute === 'function';
|
|
42
|
+
}
|
|
43
|
+
/** The dialog in front, or `null`: the one holding the focus, else the last one open in the document. */
|
|
44
|
+
function dialogInFront(doc) {
|
|
45
|
+
if (typeof doc.querySelectorAll !== 'function')
|
|
46
|
+
return null;
|
|
47
|
+
const open = [...doc.querySelectorAll(DIALOG)].filter((d) => canBeRead(d) && isOnScreen(d) && !d.matches(NOT_ASKED_ABOUT));
|
|
48
|
+
const focused = doc.activeElement;
|
|
49
|
+
return open.find((d) => !!focused && d.contains(focused)) ?? open[open.length - 1] ?? null;
|
|
50
|
+
}
|
|
51
|
+
/** The world's element, or `null` when the game declared none, its selector matches nothing, or it cannot be read. */
|
|
52
|
+
function worldElement(ctx) {
|
|
53
|
+
const scope = ctx.world();
|
|
54
|
+
const el = scope.kind === 'element' && typeof ctx.doc.querySelector === 'function' ? ctx.doc.querySelector(scope.selector) : null;
|
|
55
|
+
return canBeRead(el) ? el : null;
|
|
56
|
+
}
|
|
57
|
+
/** Does the world draw on a canvas the engine did not put there? Then its words are pixels. */
|
|
58
|
+
function drawsOnCanvas(world) {
|
|
59
|
+
const canvases = world.matches('canvas') ? [world] : [...world.querySelectorAll('canvas')];
|
|
60
|
+
return canvases.some((c) => !c.closest(NOT_ASKED_ABOUT) && isOnScreen(c));
|
|
61
|
+
}
|
|
62
|
+
/** The words an element stands for instead of its children, or `null` to read its children. */
|
|
63
|
+
function spokenAs(el) {
|
|
64
|
+
if (el.getAttribute('role') === 'img')
|
|
65
|
+
return el.getAttribute('aria-label') ?? '';
|
|
66
|
+
if (el.localName === 'img')
|
|
67
|
+
return el.getAttribute('alt') ?? '';
|
|
68
|
+
if (el.localName === 'select')
|
|
69
|
+
return el.selectedOptions[0]?.textContent ?? '';
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
/** Does the element start a line of its own? Everything that is not inline does — a button, a heading, a row. */
|
|
73
|
+
function breaksTheLine(el) {
|
|
74
|
+
const display = el.ownerDocument?.defaultView?.getComputedStyle(el).display ?? 'block';
|
|
75
|
+
return el.localName === 'br' || (display !== 'inline' && display !== 'contents');
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The text under `root`, in DOM order, one line per block. Lines are joined as sentences, so the voice pauses between the
|
|
79
|
+
* statement and each option and the interpreter receives them apart.
|
|
80
|
+
*/
|
|
81
|
+
function textOf(root) {
|
|
82
|
+
const lines = [];
|
|
83
|
+
let line = '';
|
|
84
|
+
const endLine = () => {
|
|
85
|
+
const words = line.replace(/\s+/gu, ' ').trim();
|
|
86
|
+
if (words)
|
|
87
|
+
lines.push(words);
|
|
88
|
+
line = '';
|
|
89
|
+
};
|
|
90
|
+
const readChildren = (el) => {
|
|
91
|
+
for (const child of el.childNodes ?? []) {
|
|
92
|
+
if (child.nodeType === 3)
|
|
93
|
+
line += child.textContent ?? '';
|
|
94
|
+
else if (child.nodeType === 1)
|
|
95
|
+
visit(child);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const visit = (el) => {
|
|
99
|
+
if (!isShown(el) || el.matches(NOT_ASKED_ABOUT) || NOT_WORDS.test(el.localName))
|
|
100
|
+
return;
|
|
101
|
+
const own = breaksTheLine(el);
|
|
102
|
+
if (own)
|
|
103
|
+
endLine();
|
|
104
|
+
const said = spokenAs(el);
|
|
105
|
+
if (said === null)
|
|
106
|
+
readChildren(el);
|
|
107
|
+
else
|
|
108
|
+
line += ` ${said} `;
|
|
109
|
+
if (own)
|
|
110
|
+
endLine();
|
|
111
|
+
};
|
|
112
|
+
visit(root);
|
|
113
|
+
endLine();
|
|
114
|
+
return lines.map((l) => (ENDS_A_SENTENCE.test(l) ? l : `${l}.`)).join(' ');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* WHAT IS ON THE SCREEN NOW, as the sonar reads it — `''` when there is nothing the engine can read: no world, an empty one,
|
|
118
|
+
* or a world drawn on a canvas.
|
|
119
|
+
*/
|
|
120
|
+
export function screenText(ctx) {
|
|
121
|
+
const front = dialogInFront(ctx.doc);
|
|
122
|
+
if (front)
|
|
123
|
+
return textOf(front);
|
|
124
|
+
const world = worldElement(ctx);
|
|
125
|
+
return world && !drawsOnCanvas(world) ? textOf(world) : '';
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The `problems` line for a world the sonar cannot read — none, or one (ADR-0169: the subject, the child's cost, the fix).
|
|
129
|
+
* Measured at every read of `problems`: a canvas is often drawn after the boot.
|
|
130
|
+
*/
|
|
131
|
+
export function unreadableWorldProblems(ctx) {
|
|
132
|
+
const world = worldElement(ctx);
|
|
133
|
+
if (!world || !drawsOnCanvas(world))
|
|
134
|
+
return [];
|
|
135
|
+
return ['the sonar cannot read this game\'s screen: its world draws on a <canvas>, whose words are pixels to the engine, so '
|
|
136
|
+
+ 'a child who presses the sonar hears only the nearest target\'s name and side instead of what is written on screen — '
|
|
137
|
+
+ 'and in deaf mode the interpreter signs that, not the screen (ADR-0234). Write the words the child must read as text '
|
|
138
|
+
+ 'in the page, inside the world; a contract field for a game to hand the engine its screen\'s text is a decision the '
|
|
139
|
+
+ 'Dev has not taken'];
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* A press made WITH A MENU OPEN: the menu sonar's position reads what is in front (`read`) and takes the press. Any other
|
|
143
|
+
* position is left to the menus — answers whether this one was taken.
|
|
144
|
+
*/
|
|
145
|
+
export function menuSonarPress(action, ctx, read) {
|
|
146
|
+
if (action !== MENU_SONAR)
|
|
147
|
+
return false;
|
|
148
|
+
const text = screenText(ctx);
|
|
149
|
+
if (text)
|
|
150
|
+
read(text);
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Translate } from '../core/i18n.js';
|
|
3
|
+
/**
|
|
4
|
+
* What the clock needs, all lent by the root. The three host ports are REQUIRED and may carry `undefined` — a host without
|
|
5
|
+
* them is answered here, not with a branch in the root (ADR-0232 erratum of 2026-09-25): with no clock or no tick there is no
|
|
6
|
+
* session to measure, and nothing is mounted, silently, as a capability of the environment (ADR-0169).
|
|
7
|
+
*/
|
|
8
|
+
export interface SessionClockCtx {
|
|
9
|
+
readonly doc: Document;
|
|
10
|
+
/** Where the clock goes: the HUD row's centre cell. Absent, or a node that takes no children, and nothing is mounted. */
|
|
11
|
+
readonly slot: HTMLElement | null;
|
|
12
|
+
readonly t: Translate;
|
|
13
|
+
/** The host's `performance`, milliseconds and monotonic. The session starts at the mount. */
|
|
14
|
+
readonly performance: {
|
|
15
|
+
now(): number;
|
|
16
|
+
} | undefined;
|
|
17
|
+
readonly setInterval: ((fn: () => void, ms: number) => number) | undefined;
|
|
18
|
+
readonly clearInterval: ((handle: number) => void) | undefined;
|
|
19
|
+
/** The polite announcer: said once, when the hour runs out. */
|
|
20
|
+
readonly announce: (text: string) => void;
|
|
21
|
+
/** Called after every redraw, so the root can measure the row again when the clock's size changed. */
|
|
22
|
+
readonly drawn: () => void;
|
|
23
|
+
}
|
|
24
|
+
export interface SessionClockMounted {
|
|
25
|
+
readonly el: HTMLElement;
|
|
26
|
+
/** Reads the time again and redraws what changed (the tick calls it; a language change too). */
|
|
27
|
+
refresh(): void;
|
|
28
|
+
/** Stops the tick and takes the clock off the page. */
|
|
29
|
+
remove(): void;
|
|
30
|
+
}
|
|
31
|
+
/** Mounts the clock in its slot, draws it now, and redraws it every second until `remove()`; `null` where it cannot. */
|
|
32
|
+
export declare function mountSessionClock(ctx: SessionClockCtx): SessionClockMounted | null;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import { readSession, clockWords, clockDigits } from '../core/session-clock.js';
|
|
3
|
+
/** One tick a second: the digits move by the second, and the hour's pie by a tenth of a degree, which reads as continuous. */
|
|
4
|
+
const TICK_MS = 1000;
|
|
5
|
+
/** Writes `text` into `node` only when it changed — a rewrite is a repaint, and on school hardware a repaint costs. */
|
|
6
|
+
function write(node, text) {
|
|
7
|
+
if (node.textContent !== text)
|
|
8
|
+
node.textContent = text;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Builds the clock's three parts: the label and the digits in a column, the pie to their right.
|
|
12
|
+
*
|
|
13
|
+
* 🔴 THE PARTS ARE `aria-hidden`: they are the picture, and the image's name is what a listener gets. ARIA calls an image's
|
|
14
|
+
* children presentational, but not every accessibility API prunes them — Gecko keeps a graphic's children unless it has exactly
|
|
15
|
+
* one text child, and NVDA then read «TEMPO. 56:07.» instead of the words (the Dev, 2026-09-25). Hidden here, no API has any
|
|
16
|
+
* text under the image to hand out. Gate: `tests/quiz-accessibility-tree.browser.test.js`, on the browser's own tree.
|
|
17
|
+
*/
|
|
18
|
+
function build(doc) {
|
|
19
|
+
const part = (cls) => { const n = doc.createElement('span'); n.className = cls; return n; };
|
|
20
|
+
const el = doc.createElement('div');
|
|
21
|
+
el.className = 'session-clock';
|
|
22
|
+
el.setAttribute('role', 'img');
|
|
23
|
+
const text = part('session-clock-text');
|
|
24
|
+
const label = part('session-clock-label');
|
|
25
|
+
const digits = part('session-clock-digits');
|
|
26
|
+
const pie = part('session-clock-pie');
|
|
27
|
+
text.setAttribute('aria-hidden', 'true');
|
|
28
|
+
pie.setAttribute('aria-hidden', 'true');
|
|
29
|
+
text.append(label, digits);
|
|
30
|
+
el.append(text, pie);
|
|
31
|
+
return { el, label, digits, pie };
|
|
32
|
+
}
|
|
33
|
+
/** Mounts the clock in its slot, draws it now, and redraws it every second until `remove()`; `null` where it cannot. */
|
|
34
|
+
export function mountSessionClock(ctx) {
|
|
35
|
+
const { slot, performance: clock, setInterval: every } = ctx;
|
|
36
|
+
if (!slot || typeof slot.appendChild !== 'function' || !clock || typeof every !== 'function')
|
|
37
|
+
return null;
|
|
38
|
+
const { el, label, digits, pie } = build(ctx.doc);
|
|
39
|
+
slot.appendChild(el);
|
|
40
|
+
const timer = clock; // the guard's answer, kept for the tick
|
|
41
|
+
const start = timer.now();
|
|
42
|
+
let look = null;
|
|
43
|
+
function refresh() {
|
|
44
|
+
const reading = readSession(timer.now() - start);
|
|
45
|
+
const next = reading.over ? 'red' : 'running';
|
|
46
|
+
pie.style.setProperty('--left', reading.left.toFixed(4));
|
|
47
|
+
write(label, ctx.t('clock.label'));
|
|
48
|
+
write(digits, clockDigits(reading.leftMs));
|
|
49
|
+
const words = clockWords(reading);
|
|
50
|
+
const name = ctx.t(words.key, { minutes: words.minutes });
|
|
51
|
+
if (el.getAttribute('aria-label') !== name)
|
|
52
|
+
el.setAttribute('aria-label', name);
|
|
53
|
+
if (next !== 'running' && look === 'running')
|
|
54
|
+
ctx.announce(name);
|
|
55
|
+
if (next !== look)
|
|
56
|
+
el.dataset.look = next;
|
|
57
|
+
look = next;
|
|
58
|
+
ctx.drawn();
|
|
59
|
+
}
|
|
60
|
+
refresh();
|
|
61
|
+
const handle = every(refresh, TICK_MS);
|
|
62
|
+
return {
|
|
63
|
+
el,
|
|
64
|
+
refresh,
|
|
65
|
+
remove: () => { ctx.clearInterval?.(handle); el.remove(); },
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Translate } from '../core/i18n.js';
|
|
3
|
+
import type { LetterCase } from '../core/state.js';
|
|
4
|
+
import { type AacSet } from './aac-sets.js';
|
|
5
|
+
import { type ControlRowSpec } from './panel-widgets.js';
|
|
6
|
+
import type { PanelShellCtx } from './panel-shell.js';
|
|
7
|
+
/**
|
|
8
|
+
* The LETTERS row is a SWITCH, not two options (the Dev's decision). On = upper case only; off = upper and lower case.
|
|
9
|
+
* A binary question presented as two rows makes the child compare both to discover they are the same question.
|
|
10
|
+
*/
|
|
11
|
+
export declare function upperCaseOn(letterCase: LetterCase): boolean;
|
|
12
|
+
/** The id of a set's control. It comes from the catalogue `key`, unique by construction (`AAC_BY_KEY`). */
|
|
13
|
+
export declare const aacControlId: (key: string) => string;
|
|
14
|
+
/** The letters switch. Always available: it is the offline floor, and never depended on any file. */
|
|
15
|
+
export declare function lettersRowSpec(t: Translate): ControlRowSpec;
|
|
16
|
+
/**
|
|
17
|
+
* A menu row: a SHORT LABEL and nothing else in view.
|
|
18
|
+
*
|
|
19
|
+
* Everything that explains — note, licence, status — goes into a single `.opt-hint`, which the shell (`fillExplain`)
|
|
20
|
+
* recognises and MOVES to the footer. Prose hung inside the row turns the menu into a manual, closer to a configuration
|
|
21
|
+
* file than to a videogame menu — the Dev saw exactly that.
|
|
22
|
+
*
|
|
23
|
+
* `ariaLabel` carries the reason, so whoever navigates by keyboard hears why the row does not respond without hunting
|
|
24
|
+
* for the footer. `disabled` belongs to the CONTROL and not the text: the status leaves the label, never the button.
|
|
25
|
+
*/
|
|
26
|
+
export declare function aacRowSpec(t: Translate, s: AacSet): ControlRowSpec;
|
|
27
|
+
/**
|
|
28
|
+
* The menu's two sections: what works now (the letters switch), and the pictogram sets, each only with a licence
|
|
29
|
+
* (ADR-0233). Whether a set row is locked is the row's own business (its reason and its `disabled`), so a licence that
|
|
30
|
+
* arrives changes one row, not the sections.
|
|
31
|
+
*
|
|
32
|
+
* 📌 Each produces its own rows instead of filtering the catalogue, because the first does not come from the catalogue
|
|
33
|
+
* — the letters are a switch and not a set, the Dev's decision that took them out of the list. A table whose first row
|
|
34
|
+
* is the exception to all the others lies about what it is.
|
|
35
|
+
*/
|
|
36
|
+
export declare const AAC_SECTIONS: ReadonlyArray<{
|
|
37
|
+
title: string;
|
|
38
|
+
tag: string;
|
|
39
|
+
rows: (t: Translate) => ControlRowSpec[];
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Mounts the menu's inside ONCE. Called again, it RELABELS instead of rebuilding.
|
|
43
|
+
*
|
|
44
|
+
* ⚠️ Relabel and not rebuild, for the reason `labelRow` already states: listeners are wired at boot, and remaking the
|
|
45
|
+
* row would leave a control in the document with no listener — a dead button that looks alive (ADR-0106 §5). And the
|
|
46
|
+
* text may have been captured at boot, while the language was still the fallback.
|
|
47
|
+
*/
|
|
48
|
+
export declare function mountAacInside(t: Translate, ctx: PanelShellCtx, list: HTMLElement): void;
|
|
49
|
+
export interface SettingsAacCtx {
|
|
50
|
+
/** Translates in the page's language — the root's translator (ADR-0232 D3). REQUIRED: text built from nowhere is a raw key. */
|
|
51
|
+
t: Translate;
|
|
52
|
+
$: <T extends Element = Element>(sel: string) => T | null;
|
|
53
|
+
srSay: (msg: string) => void;
|
|
54
|
+
/** Live read of core/state `letterCase` (the binding is reassigned by the setter). */
|
|
55
|
+
getLetterCase: () => LetterCase;
|
|
56
|
+
/** core/state `setLetterCaseValue` PLUS the reflection the game needs (re-rendering its text, labels). */
|
|
57
|
+
setLetterCase: (c: LetterCase) => void;
|
|
58
|
+
frontOverlay: (el: HTMLElement | null) => void;
|
|
59
|
+
/** Moves the rows' prose to the footer (ui/settings-panel `fillExplain`). Called on EVERY render, not only on open:
|
|
60
|
+
* relabelling a row puts the hint back inside it, and without this call the menu turns into a manual again on the
|
|
61
|
+
* first click. */
|
|
62
|
+
fillExplain: (card: HTMLElement | null) => void;
|
|
63
|
+
restoreFocus?: (id: string) => boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface SettingsAacApi {
|
|
66
|
+
render: () => void;
|
|
67
|
+
open: () => void;
|
|
68
|
+
close: () => void;
|
|
69
|
+
}
|
|
70
|
+
export declare function initSettingsAac(ctx: SettingsAacCtx): SettingsAacApi;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import { DEFAULTS } from '../core/setting-defaults.js';
|
|
3
|
+
import { AAC_SETS, AAC_BY_KEY, aacMenuLocked, aacReason, aacSelectable } from './aac-sets.js';
|
|
4
|
+
import { markChanged, markMenuChanged } from './changed-mark.js';
|
|
5
|
+
import { controlRow, labelRow, sectionHeader } from './panel-widgets.js';
|
|
6
|
+
import { toggleLabel } from './dom.js';
|
|
7
|
+
/**
|
|
8
|
+
* The LETTERS row is a SWITCH, not two options (the Dev's decision). On = upper case only; off = upper and lower case.
|
|
9
|
+
* A binary question presented as two rows makes the child compare both to discover they are the same question.
|
|
10
|
+
*/
|
|
11
|
+
export function upperCaseOn(letterCase) {
|
|
12
|
+
return letterCase === 'upper';
|
|
13
|
+
}
|
|
14
|
+
/** The id of a set's control. It comes from the catalogue `key`, unique by construction (`AAC_BY_KEY`). */
|
|
15
|
+
export const aacControlId = (key) => `caa-set-${key}`;
|
|
16
|
+
/** The letters switch. Always available: it is the offline floor, and never depended on any file. */
|
|
17
|
+
export function lettersRowSpec(t) {
|
|
18
|
+
return { id: 'caa-caixa-alta', label: t('aac.letras'), hint: t('aac.letras.dica') };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A menu row: a SHORT LABEL and nothing else in view.
|
|
22
|
+
*
|
|
23
|
+
* Everything that explains — note, licence, status — goes into a single `.opt-hint`, which the shell (`fillExplain`)
|
|
24
|
+
* recognises and MOVES to the footer. Prose hung inside the row turns the menu into a manual, closer to a configuration
|
|
25
|
+
* file than to a videogame menu — the Dev saw exactly that.
|
|
26
|
+
*
|
|
27
|
+
* `ariaLabel` carries the reason, so whoever navigates by keyboard hears why the row does not respond without hunting
|
|
28
|
+
* for the footer. `disabled` belongs to the CONTROL and not the text: the status leaves the label, never the button.
|
|
29
|
+
*/
|
|
30
|
+
export function aacRowSpec(t, s) {
|
|
31
|
+
const reason = aacReason(s);
|
|
32
|
+
const explains = [s.note, s.license ? `Licença: ${s.license}` : '', reason ? t(reason) : '']
|
|
33
|
+
.filter(Boolean).join(' · ');
|
|
34
|
+
return {
|
|
35
|
+
id: aacControlId(s.key),
|
|
36
|
+
label: s.name,
|
|
37
|
+
...(explains ? { hint: explains } : {}),
|
|
38
|
+
ariaLabel: `${s.name}${reason ? ', ' + t(reason) : ''}`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The menu's two sections: what works now (the letters switch), and the pictogram sets, each only with a licence
|
|
43
|
+
* (ADR-0233). Whether a set row is locked is the row's own business (its reason and its `disabled`), so a licence that
|
|
44
|
+
* arrives changes one row, not the sections.
|
|
45
|
+
*
|
|
46
|
+
* 📌 Each produces its own rows instead of filtering the catalogue, because the first does not come from the catalogue
|
|
47
|
+
* — the letters are a switch and not a set, the Dev's decision that took them out of the list. A table whose first row
|
|
48
|
+
* is the exception to all the others lies about what it is.
|
|
49
|
+
*/
|
|
50
|
+
export const AAC_SECTIONS = [
|
|
51
|
+
{ title: 'aac.secao.agora', tag: 'aac.secao.agoraTag', rows: (t) => [lettersRowSpec(t)] },
|
|
52
|
+
{
|
|
53
|
+
title: 'aac.section.pictograms',
|
|
54
|
+
tag: 'aac.section.pictogramsTag',
|
|
55
|
+
rows: (t) => AAC_SETS.map((s) => aacRowSpec(t, s)),
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* Mounts the menu's inside ONCE. Called again, it RELABELS instead of rebuilding.
|
|
60
|
+
*
|
|
61
|
+
* ⚠️ Relabel and not rebuild, for the reason `labelRow` already states: listeners are wired at boot, and remaking the
|
|
62
|
+
* row would leave a control in the document with no listener — a dead button that looks alive (ADR-0106 §5). And the
|
|
63
|
+
* text may have been captured at boot, while the language was still the fallback.
|
|
64
|
+
*/
|
|
65
|
+
export function mountAacInside(t, ctx, list) {
|
|
66
|
+
for (const section of AAC_SECTIONS) {
|
|
67
|
+
const specs = section.rows(t);
|
|
68
|
+
const header = sectionHeader(ctx, t(section.title), t(section.tag), specs.length);
|
|
69
|
+
if (header && !list.querySelector(`[data-caa-section="${section.title}"]`)) {
|
|
70
|
+
header.setAttribute('data-caa-section', section.title);
|
|
71
|
+
list.appendChild(header);
|
|
72
|
+
}
|
|
73
|
+
for (const spec of specs) {
|
|
74
|
+
const old = ctx.find('#' + spec.id)?.closest('.ctrl-row');
|
|
75
|
+
if (old)
|
|
76
|
+
labelRow(old, spec);
|
|
77
|
+
else
|
|
78
|
+
list.appendChild(newRow(ctx, spec));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A new row, with what the kit does not know about this panel: the set's key and the lock.
|
|
84
|
+
*
|
|
85
|
+
* No set is licensed today (ADR-0233). A button that does nothing is worse than absence, because it spends trust — so an
|
|
86
|
+
* unlicensed set comes locked, and the reason is already in `ariaLabel` for whoever navigates by keyboard.
|
|
87
|
+
*/
|
|
88
|
+
function newRow(ctx, spec) {
|
|
89
|
+
const { row: row, control: control } = controlRow(ctx, spec);
|
|
90
|
+
if (spec.id === 'caa-caixa-alta') {
|
|
91
|
+
row.id = 'caa-letras';
|
|
92
|
+
return row;
|
|
93
|
+
}
|
|
94
|
+
const key = spec.id.replace('caa-set-', '');
|
|
95
|
+
control.setAttribute('data-caa', key);
|
|
96
|
+
const set = AAC_BY_KEY[key];
|
|
97
|
+
if (!set || !aacSelectable(set))
|
|
98
|
+
control.setAttribute('disabled', '');
|
|
99
|
+
return row;
|
|
100
|
+
}
|
|
101
|
+
export function initSettingsAac(ctx) {
|
|
102
|
+
const { t } = ctx;
|
|
103
|
+
/*
|
|
104
|
+
* 📌 THE KIT'S CTX COMES FROM THE LIST NODE ITSELF, not from a global `document` nor a new contract field.
|
|
105
|
+
* `ownerDocument` is the document that list LIVES in — exactly the document the rows must be born in —, so this
|
|
106
|
+
* module's global reach stays ZERO (ADR-0221) and `SettingsAacCtx`, which is published surface, gains no required
|
|
107
|
+
* member (ADR-0172).
|
|
108
|
+
*/
|
|
109
|
+
const panelCtx = (list) => ({
|
|
110
|
+
find: (sel) => ctx.$(sel),
|
|
111
|
+
create: (tag) => list.ownerDocument.createElement(tag),
|
|
112
|
+
});
|
|
113
|
+
function reflect() {
|
|
114
|
+
const b = ctx.$('#caa-caixa-alta');
|
|
115
|
+
if (!b)
|
|
116
|
+
return;
|
|
117
|
+
const on = upperCaseOn(ctx.getLetterCase());
|
|
118
|
+
b.classList.toggle('is-on', on);
|
|
119
|
+
b.setAttribute('aria-pressed', String(on));
|
|
120
|
+
// The switch's text is the STATE; its name is in the `<strong>` beside it and in the `aria-label`.
|
|
121
|
+
b.textContent = toggleLabel(t, on);
|
|
122
|
+
}
|
|
123
|
+
function render() {
|
|
124
|
+
const el = ctx.$('#caa-list');
|
|
125
|
+
if (!el)
|
|
126
|
+
return;
|
|
127
|
+
mountAacInside(t, panelCtx(el), el);
|
|
128
|
+
reflect();
|
|
129
|
+
ctx.fillExplain(ctx.$('#caa .overlay__card'));
|
|
130
|
+
refreshMarks();
|
|
131
|
+
}
|
|
132
|
+
/** The left-the-default mark (ADR-0029), on the chosen row and on the menu's button. */
|
|
133
|
+
function refreshMarks() {
|
|
134
|
+
const changed = ctx.getLetterCase() !== DEFAULTS.letterCase;
|
|
135
|
+
markChanged(t, ctx.$('#caa-letras'), changed);
|
|
136
|
+
markMenuChanged(t, ctx.$('[data-act="caa"]'), [changed]);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* THE MENU'S DOOR IS DISABLED while no pictogram set is licensed (ADR-0233 erratum), with the pause card's lock
|
|
140
|
+
* (ADR-0161): `aria-disabled` and the reason in `data-motivo`, which the menu navigation speaks on reach and writes in
|
|
141
|
+
* the footer. The reason is ONLY «menu disabled»: the licence story is not the child's to hear. No unlock branch: the
|
|
142
|
+
* catalogue is static, so a licensed set means the door is never locked in the first place.
|
|
143
|
+
*/
|
|
144
|
+
function lockDoor() {
|
|
145
|
+
const door = ctx.$('[data-act="caa"]');
|
|
146
|
+
if (!door || !aacMenuLocked())
|
|
147
|
+
return;
|
|
148
|
+
door.setAttribute('aria-disabled', 'true');
|
|
149
|
+
door.dataset.motivo = t('pause.motivo.caa');
|
|
150
|
+
}
|
|
151
|
+
function open() {
|
|
152
|
+
// A game that wires its own door to `open` meets the same lock: the reason is said and nothing opens, so no
|
|
153
|
+
// per-set licence row reaches the child.
|
|
154
|
+
if (aacMenuLocked()) {
|
|
155
|
+
lockDoor();
|
|
156
|
+
ctx.srSay(t('pause.motivo.caa'));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const ov = ctx.$('#caa');
|
|
160
|
+
if (!ov)
|
|
161
|
+
return;
|
|
162
|
+
render();
|
|
163
|
+
ov.hidden = false;
|
|
164
|
+
ctx.frontOverlay(ov);
|
|
165
|
+
const f = ov.querySelector('button');
|
|
166
|
+
if (f)
|
|
167
|
+
f.focus();
|
|
168
|
+
}
|
|
169
|
+
function close() {
|
|
170
|
+
const ov = ctx.$('#caa');
|
|
171
|
+
if (!ov)
|
|
172
|
+
return;
|
|
173
|
+
ov.hidden = true;
|
|
174
|
+
ctx.restoreFocus?.('caa');
|
|
175
|
+
}
|
|
176
|
+
/*
|
|
177
|
+
* The listeners are wired ONCE, on the list, by delegation — which mounting once allows. What protects an
|
|
178
|
+
* unavailable set is its own button's `disabled`, written where it is born; a listener that only guards and then does
|
|
179
|
+
* nothing would be inert code dressed as protection.
|
|
180
|
+
*/
|
|
181
|
+
const list = ctx.$('#caa-list');
|
|
182
|
+
if (list)
|
|
183
|
+
list.addEventListener('click', (ev) => {
|
|
184
|
+
const hit = ev.target?.closest('#caa-caixa-alta');
|
|
185
|
+
if (!hit)
|
|
186
|
+
return;
|
|
187
|
+
const turnOn = !upperCaseOn(ctx.getLetterCase());
|
|
188
|
+
ctx.setLetterCase(turnOn ? 'upper' : 'mixed');
|
|
189
|
+
render();
|
|
190
|
+
ctx.srSay(t(turnOn ? 'sr.aac.caixaAltaOn' : 'sr.aac.caixaAltaOff'));
|
|
191
|
+
});
|
|
192
|
+
const closeBtn = ctx.$('#caa-close');
|
|
193
|
+
if (closeBtn)
|
|
194
|
+
closeBtn.addEventListener('click', close);
|
|
195
|
+
lockDoor();
|
|
196
|
+
// ---- reset THIS menu's defaults (ADR-0028) ----
|
|
197
|
+
// The menu has one choice, so the reset is one line — but where it returns to is worth saying: the default case,
|
|
198
|
+
// where Brazilian literacy usually starts. A child who switched the case and can no longer read the screen needs a way
|
|
199
|
+
// back that ends at what their teacher uses.
|
|
200
|
+
const resetBtn = ctx.$('#caa-reset');
|
|
201
|
+
if (resetBtn)
|
|
202
|
+
resetBtn.addEventListener('click', () => {
|
|
203
|
+
ctx.setLetterCase(DEFAULTS.letterCase);
|
|
204
|
+
render();
|
|
205
|
+
ctx.srSay(t('sr.aac.reset'));
|
|
206
|
+
});
|
|
207
|
+
return { render, open, close };
|
|
208
|
+
}
|