@the-inclusionist/engine 10.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 +32 -1
- package/app/css/style.css +216 -42
- 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 +11 -1175
- package/dist-pkg/boot/create-game.d.ts +84 -33
- package/dist-pkg/boot/create-game.js +708 -307
- package/dist-pkg/core/a11y-sr.d.ts +1 -1
- package/dist-pkg/core/a11y-sr.js +3 -5
- package/dist-pkg/core/accommodations.d.ts +26 -8
- package/dist-pkg/core/accommodations.js +27 -10
- package/dist-pkg/core/actions.d.ts +39 -10
- package/dist-pkg/core/actions.js +28 -6
- package/dist-pkg/core/contract.d.ts +0 -2
- package/dist-pkg/core/contract.js +0 -2
- package/dist-pkg/core/i18n.d.ts +36 -71
- package/dist-pkg/core/i18n.js +131 -198
- package/dist-pkg/core/session-clock.d.ts +23 -0
- package/dist-pkg/core/session-clock.js +37 -0
- package/dist-pkg/i18n/en.js +44 -49
- package/dist-pkg/i18n/es.js +44 -49
- package/dist-pkg/i18n/pt.js +49 -54
- package/dist-pkg/input/gamepad.d.ts +42 -11
- package/dist-pkg/input/gamepad.js +50 -15
- 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 +0 -4
- package/dist-pkg/input/keyboard.d.ts +0 -1
- package/dist-pkg/input/keydown.d.ts +5 -11
- package/dist-pkg/input/keydown.js +3 -3
- package/dist-pkg/input/latch-edge.d.ts +10 -2
- package/dist-pkg/input/latch-edge.js +4 -3
- package/dist-pkg/input/latch-scope.d.ts +27 -22
- package/dist-pkg/input/latch-scope.js +25 -37
- package/dist-pkg/input/latch-store.d.ts +9 -12
- package/dist-pkg/input/latch-store.js +13 -18
- package/dist-pkg/input/latch-sync.d.ts +5 -4
- package/dist-pkg/input/latch-sync.js +5 -5
- package/dist-pkg/input/pad-reading.js +7 -2
- package/dist-pkg/input/pad-wizard.d.ts +4 -1
- package/dist-pkg/input/pad-wizard.js +60 -9
- package/dist-pkg/input/switch-scan.d.ts +29 -12
- package/dist-pkg/input/switch-scan.js +15 -2
- package/dist-pkg/input/touch-bindings.d.ts +3 -6
- package/dist-pkg/input/touch.d.ts +17 -2
- package/dist-pkg/input/touch.js +55 -17
- package/dist-pkg/input/transport-in-use.d.ts +5 -5
- package/dist-pkg/input/transport-in-use.js +5 -5
- package/dist-pkg/input/transports.d.ts +0 -9
- package/dist-pkg/input/transports.js +1 -1
- package/dist-pkg/input/virtual-controller.d.ts +39 -3
- package/dist-pkg/input/virtual-controller.js +32 -4
- package/dist-pkg/input/voice-map.d.ts +27 -11
- package/dist-pkg/input/voice-map.js +41 -43
- package/dist-pkg/platform/audio-ambient.d.ts +0 -1
- package/dist-pkg/platform/audio-ambient.js +3 -1
- package/dist-pkg/platform/audio-mixer.js +4 -9
- package/dist-pkg/platform/audio-sonar.d.ts +8 -94
- package/dist-pkg/platform/audio-sonar.js +22 -207
- package/dist-pkg/platform/audio.d.ts +10 -1
- package/dist-pkg/platform/audio.js +35 -2
- 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/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 +46 -0
- package/dist-pkg/platform/heavy-catalogue.js +47 -14
- package/dist-pkg/platform/heavy-mirror.d.ts +3 -9
- package/dist-pkg/platform/heavy-mirror.js +14 -17
- package/dist-pkg/platform/heavy.d.ts +40 -8
- package/dist-pkg/platform/heavy.js +177 -22
- package/dist-pkg/platform/interruptible-speech.d.ts +15 -8
- package/dist-pkg/platform/interruptible-speech.js +37 -13
- package/dist-pkg/platform/listener-scope.js +22 -13
- package/dist-pkg/platform/locale-host.d.ts +7 -3
- package/dist-pkg/platform/locale-host.js +13 -2
- package/dist-pkg/platform/reading-in-worker.d.ts +24 -0
- package/dist-pkg/platform/reading-in-worker.js +38 -0
- package/dist-pkg/platform/reading-model.d.ts +21 -0
- package/dist-pkg/platform/reading-model.js +25 -0
- package/dist-pkg/platform/reading-runtime.js +13 -8
- package/dist-pkg/platform/reading.d.ts +12 -1
- package/dist-pkg/platform/reading.js +9 -1
- package/dist-pkg/platform/speech-recognition.d.ts +10 -1
- package/dist-pkg/platform/speech-recognition.js +29 -9
- package/dist-pkg/platform/speech.d.ts +10 -1
- package/dist-pkg/platform/speech.js +24 -13
- package/dist-pkg/platform/tts.d.ts +37 -4
- package/dist-pkg/platform/tts.js +279 -57
- package/dist-pkg/platform/voice-listener.d.ts +6 -2
- package/dist-pkg/platform/voice-listener.js +1 -1
- package/dist-pkg/platform/voice-plan.d.ts +13 -0
- package/dist-pkg/platform/voice-plan.js +57 -2
- package/dist-pkg/platform/vosk-runtime.d.ts +25 -0
- package/dist-pkg/platform/vosk-runtime.js +59 -1
- package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
- package/dist-pkg/platform/vosk-vocabulary.js +178 -0
- package/dist-pkg/render/crt.d.ts +11 -9
- package/dist-pkg/render/crt.js +6 -10
- package/dist-pkg/render/cvd-matrices.d.ts +5 -1
- package/dist-pkg/render/cvd-matrices.js +5 -1
- package/dist-pkg/render/high-contrast.d.ts +1 -2
- package/dist-pkg/render/high-contrast.js +5 -1
- package/dist-pkg/render/viz-axes.d.ts +9 -0
- package/dist-pkg/render/viz-axes.js +15 -2
- package/dist-pkg/ui/aac-sets.d.ts +29 -24
- package/dist-pkg/ui/aac-sets.js +22 -30
- package/dist-pkg/ui/audio-choices.d.ts +10 -5
- package/dist-pkg/ui/audio-choices.js +14 -10
- package/dist-pkg/ui/camera-control.d.ts +47 -0
- package/dist-pkg/ui/camera-control.js +35 -1
- package/dist-pkg/ui/declared-words.d.ts +21 -0
- package/dist-pkg/ui/declared-words.js +66 -0
- package/dist-pkg/ui/drawing-problems.js +4 -3
- package/dist-pkg/ui/eye-control.js +17 -17
- package/dist-pkg/ui/face-control.js +15 -15
- package/dist-pkg/ui/fonts.d.ts +42 -8
- package/dist-pkg/ui/fonts.js +58 -24
- 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 +14 -9
- package/dist-pkg/ui/game-options.js +41 -21
- package/dist-pkg/ui/hand-control.js +15 -15
- package/dist-pkg/ui/help-panel.d.ts +19 -8
- package/dist-pkg/ui/help-panel.js +15 -5
- package/dist-pkg/ui/hud-bands.d.ts +29 -12
- package/dist-pkg/ui/hud-bands.js +63 -25
- 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 +0 -3
- package/dist-pkg/ui/layout.js +5 -2
- 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/menu-intent.d.ts +29 -0
- package/dist-pkg/ui/menu-intent.js +35 -1
- package/dist-pkg/ui/menu-items.d.ts +10 -0
- package/dist-pkg/ui/menu-items.js +29 -0
- package/dist-pkg/ui/menu-nav.d.ts +40 -4
- package/dist-pkg/ui/menu-nav.js +132 -47
- package/dist-pkg/ui/panel-widgets.d.ts +34 -0
- package/dist-pkg/ui/panel-widgets.js +86 -0
- package/dist-pkg/ui/pause-icons.d.ts +30 -14
- package/dist-pkg/ui/pause-icons.js +106 -45
- package/dist-pkg/ui/scan-overlay.d.ts +3 -3
- package/dist-pkg/ui/scan-overlay.js +11 -3
- 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 +3 -1
- package/dist-pkg/ui/settings-aac.js +32 -13
- package/dist-pkg/ui/settings-audio.d.ts +10 -5
- package/dist-pkg/ui/settings-audio.js +101 -35
- package/dist-pkg/ui/settings-controls.d.ts +0 -4
- package/dist-pkg/ui/settings-mobility.d.ts +3 -6
- package/dist-pkg/ui/settings-mobility.js +4 -46
- package/dist-pkg/ui/settings-motion.js +2 -2
- package/dist-pkg/ui/settings-panel.d.ts +10 -0
- package/dist-pkg/ui/settings-panel.js +25 -1
- package/dist-pkg/ui/settings-typo.d.ts +5 -6
- package/dist-pkg/ui/settings-typo.js +20 -11
- package/dist-pkg/ui/settings-visual.js +2 -2
- package/dist-pkg/ui/shell.d.ts +1 -3
- package/dist-pkg/ui/shell.js +8 -4
- package/dist-pkg/ui/title.d.ts +2 -11
- package/dist-pkg/ui/title.js +39 -6
- package/dist-pkg/ui/top-band.d.ts +5 -3
- package/dist-pkg/ui/top-band.js +21 -25
- package/dist-pkg/ui/typo-choices.d.ts +3 -3
- package/dist-pkg/ui/typo-choices.js +9 -8
- package/dist-pkg/ui/vlibras.d.ts +71 -27
- package/dist-pkg/ui/vlibras.js +116 -44
- package/dist-pkg/ui/voice-control.d.ts +23 -1
- package/dist-pkg/ui/voice-control.js +149 -16
- package/dist-pkg/ui/voice-settings.d.ts +2 -3
- package/dist-pkg/ui/voice-settings.js +53 -3
- package/dist-pkg/ui/where-the-child-is.js +2 -2
- package/docs/CREDITS.md +122 -10
- package/docs/LICENSES.md +36 -7
- package/package.json +34 -9
- 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 +284 -40
- 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/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 +35 -21
- package/app/public/vendor/fonts/bitter-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/bitter-var.woff2 +0 -0
- package/app/public/vendor/fonts/bodonimoda-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/bodonimoda-var.woff2 +0 -0
- package/app/public/vendor/fonts/cat-abril_fatface-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-abril_fatface-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-adlam_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-adlam_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-agu_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-agu_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-alfa_slab_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-alfa_slab_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-are_you_serious-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-are_you_serious-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-asimovian-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-asimovian-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-atkinson_hyperlegible_next-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bakbak_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bakbak_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bangers-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bangers-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-barriecito-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-barriecito-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-berkshire_swash-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-berkshire_swash-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bevan-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bevan-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bitcount-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bitcount-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bowlby_one_sc-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bowlby_one_sc-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bungee_shade-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-bungee_shade-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-charm-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-charm-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-charm-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-charm-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-cherry_bomb_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-cherry_bomb_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-chokokutai-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-chokokutai-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-chonburi-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-chonburi-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-climate_crisis-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-climate_crisis-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-cookie-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-dela_gothic_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-dela_gothic_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-fascinate_inline-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-fascinate_inline-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ga_maamli-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ga_maamli-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-itim-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-itim-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-jacquard_24-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-jacquard_24-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kablammo-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kablammo-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kalam-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kalam-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kalam-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-kalam-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-katibeh-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-katibeh-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lemonada-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lemonada-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lilita_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lilita_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lobster-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-lobster-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-luckiest_guy-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-luckiest_guy-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-marhey-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-marhey-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-modak-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-modak-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-momo_signature-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-momo_signature-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monofett-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monofett-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monomakh-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monomakh-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monoton-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-monoton-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-nerko_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-nerko_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_adlam-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_adlam-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_arabic-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_arabic-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_devanagari-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_devanagari-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_hebrew-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_hebrew-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_jp-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_jp-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_khmer-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_khmer-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_kr-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_kr-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_sc-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_sc-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_thai-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-noto_sans_thai-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ole-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ole-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-pacifico-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-pacifico-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-patrick_hand-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-patrick_hand-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-petit_formal_script-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-petit_formal_script-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-pixelify_sans-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-pixelify_sans-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-plaster-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-plaster-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ar_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_at-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_at_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_nsw-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_nsw_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_qld-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_qld_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_sa-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_sa_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_tas-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_tas_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_vic-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_au_vic_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_be_vlg-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_be_vlg_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_be_wal-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_be_wal_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_br_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ca_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_cl_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_co_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_cu_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_cz-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_cz_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_grund-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_grund_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_la-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_la_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_sas-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_sas_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_va-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_de_va_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_dk_loopet-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_dk_loopet_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_dk_uloopet-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_dk_uloopet_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_es_deco_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_es_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_fr_moderne-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_fr_moderne_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_fr_trad-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_fr_trad_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_gb_j_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_gb_s_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hr-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hr_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hr_lijeva-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hr_lijeva_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hu-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_hu_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_id-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_id_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ie-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ie_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_in-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_in_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_is-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_is_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_it_moderna-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_it_moderna_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_it_trad-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_it_trad_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_mx_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ng_modern-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ng_modern_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nl-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nl_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_no-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_no_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nz-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nz_basic-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nz_basic_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_nz_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_pe_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_pl-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_pl_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_pt_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ro-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_ro_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_sk-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_sk_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_tz-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_tz_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_us_modern_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_us_trad_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_vn-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_vn_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_za-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-playwrite_za_guides-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-potta_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-potta_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranchers-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranchers-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranga-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranga-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranga-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ranga-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-risque-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-risque-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-rowdies-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-rowdies-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-rowdies-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-rowdies-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ruge_boogie-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ruge_boogie-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ruslan_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-ruslan_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sacramento-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sacramento-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sancreek-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sancreek-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sankofa_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sankofa_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sedgwick_ave_display-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sedgwick_ave_display-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-shantell_sans-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-shantell_sans-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-smokum-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-smokum-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-solitreo-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-solitreo-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-spicy_rice-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-spicy_rice-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sriracha-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-sriracha-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-srisakdi-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-srisakdi-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-srisakdi-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-srisakdi-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-stix_two_math-400-0.woff2 +0 -0
- package/app/public/vendor/fonts/cat-tillana-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-tillana-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-tillana-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-tillana-700.woff2 +0 -0
- package/app/public/vendor/fonts/cat-titan_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-titan_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-yatra_one-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-yatra_one-400.woff2 +0 -0
- package/app/public/vendor/fonts/cat-yomogi-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/cat-yomogi-400.woff2 +0 -0
- package/app/public/vendor/fonts/dmserifdisplay-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/dmserifdisplay-400.woff2 +0 -0
- package/app/public/vendor/fonts/domine-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/domine-var.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/fraunces-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/fraunces-var.woff2 +0 -0
- package/app/public/vendor/fonts/fredoka-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/fredoka-var.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/jakarta-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/jakarta-var.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/lora-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/lora-var.woff2 +0 -0
- package/app/public/vendor/fonts/merriweather-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/merriweather-var.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/notosans-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/notosans-var.woff2 +0 -0
- package/app/public/vendor/fonts/nunito-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/nunito-var.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/playfair-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/playfair-var.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/quicksand-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/quicksand-var.woff2 +0 -0
- package/app/public/vendor/fonts/robotoflex-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/robotoflex-var.woff2 +0 -0
- package/app/public/vendor/fonts/sora-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/sora-var.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/spacegrotesk-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/spacegrotesk-var.woff2 +0 -0
- package/app/public/vendor/fonts/spectral-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/spectral-400.woff2 +0 -0
- package/app/public/vendor/fonts/spectral-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/spectral-700.woff2 +0 -0
- package/app/public/vendor/fonts/teachers-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/teachers-var.woff2 +0 -0
- package/app/public/vendor/fonts/ubuntu-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/ubuntu-400.woff2 +0 -0
- package/app/public/vendor/fonts/ubuntu-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/ubuntu-700.woff2 +0 -0
- package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
- package/dist-pkg/platform/guide-intensity.d.ts +0 -39
- package/dist-pkg/platform/guide-intensity.js +0 -71
- package/dist-pkg/ui/latch-refusal.d.ts +0 -33
- package/dist-pkg/ui/latch-refusal.js +0 -60
|
@@ -31,7 +31,7 @@ import { ACTIONS } from '../core/actions.js';
|
|
|
31
31
|
* on-screen legend. A help screen ordered by whatever order the game happened to write its object in would
|
|
32
32
|
* teach a different order from every other surface.
|
|
33
33
|
*
|
|
34
|
-
* @param preset
|
|
34
|
+
* @param preset this game's positions and their words, RESOLVED now in the page's language (`core/actions.wordsOf`).
|
|
35
35
|
* @param keysOf the codes bound to a position FOR THIS SEAT. `kbFor(seat)[action]`, so a child who remapped
|
|
36
36
|
* sees her own key. `null`/empty means the keyboard does not reach it.
|
|
37
37
|
* @param keyName code → readable label (`ui/settings-controls.keyName`), injected so this half stays pure.
|
|
@@ -57,6 +57,16 @@ export function helpRows(preset, keysOf, keyName) {
|
|
|
57
57
|
}
|
|
58
58
|
/** What the slide says where the keyboard reaches nothing. A KEY, not a sentence — the caller translates it. */
|
|
59
59
|
export const NO_KEY = 'help.noKey';
|
|
60
|
+
/**
|
|
61
|
+
* The cartridge's slides, their texts resolved NOW through `word` (`Translator.word`). A slide whose text the game's
|
|
62
|
+
* dictionaries lack is left out — never shown as its key — and `problems` names it (`ui/declared-words`).
|
|
63
|
+
*/
|
|
64
|
+
export function playSlidesOf(slides, word) {
|
|
65
|
+
return slides.flatMap((s) => {
|
|
66
|
+
const text = word(s.textKey);
|
|
67
|
+
return text ? [{ text, ...(s.figure ? { figure: s.figure } : {}) }] : [];
|
|
68
|
+
});
|
|
69
|
+
}
|
|
60
70
|
/** Why a `howToPlay` declaration is malformed; empty when well formed. Absent is well formed: the help shows the buttons alone. */
|
|
61
71
|
export function howToPlayProblems(slides) {
|
|
62
72
|
if (slides === undefined)
|
|
@@ -70,14 +80,14 @@ export function howToPlayProblems(slides) {
|
|
|
70
80
|
out.push(`${at} must be a slide`);
|
|
71
81
|
return;
|
|
72
82
|
}
|
|
73
|
-
if (typeof s.
|
|
74
|
-
out.push(`${at}.
|
|
83
|
+
if (typeof s.textKey !== 'string' || !s.textKey.trim())
|
|
84
|
+
out.push(`${at}.textKey must name the slide's text by a key of the game's dictionary`);
|
|
75
85
|
if (s.figure !== undefined && typeof s.figure !== 'function')
|
|
76
86
|
out.push(`${at}.figure must be a function drawing on the surface it is given`);
|
|
77
87
|
});
|
|
78
88
|
return out;
|
|
79
89
|
}
|
|
80
|
-
const isFromGame = (s) => typeof s.text === '
|
|
90
|
+
const isFromGame = (s) => typeof s.text === 'string';
|
|
81
91
|
/**
|
|
82
92
|
* Draws the shown slide's figure, and keeps drawing it while the slide show is in the document and the same slide is shown.
|
|
83
93
|
* Returns a stop. A figure that throws is a cartridge defect: it stops drawing and the text stays.
|
|
@@ -208,7 +218,7 @@ function showPlaySlide(p, r) {
|
|
|
208
218
|
p.figure.hidden = !r.figure;
|
|
209
219
|
p.keyCap.hidden = true;
|
|
210
220
|
p.word.hidden = true;
|
|
211
|
-
const phrase = r.text
|
|
221
|
+
const phrase = r.text;
|
|
212
222
|
p.text.textContent = phrase;
|
|
213
223
|
p.text.hidden = false;
|
|
214
224
|
return joinParts([phrase]);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
-
import type {
|
|
3
|
-
import type { Translate } from '../core/i18n.js';
|
|
2
|
+
import type { Translator } from '../core/i18n.js';
|
|
4
3
|
export type HudBand = 'identity' | 'mission' | 'power' | 'learning';
|
|
5
4
|
/**
|
|
6
5
|
* A skill's bar, as `educational/segment-bar.barOf` returns it — the same field names and values, so its `Bar` passes
|
|
@@ -12,8 +11,8 @@ export interface HudBar {
|
|
|
12
11
|
}
|
|
13
12
|
export type HudNumber = {
|
|
14
13
|
readonly band: 'identity' | 'mission' | 'power';
|
|
15
|
-
/**
|
|
16
|
-
readonly
|
|
14
|
+
/** The key of what is counted («points», «balls») in the game's dictionary. */
|
|
15
|
+
readonly nameKey: string;
|
|
17
16
|
/** A count, or how many of how many, for seat `seat`. Read on every animation frame while mounted: keep it cheap. */
|
|
18
17
|
readonly value: (seat: number) => number | {
|
|
19
18
|
readonly have: number;
|
|
@@ -21,25 +20,43 @@ export type HudNumber = {
|
|
|
21
20
|
};
|
|
22
21
|
} | {
|
|
23
22
|
readonly band: 'learning';
|
|
24
|
-
/** The skill
|
|
25
|
-
readonly
|
|
23
|
+
/** The key of the skill's name in the game's dictionary. */
|
|
24
|
+
readonly nameKey: string;
|
|
26
25
|
readonly value: (seat: number) => HudBar;
|
|
27
26
|
};
|
|
27
|
+
/** What the HUD asks of the root's translator: the engine's frames, and the game's declared words. */
|
|
28
|
+
type HudTranslator = Pick<Translator, 't' | 'word'>;
|
|
28
29
|
/** Why a `hud` declaration is malformed; empty when it is well formed. Absent is well formed: no HUD is mounted. */
|
|
29
30
|
export declare function hudNumbersProblems(numbers: unknown): string[];
|
|
31
|
+
/** The HUD row's cells the bands go into (`ui/hud-row`, ADR-0239). */
|
|
32
|
+
export interface HudRowSlots {
|
|
33
|
+
readonly learning: HTMLElement;
|
|
34
|
+
readonly score: HTMLElement;
|
|
35
|
+
}
|
|
30
36
|
export interface HudBandsMounted {
|
|
31
|
-
/** The top
|
|
37
|
+
/** The mission, at the top centre under the quick bar (the name is from when it sat top left). */
|
|
32
38
|
readonly left: HTMLElement;
|
|
33
|
-
/** The
|
|
39
|
+
/** The power in use, above the score. */
|
|
34
40
|
readonly right: HTMLElement;
|
|
41
|
+
/** The identity numbers — the score — in five digits (ADR-0238). */
|
|
42
|
+
readonly points: HTMLElement;
|
|
35
43
|
readonly learning: HTMLElement;
|
|
36
44
|
/** Rewrites what changed; `true` when a text at the top did, so the caller measures the room again. */
|
|
37
45
|
refresh(): boolean;
|
|
38
46
|
remove(): void;
|
|
39
47
|
}
|
|
40
48
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
|
|
49
|
+
* A count as FIVE DIGITS WITH LEADING ZEROS, clamped to 0…99999 (ADR-0238): 12 is «00012». `shown` is the number those digits
|
|
50
|
+
* say, which is what a listener hears — the same number a sighted child sees, never the zeros.
|
|
51
|
+
*/
|
|
52
|
+
export declare function fiveDigits(count: number): {
|
|
53
|
+
readonly digits: string;
|
|
54
|
+
readonly shown: number;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Mounts the bands, one element per declared number, and fills them: the mission in the game region, the rest in the HUD
|
|
58
|
+
* row's cells (`row`). A place with no number is hidden. Without a row every band goes in the region itself — the learning
|
|
59
|
+
* band BEFORE the screen footer when one exists, so the explanation band, drawn later on the same layer, covers it.
|
|
44
60
|
*/
|
|
45
|
-
export declare function mountHudBands(
|
|
61
|
+
export declare function mountHudBands(tr: HudTranslator, doc: Document, region: HTMLElement, numbers: readonly HudNumber[], seat?: number, row?: HudRowSlots): HudBandsMounted;
|
|
62
|
+
export {};
|
package/dist-pkg/ui/hud-bands.js
CHANGED
|
@@ -13,8 +13,8 @@ export function hudNumbersProblems(numbers) {
|
|
|
13
13
|
numbers.forEach((n, i) => {
|
|
14
14
|
if (!n || !HUD_BANDS.includes(n.band))
|
|
15
15
|
out.push(`hud[${i}].band must be one of ${HUD_BANDS.join(', ')}`);
|
|
16
|
-
if (!n || typeof n.
|
|
17
|
-
out.push(`hud[${i}].
|
|
16
|
+
if (!n || typeof n.nameKey !== 'string' || !n.nameKey.trim())
|
|
17
|
+
out.push(`hud[${i}].nameKey must name what is counted by a key of the game's dictionary`);
|
|
18
18
|
if (!n || typeof n.value !== 'function')
|
|
19
19
|
out.push(`hud[${i}].value must be a function of the seat`);
|
|
20
20
|
});
|
|
@@ -23,12 +23,29 @@ export function hudNumbersProblems(numbers) {
|
|
|
23
23
|
out.push(`hud declares ${bars} learning bars: at most ${MAX_BARS}, one per skill the adult enabled (ADR-0049 §5)`);
|
|
24
24
|
return out;
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/** The highest count five digits hold; a larger score is shown as this (ADR-0238). */
|
|
27
|
+
const MAX_POINTS = 99_999;
|
|
28
|
+
/**
|
|
29
|
+
* A count as FIVE DIGITS WITH LEADING ZEROS, clamped to 0…99999 (ADR-0238): 12 is «00012». `shown` is the number those digits
|
|
30
|
+
* say, which is what a listener hears — the same number a sighted child sees, never the zeros.
|
|
31
|
+
*/
|
|
32
|
+
export function fiveDigits(count) {
|
|
33
|
+
const shown = Math.min(MAX_POINTS, Math.max(0, Math.floor(count) || 0));
|
|
34
|
+
return { digits: String(shown).padStart(5, '0'), shown };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* What the child reads, and — for the points — what a listener hears instead (`label`): the frame in the dictionary, the name
|
|
38
|
+
* — resolved from the game's key at this refresh (ADR-0232 D3) — through a parameter (pillar 3). A count of objectives keeps
|
|
39
|
+
* its «3 of 10» wherever it is declared.
|
|
40
|
+
*/
|
|
41
|
+
function lineFace(t, name, n, seat) {
|
|
28
42
|
const v = n.value(seat);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
43
|
+
if (typeof v !== 'number')
|
|
44
|
+
return { text: t('hud.contador', { have: String(v.have), need: String(v.need), nome: name }), label: null };
|
|
45
|
+
if (n.band !== 'identity')
|
|
46
|
+
return { text: t('hud.numero', { nome: name, valor: String(v) }), label: null };
|
|
47
|
+
const { digits, shown } = fiveDigits(v);
|
|
48
|
+
return { text: digits, label: t('hud.points', { count: String(shown), name }) };
|
|
32
49
|
}
|
|
33
50
|
function barLabel(t, name, bar) {
|
|
34
51
|
const count = (c) => String(bar.segmentos.filter((s) => s === c).length);
|
|
@@ -36,11 +53,12 @@ function barLabel(t, name, bar) {
|
|
|
36
53
|
return bar.cor === 'roxa' ? `${base}. ${t('hud.barra.sobe')}` : bar.cor === 'laranja' ? `${base}. ${t('hud.barra.desce')}` : base;
|
|
37
54
|
}
|
|
38
55
|
/**
|
|
39
|
-
* Mounts the
|
|
40
|
-
*
|
|
41
|
-
* same layer, covers it.
|
|
56
|
+
* Mounts the bands, one element per declared number, and fills them: the mission in the game region, the rest in the HUD
|
|
57
|
+
* row's cells (`row`). A place with no number is hidden. Without a row every band goes in the region itself — the learning
|
|
58
|
+
* band BEFORE the screen footer when one exists, so the explanation band, drawn later on the same layer, covers it.
|
|
42
59
|
*/
|
|
43
|
-
export function mountHudBands(
|
|
60
|
+
export function mountHudBands(tr, doc, region, numbers, seat = 0, row) {
|
|
61
|
+
const { t } = tr;
|
|
44
62
|
const band = (cls, count) => {
|
|
45
63
|
const el = doc.createElement('div');
|
|
46
64
|
el.className = `hud-faixa ${cls}`;
|
|
@@ -49,17 +67,17 @@ export function mountHudBands(t, doc, region, numbers, seat = 0) {
|
|
|
49
67
|
};
|
|
50
68
|
const texts = numbers.filter((n) => n.band !== 'learning');
|
|
51
69
|
const bars = numbers.filter((n) => n.band === 'learning');
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const right = band('hud-direita', rightTexts.length);
|
|
70
|
+
const ofBand = (b) => texts.filter((n) => n.band === b);
|
|
71
|
+
const left = band('hud-esquerda', ofBand('mission').length);
|
|
72
|
+
const right = band('hud-direita', ofBand('power').length);
|
|
73
|
+
const points = band('hud-points', ofBand('identity').length);
|
|
57
74
|
const learning = band('hud-aprendizagem', bars.length);
|
|
58
|
-
const
|
|
75
|
+
const place = { identity: points, mission: left, power: right };
|
|
76
|
+
const lines = texts.map((n) => {
|
|
59
77
|
const p = doc.createElement('p');
|
|
60
78
|
p.className = 'hud-numero';
|
|
61
79
|
p.dataset.band = n.band;
|
|
62
|
-
|
|
80
|
+
place[n.band].appendChild(p);
|
|
63
81
|
return [n, p];
|
|
64
82
|
});
|
|
65
83
|
const bardivs = bars.map((n) => {
|
|
@@ -72,21 +90,40 @@ export function mountHudBands(t, doc, region, numbers, seat = 0) {
|
|
|
72
90
|
return [n, div];
|
|
73
91
|
});
|
|
74
92
|
region.appendChild(left);
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
// the power ABOVE the score (ADR-0239 point 3): the order of the two in their cell is the order on screen
|
|
94
|
+
(row?.score ?? region).append(right, points);
|
|
95
|
+
if (row)
|
|
96
|
+
row.learning.appendChild(learning);
|
|
97
|
+
else
|
|
98
|
+
region.insertBefore(learning, [...region.children].find((c) => c.classList.contains('rodape-da-tela')) ?? null);
|
|
77
99
|
function refresh() {
|
|
78
100
|
let changed = false;
|
|
79
101
|
for (const [n, p] of lines) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
102
|
+
// a name the game's dictionaries lack hides its line — never its key on screen (`problems` names it)
|
|
103
|
+
const name = tr.word(n.nameKey);
|
|
104
|
+
if (p.hidden !== !name) {
|
|
105
|
+
p.hidden = !name;
|
|
83
106
|
changed = true;
|
|
84
107
|
}
|
|
108
|
+
const face = name ? lineFace(t, name, n, seat) : { text: '', label: null };
|
|
109
|
+
if (p.textContent !== face.text) {
|
|
110
|
+
p.textContent = face.text;
|
|
111
|
+
changed = true;
|
|
112
|
+
}
|
|
113
|
+
// the points are an image of a number for a listener: the name says «12 points», never «zero zero zero one two»
|
|
114
|
+
if (face.label !== null && p.getAttribute('aria-label') !== face.label) {
|
|
115
|
+
p.setAttribute('role', 'img');
|
|
116
|
+
p.setAttribute('aria-label', face.label);
|
|
117
|
+
}
|
|
85
118
|
}
|
|
86
119
|
for (const [n, div] of bardivs) {
|
|
120
|
+
const name = tr.word(n.nameKey);
|
|
121
|
+
div.hidden = !name;
|
|
122
|
+
if (!name)
|
|
123
|
+
continue;
|
|
87
124
|
const bar = n.value(seat);
|
|
88
125
|
const shown = bar.segmentos.slice(-SEGMENTS);
|
|
89
|
-
const label = barLabel(t,
|
|
126
|
+
const label = barLabel(t, name, { segmentos: shown, cor: bar.cor }); // in the key: a language change rewrites it
|
|
90
127
|
const key = `${bar.cor}:${shown.join(',')}:${label}`;
|
|
91
128
|
if (div.dataset.estado === key)
|
|
92
129
|
continue;
|
|
@@ -101,8 +138,9 @@ export function mountHudBands(t, doc, region, numbers, seat = 0) {
|
|
|
101
138
|
return {
|
|
102
139
|
left,
|
|
103
140
|
right,
|
|
141
|
+
points,
|
|
104
142
|
learning,
|
|
105
143
|
refresh,
|
|
106
|
-
remove: () => { left.remove(); right.remove(); learning.remove(); },
|
|
144
|
+
remove: () => { left.remove(); points.remove(); right.remove(); learning.remove(); },
|
|
107
145
|
};
|
|
108
146
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/** The row's cells, each a place something else fills: the bands (`ui/hud-bands`), the clock (`ui/session-clock`), the map. */
|
|
3
|
+
export interface HudRow {
|
|
4
|
+
readonly row: HTMLElement;
|
|
5
|
+
/** Bottom left: the learning bars. */
|
|
6
|
+
readonly learning: HTMLElement;
|
|
7
|
+
/** Bottom centre: the session clock. */
|
|
8
|
+
readonly clock: HTMLElement;
|
|
9
|
+
/** Between the centre and the right: the power above the score. */
|
|
10
|
+
readonly score: HTMLElement;
|
|
11
|
+
/** Bottom right: where a game mounts its own map. Empty, it is not drawn (ADR-0239 point 4). */
|
|
12
|
+
readonly map: HTMLElement;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Builds the row in `region`, BEFORE the screen footer when one exists, so the explanation band — drawn later on the same
|
|
16
|
+
* layer — covers it. `null` where the region takes no children.
|
|
17
|
+
*/
|
|
18
|
+
export declare function mountHudRow(doc: Document, region: HTMLElement | null): HudRow | null;
|
|
19
|
+
/** What `reserveBottomBand` measures. The pad is the on-screen controller (`#touch-controls`), when the page has one. */
|
|
20
|
+
export interface BottomBandCtx {
|
|
21
|
+
readonly region: HTMLElement | null;
|
|
22
|
+
readonly row: HTMLElement | null;
|
|
23
|
+
readonly pad: HTMLElement | null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* THE ROW FOLLOWS THE PAD AT ONCE (ADR-0239 §6): `measure` runs again whenever the on-screen pad under `host` shows, hides or is
|
|
27
|
+
* rebuilt, by whichever door — a touch, a key, a menu opening or closing (ADR-0166), a new cartridge. A resize and the session
|
|
28
|
+
* clock's tick are not enough: between them the row stood behind the pad for up to a second, and the explanation band that
|
|
29
|
+
* stands where the row stands lay over the pad's START pill. A mutation observer answers before the next frame is drawn.
|
|
30
|
+
* Returns what stops it; nothing is watched where the host has no observer.
|
|
31
|
+
*/
|
|
32
|
+
export declare function followThePad(host: Node | null, Observer: typeof MutationObserver | undefined, measure: () => void): () => void;
|
|
33
|
+
/** Measures the bottom and writes `--hud-row-bottom` and `--hud-row-h` on the region (see the header). */
|
|
34
|
+
export declare function reserveBottomBand(ctx: BottomBandCtx): void;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// ui/hud-row — THE HUD IS ONE ROW AT THE BOTTOM of the game region (ADR-0239; issue #94), and this module builds the row's
|
|
3
|
+
// cells and measures the room it takes.
|
|
4
|
+
//
|
|
5
|
+
// Left to right: the learning bars · the session clock, in the centre · the score, with the power above it · the game's map.
|
|
6
|
+
// The mission is not here: it sits at the top centre, just under the quick bar (ADR-0239 erratum; `ui/top-band`).
|
|
7
|
+
//
|
|
8
|
+
// WHO SITS OVER WHOM at the bottom (ADR-0239 point 6), written as two variables on the region that the stylesheet reads:
|
|
9
|
+
// · `--hud-row-bottom` — how far above the region's lower edge the row stands: 0, or the height of the on-screen pad's
|
|
10
|
+
// lower parts while the pad shows, so the row sits ABOVE the pad;
|
|
11
|
+
// · `--hud-row-h` — the row's own height, so the sound caption and the button legend sit above it, and a game's workspace
|
|
12
|
+
// ends above it: `--rodape-h` is these two and nothing else, because the caption and the legend are momentary and
|
|
13
|
+
// overlay the workspace while they show (ADR-0239 erratum).
|
|
14
|
+
// The explanation band covers the row while a menu is open: that is the stylesheet's alone.
|
|
15
|
+
//
|
|
16
|
+
// ⚠️ IT RECEIVES THE NODES and reaches no global (ADR-0232), like `ui/top-band`.
|
|
17
|
+
/**
|
|
18
|
+
* Builds the row in `region`, BEFORE the screen footer when one exists, so the explanation band — drawn later on the same
|
|
19
|
+
* layer — covers it. `null` where the region takes no children.
|
|
20
|
+
*/
|
|
21
|
+
export function mountHudRow(doc, region) {
|
|
22
|
+
if (!region || typeof region.insertBefore !== 'function')
|
|
23
|
+
return null;
|
|
24
|
+
const cell = (cls) => { const el = doc.createElement('div'); el.className = cls; return el; };
|
|
25
|
+
const row = cell('hud-row');
|
|
26
|
+
const learning = cell('hud-row-cell hud-row-learning');
|
|
27
|
+
const clock = cell('hud-row-cell hud-row-clock');
|
|
28
|
+
const end = cell('hud-row-cell hud-row-end');
|
|
29
|
+
const score = cell('hud-score');
|
|
30
|
+
const map = cell('hud-map');
|
|
31
|
+
end.appendChild(score);
|
|
32
|
+
end.appendChild(map);
|
|
33
|
+
for (const c of [learning, clock, end])
|
|
34
|
+
row.appendChild(c);
|
|
35
|
+
// `children` may be missing in a host double; then there is no footer to go before
|
|
36
|
+
region.insertBefore(row, Array.from(region.children ?? []).find((c) => c.classList.contains('rodape-da-tela')) ?? null);
|
|
37
|
+
return { row, learning, clock, score, map };
|
|
38
|
+
}
|
|
39
|
+
/** A pad part counts when it stands on the region's lower edge — within this many pixels of it. */
|
|
40
|
+
const ON_THE_EDGE_PX = 24;
|
|
41
|
+
/** How high the pad's lower parts reach above the region's lower edge while the pad shows; 0 when it is hidden or absent. */
|
|
42
|
+
function padReach(pad, regionBottom) {
|
|
43
|
+
if (!pad || pad.hidden)
|
|
44
|
+
return 0;
|
|
45
|
+
let reach = 0;
|
|
46
|
+
for (const part of [...pad.children]) {
|
|
47
|
+
const b = part.getBoundingClientRect();
|
|
48
|
+
if (b.height > 0 && regionBottom - b.bottom <= ON_THE_EDGE_PX)
|
|
49
|
+
reach = Math.max(reach, regionBottom - b.top);
|
|
50
|
+
}
|
|
51
|
+
return reach;
|
|
52
|
+
}
|
|
53
|
+
/** The pad, or a part of it, in a mutation: its `hidden` changed, its parts were rebuilt, or it came or went. */
|
|
54
|
+
function aboutThePad(r) {
|
|
55
|
+
return [r.target, ...Array.from(r.addedNodes), ...Array.from(r.removedNodes)].some((n) => !!n.closest?.('#touch-controls'));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* THE ROW FOLLOWS THE PAD AT ONCE (ADR-0239 §6): `measure` runs again whenever the on-screen pad under `host` shows, hides or is
|
|
59
|
+
* rebuilt, by whichever door — a touch, a key, a menu opening or closing (ADR-0166), a new cartridge. A resize and the session
|
|
60
|
+
* clock's tick are not enough: between them the row stood behind the pad for up to a second, and the explanation band that
|
|
61
|
+
* stands where the row stands lay over the pad's START pill. A mutation observer answers before the next frame is drawn.
|
|
62
|
+
* Returns what stops it; nothing is watched where the host has no observer.
|
|
63
|
+
*/
|
|
64
|
+
export function followThePad(host, Observer, measure) {
|
|
65
|
+
if (!host || typeof Observer !== 'function')
|
|
66
|
+
return () => { };
|
|
67
|
+
const observer = new Observer((records) => { if (records.some(aboutThePad))
|
|
68
|
+
measure(); });
|
|
69
|
+
observer.observe(host, { attributes: true, attributeFilter: ['hidden'], childList: true, subtree: true });
|
|
70
|
+
return () => observer.disconnect();
|
|
71
|
+
}
|
|
72
|
+
/** Measures the bottom and writes `--hud-row-bottom` and `--hud-row-h` on the region (see the header). */
|
|
73
|
+
export function reserveBottomBand(ctx) {
|
|
74
|
+
const { region, row } = ctx;
|
|
75
|
+
if (!region || !row || typeof region.getBoundingClientRect !== 'function')
|
|
76
|
+
return;
|
|
77
|
+
const lift = Math.ceil(padReach(ctx.pad, region.getBoundingClientRect().bottom));
|
|
78
|
+
region.style.setProperty('--hud-row-bottom', `${lift}px`);
|
|
79
|
+
region.style.setProperty('--hud-row-h', `${Math.ceil(row.getBoundingClientRect().height)}px`);
|
|
80
|
+
}
|
package/dist-pkg/ui/hud.d.ts
CHANGED
|
@@ -3,15 +3,12 @@ import type { PlayerView } from '../core/entity.js';
|
|
|
3
3
|
import type { Objective } from '../core/contract.js';
|
|
4
4
|
import type { Translate } from '../core/i18n.js';
|
|
5
5
|
import type { DomQuery } from '../core/dom-query.js';
|
|
6
|
-
/** Minimal DOM-selector shape (matches ui/dom.ts's `$`). */
|
|
7
|
-
export type { DomQuery } from '../core/dom-query.js';
|
|
8
6
|
/** Only the player fields the HUD reads. Structural on purpose: the real `players[]` is `unknown[]` in core/state. */
|
|
9
7
|
/** What the HUD reads from the PLAYER: the active power and whether they quit. Progress comes from the `Objective`,
|
|
10
8
|
* not from here. */
|
|
11
9
|
export type HudPlayer = PlayerView<'activePower' | 'quit'>;
|
|
12
10
|
/** Screen grid: 1 → 1×1, 2 → 2×1, 3-4 → 2×2 (the 3rd screen is centred on the bottom row). */
|
|
13
11
|
export { screenGrid } from '../core/screens.js';
|
|
14
|
-
export type { ScreenGrid } from '../core/screens.js';
|
|
15
12
|
/** Screen `i`'s rectangle in CSS percentages, ready for `style.left/top/width/height`. */
|
|
16
13
|
export interface ScreenRect {
|
|
17
14
|
L: string;
|
package/dist-pkg/ui/layout.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// the target floor, the reporters' rules) is exported as functions; `createLayout` is the shell that measures a
|
|
5
5
|
// document it is HANDED and calls `afterScale` (the root's CRT re-anchoring its scanlines) — ADR-0232 D4, issue #207.
|
|
6
6
|
//
|
|
7
|
-
// IT RESERVES NO SPACE FOR THE INTERPRETER:
|
|
8
|
-
//
|
|
7
|
+
// IT RESERVES NO SPACE FOR THE INTERPRETER: in deaf mode the interpreter appears IN FRONT of the screen when the sonar
|
|
8
|
+
// calls it (ADR-0234, see ui/vlibras), so the layout does not shift the game for it.
|
|
9
9
|
import { screenBaseSize } from '../core/screens.js';
|
|
10
10
|
/**
|
|
11
11
|
* THE TOUCH TARGET FLOOR, in CSS px, for a CSS scale factor `k` (ADR-0163).
|
|
@@ -93,6 +93,9 @@ export function applyScale(region, e) {
|
|
|
93
93
|
// from `minimumTarget`, so a display scale that gives k under 2 (Windows 110%) no longer drops `--tap` under 44 px.
|
|
94
94
|
region.style.setProperty('--tap', minimumTarget(e.k) + 'px');
|
|
95
95
|
region.style.setProperty('--alvo-min', minimumTarget(e.k) + 'px'); // 44 px at 640×360, growing with k (ADR-0163)
|
|
96
|
+
// THE EDGE MARGIN (interface log 2026-09-26): 4 logical px between the region's edge and every text and button but the quick
|
|
97
|
+
// bar's — 8 px at 640×360, growing with k like the text. The stylesheet reads it; the quick bar keeps the edge (ADR-0180).
|
|
98
|
+
region.style.setProperty('--margem-borda', (4 * e.k) + 'px');
|
|
96
99
|
}
|
|
97
100
|
/**
|
|
98
101
|
* Builds a stage scaler over the document and window it is handed. It keeps nothing between calls: every `layout()`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/** One track of a three.js AnimationClip JSON, as the export writes it. */
|
|
3
|
+
export interface TrackJson {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly type: string;
|
|
6
|
+
readonly times: readonly number[];
|
|
7
|
+
readonly values: readonly number[];
|
|
8
|
+
readonly interpolation?: number;
|
|
9
|
+
}
|
|
10
|
+
/** A three.js AnimationClip JSON (`AnimationClip.parse`), as the export writes it. */
|
|
11
|
+
export interface ClipJson {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly duration: number;
|
|
14
|
+
readonly tracks: readonly TrackJson[];
|
|
15
|
+
}
|
|
16
|
+
/** A track's value at `time`, as three.js interpolates it: held before the first key and after the last. */
|
|
17
|
+
export declare function valueAt(track: TrackJson, time: number): number[];
|
|
18
|
+
/**
|
|
19
|
+
* The clip from `from` seconds on, its times shifted to start at zero: each track keeps its value AT `from` as its first key,
|
|
20
|
+
* then its later keys. A track whose keys all lie before `from` holds its last value. `from` of zero is the clip itself.
|
|
21
|
+
*/
|
|
22
|
+
export declare function clipFrom(clip: ClipJson, from: number): ClipJson;
|
|
23
|
+
/**
|
|
24
|
+
* The face's tracks, bound to every mesh that carries the morph targets. The export names a morph track after the head's NODE
|
|
25
|
+
* (`cabecaModifAlisson.morphTargetInfluences[Sorriso]`), and three.js loads a node whose mesh has two primitives as a GROUP of
|
|
26
|
+
* two meshes, each with its own copy of the targets — a track on the group moves neither. `meshesOf(node)` answers the meshes
|
|
27
|
+
* a track on that node must reach (by the names three.js binds, e.g. their uuids), or `null` where the node is itself the mesh;
|
|
28
|
+
* the track is written once for each.
|
|
29
|
+
*/
|
|
30
|
+
export declare function bindFaceTracks(clip: ClipJson, meshesOf: (node: string) => readonly string[] | null): ClipJson;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// ui/libras-avatar-clip — A SIGN CLIP, BEFORE three.js READS IT (ADR-0234, route B, phase B2). Pure: no three.js, no DOM.
|
|
3
|
+
//
|
|
4
|
+
// The B1 export hands each sign over as three.js AnimationClip JSON (`scripts/libras-export.mjs`), and two things about it are
|
|
5
|
+
// answered here, on the JSON, where node can hold them (`tests/libras-avatar-plan.node.test.js`): a clip whose sign starts
|
|
6
|
+
// later than the clip does — FALA, whose export starts at a stray keyframe — is played from its sign (`clipFrom`), and the
|
|
7
|
+
// face's tracks, named after the head's node, are written for each mesh three.js loads the head as (`bindFaceTracks`).
|
|
8
|
+
// `ui/libras-avatar-stage` parses what comes out.
|
|
9
|
+
/** three.js `InterpolateDiscrete`: the export marks a STEP track with it. */
|
|
10
|
+
const DISCRETE = 2300;
|
|
11
|
+
function slerp(a, b, u) {
|
|
12
|
+
let dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
|
|
13
|
+
const bb = dot < 0 ? b.map((x) => -x) : [...b];
|
|
14
|
+
dot = Math.abs(dot);
|
|
15
|
+
if (dot > 0.9995) {
|
|
16
|
+
const q = a.map((x, c) => x + (bb[c] - x) * u);
|
|
17
|
+
const l = Math.hypot(...q);
|
|
18
|
+
return q.map((x) => x / l);
|
|
19
|
+
}
|
|
20
|
+
const th = Math.acos(dot);
|
|
21
|
+
const s = Math.sin(th);
|
|
22
|
+
return a.map((x, c) => (Math.sin((1 - u) * th) * x + Math.sin(u * th) * bb[c]) / s);
|
|
23
|
+
}
|
|
24
|
+
/** A track's value at `time`, as three.js interpolates it: held before the first key and after the last. */
|
|
25
|
+
export function valueAt(track, time) {
|
|
26
|
+
const { times, values } = track;
|
|
27
|
+
const width = values.length / times.length;
|
|
28
|
+
const key = (i) => values.slice(i * width, i * width + width);
|
|
29
|
+
const last = times.length - 1;
|
|
30
|
+
if (time <= times[0] || last === 0)
|
|
31
|
+
return key(0);
|
|
32
|
+
if (time >= times[last])
|
|
33
|
+
return key(last);
|
|
34
|
+
let i = 0;
|
|
35
|
+
while (times[i + 1] <= time)
|
|
36
|
+
i += 1;
|
|
37
|
+
if (time === times[i] || track.interpolation === DISCRETE)
|
|
38
|
+
return key(i);
|
|
39
|
+
const u = (time - times[i]) / (times[i + 1] - times[i]);
|
|
40
|
+
const a = key(i);
|
|
41
|
+
const b = key(i + 1);
|
|
42
|
+
return track.type === 'quaternion' ? slerp(a, b, u) : a.map((x, c) => x + (b[c] - x) * u);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The clip from `from` seconds on, its times shifted to start at zero: each track keeps its value AT `from` as its first key,
|
|
46
|
+
* then its later keys. A track whose keys all lie before `from` holds its last value. `from` of zero is the clip itself.
|
|
47
|
+
*/
|
|
48
|
+
export function clipFrom(clip, from) {
|
|
49
|
+
if (!(from > 0))
|
|
50
|
+
return clip;
|
|
51
|
+
const tracks = clip.tracks.map((t) => {
|
|
52
|
+
const times = [0];
|
|
53
|
+
const values = [...valueAt(t, from)];
|
|
54
|
+
const width = t.values.length / t.times.length;
|
|
55
|
+
t.times.forEach((time, i) => {
|
|
56
|
+
if (time <= from)
|
|
57
|
+
return;
|
|
58
|
+
times.push(time - from);
|
|
59
|
+
values.push(...t.values.slice(i * width, i * width + width));
|
|
60
|
+
});
|
|
61
|
+
return { ...t, times, values };
|
|
62
|
+
});
|
|
63
|
+
return { name: clip.name, duration: Math.max(0, clip.duration - from), tracks };
|
|
64
|
+
}
|
|
65
|
+
const MORPH_TRACK = /^(.+)\.morphTargetInfluences\[(.+)\]$/u;
|
|
66
|
+
/**
|
|
67
|
+
* The face's tracks, bound to every mesh that carries the morph targets. The export names a morph track after the head's NODE
|
|
68
|
+
* (`cabecaModifAlisson.morphTargetInfluences[Sorriso]`), and three.js loads a node whose mesh has two primitives as a GROUP of
|
|
69
|
+
* two meshes, each with its own copy of the targets — a track on the group moves neither. `meshesOf(node)` answers the meshes
|
|
70
|
+
* a track on that node must reach (by the names three.js binds, e.g. their uuids), or `null` where the node is itself the mesh;
|
|
71
|
+
* the track is written once for each.
|
|
72
|
+
*/
|
|
73
|
+
export function bindFaceTracks(clip, meshesOf) {
|
|
74
|
+
const tracks = [];
|
|
75
|
+
for (const t of clip.tracks) {
|
|
76
|
+
const m = MORPH_TRACK.exec(t.name);
|
|
77
|
+
const meshes = m ? meshesOf(m[1]) : null;
|
|
78
|
+
if (!m || !meshes) {
|
|
79
|
+
tracks.push(t);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
for (const mesh of meshes)
|
|
83
|
+
tracks.push({ ...t, name: `${mesh}.morphTargetInfluences[${m[2]}]` });
|
|
84
|
+
}
|
|
85
|
+
return { ...clip, tracks };
|
|
86
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import { type AvatarManifest } from './libras-avatar-plan.js';
|
|
3
|
+
import type { AvatarStage } from './libras-avatar-stage.js';
|
|
4
|
+
/** The host's `fetch`, lent unbound — and called bare, never as a method of what carries it. */
|
|
5
|
+
export type FetchFile = ((url: string) => Promise<Response>) | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Why a delivery with no avatar cannot sign, and the fix (ADR-0169): the reason `NO_INTERPRETER` gives, word for word — the
|
|
8
|
+
* root's interpreter answers a delivery built without `--libras` exactly as a root with no player would.
|
|
9
|
+
*/
|
|
10
|
+
export declare const NOT_SHIPPED = "a Libras player is not installed in this delivery \u2014 build it with `inclusionist-heavy <folder> --libras`";
|
|
11
|
+
/** Why a request that waited across a `hide()` or the root's end was not signed. */
|
|
12
|
+
export declare const RELEASED = "the interpreter was taken off the screen before it signed";
|
|
13
|
+
/** Where the delivery's files are: the avatar's folder, its manifest, and the glosses `--libras` writes beside them. */
|
|
14
|
+
export interface AvatarPlace {
|
|
15
|
+
readonly folder: string;
|
|
16
|
+
readonly manifest: string;
|
|
17
|
+
readonly glosses: string;
|
|
18
|
+
}
|
|
19
|
+
/** The addresses under `base`, or `null` where it resolves nothing — a host whose document has no address finds no avatar. */
|
|
20
|
+
export declare function avatarPlace(base: string, folder?: string): AvatarPlace | null;
|
|
21
|
+
/** The delivery's manifest, or `null` for a delivery that did not ship the avatar. */
|
|
22
|
+
export declare const readManifest: (fetchFile: FetchFile, place: AvatarPlace) => Promise<AvatarManifest | null>;
|
|
23
|
+
/** The canvas the avatar is drawn on: the bottom right, in front of the screen, watched and never operated. */
|
|
24
|
+
export declare function avatarCanvas(doc: Document, title: string): HTMLCanvasElement;
|
|
25
|
+
export interface AvatarOpening {
|
|
26
|
+
readonly fetchFile: FetchFile;
|
|
27
|
+
/** The avatar's address, from the manifest. */
|
|
28
|
+
readonly avatarUrl: string;
|
|
29
|
+
readonly loadStage: (canvas: HTMLCanvasElement, avatar: ArrayBuffer) => Promise<AvatarStage>;
|
|
30
|
+
readonly timeoutMs: number;
|
|
31
|
+
readonly win: Pick<Window, 'setTimeout' | 'clearTimeout'>;
|
|
32
|
+
}
|
|
33
|
+
/** A stage, or why there is none. */
|
|
34
|
+
export type Opened = {
|
|
35
|
+
readonly stage: AvatarStage;
|
|
36
|
+
} | {
|
|
37
|
+
readonly reason: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Builds the stage on `canvas` from the delivery's avatar: the stage, or why not — an avatar the delivery cannot give, a device
|
|
41
|
+
* that cannot draw it, a load past `timeoutMs`. `wanted()` is asked when the stage arrives: false, and it is released at once.
|
|
42
|
+
* `cancel()` answers «released» now and clears the timer, so nothing of a released root outlives it.
|
|
43
|
+
*/
|
|
44
|
+
export declare function openAvatar(canvas: HTMLCanvasElement, o: AvatarOpening, wanted: () => boolean): {
|
|
45
|
+
readonly done: Promise<Opened>;
|
|
46
|
+
readonly cancel: () => void;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Makes each clip of `names` playable on `stage`, fetching the ones it has not got — once each, remembered in `ready` — and
|
|
50
|
+
* answers the names whose file could not be read or prepared.
|
|
51
|
+
*/
|
|
52
|
+
export declare function prepareClips(stage: AvatarStage, names: readonly string[], manifest: AvatarManifest, place: AvatarPlace, fetchFile: FetchFile, ready: Map<string, Promise<boolean>>): Promise<string[]>;
|