@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
package/dist-pkg/input/touch.js
CHANGED
|
@@ -1,46 +1,49 @@
|
|
|
1
1
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
2
|
// input/touch.ts — on-screen touch controls (Estágio 4): the physical geometry of the touch pad (mm→px) and
|
|
3
|
-
// its config UI (#touchcfg, #touch-controls visibility). Extracted from
|
|
3
|
+
// its config UI (#touchcfg, #touch-controls visibility). Extracted from the monolith's E13 block. Geometry/layout/
|
|
4
4
|
// touch-map-merge are pure (padPxPerMm/padHandTag/computePadPhysicalPx/padLayoutFromId/normalizeTouchMap —
|
|
5
5
|
// project node); DOM wiring + persisted state (touchMap/padDesign/padBtnMm/padGapMm/padStickMm/padTravelMm/
|
|
6
6
|
// padDpadMm/padDir) live behind initTouch(ctx). PAD_DESIGNS/TOUCH_ACT_LABELS/TOUCH_DEFAULT come from
|
|
7
7
|
// ./devices.js (not reimplemented). Reading the real Gamepad API (polling, mapping wizard) is input/gamepad's
|
|
8
|
-
// territory, not this module's
|
|
8
|
+
// territory, not this module's.
|
|
9
9
|
import { PAD_DESIGNS, TOUCH_DEFAULT } from './devices.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
//
|
|
15
|
-
// Alvo físico ancorado no iPhone 16 a tela cheia (aresta longa 141,1mm do display 1179×2556 @460ppi →
|
|
16
|
-
// ~6,04 px CSS/mm). Ver o comentário original em game.js para a justificativa completa (WCAG 2.5.5 / GAG).
|
|
10
|
+
import { migrateTouchMap } from './vocabulary-migration.js';
|
|
11
|
+
import { KEYS } from '../platform/storage-keys.js'; // the names only — reading and writing go through ctx.store (ADR-0232)
|
|
12
|
+
// ===================== PURE (no DOM/store — node project) =====================
|
|
13
|
+
// Physical target anchored on a full-screen iPhone 16 (the long edge of the 1179×2556 @460ppi display is 141.1 mm →
|
|
14
|
+
// ~6.04 CSS px/mm) — see `padPxPerMm` for what this estimate is and is not (WCAG 2.5.5 / GAG).
|
|
17
15
|
export const IPHONE16_LONG_MM = 141.1;
|
|
18
16
|
export const IPHONE16_LONG_PX = 852;
|
|
19
|
-
export const IPHONE16_PXMM = IPHONE16_LONG_PX / IPHONE16_LONG_MM; // ~6
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
17
|
+
export const IPHONE16_PXMM = IPHONE16_LONG_PX / IPHONE16_LONG_MM; // ~6.04 CSS px/mm
|
|
18
|
+
/**
|
|
19
|
+
* CSS px per ASSUMED millimetre — an estimate anchored on one phone, NOT a measurement of the device (plan phase 5b).
|
|
20
|
+
* On a mobile, the window's long edge is taken to be an iPhone 16's display (141.1 mm), whatever the device: a 10-inch
|
|
21
|
+
* tablet window of 1280×800 is read as 141.1 mm long, about 9.07 px/mm, where its glass is about 216 mm. On a desktop it is
|
|
22
|
+
* the iPhone 16 ratio, fixed (it does not grow with the monitor). The browser exposes no physical size, so a «real
|
|
23
|
+
* millimetre» is not reachable from here; targets that must meet a floor use the engine's `--alvo-min` (ADR-0163).
|
|
24
|
+
* Pure: `mobile`/`viewW`/`viewH` arrive resolved (isMobile()/innerWidth/innerHeight stay on the impure side).
|
|
25
|
+
*/
|
|
23
26
|
export function padPxPerMm(mobile, viewW, viewH) {
|
|
24
27
|
return mobile ? Math.max(viewW, viewH) / IPHONE16_LONG_MM : IPHONE16_PXMM;
|
|
25
28
|
}
|
|
26
|
-
/**
|
|
27
|
-
*
|
|
29
|
+
/** Sorts a value in mm into the child's-hand / in-between / adult's-hand band (used by the touch settings panel's
|
|
30
|
+
* tags). */
|
|
28
31
|
export function padHandTag(v, lo, hi) {
|
|
29
32
|
return v <= lo ? 'crianca' : v >= hi ? 'adulto' : 'inter';
|
|
30
33
|
}
|
|
31
|
-
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
+
/** All the geometry in px from the configured mm + the px/mm factor — kept pure so it is testable (high/low dpr, small
|
|
35
|
+
* screen, extreme values). applyPadPhysical() only calls this and writes the result into CSS custom properties + the
|
|
36
|
+
* panel's labels. */
|
|
34
37
|
export function computePadPhysicalPx(mm, pxPerMm) {
|
|
35
38
|
const btnPx = mm.btn * pxPerMm, gapPx = mm.gap * pxPerMm;
|
|
36
|
-
const diamPx = btnPx + Math.SQRT2 * (btnPx + gapPx); //
|
|
39
|
+
const diamPx = btnPx + Math.SQRT2 * (btnPx + gapPx); // diamond: edge clearance = gap
|
|
37
40
|
const knobPx = mm.stick * pxPerMm, travelPx = mm.travel * pxPerMm;
|
|
38
|
-
const basePx = knobPx + 2 * travelPx + 16; // base
|
|
39
|
-
const armPx = mm.dpad * pxPerMm, armWPx = armPx * 0.8, spanPx = 2 * armPx + armWPx; //
|
|
40
|
-
const stickTravelPx = travelPx, stickDeadPx = Math.max(6, travelPx * 0.4); //
|
|
41
|
+
const basePx = knobPx + 2 * travelPx + 16; // stick base = contact + travel
|
|
42
|
+
const armPx = mm.dpad * pxPerMm, armWPx = armPx * 0.8, spanPx = 2 * armPx + armWPx; // cross: arm + width (0.8×)
|
|
43
|
+
const stickTravelPx = travelPx, stickDeadPx = Math.max(6, travelPx * 0.4); // dead zone ~40% of the travel
|
|
41
44
|
return { btnPx, diamPx, knobPx, basePx, armPx, armWPx, spanPx, stickTravelPx, stickDeadPx };
|
|
42
45
|
}
|
|
43
|
-
/**
|
|
46
|
+
/** The button-labelling layout from the controller's reported id (a substring/VID heuristic). */
|
|
44
47
|
export function padLayoutFromId(id) {
|
|
45
48
|
const s = (id || '').toLowerCase();
|
|
46
49
|
if (/dualshock|dualsense|playstation|054c/.test(s))
|
|
@@ -51,54 +54,50 @@ export function padLayoutFromId(id) {
|
|
|
51
54
|
return 'microsoft';
|
|
52
55
|
return 'generic';
|
|
53
56
|
}
|
|
54
|
-
/**
|
|
55
|
-
// `lbl`
|
|
56
|
-
//
|
|
57
|
-
//
|
|
57
|
+
/** The 13 remappable touch slots (d-pad×4, START, buttons 0–3, the four shoulders) — `lbl` is the label's i18n key. */
|
|
58
|
+
// `lbl` keeps the i18n KEY, not the text: a module table resolved on import would freeze the language at boot (see the
|
|
59
|
+
// note in input/devices). The arrow and the button's name travel INSIDE the translation, because in English the
|
|
60
|
+
// direction word changes and the arrow stays where it is — it is the whole frame, not interpolated content.
|
|
58
61
|
export const TOUCH_SLOTS = [
|
|
59
62
|
{ k: 'up', lbl: 'touch.slot.up' }, { k: 'down', lbl: 'touch.slot.down' },
|
|
60
63
|
{ k: 'left', lbl: 'touch.slot.left' }, { k: 'right', lbl: 'touch.slot.right' },
|
|
61
64
|
{ k: 'start', lbl: 'touch.slot.start' },
|
|
62
65
|
{ k: 'b0', lbl: 'touch.slot.b0' }, { k: 'b1', lbl: 'touch.slot.b1' },
|
|
63
66
|
{ k: 'b2', lbl: 'touch.slot.b2' }, { k: 'b3', lbl: 'touch.slot.b3' },
|
|
67
|
+
{ k: 'bl2', lbl: 'touch.slot.bl2' }, { k: 'bl1', lbl: 'touch.slot.bl1' },
|
|
68
|
+
{ k: 'br2', lbl: 'touch.slot.br2' }, { k: 'br1', lbl: 'touch.slot.br1' },
|
|
64
69
|
];
|
|
65
70
|
/**
|
|
66
|
-
*
|
|
71
|
+
* The actions the touch TRANSPORT can carry.
|
|
67
72
|
*
|
|
68
|
-
* ⚠️
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* As duas coisas eram a mesma por acidente enquanto só havia um jogo.
|
|
73
|
+
* ⚠️ IT IS NOT THE `<select>`'S LIST: the options come from `ctx.gameActions()`, because the game decides which actions
|
|
74
|
+
* exist. This list is what THIS transport reaches — and it is against it that `input/touch-bindings`' gate checks the
|
|
75
|
+
* dispatch recognises everything that can be offered. The two were the same by accident while there was one game.
|
|
72
76
|
*/
|
|
73
|
-
export const TOUCH_ACTS = ['left', 'right', 'up', 'down', 'action2', 'action1', 'action3', 'action4', 'start'
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
*
|
|
77
|
+
export const TOUCH_ACTS = ['left', 'right', 'up', 'down', 'action2', 'action1', 'action3', 'action4', 'start',
|
|
78
|
+
'leftShoulder', 'leftTrigger', 'rightShoulder', 'rightTrigger'];
|
|
79
|
+
/** Merges the persisted map (loose JSON from localStorage) over TOUCH_DEFAULT. It does NOT validate keys/values
|
|
80
|
+
* against TOUCH_SLOTS/TOUCH_ACTS — malformed JSON with strange keys/values passes as it is (it only fails if it is not
|
|
81
|
+
* an object). */
|
|
77
82
|
export function normalizeTouchMap(stored) {
|
|
78
|
-
// ⚠️
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
const
|
|
83
|
-
return Object.assign({}, TOUCH_DEFAULT,
|
|
84
|
-
}
|
|
85
|
-
/** UNUSED hoje — grep em game.js (`\bpadKind\b`) só acha a própria definição, nenhum chamador. Extraído porque
|
|
86
|
-
* a fronteira explicitamente listou; NÃO apagado (relatado, não conserto). Lê navigator.getGamepads() direto,
|
|
87
|
-
* no mesmo padrão de ui/settings-audio.ts / core/i18n.ts (acesso direto a navigator, sem DI) — mesmo assim,
|
|
88
|
-
* é semanticamente "ler o controle", território do agente de input/gamepad; ver a nota de fronteira no retorno. */
|
|
89
|
-
export function padKind() {
|
|
90
|
-
let kind = 'kb';
|
|
91
|
-
const pads = navigator.getGamepads ? navigator.getGamepads() : [];
|
|
92
|
-
for (const gp of pads) {
|
|
93
|
-
if (!gp)
|
|
94
|
-
continue;
|
|
95
|
-
kind = gp.mapping === 'standard' ? 'x' : 'd';
|
|
96
|
-
if (kind === 'x')
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
return kind;
|
|
83
|
+
// ⚠️ WHAT IS STORED GOES THROUGH THE TRANSLATOR BEFORE THE MERGE, and the order is what matters: `Object.assign`
|
|
84
|
+
// lets the stored map WIN over the default, so a `b0: 'jump'` from before ADR-0086 would overwrite the correct
|
|
85
|
+
// `b0: 'action2'` and the on-screen button would stop doing anything — with no error at all. Here the action name
|
|
86
|
+
// is in the VALUE, not the key, which is why it needs its own translator. See `input/vocabulary-migration.ts`.
|
|
87
|
+
const migrated = migrateTouchMap(stored && typeof stored === 'object' ? stored : null);
|
|
88
|
+
return Object.assign({}, TOUCH_DEFAULT, migrated || {});
|
|
100
89
|
}
|
|
90
|
+
/** The five size sliders a page's touch panel may carry, each writing its own measure (mm). */
|
|
91
|
+
const PAD_SLIDERS = [
|
|
92
|
+
['#pad-size', 'btn'], ['#pad-gap', 'gap'], ['#pad-stick', 'stick'], ['#pad-travel', 'travel'], ['#pad-dpad', 'dpad'],
|
|
93
|
+
];
|
|
94
|
+
/** The two presets: every size at once, and the sentence that says so — a child who cannot see five sliders move hears it. */
|
|
95
|
+
const PAD_PRESETS = [
|
|
96
|
+
['#pad-preset-child', { btn: 12, gap: 2.5, stick: 16.5, travel: 4, dpad: 11.5 }, 'sr.touch.presetChild'],
|
|
97
|
+
['#pad-preset-adult', { btn: 14, gap: 4.5, stick: 20, travel: 5.5, dpad: 14 }, 'sr.touch.presetAdult'],
|
|
98
|
+
];
|
|
101
99
|
export function initTouch(ctx) {
|
|
100
|
+
const { t } = ctx;
|
|
102
101
|
let padDesign = ctx.store.get(KEYS.padDesign, 'generic') || 'generic';
|
|
103
102
|
let padBtnMm = ctx.store.getNum(KEYS.padBtnMm, 12.5);
|
|
104
103
|
let padGapMm = ctx.store.getNum(KEYS.padGapMm, 3);
|
|
@@ -106,47 +105,84 @@ export function initTouch(ctx) {
|
|
|
106
105
|
let padTravelMm = ctx.store.getNum(KEYS.padTravelMm, 4.5);
|
|
107
106
|
let padDpadMm = ctx.store.getNum(KEYS.padDpadMm, 12);
|
|
108
107
|
let padDir = ctx.store.get(KEYS.padDir, 'stick') || 'stick';
|
|
109
|
-
let _stickTravelPx = 42, _stickDeadPx = 12; //
|
|
108
|
+
let _stickTravelPx = 42, _stickDeadPx = 12; // boot values; applyPadPhysical() sets the real ones
|
|
110
109
|
const touchMap = normalizeTouchMap(ctx.store.getJSON(KEYS.touchmap, null));
|
|
110
|
+
/** A slot's choice landed: store it, and say it in the game's word — never the abstract name. */
|
|
111
|
+
function slotChosen(slot, slotLabel, action) {
|
|
112
|
+
touchMap[slot] = action;
|
|
113
|
+
ctx.store.setJSON(KEYS.touchmap, touchMap);
|
|
114
|
+
// ⚠️ The spoken word is the SAME as the one read: it comes from the list that just built the control, so nothing has
|
|
115
|
+
// to make two tables agree.
|
|
116
|
+
const chosen = ctx.gameActions().find((x) => x.action === action);
|
|
117
|
+
const slotName = slotLabel || t('touch.slot.fallback');
|
|
118
|
+
// ⚠️ WITHOUT THE GAME'S WORD, THE ANNOUNCEMENT DROPS THE POSITION — IT DOES NOT FALL BACK TO THE ID. `action` is the
|
|
119
|
+
// ABSTRACT name (`action3`), and ADR-0074 says it never reaches a person; `7742ac0` already paid for this defect on the
|
|
120
|
+
// remapping screen and the way out is the same: a key of its own that says what matters.
|
|
121
|
+
// 📌 The fallback is reachable because `gameActions()` is a FUNCTION of the cartridge, reread on every choice: in an
|
|
122
|
+
// activity hub the list changes underneath and the control drawn before is orphaned.
|
|
123
|
+
ctx.srSay(chosen
|
|
124
|
+
? t('sr.touch.slotSet', { slot: slotName, acao: chosen.label })
|
|
125
|
+
: t('sr.touch.slotSetUnnamed', { slot: slotName }));
|
|
126
|
+
}
|
|
111
127
|
function renderTouchMap() {
|
|
112
128
|
const el = ctx.$('#touchmap-list');
|
|
113
129
|
if (!el)
|
|
114
130
|
return;
|
|
131
|
+
if (ctx.drawChoice) {
|
|
132
|
+
drawSlotChoices(el, ctx.drawChoice);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
115
135
|
el.innerHTML = TOUCH_SLOTS.map((s) => `<div class="ctrl-row"><label for="tm-${s.k}">${t(s.lbl)}</label><select id="tm-${s.k}" class="vol" data-slot="${s.k}">` +
|
|
116
|
-
// ⚠️
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
ctx.
|
|
136
|
+
// ⚠️ THE OPTION IS BORN EMPTY and the `label` goes in just below through `textContent` (issue #106). It is the
|
|
137
|
+
// game's WORD — `gameActions()` comes from the preset —, and a game lives in another repository (ADR-0083), so
|
|
138
|
+
// this text is not reviewed by this tree. `value="${slotAction}"` stays: `slotAction` is the ABSTRACT name, and
|
|
139
|
+
// the engine enumerates it in `core/actions`; it is the engine's and not the game's.
|
|
140
|
+
ctx.gameActions().map(({ action: slotAction }) => `<option value="${slotAction}"${touchMap[s.k] === slotAction ? ' selected' : ''}></option>`).join('') +
|
|
121
141
|
`</select></div>`).join('');
|
|
122
|
-
//
|
|
142
|
+
// The game's words, through `textContent` — which escapes by construction. The order matches because it is the same list.
|
|
123
143
|
for (const sel of el.querySelectorAll('select[data-slot]')) {
|
|
124
|
-
const
|
|
125
|
-
for (let i = 0; i < sel.options.length && i <
|
|
126
|
-
sel.options[i].textContent =
|
|
144
|
+
const words = ctx.gameActions();
|
|
145
|
+
for (let i = 0; i < sel.options.length && i < words.length; i++) {
|
|
146
|
+
sel.options[i].textContent = words[i].label;
|
|
127
147
|
}
|
|
128
148
|
}
|
|
129
149
|
el.querySelectorAll('select[data-slot]').forEach((sel) => {
|
|
130
150
|
sel.addEventListener('change', () => {
|
|
131
|
-
const slot = sel.dataset.slot || '';
|
|
132
|
-
touchMap[slot] = sel.value;
|
|
133
|
-
ctx.store.setJSON(KEYS.touchmap, touchMap);
|
|
134
151
|
const label = sel.previousElementSibling ? sel.previousElementSibling.textContent : null;
|
|
135
|
-
|
|
136
|
-
// Antes vinham de tabelas diferentes e nada obrigava as duas a concordar.
|
|
137
|
-
const escolhida = ctx.acoesDoJogo().find((x) => x.acao === sel.value);
|
|
138
|
-
const nomeDoSlot = label || t('touch.slot.fallback');
|
|
139
|
-
// ⚠️ SEM PALAVRA DO JOGO, O ANÚNCIO PERDE A POSIÇÃO — NÃO RECUA PARA O ID. `sel.value` é o nome
|
|
140
|
-
// ABSTRATO (`action3`), e o ADR-0074 diz que ele nunca chega a uma pessoa; o `7742ac0` já pagou este
|
|
141
|
-
// defeito no ecrã de remapeamento e a saída é a mesma: uma chave própria que diz o que importa.
|
|
142
|
-
// 📌 O recuo é alcançável porque `acoesDoJogo()` é FUNÇÃO do cartucho, relida a cada `change`: num hub
|
|
143
|
-
// de atividades a lista muda por baixo e a `<option>` desenhada antes fica órfã.
|
|
144
|
-
ctx.srSay(escolhida
|
|
145
|
-
? t('sr.touch.slotSet', { slot: nomeDoSlot, acao: escolhida.rotulo })
|
|
146
|
-
: t('sr.touch.slotSetUnnamed', { slot: nomeDoSlot }));
|
|
152
|
+
slotChosen(sel.dataset.slot || '', label, sel.value);
|
|
147
153
|
});
|
|
148
154
|
});
|
|
149
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* THE SLOTS DRAWN BY THEIR SIZE (ADR-0130 rule 3), node by node: each slot is a choice among the game's named positions,
|
|
158
|
+
* so a game naming five or fewer gets cycle rows «◀ Botão 0: Confirmar ▶», and one naming more gets dropdowns. The id
|
|
159
|
+
* (`#tm-<slot>`) and `data-slot` stay on the control in both shapes — they are how the root finds the slots it hides.
|
|
160
|
+
*/
|
|
161
|
+
function drawSlotChoices(el, draw) {
|
|
162
|
+
while (el.firstChild)
|
|
163
|
+
el.removeChild(el.firstChild);
|
|
164
|
+
const doc = el.ownerDocument;
|
|
165
|
+
const positions = ctx.gameActions().map(({ action, label }) => ({ value: action, label }));
|
|
166
|
+
for (const s of TOUCH_SLOTS) {
|
|
167
|
+
const slotName = t(s.lbl);
|
|
168
|
+
const control = draw({ label: slotName, values: positions, current: touchMap[s.k] ?? '' }, (action) => slotChosen(s.k, slotName, action));
|
|
169
|
+
control.id = `tm-${s.k}`;
|
|
170
|
+
control.dataset.slot = s.k;
|
|
171
|
+
const row = doc.createElement('div');
|
|
172
|
+
row.className = 'ctrl-row';
|
|
173
|
+
if (control.tagName === 'SELECT') {
|
|
174
|
+
// a dropdown keeps its name beside it; a cycle row already carries it in its own text
|
|
175
|
+
const name = doc.createElement('label');
|
|
176
|
+
name.htmlFor = control.id;
|
|
177
|
+
name.textContent = slotName;
|
|
178
|
+
row.appendChild(name);
|
|
179
|
+
}
|
|
180
|
+
else
|
|
181
|
+
row.classList.add('ctrl-row--passos');
|
|
182
|
+
row.appendChild(control);
|
|
183
|
+
el.appendChild(row);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
150
186
|
function openTouchCfg() {
|
|
151
187
|
const ov = ctx.$('#touchcfg');
|
|
152
188
|
if (!ov)
|
|
@@ -172,17 +208,16 @@ export function initTouch(ctx) {
|
|
|
172
208
|
if (tc && !tc.hidden)
|
|
173
209
|
tc.hidden = true;
|
|
174
210
|
ctx.$('body')?.classList.remove('touch-mode');
|
|
175
|
-
|
|
211
|
+
ctx.onTouchControlsHidden?.();
|
|
176
212
|
}
|
|
177
213
|
function showTouchControls() {
|
|
178
|
-
// MENU
|
|
214
|
+
// A MENU up = no virtual pad: the child touches the on-screen buttons directly. The GAME decides.
|
|
179
215
|
if (!ctx.padAllowed())
|
|
180
216
|
return;
|
|
181
217
|
const tc = ctx.$('#touch-controls');
|
|
182
218
|
if (tc)
|
|
183
219
|
tc.hidden = false;
|
|
184
220
|
ctx.$('body')?.classList.add('touch-mode');
|
|
185
|
-
setMinimapCorner(true);
|
|
186
221
|
ctx.onTouchControlsShown?.();
|
|
187
222
|
}
|
|
188
223
|
function applyDirStyle() {
|
|
@@ -267,47 +302,37 @@ export function initTouch(ctx) {
|
|
|
267
302
|
ctx.onPadDesignApplied?.();
|
|
268
303
|
return padDesign;
|
|
269
304
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
305
|
+
/**
|
|
306
|
+
* The touch panel's controls, where a PAGE carries them (the engine's own panels do not): open and close, the direction, the
|
|
307
|
+
* five sizes and the two presets. The selector is not set here — the boot's `applyDirStyle` sets it to the stored direction.
|
|
308
|
+
*/
|
|
309
|
+
function wirePanel() {
|
|
310
|
+
ctx.$('#opt-touchcfg')?.addEventListener('click', openTouchCfg);
|
|
311
|
+
ctx.$('#touchcfg-close')?.addEventListener('click', closeTouchCfg);
|
|
312
|
+
const padDirSel = ctx.$('#pad-dir');
|
|
313
|
+
if (padDirSel) {
|
|
314
|
+
padDirSel.addEventListener('change', () => {
|
|
315
|
+
padDir = padDirSel.value;
|
|
316
|
+
ctx.store.set(KEYS.padDir, padDir);
|
|
317
|
+
applyDirStyle();
|
|
318
|
+
ctx.srSay(t('sr.touch.dirSet', { tipo: t(padDir === 'cross' ? 'touch.dir.cross' : 'touch.dir.stick') }));
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
for (const [id, field] of PAD_SLIDERS) {
|
|
322
|
+
const slider = ctx.$(id);
|
|
323
|
+
if (!slider)
|
|
324
|
+
continue;
|
|
325
|
+
slider.addEventListener('input', () => { const patch = {}; patch[field] = parseFloat(slider.value); setPadMm(patch); });
|
|
326
|
+
}
|
|
327
|
+
for (const [id, mm, said] of PAD_PRESETS) {
|
|
328
|
+
ctx.$(id)?.addEventListener('click', () => { setPadMm(mm); ctx.srSay(t(said)); });
|
|
329
|
+
}
|
|
287
330
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
padGapEl.addEventListener('input', () => setPadMm({ gap: parseFloat(padGapEl.value) }));
|
|
294
|
-
const padStickEl = ctx.$('#pad-stick');
|
|
295
|
-
if (padStickEl)
|
|
296
|
-
padStickEl.addEventListener('input', () => setPadMm({ stick: parseFloat(padStickEl.value) }));
|
|
297
|
-
const padTravelEl = ctx.$('#pad-travel');
|
|
298
|
-
if (padTravelEl)
|
|
299
|
-
padTravelEl.addEventListener('input', () => setPadMm({ travel: parseFloat(padTravelEl.value) }));
|
|
300
|
-
const padDpadEl = ctx.$('#pad-dpad');
|
|
301
|
-
if (padDpadEl)
|
|
302
|
-
padDpadEl.addEventListener('input', () => setPadMm({ dpad: parseFloat(padDpadEl.value) }));
|
|
303
|
-
const padPresetChild = ctx.$('#pad-preset-child');
|
|
304
|
-
if (padPresetChild)
|
|
305
|
-
padPresetChild.addEventListener('click', () => { setPadMm({ btn: 12, gap: 2.5, stick: 16.5, travel: 4, dpad: 11.5 }); ctx.srSay(t('sr.touch.presetChild')); });
|
|
306
|
-
const padPresetAdult = ctx.$('#pad-preset-adult');
|
|
307
|
-
if (padPresetAdult)
|
|
308
|
-
padPresetAdult.addEventListener('click', () => { setPadMm({ btn: 14, gap: 4.5, stick: 20, travel: 5.5, dpad: 14 }); ctx.srSay(t('sr.touch.presetAdult')); });
|
|
309
|
-
addEventListener('resize', applyPadPhysical); // recalcula os px ao girar/redimensionar; os mm são fixos
|
|
310
|
-
// estado inicial (equivalente aos `applyPadDesign(padDesign); applyPadPhysical(); applyDirStyle();` de boot no game.js)
|
|
331
|
+
wirePanel();
|
|
332
|
+
// Recomputes the px on rotate/resize; the mm are fixed.
|
|
333
|
+
// ⚠️ THE WINDOW COMES THROUGH THE `ctx` (see `TouchCtx.win`). Without a window there is nothing to listen to.
|
|
334
|
+
ctx.win?.addEventListener('resize', applyPadPhysical);
|
|
335
|
+
// initial state: the stored design, geometry and direction applied once at boot
|
|
311
336
|
applyPadDesign();
|
|
312
337
|
applyPadPhysical();
|
|
313
338
|
applyDirStyle();
|
|
@@ -320,3 +345,214 @@ export function initTouch(ctx) {
|
|
|
320
345
|
getStickDeadPx: () => _stickDeadPx,
|
|
321
346
|
};
|
|
322
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* A BUTTON'S NAME, from the position it fires (ADR-0165): the same in every game — 1 to 4, L1/L2/R1/R2, SELECT, START,
|
|
350
|
+
* and the four directions by their spoken name. The cartridge's word is the FUNCTION, and it never reaches the face. The pad
|
|
351
|
+
* wizard asks by these names where the game names no position (`input/pad-wizard`, ADR-0144 erratum of 2026-09-26).
|
|
352
|
+
*/
|
|
353
|
+
const SLOT_NAME = {
|
|
354
|
+
action1: '1', action2: '2', action3: '3', action4: '4',
|
|
355
|
+
leftShoulder: 'L1', leftTrigger: 'L2', rightShoulder: 'R1', rightTrigger: 'R2',
|
|
356
|
+
select: 'SELECT', start: 'START',
|
|
357
|
+
};
|
|
358
|
+
export function buttonName(t, slotAction) {
|
|
359
|
+
if (SLOT_NAME[slotAction])
|
|
360
|
+
return SLOT_NAME[slotAction];
|
|
361
|
+
return slotAction === 'up' || slotAction === 'down' || slotAction === 'left' || slotAction === 'right' ? t(`touch.nome.${slotAction}`) : null;
|
|
362
|
+
}
|
|
363
|
+
/** The four direction slots, in the order the cross draws them. */
|
|
364
|
+
const DIRECTIONS = ['up', 'left', 'right', 'down'];
|
|
365
|
+
/** The four action-button slots, in the diamond's order. */
|
|
366
|
+
const BUTTONS = ['b0', 'b1', 'b2', 'b3'];
|
|
367
|
+
/** The SHOULDERS per corner, top to bottom (ADR-0160): the trigger (2) over the shoulder (1). */
|
|
368
|
+
const SHOULDERS = [['esq', ['bl2', 'bl1']], ['dir', ['br2', 'br1']]];
|
|
369
|
+
/**
|
|
370
|
+
* Builds (or reuses) `#touch-controls` and returns it.
|
|
371
|
+
*
|
|
372
|
+
* ⚠️ IT IS BORN HIDDEN, and that is not a detail: switching by modality belongs to `touch-bindings` — a touch or click
|
|
373
|
+
* SHOWS it, the keyboard or a pad HIDES it. A pad born on screen covers the game of whoever will never touch it.
|
|
374
|
+
*
|
|
375
|
+
* 🔴 ONLY WHAT THE GAME NAMES, since ADR-0162 — which undid ADR-0157's minimum (directions and four buttons in every
|
|
376
|
+
* game, with the physical legend on the unnamed ones): «Vale para todos os botões: somente aparecem se o jogo os
|
|
377
|
+
* nomeia.» SELECT and START always stay, because they are the pause's doors. ⚠️ A game that names no direction does not
|
|
378
|
+
* move through menus by touch; that is why `consumer-quiz` declares the positions it uses. The four buttons sit in a 2×2
|
|
379
|
+
* block by the action's NUMBER (ADR-0160): 1 and 4 on top, 2 and 3 below.
|
|
380
|
+
*
|
|
381
|
+
* Idempotent: mounting twice returns the same node, its content rebuilt for the map of now.
|
|
382
|
+
*/
|
|
383
|
+
export function mountTouchControls(ctx, spec) {
|
|
384
|
+
const { t } = ctx;
|
|
385
|
+
const touchControls = ctx.find('#touch-controls') ?? ctx.create('div');
|
|
386
|
+
touchControls.id = 'touch-controls';
|
|
387
|
+
touchControls.className = 'touch';
|
|
388
|
+
touchControls.hidden = true;
|
|
389
|
+
while (touchControls.firstChild)
|
|
390
|
+
touchControls.removeChild(touchControls.firstChild);
|
|
391
|
+
const f = padFacesOf(t, spec);
|
|
392
|
+
// in the order they sit on the screen; a part the game names nothing for is an empty list, never an empty box
|
|
393
|
+
const parts = [...directionPad(ctx, spec, f), ...actionButtons(ctx, spec, f), ...shoulderCorners(ctx, f), systemPills(ctx, f)];
|
|
394
|
+
for (const part of parts)
|
|
395
|
+
touchControls.appendChild(part);
|
|
396
|
+
return touchControls;
|
|
397
|
+
}
|
|
398
|
+
function padFacesOf(t, spec) {
|
|
399
|
+
// 🔴 ONLY WHAT THE GAME NAMES (ADR-0162, superseding ADR-0157's minimum): «Vale para todos os botões: somente
|
|
400
|
+
// aparecem se o jogo os nomeia.» A button on screen is a promise that it does something, and the game is who knows.
|
|
401
|
+
const named = (slot) => spec.gameActions.has(spec.map[slot] ?? '');
|
|
402
|
+
// ADR-0165: the face is the NAME of the position the slot fires; the accessible name is «name, function».
|
|
403
|
+
const nameOf = (slot) => buttonName(t, spec.map[slot] ?? slot) ?? spec.slotLabel(slot);
|
|
404
|
+
const accessible = (slot) => {
|
|
405
|
+
const name = nameOf(slot);
|
|
406
|
+
const purpose = spec.slotLabel(slot);
|
|
407
|
+
return purpose && purpose !== name ? `${name}, ${purpose}` : name;
|
|
408
|
+
};
|
|
409
|
+
return { named, nameOf, accessible };
|
|
410
|
+
}
|
|
411
|
+
/** The directional, where the game names a direction: the analog stick with its knob, or the cross with its arms. */
|
|
412
|
+
function directionPad(ctx, spec, f) {
|
|
413
|
+
const live = DIRECTIONS.filter(f.named);
|
|
414
|
+
if (!live.length)
|
|
415
|
+
return [];
|
|
416
|
+
const kind = spec.dpad === 'analogico' ? 'touch-stick' : 'touch-cross';
|
|
417
|
+
const dir = ctx.create('div');
|
|
418
|
+
dir.id = kind;
|
|
419
|
+
dir.className = kind; // the id is what `touch-bindings` finds; the class is what the stylesheet DRAWS
|
|
420
|
+
if (kind === 'touch-stick') {
|
|
421
|
+
// `touch-bindings` requires the `.touch-knob` inside the base (`if (stick && knob)`), and without it gives up on the
|
|
422
|
+
// whole stick — silently.
|
|
423
|
+
const knob = ctx.create('div');
|
|
424
|
+
knob.className = 'touch-knob';
|
|
425
|
+
dir.appendChild(knob);
|
|
426
|
+
return [dir];
|
|
427
|
+
}
|
|
428
|
+
for (const d of live) {
|
|
429
|
+
const arm = ctx.create('button');
|
|
430
|
+
// ⚠️ THE THREE CLASSES, and each has a reader. `touch-arm` is this module's; `dpad-arm` is the one the stylesheet
|
|
431
|
+
// DRAWS; `dpad-<dir>` is the one `touch-bindings` LIGHTS on touch (`.dpad-up` & co.). With only the first, the arm
|
|
432
|
+
// is an unstyled button that never lights, and no case sees it unless both are mounted together.
|
|
433
|
+
arm.className = `touch-arm dpad-arm dpad-${d}`;
|
|
434
|
+
arm.setAttribute('type', 'button');
|
|
435
|
+
arm.setAttribute('aria-label', f.accessible(d));
|
|
436
|
+
dir.appendChild(arm);
|
|
437
|
+
}
|
|
438
|
+
return [dir];
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* One button the dispatch can read back: `data-btn` is the slot without its `b` (`b2` -> `2`, `bl1` -> `l1`), which is
|
|
442
|
+
* what `'b' + dataset.btn` in `touch-bindings` recomposes. Writing the ACTION here would be a second source for the same
|
|
443
|
+
* answer, and the child's remapping would stop counting.
|
|
444
|
+
*/
|
|
445
|
+
function padButton(ctx, f, slot, className) {
|
|
446
|
+
const button = ctx.create('button');
|
|
447
|
+
button.className = className;
|
|
448
|
+
button.dataset.btn = slot.slice(1);
|
|
449
|
+
button.setAttribute('type', 'button');
|
|
450
|
+
button.setAttribute('aria-label', f.accessible(slot));
|
|
451
|
+
button.textContent = f.nameOf(slot);
|
|
452
|
+
return button;
|
|
453
|
+
}
|
|
454
|
+
/** The four action buttons, where the game names them, in a 2×2 block by the action's NUMBER (ADR-0160). */
|
|
455
|
+
function actionButtons(ctx, spec, f) {
|
|
456
|
+
const live = BUTTONS.filter(f.named);
|
|
457
|
+
if (!live.length)
|
|
458
|
+
return [];
|
|
459
|
+
const rhombus = ctx.create('div');
|
|
460
|
+
rhombus.className = 'touch-pad';
|
|
461
|
+
for (const b of live) {
|
|
462
|
+
const button = padButton(ctx, f, b, 'touch-btn');
|
|
463
|
+
// THE PLACE FOLLOWS THE ACTION, not the slot (ADR-0160: 1 4 on top, 2 3 below): the stylesheet puts each button in
|
|
464
|
+
// its number's cell, and a remapped slot takes the button to the place of the action it now fires.
|
|
465
|
+
button.dataset.acao = spec.map[b] ?? '';
|
|
466
|
+
rhombus.appendChild(button);
|
|
467
|
+
}
|
|
468
|
+
return [rhombus];
|
|
469
|
+
}
|
|
470
|
+
/** THE SHOULDERS, each pair in its top corner (ADR-0160), and only those the game names (ADR-0162) — no empty corner. */
|
|
471
|
+
function shoulderCorners(ctx, f) {
|
|
472
|
+
return SHOULDERS.flatMap(([side, slots]) => {
|
|
473
|
+
const named = slots.filter(f.named);
|
|
474
|
+
if (!named.length)
|
|
475
|
+
return [];
|
|
476
|
+
const corner = ctx.create('div');
|
|
477
|
+
corner.className = `touch-ombros touch-ombros--${side}`;
|
|
478
|
+
for (const s of named)
|
|
479
|
+
corner.appendChild(padButton(ctx, f, s, 'touch-btn touch-ombro'));
|
|
480
|
+
return [corner];
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
/*
|
|
484
|
+
* THE TWO SYSTEM PILLS, side by side in the centre: SELECT (the menus) and START (the quick pause), in a console pad's
|
|
485
|
+
* order. ⚠️ BOTH UNCONDITIONAL, for the same reason: since ADR-0155 they are the pause's two doors, and the pause cannot
|
|
486
|
+
* be declined (ADR-0122) — a tablet without a keyboard has no other way to reach "Quit".
|
|
487
|
+
*/
|
|
488
|
+
function systemPills(ctx, f) {
|
|
489
|
+
const system = ctx.create('div');
|
|
490
|
+
system.className = 'touch-sistema';
|
|
491
|
+
for (const slot of ['select', 'start']) {
|
|
492
|
+
const b = ctx.create('button');
|
|
493
|
+
b.id = `touch-${slot}`;
|
|
494
|
+
b.className = `touch-btn touch-${slot}`;
|
|
495
|
+
b.setAttribute('type', 'button');
|
|
496
|
+
b.setAttribute('aria-label', f.accessible(slot));
|
|
497
|
+
// ⚠️ AND WRITTEN, not only spoken: a pill with no text is a button a sighted child cannot read.
|
|
498
|
+
b.textContent = f.nameOf(slot);
|
|
499
|
+
system.appendChild(b);
|
|
500
|
+
}
|
|
501
|
+
return system;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* What this game does NOT reach by touch, said instead of kept quiet — the half of ADR-0143 §4 that is not markup.
|
|
505
|
+
*
|
|
506
|
+
* 📌 It returns LINES and does not throw: a host gap never takes the boot down, by the same rule the rest of
|
|
507
|
+
* `problems` follows. The sentences go to the consumer that INTEGRATES the engine, not to a child.
|
|
508
|
+
*/
|
|
509
|
+
export function touchGaps(spec) {
|
|
510
|
+
// ⚠️ WITHOUT `preset` THE PAD HAS ONLY SELECT AND START (ADR-0162): no direction, no button — not even to move
|
|
511
|
+
// through menus. It is the integrator's gap, and it is said.
|
|
512
|
+
if (!spec.gameActions.size) {
|
|
513
|
+
return ['the virtual pad shows only SELECT and START — no direction and no button: a child on a tablet without a '
|
|
514
|
+
+ 'keyboard cannot play — declare `preset` with the positions this game uses and a word for each'];
|
|
515
|
+
}
|
|
516
|
+
// ⚠️ AND THE PARTIAL GAP IS SAID TOO. A game may declare an action no slot fires: it exists on the keyboard and not on
|
|
517
|
+
// touch, and without this line that would show up nowhere.
|
|
518
|
+
const reached = new Set(TOUCH_SLOTS.map((s) => spec.map[s.k]).filter(Boolean));
|
|
519
|
+
const outsideTouch = [...spec.gameActions].filter((a) => !reached.has(a));
|
|
520
|
+
if (!outsideTouch.length)
|
|
521
|
+
return [];
|
|
522
|
+
return [`the virtual pad does not reach ${outsideTouch.join(', ')}: no slot fires them, so a child playing by touch `
|
|
523
|
+
+ 'does not have them — remap a slot in the pad panel, or declare fewer actions'];
|
|
524
|
+
}
|
|
525
|
+
/** The factory pad of `input/touch`, the base the non-button sizes are proportioned from. */
|
|
526
|
+
const FACTORY = { btn: 12.5, gap: 3, stick: 18, travel: 4.5, dpad: 12 };
|
|
527
|
+
/** A persona's pad: the button from the sources, the rest in proportion to the factory pad. */
|
|
528
|
+
function pad(btn) {
|
|
529
|
+
const k = btn / FACTORY.btn;
|
|
530
|
+
const r = (n) => Math.round(n * k * 10) / 10;
|
|
531
|
+
return { btn, gap: r(FACTORY.gap), stick: r(FACTORY.stick), travel: r(FACTORY.travel), dpad: r(FACTORY.dpad) };
|
|
532
|
+
}
|
|
533
|
+
/** The four, in the Dev's order. */
|
|
534
|
+
export const PERSONAS_DO_PAD = Object.freeze([
|
|
535
|
+
// 16 mm: an adult's 9.6 mm plus twice the extra spread of a 3-year-old (≈ 2.4 mm each side), rounded up.
|
|
536
|
+
{ key: 'crianca-pequena', label: 'motora.pad.crianca-pequena', mm: pad(16) },
|
|
537
|
+
// 14 mm: 9 mm is still missed once in six until 17 (Anthony), and 12.7 mm was the size that did not trouble them.
|
|
538
|
+
{ key: 'crianca-grande', label: 'motora.pad.crianca-grande', mm: pad(14) },
|
|
539
|
+
// 11.5 mm: where adult performance levels off (Parhi) — above it there is no gain, only lost room.
|
|
540
|
+
{ key: 'adulto-pequeno', label: 'motora.pad.adulto-pequeno', mm: pad(11.5) },
|
|
541
|
+
// 15 mm: a 16–20 mm finger covers anything smaller and hides the label under the thumb (MIT Touch Lab).
|
|
542
|
+
{ key: 'adulto-maos-grandes', label: 'motora.pad.adulto-maos-grandes', mm: pad(15) },
|
|
543
|
+
]);
|
|
544
|
+
/**
|
|
545
|
+
* The persona whose button is closest to `btnMm` — what the step control shows for a pad that was sized before
|
|
546
|
+
* the personas existed (the factory 12.5 mm reads as «small adult»). Ties go to the LARGER button: when in doubt,
|
|
547
|
+
* the easier target.
|
|
548
|
+
*/
|
|
549
|
+
export function closestPersona(btnMm) {
|
|
550
|
+
let best = 0;
|
|
551
|
+
PERSONAS_DO_PAD.forEach((p, i) => {
|
|
552
|
+
const d = Math.abs(p.mm.btn - btnMm);
|
|
553
|
+
const dm = Math.abs(PERSONAS_DO_PAD[best].mm.btn - btnMm);
|
|
554
|
+
if (d < dm || (d === dm && p.mm.btn > PERSONAS_DO_PAD[best].mm.btn))
|
|
555
|
+
best = i;
|
|
556
|
+
});
|
|
557
|
+
return best;
|
|
558
|
+
}
|