@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,201 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// ui/footer-scroll-driver — A FOOTER EXPLANATION LONGER THAN ITS LINES MOVES INSIDE THEM (ADR-0245): the DOM half of
|
|
3
|
+
// `ui/footer-scroll`, which holds the pace.
|
|
4
|
+
//
|
|
5
|
+
// Watches the region for the two explanation footers — the screen's band (`.barra-explicacao`) and a panel's
|
|
6
|
+
// (`.opt-explain`). A NEW text, or a footer that comes into view, starts from the top; a text that fits is measured once and
|
|
7
|
+
// left alone, its DOM untouched. The box does not change: `[data-scroll]` swaps the two-line clamp for a block of the same
|
|
8
|
+
// lines (style.css).
|
|
9
|
+
// · GLIDE: the words rise continuously (ADR-0245 erratum, 2026-09-26 — a line at a time was what the Dev rejected). They are
|
|
10
|
+
// moved into one `.footer-scroll-text` block, and a Web Animation translates it: sub-pixel and on the compositor, where
|
|
11
|
+
// `scrollTop` stands on whole pixels. The text node the game wrote is MOVED, not copied, in the same task as the write and
|
|
12
|
+
// before a frame is drawn, and nothing is written into the live region after — narration and the screen reader still get
|
|
13
|
+
// the whole text once (§4).
|
|
14
|
+
// · PAGES (reduced motion): no slide, so `scrollTop` and a timer per page, as the plan says.
|
|
15
|
+
// Pointer over it or focus in it holds the motion where it is (§3, WCAG 2.2.2): the animation paused, or the page timer
|
|
16
|
+
// cleared. A footer that leaves the screen keeps no animation and no timer.
|
|
17
|
+
//
|
|
18
|
+
// 📌 Everything it reaches arrives through the host (ADR-0232): the document, the timers, the styles and the observer.
|
|
19
|
+
import { footerScrollPlan, readLines } from './footer-scroll.js';
|
|
20
|
+
const FOOTERS = '.barra-explicacao, .opt-explain';
|
|
21
|
+
/** The block the words glide in (style.css makes it a block while the footer scrolls). */
|
|
22
|
+
const TEXT = 'footer-scroll-text';
|
|
23
|
+
/** Starts watching `root`. Returns the way to stop: every animation cancelled and timer cleared, the observer disconnected. */
|
|
24
|
+
export function watchFooterScroll(root, host) {
|
|
25
|
+
const seen = new Map();
|
|
26
|
+
const held = new WeakSet();
|
|
27
|
+
const wired = new WeakSet();
|
|
28
|
+
const visible = (el) => el.isConnected && el.getClientRects().length > 0;
|
|
29
|
+
const linesShown = (el) => parseInt(host.getComputedStyle(el).getPropertyValue('--footer-lines'), 10) || 2;
|
|
30
|
+
function wordTops(el) {
|
|
31
|
+
const tops = [];
|
|
32
|
+
const walker = host.doc.createTreeWalker(el, 4); // NodeFilter.SHOW_TEXT
|
|
33
|
+
const range = host.doc.createRange();
|
|
34
|
+
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
|
|
35
|
+
for (const m of (n.textContent ?? '').matchAll(/\S+/g)) {
|
|
36
|
+
range.setStart(n, m.index);
|
|
37
|
+
range.setEnd(n, m.index + m[0].length);
|
|
38
|
+
const box = range.getClientRects()[0];
|
|
39
|
+
if (box)
|
|
40
|
+
tops.push(box.top);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return tops;
|
|
44
|
+
}
|
|
45
|
+
function forget(el) {
|
|
46
|
+
const s = seen.get(el);
|
|
47
|
+
if (s?.timer != null)
|
|
48
|
+
host.clearTimeout(s.timer);
|
|
49
|
+
if (s?.glide) {
|
|
50
|
+
s.glide.anim.onfinish = null;
|
|
51
|
+
s.glide.anim.cancel();
|
|
52
|
+
}
|
|
53
|
+
seen.delete(el);
|
|
54
|
+
delete el.dataset.scroll;
|
|
55
|
+
delete el.dataset.topLine;
|
|
56
|
+
el.scrollTop = 0;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The words inside the one block that glides, MOVED there (never copied: the game's text node stays the one it wrote). The
|
|
60
|
+
* block a footer already has is kept — a restart, or the same text written again, goes on in it.
|
|
61
|
+
*/
|
|
62
|
+
function gather(el, text) {
|
|
63
|
+
let block = text;
|
|
64
|
+
if (!block) {
|
|
65
|
+
const only = el.childNodes.length === 1 ? el.firstElementChild : null;
|
|
66
|
+
if (only instanceof HTMLElement && only.classList.contains(TEXT))
|
|
67
|
+
return only;
|
|
68
|
+
block = host.doc.createElement('span');
|
|
69
|
+
block.className = TEXT;
|
|
70
|
+
}
|
|
71
|
+
const loose = [...el.childNodes].filter((n) => n !== block);
|
|
72
|
+
if (loose.length)
|
|
73
|
+
block.replaceChildren(...loose);
|
|
74
|
+
if (block.parentNode !== el)
|
|
75
|
+
el.append(block);
|
|
76
|
+
return block;
|
|
77
|
+
}
|
|
78
|
+
/** Paces a footer as it is now: held, it stays where it is; free, it goes on from there. */
|
|
79
|
+
function pace(el, s) {
|
|
80
|
+
if (s.glide) {
|
|
81
|
+
if (held.has(el))
|
|
82
|
+
s.glide.anim.pause();
|
|
83
|
+
else
|
|
84
|
+
s.glide.anim.play();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
arm(el, s);
|
|
88
|
+
}
|
|
89
|
+
function glide(el, s, plan) {
|
|
90
|
+
const text = gather(el);
|
|
91
|
+
const rise = `translateY(${-s.lines.starts[plan.toLine]}px)`;
|
|
92
|
+
const total = plan.waitMs + plan.travelMs + plan.holdMs;
|
|
93
|
+
// still while the first view is read, one speed to the last view, still while it is read
|
|
94
|
+
const anim = text.animate([
|
|
95
|
+
{ transform: 'translateY(0)', offset: 0 },
|
|
96
|
+
{ transform: 'translateY(0)', offset: plan.waitMs / total },
|
|
97
|
+
{ transform: rise, offset: (plan.waitMs + plan.travelMs) / total },
|
|
98
|
+
{ transform: rise, offset: 1 },
|
|
99
|
+
], { duration: total, easing: 'linear' });
|
|
100
|
+
anim.onfinish = () => start(el, true); // the end: again from the top, measured again
|
|
101
|
+
s.glide = { text, anim };
|
|
102
|
+
pace(el, s);
|
|
103
|
+
}
|
|
104
|
+
const pagesOf = (s) => (s.plan?.mode === 'pages' ? s.plan : null);
|
|
105
|
+
function arm(el, s) {
|
|
106
|
+
if (s.timer != null)
|
|
107
|
+
host.clearTimeout(s.timer);
|
|
108
|
+
s.timer = null;
|
|
109
|
+
const pages = pagesOf(s);
|
|
110
|
+
if (!pages || held.has(el))
|
|
111
|
+
return;
|
|
112
|
+
s.timer = host.setTimeout(() => {
|
|
113
|
+
s.timer = null;
|
|
114
|
+
if (s.step + 1 < pages.steps.length)
|
|
115
|
+
show(el, s, pages, s.step + 1);
|
|
116
|
+
else
|
|
117
|
+
start(el, true); // the end: again from the top, measured again
|
|
118
|
+
}, pages.steps[s.step].holdMs);
|
|
119
|
+
}
|
|
120
|
+
function show(el, s, pages, step) {
|
|
121
|
+
s.step = step;
|
|
122
|
+
const line = pages.steps[step].line;
|
|
123
|
+
el.dataset.topLine = String(line);
|
|
124
|
+
el.scrollTop = s.lines.starts[line];
|
|
125
|
+
arm(el, s);
|
|
126
|
+
}
|
|
127
|
+
function wire(el) {
|
|
128
|
+
if (wired.has(el))
|
|
129
|
+
return;
|
|
130
|
+
wired.add(el);
|
|
131
|
+
const hold = () => { held.add(el); const s = seen.get(el); if (s)
|
|
132
|
+
pace(el, s); };
|
|
133
|
+
const release = () => { held.delete(el); const s = seen.get(el); if (s)
|
|
134
|
+
pace(el, s); };
|
|
135
|
+
el.addEventListener('pointerenter', hold);
|
|
136
|
+
el.addEventListener('pointerleave', release);
|
|
137
|
+
el.addEventListener('focusin', hold);
|
|
138
|
+
el.addEventListener('focusout', (e) => { if (!el.contains(e.relatedTarget))
|
|
139
|
+
release(); });
|
|
140
|
+
}
|
|
141
|
+
/** A footer whose text or lines changed, or that came into view: measured, and moved only if it does not fit. */
|
|
142
|
+
function start(el, again = false) {
|
|
143
|
+
const key = `${linesShown(el)}|${el.textContent ?? ''}`;
|
|
144
|
+
const had = seen.get(el);
|
|
145
|
+
if (!again && had?.key === key) {
|
|
146
|
+
// the same text written again is not a new text: it goes on gliding, in the block it was in
|
|
147
|
+
if (had.glide)
|
|
148
|
+
gather(el, had.glide.text);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
forget(el);
|
|
152
|
+
if (!visible(el))
|
|
153
|
+
return;
|
|
154
|
+
el.dataset.scroll = ''; // measured as it will scroll: a block, no clamp
|
|
155
|
+
const lines = readLines(wordTops(el), parseFloat(host.getComputedStyle(el).lineHeight));
|
|
156
|
+
// a page without Web Animations turns pages: the text still passes whole, at the same pace
|
|
157
|
+
const reduced = host.reduced() || typeof el.animate !== 'function';
|
|
158
|
+
const plan = footerScrollPlan(lines.words, linesShown(el), host.ppm(), reduced);
|
|
159
|
+
const s = { key, plan, lines, step: 0, timer: null, glide: null };
|
|
160
|
+
seen.set(el, s);
|
|
161
|
+
if (!plan) {
|
|
162
|
+
delete el.dataset.scroll;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
el.dataset.scroll = plan.mode;
|
|
166
|
+
wire(el);
|
|
167
|
+
if (plan.mode === 'glide')
|
|
168
|
+
glide(el, s, plan);
|
|
169
|
+
else
|
|
170
|
+
show(el, s, plan, 0);
|
|
171
|
+
}
|
|
172
|
+
function footersIn(node, into) {
|
|
173
|
+
const el = node.nodeType === 1 ? node : node.parentElement;
|
|
174
|
+
const own = el?.closest(FOOTERS);
|
|
175
|
+
if (own)
|
|
176
|
+
into.add(own);
|
|
177
|
+
if (node.nodeType === 1)
|
|
178
|
+
el.querySelectorAll(FOOTERS).forEach((f) => into.add(f));
|
|
179
|
+
}
|
|
180
|
+
const observer = new host.MutationObserver((records) => {
|
|
181
|
+
const touched = new Set();
|
|
182
|
+
for (const r of records) {
|
|
183
|
+
footersIn(r.target, touched);
|
|
184
|
+
r.addedNodes.forEach((n) => footersIn(n, touched));
|
|
185
|
+
}
|
|
186
|
+
// a `hidden` changed somewhere: every footer may have come into view, or changed its number of lines
|
|
187
|
+
if (records.some((r) => r.type === 'attributes'))
|
|
188
|
+
footersIn(root, touched);
|
|
189
|
+
for (const el of [...seen.keys()])
|
|
190
|
+
if (!visible(el))
|
|
191
|
+
forget(el);
|
|
192
|
+
touched.forEach((el) => start(el));
|
|
193
|
+
});
|
|
194
|
+
observer.observe(root, { childList: true, characterData: true, subtree: true, attributes: true, attributeFilter: ['hidden'] });
|
|
195
|
+
root.querySelectorAll(FOOTERS).forEach((el) => start(el));
|
|
196
|
+
return () => {
|
|
197
|
+
observer.disconnect();
|
|
198
|
+
for (const el of [...seen.keys()])
|
|
199
|
+
forget(el);
|
|
200
|
+
};
|
|
201
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/** One page: the first line on show, and how long it stays before the next. */
|
|
3
|
+
export interface FooterScrollStep {
|
|
4
|
+
readonly line: number;
|
|
5
|
+
readonly holdMs: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Rises continuously: still for `waitMs`, then up at one speed for `travelMs` until `toLine` tops the view (the last view),
|
|
9
|
+
* held there `holdMs`.
|
|
10
|
+
*/
|
|
11
|
+
export interface FooterGlidePlan {
|
|
12
|
+
readonly mode: 'glide';
|
|
13
|
+
readonly waitMs: number;
|
|
14
|
+
readonly travelMs: number;
|
|
15
|
+
readonly holdMs: number;
|
|
16
|
+
readonly toLine: number;
|
|
17
|
+
}
|
|
18
|
+
/** Turns a whole view at a time, without sliding (reduced motion). */
|
|
19
|
+
export interface FooterPagesPlan {
|
|
20
|
+
readonly mode: 'pages';
|
|
21
|
+
readonly steps: readonly FooterScrollStep[];
|
|
22
|
+
}
|
|
23
|
+
export type FooterScrollPlan = FooterGlidePlan | FooterPagesPlan;
|
|
24
|
+
/** The rendered lines: how many words each holds, and where each starts, from the top of the first. */
|
|
25
|
+
export interface FooterLines {
|
|
26
|
+
readonly words: readonly number[];
|
|
27
|
+
readonly starts: readonly number[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The lines, from the TOP of each word as laid out. A word lower than the line's top by more than half a line opens a new one;
|
|
31
|
+
* a word broken across two lines counts where it starts.
|
|
32
|
+
*/
|
|
33
|
+
export declare function readLines(wordTops: readonly number[], lineHeight: number): FooterLines;
|
|
34
|
+
/**
|
|
35
|
+
* The plan for a text of `wordsPerLine.length` lines shown `shown` at a time, or `null` when it fits — a text that fits never
|
|
36
|
+
* moves. The rate is one of the three the child can choose; any other number reads as the slowest (`isCaptionRate`).
|
|
37
|
+
*/
|
|
38
|
+
export declare function footerScrollPlan(wordsPerLine: readonly number[], shown: number, ppm: number, reduced: boolean): FooterScrollPlan | null;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// ui/footer-scroll — WHEN A LONG FOOTER EXPLANATION MOVES, AND FOR HOW LONG (ADR-0245).
|
|
3
|
+
//
|
|
4
|
+
// The footer shows its lines (two; one while the button legend shares the column, ADR-0164). A text that needs more moves
|
|
5
|
+
// INSIDE them, at the child's caption rate — the arithmetic of `core/caption-duration`, 60000 / ppm ms a word:
|
|
6
|
+
// · GLIDE (ADR-0245 erratum, 2026-09-26: «suave e contínua, lentamente»): it waits for the first view to be read, then rises
|
|
7
|
+
// at ONE constant speed until its last line is in view — the distance passes in the time the words below the first view
|
|
8
|
+
// take, so the last line arrives when every word has been read —, holds the last view for its words, and the caller starts
|
|
9
|
+
// again from the top;
|
|
10
|
+
// · PAGES, with reduced motion: no slide — a whole view at a time, each page held for the words it brings.
|
|
11
|
+
//
|
|
12
|
+
// 📌 PURE: word positions and numbers in, a plan out. The DOM half (`ui/footer-scroll-driver`) measures and moves.
|
|
13
|
+
import { isCaptionRate } from '../core/caption-duration.js';
|
|
14
|
+
/**
|
|
15
|
+
* The lines, from the TOP of each word as laid out. A word lower than the line's top by more than half a line opens a new one;
|
|
16
|
+
* a word broken across two lines counts where it starts.
|
|
17
|
+
*/
|
|
18
|
+
export function readLines(wordTops, lineHeight) {
|
|
19
|
+
const words = [];
|
|
20
|
+
const starts = [];
|
|
21
|
+
let top = -Infinity;
|
|
22
|
+
for (const t of wordTops) {
|
|
23
|
+
if (t > top + lineHeight / 2) {
|
|
24
|
+
top = t;
|
|
25
|
+
words.push(0);
|
|
26
|
+
starts.push(t - (wordTops[0] ?? 0));
|
|
27
|
+
}
|
|
28
|
+
words[words.length - 1] += 1;
|
|
29
|
+
}
|
|
30
|
+
return { words, starts };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The plan for a text of `wordsPerLine.length` lines shown `shown` at a time, or `null` when it fits — a text that fits never
|
|
34
|
+
* moves. The rate is one of the three the child can choose; any other number reads as the slowest (`isCaptionRate`).
|
|
35
|
+
*/
|
|
36
|
+
export function footerScrollPlan(wordsPerLine, shown, ppm, reduced) {
|
|
37
|
+
const last = wordsPerLine.length - shown; // the first line of the last view
|
|
38
|
+
if (shown < 1 || last <= 0)
|
|
39
|
+
return null;
|
|
40
|
+
const msPerWord = 60_000 / isCaptionRate(ppm);
|
|
41
|
+
const read = (from, to) => Math.round(wordsPerLine.slice(from, to).reduce((a, b) => a + b, 0) * msPerWord);
|
|
42
|
+
// the last view is held as long as its lines take to read
|
|
43
|
+
const endHold = read(last, last + shown);
|
|
44
|
+
if (!reduced) {
|
|
45
|
+
return { mode: 'glide', waitMs: read(0, shown), travelMs: read(shown, wordsPerLine.length), holdMs: endHold, toLine: last };
|
|
46
|
+
}
|
|
47
|
+
const steps = [{ line: 0, holdMs: read(0, shown) }];
|
|
48
|
+
for (let line = shown; steps[steps.length - 1].line < last; line += shown) {
|
|
49
|
+
const top = Math.min(line, last);
|
|
50
|
+
const before = steps[steps.length - 1].line;
|
|
51
|
+
// every other page, as long as the lines it brought
|
|
52
|
+
steps.push({ line: top, holdMs: top === last ? endHold : read(before + shown, top + shown) });
|
|
53
|
+
}
|
|
54
|
+
return { mode: 'pages', steps };
|
|
55
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Translate } from '../core/i18n.js';
|
|
3
|
+
import type { PanelShellCtx } from './panel-shell.js';
|
|
4
|
+
/** One position of a steps or list row: the value the cartridge reads and writes, and the key of its label. */
|
|
5
|
+
export interface GameOptionValue {
|
|
6
|
+
readonly value: string;
|
|
7
|
+
readonly labelKey: string;
|
|
8
|
+
}
|
|
9
|
+
interface GameOptionBase {
|
|
10
|
+
/** Stable and unique among the game's rows; the control is `#game-option-<id>`. */
|
|
11
|
+
readonly id: string;
|
|
12
|
+
/** The key of the row's short name, in the game's dictionary. */
|
|
13
|
+
readonly labelKey: string;
|
|
14
|
+
/** The key of the explanation, shown in the footer (CLAUDE.md §4). */
|
|
15
|
+
readonly hintKey?: string;
|
|
16
|
+
}
|
|
17
|
+
export type GameOption = (GameOptionBase & {
|
|
18
|
+
/**
|
|
19
|
+
* An exclusive choice. The engine draws it by its SIZE (ADR-0130 rule 3): five positions or fewer are one row «◀ Label:
|
|
20
|
+
* value ▶», more a dropdown — whichever kind is declared. `steps` still refuses more than five, since the game asked for a cycle.
|
|
21
|
+
*/
|
|
22
|
+
readonly kind: 'steps' | 'list';
|
|
23
|
+
readonly values: readonly GameOptionValue[];
|
|
24
|
+
/** The value in use. Read at every opening and after every write: what shows is what the cartridge keeps. */
|
|
25
|
+
readonly read: () => string;
|
|
26
|
+
readonly write: (value: string) => void;
|
|
27
|
+
}) | (GameOptionBase & {
|
|
28
|
+
readonly kind: 'switch';
|
|
29
|
+
readonly read: () => boolean;
|
|
30
|
+
readonly write: (on: boolean) => void;
|
|
31
|
+
});
|
|
32
|
+
/** Why a `gameOptions` declaration is malformed; empty when it is well formed. Absent is well formed: no options of its own. */
|
|
33
|
+
export declare function gameOptionsProblems(options: unknown): string[];
|
|
34
|
+
export interface GameOptionsDrawCtx extends PanelShellCtx {
|
|
35
|
+
/** Translates the engine's own words in the page's language — the root's translator (ADR-0232 D3). */
|
|
36
|
+
t: Translate;
|
|
37
|
+
/** Resolves a key the GAME declared, in the page's language; `null` when its dictionaries lack it (`Translator.word`). */
|
|
38
|
+
readonly word: (key: string) => string | null;
|
|
39
|
+
/** Where a change is said (the polite live region). */
|
|
40
|
+
readonly say: (text: string) => void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Draws the rows into `list`, replacing what was there — the rows are the CURRENT cartridge's, and `mount()` may have
|
|
44
|
+
* swapped it (ADR-0142). Every value shown is READ from the cartridge, and every word RESOLVED, at drawing and after each write.
|
|
45
|
+
*/
|
|
46
|
+
export declare function drawGameOptions(ctx: GameOptionsDrawCtx, list: HTMLElement, options: readonly GameOption[]): void;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import { controlRow, mountSteps, updateSteps, nextStep, MAX_CYCLE_POSITIONS } from './panel-widgets.js';
|
|
3
|
+
import { toggleLabel } from './dom.js';
|
|
4
|
+
const KINDS = ['steps', 'list', 'switch'];
|
|
5
|
+
/** Why a `gameOptions` declaration is malformed; empty when it is well formed. Absent is well formed: no options of its own. */
|
|
6
|
+
export function gameOptionsProblems(options) {
|
|
7
|
+
if (options === undefined)
|
|
8
|
+
return [];
|
|
9
|
+
if (!Array.isArray(options))
|
|
10
|
+
return ['gameOptions must be a list of rows'];
|
|
11
|
+
// a repeated id is only wrong the second time, so the ids seen so far travel from row to row
|
|
12
|
+
const ids = new Set();
|
|
13
|
+
return options.flatMap((o, i) => rowProblems(o, `gameOptions[${i}]`, ids));
|
|
14
|
+
}
|
|
15
|
+
/** What is wrong with one row, in the order a reader of the declaration meets it: the row, its id, its fields, its positions. */
|
|
16
|
+
function rowProblems(o, at, ids) {
|
|
17
|
+
if (!o || typeof o !== 'object')
|
|
18
|
+
return [`${at} must be a row`];
|
|
19
|
+
const out = [...idProblems(o, at, ids), ...FIELD_CHECKS.filter(([holds]) => !holds(o)).map(([, says]) => `${at}.${says}`)];
|
|
20
|
+
if (o.kind === 'steps' || o.kind === 'list')
|
|
21
|
+
out.push(...valuesProblems(o, at));
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
function idProblems(o, at, ids) {
|
|
25
|
+
if (typeof o.id !== 'string' || !o.id.trim())
|
|
26
|
+
return [`${at}.id must name the row`];
|
|
27
|
+
if (ids.has(o.id))
|
|
28
|
+
return [`${at}.id «${o.id}» repeats an earlier row's`];
|
|
29
|
+
ids.add(o.id);
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
/** A key: text that is not blank. */
|
|
33
|
+
const isKey = (k) => typeof k === 'string' && !!k.trim();
|
|
34
|
+
/** Each field a row must have, and what is said when it does not: a row comes from outside the engine, so its TYPE is checked. */
|
|
35
|
+
const FIELD_CHECKS = [
|
|
36
|
+
[(o) => KINDS.includes(o.kind), `kind must be one of ${KINDS.join(', ')}`],
|
|
37
|
+
[(o) => isKey(o.labelKey), "labelKey must name the row by a key of the game's dictionary"],
|
|
38
|
+
[(o) => o.hintKey === undefined || isKey(o.hintKey), "hintKey must be a key of the game's dictionary"],
|
|
39
|
+
[(o) => typeof o.read === 'function', 'read must be a function returning the value in use'],
|
|
40
|
+
[(o) => typeof o.write === 'function', 'write must be a function taking the new value'],
|
|
41
|
+
];
|
|
42
|
+
/** The positions of a steps or list row: at least two, at most five for steps, each with a value and a label key, none repeated. */
|
|
43
|
+
function valuesProblems(o, at) {
|
|
44
|
+
const values = o.values;
|
|
45
|
+
if (!Array.isArray(values) || values.length < 2)
|
|
46
|
+
return [`${at}.values must hold at least two positions`];
|
|
47
|
+
const out = o.kind === 'steps' && values.length > MAX_CYCLE_POSITIONS
|
|
48
|
+
? [`${at}.values holds ${values.length} steps: steps hold at most five positions — past that, declare a list (ADR-0130)`] : [];
|
|
49
|
+
const seen = new Set();
|
|
50
|
+
values.forEach((v, j) => {
|
|
51
|
+
const problem = positionProblem(v, `${at}.values[${j}]`, seen);
|
|
52
|
+
if (problem)
|
|
53
|
+
out.push(problem);
|
|
54
|
+
});
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
function positionProblem(v, at, seen) {
|
|
58
|
+
if (!v || typeof v.value !== 'string' || !isKey(v.labelKey))
|
|
59
|
+
return `${at} must have a value and a labelKey`;
|
|
60
|
+
if (seen.has(v.value))
|
|
61
|
+
return `${at} «${v.value}» repeats an earlier position`;
|
|
62
|
+
seen.add(v.value);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function rowWords(o, word) {
|
|
66
|
+
const label = word(o.labelKey);
|
|
67
|
+
if (!label)
|
|
68
|
+
return null;
|
|
69
|
+
const hint = o.hintKey ? word(o.hintKey) : null;
|
|
70
|
+
const values = new Map();
|
|
71
|
+
if (o.kind !== 'switch') {
|
|
72
|
+
for (const v of o.values) {
|
|
73
|
+
const positionLabel = word(v.labelKey);
|
|
74
|
+
if (!positionLabel)
|
|
75
|
+
return null;
|
|
76
|
+
values.set(v.value, positionLabel);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { label, ...(hint ? { hint } : {}), values };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Draws the rows into `list`, replacing what was there — the rows are the CURRENT cartridge's, and `mount()` may have
|
|
83
|
+
* swapped it (ADR-0142). Every value shown is READ from the cartridge, and every word RESOLVED, at drawing and after each write.
|
|
84
|
+
*/
|
|
85
|
+
export function drawGameOptions(ctx, list, options) {
|
|
86
|
+
const { t } = ctx;
|
|
87
|
+
while (list.firstChild)
|
|
88
|
+
list.removeChild(list.firstChild); // node by node: no markup sink, and a host without `replaceChildren` still clears
|
|
89
|
+
for (const o of options) {
|
|
90
|
+
const words = rowWords(o, ctx.word);
|
|
91
|
+
if (!words)
|
|
92
|
+
continue;
|
|
93
|
+
const id = `game-option-${o.id}`;
|
|
94
|
+
if (o.kind === 'switch') {
|
|
95
|
+
const { row: rowNode, control: switchButton } = controlRow(ctx, { id, label: words.label, hint: words.hint });
|
|
96
|
+
const reflect = () => {
|
|
97
|
+
const on = o.read();
|
|
98
|
+
switchButton.classList.toggle('is-on', on);
|
|
99
|
+
switchButton.setAttribute('aria-pressed', String(on));
|
|
100
|
+
switchButton.textContent = toggleLabel(t, on);
|
|
101
|
+
return on;
|
|
102
|
+
};
|
|
103
|
+
reflect();
|
|
104
|
+
switchButton.addEventListener('click', () => {
|
|
105
|
+
o.write(!o.read());
|
|
106
|
+
ctx.say(`${words.label}: ${toggleLabel(t, reflect())}`);
|
|
107
|
+
});
|
|
108
|
+
list.appendChild(rowNode);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const labelOf = (chosen) => words.values.get(chosen) ?? '';
|
|
112
|
+
// ⚠️ BY SIZE, NOT BY KIND (ADR-0130 rule 3): a `list` of five or fewer is a cycle row like `steps`, below
|
|
113
|
+
if (o.values.length > MAX_CYCLE_POSITIONS) {
|
|
114
|
+
const { row: rowNode, control: control } = controlRow(ctx, { id, label: words.label, hint: words.hint, shape: 'escolha' });
|
|
115
|
+
const sel = control;
|
|
116
|
+
for (const v of o.values) {
|
|
117
|
+
const op = ctx.create('option');
|
|
118
|
+
op.value = v.value;
|
|
119
|
+
op.textContent = labelOf(v.value);
|
|
120
|
+
sel.appendChild(op);
|
|
121
|
+
}
|
|
122
|
+
sel.value = o.read();
|
|
123
|
+
sel.addEventListener('change', () => {
|
|
124
|
+
o.write(sel.value);
|
|
125
|
+
sel.value = o.read();
|
|
126
|
+
ctx.say(`${words.label}: ${labelOf(sel.value)}`);
|
|
127
|
+
});
|
|
128
|
+
list.appendChild(rowNode);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// steps: the row IS the control, «◀ Label: value ▶» (ADR-0130 erratum); the hint rides in the row for the footer
|
|
132
|
+
const selectedIndex = () => Math.max(0, o.values.findIndex((v) => v.value === o.read()));
|
|
133
|
+
const spec = () => ({ label: words.label, values: o.values.map((v) => labelOf(v.value)), current: selectedIndex() });
|
|
134
|
+
const rowNode = ctx.create('div');
|
|
135
|
+
rowNode.className = 'ctrl-row ctrl-row--passos';
|
|
136
|
+
const envelope = ctx.create('span');
|
|
137
|
+
if (words.hint) {
|
|
138
|
+
const explanation = ctx.create('span');
|
|
139
|
+
explanation.className = 'opt-hint';
|
|
140
|
+
explanation.textContent = words.hint;
|
|
141
|
+
envelope.appendChild(explanation);
|
|
142
|
+
}
|
|
143
|
+
rowNode.appendChild(envelope);
|
|
144
|
+
const stepper = mountSteps(ctx, spec());
|
|
145
|
+
stepper.id = id;
|
|
146
|
+
rowNode.appendChild(stepper);
|
|
147
|
+
stepper.addEventListener('passo', (ev) => {
|
|
148
|
+
const currentIndex = selectedIndex();
|
|
149
|
+
const nextIndex = nextStep(currentIndex, o.values.length, ev.detail);
|
|
150
|
+
if (nextIndex === currentIndex)
|
|
151
|
+
return; // at the wall nothing moved, and nothing is said
|
|
152
|
+
o.write(o.values[nextIndex].value);
|
|
153
|
+
updateSteps(stepper, spec());
|
|
154
|
+
ctx.say(`${words.label}: ${labelOf(o.read())}`);
|
|
155
|
+
});
|
|
156
|
+
list.appendChild(rowNode);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Translate } from '../core/i18n.js';
|
|
3
|
+
import type { GazeZone } from '../input/gaze-relative.js';
|
|
4
|
+
import { type GazePreview } from '../input/gaze-cycle.js';
|
|
5
|
+
import type { EyeLines } from '../platform/vision.js';
|
|
6
|
+
export type GazeRegion = GazeZone | 'middle';
|
|
7
|
+
/** Centre x, centre y, width, height — fractions of the game region. */
|
|
8
|
+
export declare const GAZE_REGIONS: {
|
|
9
|
+
readonly [R in GazeRegion]: readonly [number, number, number, number];
|
|
10
|
+
};
|
|
11
|
+
export type ButtonShape = 'triangle' | 'circle' | 'cross' | 'square';
|
|
12
|
+
/** Each zone's face button: the Xbox letter and the PlayStation shape of the button on that side (ADR-0213 erratum: north is «Y»). */
|
|
13
|
+
export declare const FACE_BUTTON: {
|
|
14
|
+
readonly [Z in GazeZone]: readonly [string, ButtonShape];
|
|
15
|
+
};
|
|
16
|
+
export declare const SHOULDER: {
|
|
17
|
+
readonly [Z in GazeZone]: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Lucide `arrow-up`, `arrow-right`, `arrow-down`, `arrow-left`, 24×24 path data. Lucide's LICENSE lists these four as derived from Feather,
|
|
21
|
+
* so the notice they carry is Feather's MIT (Cole Bemis), not Lucide's ISC — credited in docs/CREDITS.md.
|
|
22
|
+
*/
|
|
23
|
+
export declare const LUCIDE_ARROWS: {
|
|
24
|
+
readonly [Z in GazeZone]: readonly string[];
|
|
25
|
+
};
|
|
26
|
+
export interface GazeView {
|
|
27
|
+
readonly zone: GazeZone | null;
|
|
28
|
+
readonly armed: boolean;
|
|
29
|
+
readonly preparing: boolean;
|
|
30
|
+
readonly preview: GazePreview | null;
|
|
31
|
+
readonly restReady: boolean;
|
|
32
|
+
/** While the rest is being measured: how long it still needs. */
|
|
33
|
+
readonly restLeftMs?: number;
|
|
34
|
+
}
|
|
35
|
+
export type RegionShows = {
|
|
36
|
+
readonly kind: 'nothing';
|
|
37
|
+
} | {
|
|
38
|
+
readonly kind: 'text';
|
|
39
|
+
readonly key: string;
|
|
40
|
+
} | {
|
|
41
|
+
readonly kind: 'arrow';
|
|
42
|
+
} | {
|
|
43
|
+
readonly kind: 'button';
|
|
44
|
+
} | {
|
|
45
|
+
readonly kind: 'shoulder';
|
|
46
|
+
readonly label: string;
|
|
47
|
+
};
|
|
48
|
+
export declare function whatRegionShows(region: GazeRegion, v: GazeView): RegionShows;
|
|
49
|
+
/** 16 px on a 720×360 game region, in proportion to it, bounded by the tighter side. */
|
|
50
|
+
export declare const gazeFontPx: (width: number, height: number) => number;
|
|
51
|
+
type Ctx = CanvasRenderingContext2D;
|
|
52
|
+
export interface GazeOverlayOptions {
|
|
53
|
+
/** The face of this frame, to highlight the eyes and brows. */
|
|
54
|
+
readonly face?: {
|
|
55
|
+
readonly landmarks: ReadonlyArray<{
|
|
56
|
+
readonly x: number;
|
|
57
|
+
readonly y: number;
|
|
58
|
+
}>;
|
|
59
|
+
readonly lines: EyeLines;
|
|
60
|
+
} | null;
|
|
61
|
+
}
|
|
62
|
+
/** Draws the five regions and the face's lines. is the root's translator (ADR-0232 D3): the regions' words are its keys. */
|
|
63
|
+
export declare function drawGazeOverlay(t: Translate, ctx: Ctx, width: number, height: number, view: GazeView, { face }?: GazeOverlayOptions): void;
|
|
64
|
+
export {};
|