@the-inclusionist/engine 8.0.0 → 10.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 +89 -78
- package/app/css/style.css +584 -374
- 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/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/jakarta-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/jakarta-var.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/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/playfair-var-ext.woff2 +0 -0
- package/app/public/vendor/fonts/playfair-var.woff2 +0 -0
- 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/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/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.css +1167 -51
- package/dist-pkg/boot/create-game.d.ts +467 -162
- package/dist-pkg/boot/create-game.js +3563 -426
- package/dist-pkg/core/a11y-sr.d.ts +25 -3
- package/dist-pkg/core/a11y-sr.js +40 -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 +107 -0
- package/dist-pkg/core/accommodations.js +178 -0
- package/dist-pkg/core/actions.d.ts +75 -51
- package/dist-pkg/core/actions.js +98 -69
- 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 +143 -163
- package/dist-pkg/core/contract.js +223 -207
- 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 +87 -41
- package/dist-pkg/core/i18n.js +206 -153
- 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/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 +321 -215
- package/dist-pkg/i18n/es.js +320 -215
- package/dist-pkg/i18n/pt.js +342 -215
- 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 +164 -145
- package/dist-pkg/input/gamepad.js +351 -559
- 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/keyboard-runtime.d.ts +18 -20
- package/dist-pkg/input/keyboard-runtime.js +23 -27
- package/dist-pkg/input/keyboard.d.ts +68 -62
- package/dist-pkg/input/keyboard.js +83 -105
- package/dist-pkg/input/keydown.d.ts +124 -132
- package/dist-pkg/input/keydown.js +283 -288
- package/dist-pkg/input/latch-edge.d.ts +25 -21
- package/dist-pkg/input/latch-edge.js +33 -35
- package/dist-pkg/input/latch-scope.d.ts +43 -47
- package/dist-pkg/input/latch-scope.js +66 -75
- package/dist-pkg/input/latch-store.d.ts +28 -29
- package/dist-pkg/input/latch-store.js +44 -47
- package/dist-pkg/input/latch-sync.d.ts +28 -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 +164 -0
- package/dist-pkg/input/pad-wizard.d.ts +96 -0
- package/dist-pkg/input/pad-wizard.js +205 -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 +42 -0
- package/dist-pkg/input/switch-scan.js +54 -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 -113
- package/dist-pkg/input/touch-bindings.js +158 -173
- package/dist-pkg/input/touch.d.ts +130 -70
- package/dist-pkg/input/touch.js +321 -123
- 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 +96 -114
- package/dist-pkg/input/transports.js +104 -106
- package/dist-pkg/input/virtual-controller.d.ts +46 -0
- package/dist-pkg/input/virtual-controller.js +41 -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 +43 -0
- package/dist-pkg/input/voice-map.js +125 -0
- package/dist-pkg/platform/audio-ambient.d.ts +13 -1
- package/dist-pkg/platform/audio-ambient.js +11 -13
- 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 +36 -39
- package/dist-pkg/platform/audio-sonar.d.ts +96 -113
- package/dist-pkg/platform/audio-sonar.js +245 -238
- package/dist-pkg/platform/audio.d.ts +53 -19
- package/dist-pkg/platform/audio.js +161 -169
- package/dist-pkg/platform/flash-sampler.d.ts +19 -0
- package/dist-pkg/platform/flash-sampler.js +79 -0
- package/dist-pkg/platform/guide-intensity.d.ts +26 -27
- package/dist-pkg/platform/guide-intensity.js +50 -52
- package/dist-pkg/platform/heavy-catalogue.d.ts +31 -0
- package/dist-pkg/platform/heavy-catalogue.js +223 -0
- package/dist-pkg/platform/heavy-mirror.d.ts +26 -0
- package/dist-pkg/platform/heavy-mirror.js +76 -0
- package/dist-pkg/platform/heavy.d.ts +104 -0
- package/dist-pkg/platform/heavy.js +169 -0
- package/dist-pkg/platform/interruptible-speech.d.ts +16 -16
- package/dist-pkg/platform/interruptible-speech.js +50 -51
- 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 +81 -0
- package/dist-pkg/platform/locale-host.d.ts +10 -0
- package/dist-pkg/platform/locale-host.js +34 -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 +40 -0
- package/dist-pkg/platform/reading-in-worker.js +87 -0
- package/dist-pkg/platform/reading-model.d.ts +73 -0
- package/dist-pkg/platform/reading-model.js +247 -0
- package/dist-pkg/platform/reading-runtime.d.ts +24 -0
- package/dist-pkg/platform/reading-runtime.js +159 -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 +69 -0
- package/dist-pkg/platform/reading.js +128 -0
- package/dist-pkg/platform/speech-recognition.d.ts +51 -0
- package/dist-pkg/platform/speech-recognition.js +84 -0
- package/dist-pkg/platform/speech.d.ts +14 -1
- package/dist-pkg/platform/speech.js +13 -13
- 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 +51 -38
- package/dist-pkg/platform/tts.js +217 -119
- 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 +36 -0
- package/dist-pkg/platform/voice-listener.js +88 -0
- package/dist-pkg/platform/voice-plan.d.ts +6 -102
- package/dist-pkg/platform/voice-plan.js +9 -151
- package/dist-pkg/platform/vosk-runtime.d.ts +71 -0
- package/dist-pkg/platform/vosk-runtime.js +93 -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 +46 -12
- package/dist-pkg/render/crt.js +82 -80
- package/dist-pkg/render/cvd-matrices.d.ts +18 -18
- package/dist-pkg/render/cvd-matrices.js +33 -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 +66 -54
- package/dist-pkg/render/high-contrast.js +221 -216
- 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 +80 -86
- package/dist-pkg/render/viz-axes.js +115 -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 +40 -0
- package/dist-pkg/ui/aac-sets.js +49 -0
- package/dist-pkg/ui/audio-choices.d.ts +63 -0
- package/dist-pkg/ui/audio-choices.js +94 -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 +6 -0
- package/dist-pkg/ui/camera-control.js +14 -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/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 +93 -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 +118 -63
- package/dist-pkg/ui/fonts.js +267 -111
- package/dist-pkg/ui/game-options.d.ts +42 -0
- package/dist-pkg/ui/game-options.js +138 -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 +76 -0
- package/dist-pkg/ui/help-panel.js +232 -0
- package/dist-pkg/ui/hud-bands.d.ts +45 -0
- package/dist-pkg/ui/hud-bands.js +108 -0
- package/dist-pkg/ui/hud.d.ts +73 -70
- 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/latch-refusal.d.ts +22 -21
- package/dist-pkg/ui/latch-refusal.js +37 -37
- package/dist-pkg/ui/layout.d.ts +103 -28
- package/dist-pkg/ui/layout.js +114 -99
- 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 +32 -0
- package/dist-pkg/ui/menu-intent.js +54 -0
- package/dist-pkg/ui/menu-items.d.ts +10 -0
- package/dist-pkg/ui/menu-items.js +22 -0
- package/dist-pkg/ui/menu-nav.d.ts +60 -90
- package/dist-pkg/ui/menu-nav.js +301 -274
- 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 +116 -0
- package/dist-pkg/ui/panel-widgets.js +208 -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 +250 -343
- package/dist-pkg/ui/pause-icons.js +614 -605
- 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 +42 -0
- package/dist-pkg/ui/settings-aac.d.ts +68 -0
- package/dist-pkg/ui/settings-aac.js +189 -0
- package/dist-pkg/ui/settings-audio.d.ts +91 -113
- package/dist-pkg/ui/settings-audio.js +407 -405
- package/dist-pkg/ui/settings-controls.d.ts +53 -92
- 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 +195 -0
- package/dist-pkg/ui/settings-mobility.js +374 -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 +48 -45
- package/dist-pkg/ui/settings-panel.js +164 -93
- package/dist-pkg/ui/settings-typo.d.ts +28 -76
- package/dist-pkg/ui/settings-typo.js +145 -125
- 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 +113 -134
- package/dist-pkg/ui/shell.js +143 -216
- 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 +4 -4
- package/dist-pkg/ui/title.js +11 -13
- package/dist-pkg/ui/top-band.d.ts +24 -0
- package/dist-pkg/ui/top-band.js +100 -0
- package/dist-pkg/ui/typo-choices.d.ts +71 -0
- package/dist-pkg/ui/typo-choices.js +84 -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 +33 -10
- package/dist-pkg/ui/vlibras.js +58 -81
- package/dist-pkg/ui/voice-control.d.ts +46 -0
- package/dist-pkg/ui/voice-control.js +143 -0
- package/dist-pkg/ui/voice-settings.d.ts +96 -0
- package/dist-pkg/ui/voice-settings.js +302 -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 +198 -54
- package/docs/LICENSES.md +160 -145
- package/package.json +24 -25
- package/scripts/heavy-into-the-delivery.mjs +144 -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/third-party.mjs +287 -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/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/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/map-hub.d.ts +0 -56
- package/dist-pkg/ui/map-hub.js +0 -138
- package/dist-pkg/ui/settings-caa.d.ts +0 -45
- package/dist-pkg/ui/settings-caa.js +0 -137
- package/dist-pkg/ui/settings-motor.d.ts +0 -175
- package/dist-pkg/ui/settings-motor.js +0 -342
- package/dist-pkg/ui/webcam.d.ts +0 -7
- package/dist-pkg/ui/webcam.js +0 -93
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Action } from '../core/actions.js';
|
|
3
|
+
import type { GazeZone } from './gaze-relative.js';
|
|
4
|
+
/** The safe item: leaving on it commands nothing. */
|
|
5
|
+
export declare const CANCEL = "cancel";
|
|
6
|
+
export type CycleItem = Action | typeof CANCEL;
|
|
7
|
+
/** Each zone's group: the direction, the face button on that side, the shoulder (ADR-0213). */
|
|
8
|
+
export declare const GAZE_GROUPS: {
|
|
9
|
+
readonly [Z in GazeZone]: readonly [Action, Action, Action];
|
|
10
|
+
};
|
|
11
|
+
export interface GazeCycleOptions {
|
|
12
|
+
readonly entryMs?: number;
|
|
13
|
+
readonly stepMs?: number;
|
|
14
|
+
readonly closeMs?: number;
|
|
15
|
+
readonly pulseMs?: number;
|
|
16
|
+
readonly cancelFirst?: boolean;
|
|
17
|
+
readonly repeat?: boolean;
|
|
18
|
+
readonly requireOpposite?: boolean;
|
|
19
|
+
readonly oppositeMs?: number;
|
|
20
|
+
readonly deadMs?: number;
|
|
21
|
+
}
|
|
22
|
+
/** The defaults the lab settled on (ADR-0213). */
|
|
23
|
+
export declare const GAZE_CYCLE_DEFAULTS: {
|
|
24
|
+
readonly entryMs: 800;
|
|
25
|
+
readonly stepMs: 1000;
|
|
26
|
+
readonly closeMs: 2000;
|
|
27
|
+
readonly pulseMs: 400;
|
|
28
|
+
readonly cancelFirst: true;
|
|
29
|
+
readonly repeat: true;
|
|
30
|
+
readonly requireOpposite: true;
|
|
31
|
+
readonly oppositeMs: 2000;
|
|
32
|
+
readonly deadMs: 700;
|
|
33
|
+
};
|
|
34
|
+
export interface GazeFrame {
|
|
35
|
+
readonly zone?: GazeZone | null;
|
|
36
|
+
readonly eyesClosed?: boolean;
|
|
37
|
+
/** Nothing could be read this frame. */
|
|
38
|
+
readonly frozen?: boolean;
|
|
39
|
+
/** Drop the gesture in hand without commanding. */
|
|
40
|
+
readonly cancel?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface GazePreview {
|
|
43
|
+
readonly zone: GazeZone;
|
|
44
|
+
readonly item: CycleItem;
|
|
45
|
+
readonly index: number;
|
|
46
|
+
}
|
|
47
|
+
export interface GazeCycleOutput {
|
|
48
|
+
/** The action being pressed, for `pulseMs` after it was commanded. */
|
|
49
|
+
readonly pressed: Action | null;
|
|
50
|
+
/** The action commanded on THIS frame. */
|
|
51
|
+
readonly commanded: Action | null;
|
|
52
|
+
/** What leaving the zone now would command. */
|
|
53
|
+
readonly preview: GazePreview | null;
|
|
54
|
+
/** How long both eyes have been closed. */
|
|
55
|
+
readonly closedMs: number;
|
|
56
|
+
/** The zone in hand came from its opposite, so it can command. */
|
|
57
|
+
readonly armed: boolean;
|
|
58
|
+
/** The zone in hand did not arm, and will prepare the opposite one. */
|
|
59
|
+
readonly preparing: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface GazeCycle {
|
|
62
|
+
(nowMs: number, frame: GazeFrame): GazeCycleOutput;
|
|
63
|
+
}
|
|
64
|
+
export declare function createGazeCycle(options?: GazeCycleOptions): GazeCycle;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// input/gaze-cycle — TWELVE ACTIONS AND START FROM FOUR GAZE ZONES (ADR-0213; issue #194).
|
|
3
|
+
//
|
|
4
|
+
// Four zones is all the eye signal can separate, so the second dimension is TIME: the zone says which group, how long the gaze stays says
|
|
5
|
+
// which action of the group. Each group is a direction, the face button on that side and a shoulder, and the child sees the action of the
|
|
6
|
+
// moment before anything is pressed.
|
|
7
|
+
//
|
|
8
|
+
// · A zone ARMS only when the gaze came from the OPPOSITE zone within `oppositeMs` — the movement is the command, not the position, and that
|
|
9
|
+
// is what separates a decision from a gaze walking around. The visit that did not arm becomes the PREPARATION for the next; an armed visit
|
|
10
|
+
// that reached the preview spends it, so going back and forth does not command both ways, and a flicker through the target does not.
|
|
11
|
+
// · While the gaze stays, the preview walks: cancel → direction → button → shoulder, every `stepMs` after `entryMs`, and round again. Cancel
|
|
12
|
+
// comes first, so a look that lands and leaves commands nothing.
|
|
13
|
+
// · The action leaves when the gaze LEAVES the zone, as a pulse of `pulseMs` — otherwise reaching the shoulder would press the direction on
|
|
14
|
+
// the way.
|
|
15
|
+
// · For `deadMs` after any action no visit becomes a preparation: the way back from a command overshoots into the opposite zone, and that
|
|
16
|
+
// rebound must not become the next gesture.
|
|
17
|
+
// · Both eyes closed for `closeMs` press START; while they are closed the cycle freezes, because with the lids down the gaze reading is noise.
|
|
18
|
+
// · A frame that could not be read (`frozen`: the head moving, no eyes) freezes the cycle too and commands nothing, not even START, and its
|
|
19
|
+
// time is given back — a frame with no reading must never look like the gaze leaving. `cancel` drops the gesture without commanding (the
|
|
20
|
+
// reader re-centred under the gaze, so what was held was never a decision).
|
|
21
|
+
/** The safe item: leaving on it commands nothing. */
|
|
22
|
+
export const CANCEL = 'cancel';
|
|
23
|
+
/** Each zone's group: the direction, the face button on that side, the shoulder (ADR-0213). */
|
|
24
|
+
export const GAZE_GROUPS = {
|
|
25
|
+
up: ['up', 'action4', 'rightShoulder'],
|
|
26
|
+
right: ['right', 'action3', 'rightTrigger'],
|
|
27
|
+
down: ['down', 'action2', 'leftTrigger'],
|
|
28
|
+
left: ['left', 'action1', 'leftShoulder'],
|
|
29
|
+
};
|
|
30
|
+
const OPPOSITE = { up: 'down', down: 'up', left: 'right', right: 'left' };
|
|
31
|
+
/** The defaults the lab settled on (ADR-0213). */
|
|
32
|
+
export const GAZE_CYCLE_DEFAULTS = {
|
|
33
|
+
entryMs: 800, stepMs: 1000, closeMs: 2000, pulseMs: 400,
|
|
34
|
+
cancelFirst: true, repeat: true, requireOpposite: true, oppositeMs: 2000, deadMs: 700,
|
|
35
|
+
};
|
|
36
|
+
export function createGazeCycle(options = {}) {
|
|
37
|
+
const o = { ...GAZE_CYCLE_DEFAULTS, ...options };
|
|
38
|
+
let zone = null, since = 0, index = -1, closedSince = null, frozenSince = null;
|
|
39
|
+
let pressed = null, pressedAt = 0, startGiven = false, armed = false;
|
|
40
|
+
let preparation = null, commandedAt = -Infinity;
|
|
41
|
+
const items = (z) => (o.cancelFirst ? [CANCEL, ...GAZE_GROUPS[z]] : [...GAZE_GROUPS[z], CANCEL]);
|
|
42
|
+
const preview = () => (zone && index >= 0 ? { zone, item: items(zone)[index], index } : null);
|
|
43
|
+
const mayPrepare = () => since - commandedAt >= o.deadMs;
|
|
44
|
+
const clear = (now) => { zone = null; since = 0; index = -1; frozenSince = null; armed = false; preparation = null; commandedAt = now; };
|
|
45
|
+
/** A frame with no reading: nothing moves, and the moment it began is kept, to give the time back. Returns the closed time. */
|
|
46
|
+
const holdFrozen = (now) => {
|
|
47
|
+
frozenSince ??= now;
|
|
48
|
+
return closedSince === null ? 0 : frozenSince - closedSince;
|
|
49
|
+
};
|
|
50
|
+
/** The reading is back: the time spent frozen is given back to the zone and to the closed eyes. */
|
|
51
|
+
const resumeFromFreeze = (now) => {
|
|
52
|
+
if (frozenSince === null)
|
|
53
|
+
return;
|
|
54
|
+
const paused = now - frozenSince;
|
|
55
|
+
since += paused;
|
|
56
|
+
if (closedSince !== null)
|
|
57
|
+
closedSince += paused;
|
|
58
|
+
frozenSince = null;
|
|
59
|
+
};
|
|
60
|
+
/** Both eyes closed: the cycle waits, and after `closeMs` presses START — once per closing. Returns the closed time. */
|
|
61
|
+
const whileClosed = (now, command) => {
|
|
62
|
+
closedSince ??= now;
|
|
63
|
+
if (!startGiven && now - closedSince >= o.closeMs) {
|
|
64
|
+
startGiven = true;
|
|
65
|
+
command('start');
|
|
66
|
+
clear(now);
|
|
67
|
+
}
|
|
68
|
+
return now - closedSince;
|
|
69
|
+
};
|
|
70
|
+
/** The eyes open again: the time they were closed is given back to the zone, and START may come again. */
|
|
71
|
+
const reopen = (now) => {
|
|
72
|
+
if (closedSince === null)
|
|
73
|
+
return;
|
|
74
|
+
since += now - closedSince;
|
|
75
|
+
closedSince = null;
|
|
76
|
+
startGiven = false;
|
|
77
|
+
};
|
|
78
|
+
/** Leaving a zone: an armed visit commands what its preview showed and spends the preparation; an unarmed one prepares. */
|
|
79
|
+
const leave = (now, command) => {
|
|
80
|
+
if (!zone)
|
|
81
|
+
return;
|
|
82
|
+
if (!armed) {
|
|
83
|
+
if (mayPrepare())
|
|
84
|
+
preparation = { zone, at: now };
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (index < 0)
|
|
88
|
+
return; // left before the preview showed anything
|
|
89
|
+
const item = items(zone)[index];
|
|
90
|
+
if (item !== CANCEL)
|
|
91
|
+
command(item);
|
|
92
|
+
preparation = null;
|
|
93
|
+
};
|
|
94
|
+
/** Entering a zone: it arms from its opposite, prepared inside the window — or at once when that rule is off. */
|
|
95
|
+
const enter = (next, now) => {
|
|
96
|
+
zone = next;
|
|
97
|
+
since = now;
|
|
98
|
+
index = -1;
|
|
99
|
+
armed = !next || !o.requireOpposite || (!!preparation && preparation.zone === OPPOSITE[next] && now - preparation.at <= o.oppositeMs);
|
|
100
|
+
};
|
|
101
|
+
/** While an armed gaze stays, the preview walks: −1 while the look settles, then one item every `stepMs`. */
|
|
102
|
+
const walk = (now) => {
|
|
103
|
+
if (!zone || !armed)
|
|
104
|
+
return;
|
|
105
|
+
const steps = Math.floor((now - since - o.entryMs) / o.stepMs), n = items(zone).length;
|
|
106
|
+
index = o.repeat ? steps % n : Math.min(n - 1, steps);
|
|
107
|
+
};
|
|
108
|
+
return (now, { zone: next = null, eyesClosed = false, frozen = false, cancel = false }) => {
|
|
109
|
+
let commanded = null;
|
|
110
|
+
const command = (action) => { commanded = action; pressed = action; pressedAt = now; commandedAt = now; };
|
|
111
|
+
const out = (closedMs) => {
|
|
112
|
+
if (pressed && now - pressedAt >= o.pulseMs)
|
|
113
|
+
pressed = null;
|
|
114
|
+
return { pressed, commanded, preview: preview(), closedMs, armed, preparing: !!zone && !armed && mayPrepare() };
|
|
115
|
+
};
|
|
116
|
+
if (cancel) {
|
|
117
|
+
clear(now);
|
|
118
|
+
return out(0);
|
|
119
|
+
}
|
|
120
|
+
if (frozen)
|
|
121
|
+
return out(holdFrozen(now));
|
|
122
|
+
resumeFromFreeze(now);
|
|
123
|
+
if (eyesClosed)
|
|
124
|
+
return out(whileClosed(now, command));
|
|
125
|
+
reopen(now);
|
|
126
|
+
if (next !== zone) {
|
|
127
|
+
leave(now, command);
|
|
128
|
+
enter(next, now);
|
|
129
|
+
}
|
|
130
|
+
walk(now);
|
|
131
|
+
return out(0);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { EyeGaze } from './face-signals.js';
|
|
3
|
+
/** The four zones, as the gaze moves on the screen. */
|
|
4
|
+
export type GazeZone = 'up' | 'down' | 'left' | 'right';
|
|
5
|
+
/** Why a frame gave no zone, or what the reader is doing; null when it is simply reading. */
|
|
6
|
+
export type GazeReason = 'no-eyes' | 'gaze-moving' | 'measuring-rest' | 'rest-measured' | 'head-moving' | 'recentring' | null;
|
|
7
|
+
export interface GazeReaderOptions {
|
|
8
|
+
readonly restMs?: number;
|
|
9
|
+
/** The threshold up and down, in tremors of the rest. */
|
|
10
|
+
readonly vertical?: number;
|
|
11
|
+
/** The threshold to the sides, in tremors of the rest. */
|
|
12
|
+
readonly sideways?: number;
|
|
13
|
+
readonly exit?: number;
|
|
14
|
+
readonly axisSwitch?: number;
|
|
15
|
+
readonly tremorFloor?: number;
|
|
16
|
+
readonly tremorMax?: number;
|
|
17
|
+
readonly followMs?: number;
|
|
18
|
+
readonly parkedMs?: number;
|
|
19
|
+
readonly parkedFollowMs?: number;
|
|
20
|
+
readonly headMaxDegPerSecond?: number;
|
|
21
|
+
}
|
|
22
|
+
/** The defaults the lab settled on (ADR-0213): 4 tremors vertically, 8 sideways, a rest of three still seconds. */
|
|
23
|
+
export declare const GAZE_DEFAULTS: {
|
|
24
|
+
readonly restMs: 3000;
|
|
25
|
+
readonly vertical: 4;
|
|
26
|
+
readonly sideways: 8;
|
|
27
|
+
readonly exit: 0.6;
|
|
28
|
+
readonly axisSwitch: 1.3;
|
|
29
|
+
readonly tremorFloor: 0.02;
|
|
30
|
+
readonly tremorMax: 0.05;
|
|
31
|
+
readonly followMs: 12000;
|
|
32
|
+
readonly parkedMs: 10000;
|
|
33
|
+
readonly parkedFollowMs: 1500;
|
|
34
|
+
readonly headMaxDegPerSecond: 60;
|
|
35
|
+
};
|
|
36
|
+
export interface GazeSample {
|
|
37
|
+
readonly h: number | null | undefined;
|
|
38
|
+
readonly v: number | null | undefined;
|
|
39
|
+
readonly pose?: {
|
|
40
|
+
readonly yaw: number;
|
|
41
|
+
readonly pitch: number;
|
|
42
|
+
} | null;
|
|
43
|
+
}
|
|
44
|
+
export interface GazeReading {
|
|
45
|
+
readonly zone: GazeZone | null;
|
|
46
|
+
readonly ready: boolean;
|
|
47
|
+
readonly reason: GazeReason;
|
|
48
|
+
readonly rest?: EyeGaze | null;
|
|
49
|
+
readonly tremor?: EyeGaze | null;
|
|
50
|
+
/** Displacement from the rest, in tremors of each axis (the horizontal NOT scaled). */
|
|
51
|
+
readonly displacement?: EyeGaze;
|
|
52
|
+
/** The larger displacement, in vertical units. */
|
|
53
|
+
readonly strength?: number;
|
|
54
|
+
readonly parked?: boolean;
|
|
55
|
+
/** While measuring: how long the gaze has been still. */
|
|
56
|
+
readonly stillMs?: number;
|
|
57
|
+
}
|
|
58
|
+
export interface GazeReader {
|
|
59
|
+
(nowMs: number, sample: GazeSample): GazeReading;
|
|
60
|
+
state(): {
|
|
61
|
+
readonly rest: EyeGaze | null;
|
|
62
|
+
readonly tremor: EyeGaze | null;
|
|
63
|
+
readonly zone: GazeZone | null;
|
|
64
|
+
};
|
|
65
|
+
/** Forget the rest, so the next frames measure a new one. */
|
|
66
|
+
reset(): void;
|
|
67
|
+
}
|
|
68
|
+
export declare function createGazeReader(options?: GazeReaderOptions): GazeReader;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// input/gaze-relative — WHERE THE GAZE WENT, MEASURED FROM ITS OWN REST (ADR-0213; issue #194).
|
|
3
|
+
//
|
|
4
|
+
// Nothing here knows where the screen is, and there is no calibration: the reader knows where the eye RESTS and how far it has moved from
|
|
5
|
+
// there, and four zones need only the direction of the movement.
|
|
6
|
+
//
|
|
7
|
+
// · The rest is the median of `restMs` of frames that were CONTINUOUSLY still, and its scatter (MAD × 1.4826) is measured at the same time.
|
|
8
|
+
// While the gaze keeps moving the stretch restarts, so nothing is read before a real rest — the rest must never be taken while the child
|
|
9
|
+
// reads or looks around, or the threshold is born from a moving gaze and no look can reach it.
|
|
10
|
+
// · A zone is reached when the eye leaves the rest by more than `vertical` of its own tremors; the sides have their own threshold
|
|
11
|
+
// (`sideways`), because for the same intent the eyes move further sideways. The horizontal displacement is scaled into vertical units
|
|
12
|
+
// before anything looks at it, so the threshold, the exit and the contest between the axes all speak the same unit.
|
|
13
|
+
// · The zone is the axis that moved further. It holds while the displacement stays above `exit` of the threshold, and the other axis must
|
|
14
|
+
// beat it by `axisSwitch` to take it — a gaze between two zones would otherwise flicker, and every flicker restarts the command cycle.
|
|
15
|
+
// · The rest follows slowly while the gaze is near it, so a drifting sensor does not command by itself.
|
|
16
|
+
// · A gaze PARKED (range within ±2 tremors, not the MAD — a MAD shrugs off a gaze that keeps coming back) for `parkedMs` re-centres the rest
|
|
17
|
+
// onto itself: a rest that went stale leaves a zone marked after the eyes came back to the middle, and nothing else can unmark it.
|
|
18
|
+
// · A frame where the head turned fast is not read: a head turn imitates an eye movement.
|
|
19
|
+
/** The defaults the lab settled on (ADR-0213): 4 tremors vertically, 8 sideways, a rest of three still seconds. */
|
|
20
|
+
export const GAZE_DEFAULTS = {
|
|
21
|
+
restMs: 3000, vertical: 4, sideways: 8, exit: 0.6, axisSwitch: 1.3, tremorFloor: 0.02, tremorMax: 0.05,
|
|
22
|
+
followMs: 12000, parkedMs: 10000, parkedFollowMs: 1500, headMaxDegPerSecond: 60,
|
|
23
|
+
};
|
|
24
|
+
const AXIS_OF = { up: 'v', down: 'v', left: 'h', right: 'h' };
|
|
25
|
+
const median = (xs) => {
|
|
26
|
+
const a = [...xs].sort((x, y) => x - y);
|
|
27
|
+
return a.length % 2 ? a[(a.length - 1) / 2] : (a[a.length / 2 - 1] + a[a.length / 2]) / 2;
|
|
28
|
+
};
|
|
29
|
+
const spread = (xs, m) => median(xs.map((x) => Math.abs(x - m))) * 1.4826;
|
|
30
|
+
const range = (xs) => Math.max(...xs) - Math.min(...xs);
|
|
31
|
+
export function createGazeReader(options = {}) {
|
|
32
|
+
const o = { ...GAZE_DEFAULTS, ...options };
|
|
33
|
+
let stillSince = null, rest = null, tremor = null, zone = null;
|
|
34
|
+
let lastPose = null, lastMs = null, parkedSince = null;
|
|
35
|
+
const restH = [], restV = [];
|
|
36
|
+
const recentH = [], recentV = [], recentT = [];
|
|
37
|
+
/*
|
|
38
|
+
* The reading is SIX QUESTIONS asked in order, and each one is a step below instead of a paragraph inside `read`:
|
|
39
|
+
* did the head move · is there a rest yet · is the gaze still · is it parked · which zone did it reach · where does
|
|
40
|
+
* the rest go next. They are steps and not helpers: the order is the reading, and each answer feeds the next.
|
|
41
|
+
*/
|
|
42
|
+
/** What the head did since the last frame. A turn imitates an eye movement, so the frame it happens in is not read. */
|
|
43
|
+
const headMotion = (now, pose) => {
|
|
44
|
+
const dtMs = lastMs === null ? 0 : Math.max(0, now - lastMs);
|
|
45
|
+
const headMoving = pose && lastPose && dtMs > 0
|
|
46
|
+
? Math.hypot(pose.yaw - lastPose.yaw, pose.pitch - lastPose.pitch) / (dtMs / 1000) > o.headMaxDegPerSecond
|
|
47
|
+
: false;
|
|
48
|
+
lastPose = pose;
|
|
49
|
+
lastMs = now;
|
|
50
|
+
return { dtMs, headMoving };
|
|
51
|
+
};
|
|
52
|
+
/** The rest, while it is still being taken: a gaze that keeps moving restarts the stretch instead of widening it. */
|
|
53
|
+
const measureRest = (now, h, v) => {
|
|
54
|
+
stillSince ??= now;
|
|
55
|
+
restH.push(h);
|
|
56
|
+
restV.push(v);
|
|
57
|
+
const mh = median(restH), mv = median(restV), sh = spread(restH, mh), sv = spread(restV, mv);
|
|
58
|
+
if (restH.length > 4 && Math.max(sh, sv) > o.tremorMax) {
|
|
59
|
+
stillSince = now;
|
|
60
|
+
restH.length = 0;
|
|
61
|
+
restV.length = 0;
|
|
62
|
+
return { zone: null, ready: false, reason: 'gaze-moving', stillMs: 0 };
|
|
63
|
+
}
|
|
64
|
+
if (now - stillSince < o.restMs)
|
|
65
|
+
return { zone: null, ready: false, reason: 'measuring-rest', stillMs: now - stillSince };
|
|
66
|
+
rest = { h: mh, v: mv };
|
|
67
|
+
tremor = { h: Math.max(o.tremorFloor, sh), v: Math.max(o.tremorFloor, sv) };
|
|
68
|
+
return { zone: null, ready: true, reason: 'rest-measured', rest, tremor, stillMs: now - stillSince };
|
|
69
|
+
};
|
|
70
|
+
/** Was the gaze still over the LAST SECOND? The window forgets on purpose — a gaze that moved and then held must be able to settle. */
|
|
71
|
+
const stillOverTheLastSecond = (now, h, v, scatter) => {
|
|
72
|
+
recentH.push(h);
|
|
73
|
+
recentV.push(v);
|
|
74
|
+
recentT.push(now);
|
|
75
|
+
while (recentT.length && now - recentT[0] > 1000) {
|
|
76
|
+
recentH.shift();
|
|
77
|
+
recentV.shift();
|
|
78
|
+
recentT.shift();
|
|
79
|
+
}
|
|
80
|
+
return recentH.length > 5 && range(recentH) <= 4 * scatter.h && range(recentV) <= 4 * scatter.v;
|
|
81
|
+
};
|
|
82
|
+
/** A gaze still for `parkedMs` is a rest by definition: nothing is pushing it, so the rest may move onto it. */
|
|
83
|
+
const parkedFor = (now, still, headMoving) => {
|
|
84
|
+
if (!still || headMoving)
|
|
85
|
+
parkedSince = null;
|
|
86
|
+
else
|
|
87
|
+
parkedSince ??= now;
|
|
88
|
+
return parkedSince !== null && now - parkedSince >= o.parkedMs;
|
|
89
|
+
};
|
|
90
|
+
/** Which axis owns the movement: the one that went further, unless the zone in hand keeps it by `axisSwitch`. */
|
|
91
|
+
const axisThatWon = (ah, av, threshold, held) => {
|
|
92
|
+
const further = ah >= av ? 'h' : 'v';
|
|
93
|
+
if (!held)
|
|
94
|
+
return further;
|
|
95
|
+
const mine = AXIS_OF[held] === 'h' ? ah : av, other = AXIS_OF[held] === 'h' ? av : ah;
|
|
96
|
+
return mine >= threshold && other < mine * o.axisSwitch ? AXIS_OF[held] : further;
|
|
97
|
+
};
|
|
98
|
+
/** The zone the displacement reached, and how far it went — in vertical units, which is what both axes speak. */
|
|
99
|
+
const zoneReached = (dh, dv, headMoving, held) => {
|
|
100
|
+
const threshold = held ? o.vertical * o.exit : o.vertical;
|
|
101
|
+
const strength = Math.max(Math.abs(dh), Math.abs(dv));
|
|
102
|
+
if (headMoving || strength < threshold)
|
|
103
|
+
return { zone: null, strength };
|
|
104
|
+
const axis = axisThatWon(Math.abs(dh), Math.abs(dv), threshold, held);
|
|
105
|
+
return { zone: axis === 'h' ? (dh > 0 ? 'left' : 'right') : (dv > 0 ? 'down' : 'up'), strength };
|
|
106
|
+
};
|
|
107
|
+
/** Where the rest goes next: slowly towards a gaze that is near it, quickly onto one that has parked. */
|
|
108
|
+
const restFollowing = (at, h, v, dtMs, headMoving, near, parked) => {
|
|
109
|
+
if (headMoving || (!near && !parked))
|
|
110
|
+
return at;
|
|
111
|
+
const k = Math.min(1, dtMs / (parked ? o.parkedFollowMs : o.followMs));
|
|
112
|
+
return { h: at.h + (h - at.h) * k, v: at.v + (v - at.v) * k };
|
|
113
|
+
};
|
|
114
|
+
const read = (now, { h, v, pose = null }) => {
|
|
115
|
+
if (typeof h !== 'number' || typeof v !== 'number')
|
|
116
|
+
return { zone: null, ready: !!rest, reason: 'no-eyes' };
|
|
117
|
+
const { dtMs, headMoving } = headMotion(now, pose);
|
|
118
|
+
if (!rest || !tremor)
|
|
119
|
+
return measureRest(now, h, v);
|
|
120
|
+
const parked = parkedFor(now, stillOverTheLastSecond(now, h, v, tremor), headMoving);
|
|
121
|
+
const dhRaw = (h - rest.h) / tremor.h, dv = (v - rest.v) / tremor.v;
|
|
122
|
+
const { zone: reached, strength } = zoneReached(dhRaw * (o.vertical / o.sideways), dv, headMoving, zone);
|
|
123
|
+
zone = reached;
|
|
124
|
+
rest = restFollowing(rest, h, v, dtMs, headMoving, !zone && strength < o.vertical / 2, parked);
|
|
125
|
+
return {
|
|
126
|
+
zone, ready: true, displacement: { h: dhRaw, v: dv }, strength, parked, rest, tremor,
|
|
127
|
+
reason: headMoving ? 'head-moving' : parked ? 'recentring' : null,
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
return Object.assign(read, {
|
|
131
|
+
state: () => ({ rest, tremor, zone }),
|
|
132
|
+
reset: () => {
|
|
133
|
+
stillSince = null;
|
|
134
|
+
parkedSince = null;
|
|
135
|
+
rest = null;
|
|
136
|
+
tremor = null;
|
|
137
|
+
zone = null;
|
|
138
|
+
for (const a of [restH, restV, recentH, recentV, recentT])
|
|
139
|
+
a.length = 0;
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Action } from '../core/actions.js';
|
|
3
|
+
export type HandGesture = 'indexUp' | 'indexDown' | 'indexLeft' | 'indexRight' | 'iLoveYou' | 'dog' | 'victory' | 'fist' | 'openPalm' | 'zero' | 'thumbUp' | 'thumbDown' | 'threeFingers' | 'fourFingers';
|
|
4
|
+
/** The Dev's map (ADR-0210). */
|
|
5
|
+
export declare const HAND_MAP: {
|
|
6
|
+
readonly [G in HandGesture]: Action;
|
|
7
|
+
};
|
|
8
|
+
/** MediaPipe Gesture Recognizer category names the map uses, and what they are here. */
|
|
9
|
+
export declare const CANNED_GESTURES: {
|
|
10
|
+
readonly [name: string]: HandGesture;
|
|
11
|
+
};
|
|
12
|
+
export interface HandPoint {
|
|
13
|
+
readonly x: number;
|
|
14
|
+
readonly y: number;
|
|
15
|
+
readonly z?: number;
|
|
16
|
+
}
|
|
17
|
+
/** The gestures this module reads from the landmarks (usually none or one). */
|
|
18
|
+
export declare function customGestures(m: readonly HandPoint[] | null | undefined): HandGesture[];
|
|
19
|
+
/** Every gesture seen in a frame: the recognizer's categories plus the landmark rules. */
|
|
20
|
+
export declare function gesturesSeen(landmarks: readonly HandPoint[] | null | undefined, cannedNames: Iterable<string>): Set<HandGesture>;
|
|
21
|
+
/** The whole reader: a frame's gestures in, the actions held and the ones that just started out. */
|
|
22
|
+
export declare function createHandMapReader({ fullMs, mark }?: {
|
|
23
|
+
fullMs?: number;
|
|
24
|
+
mark?: number;
|
|
25
|
+
}): (ms: number, seen: ReadonlySet<HandGesture>) => {
|
|
26
|
+
held: Action[];
|
|
27
|
+
started: Action[];
|
|
28
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// input/hand-map — THE HANDS AS A CONTROLLER: FOURTEEN GESTURES AND THE ACTIONS THEY PRESS (ADR-0210, ADR-0206; issue #191).
|
|
3
|
+
//
|
|
4
|
+
// The Dev's map, measured in the lab's bar rounds (14 of 14 read, the exclusions below taken from those runs). Six gestures are MediaPipe's
|
|
5
|
+
// Gesture Recognizer's own; eight are read here from the 21 hand landmarks, in an orientation-free form — a finger is out when its tip is
|
|
6
|
+
// farther from the wrist than its middle joint, distances in palm sizes (cvzone's `fingersUp` idea without its x test, which flips with the
|
|
7
|
+
// hand). A gesture presses once it has been seen for 300 ms (its level, seen time over 600 ms, reaches 0.5), and stays pressed while seen.
|
|
8
|
+
// · Exclusions: an index pointing down brings MediaPipe's Thumb_Down, an open hand reads as four fingers (the thumb seen folded), a fist as a
|
|
9
|
+
// zero — the specific one clears the other.
|
|
10
|
+
// · Directions are the CHILD'S: the video a child sees is mirrored, so the child's right is the image's −x.
|
|
11
|
+
// ⚠️ Levels are keyed by gesture, never by action (ADR-0112); HAND_MAP turns the held gestures into actions.
|
|
12
|
+
/** The Dev's map (ADR-0210). */
|
|
13
|
+
export const HAND_MAP = {
|
|
14
|
+
indexUp: 'up', indexDown: 'down', indexLeft: 'left', indexRight: 'right', iLoveYou: 'start', dog: 'select',
|
|
15
|
+
victory: 'action1', fist: 'action2', openPalm: 'action3', zero: 'action4',
|
|
16
|
+
thumbUp: 'leftShoulder', thumbDown: 'leftTrigger', threeFingers: 'rightShoulder', fourFingers: 'rightTrigger',
|
|
17
|
+
};
|
|
18
|
+
const GESTURES = Object.keys(HAND_MAP);
|
|
19
|
+
/** MediaPipe Gesture Recognizer category names the map uses, and what they are here. */
|
|
20
|
+
export const CANNED_GESTURES = {
|
|
21
|
+
ILoveYou: 'iLoveYou', Victory: 'victory', Closed_Fist: 'fist', Open_Palm: 'openPalm', Thumb_Up: 'thumbUp', Thumb_Down: 'thumbDown',
|
|
22
|
+
};
|
|
23
|
+
// The landmark numbers MediaPipe hands out, named where the rules use them: a rule that reads `apart(MIDDLE_TIP,
|
|
24
|
+
// THUMB_TIP)` says what it is looking at, and `dist(m[12], m[4])` makes the reader count on their fingers.
|
|
25
|
+
const WRIST = 0, THUMB_JOINT = 3, THUMB_TIP = 4, INDEX_BASE = 5, INDEX_JOINT = 7, INDEX_TIP = 8;
|
|
26
|
+
const MIDDLE_BASE = 9, MIDDLE_TIP = 12, RING_TIP = 16, LITTLE_TIP = 20;
|
|
27
|
+
const FINGERS = { index: [5, 6, 8], middle: [9, 10, 12], ring: [13, 14, 16], little: [17, 18, 20] };
|
|
28
|
+
const dist = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
29
|
+
/** Where the index points, as the CHILD sees it: the video a child watches is mirrored, so the child's right is −x. */
|
|
30
|
+
const wayOfTheIndex = (m) => {
|
|
31
|
+
const dx = -(m[INDEX_TIP].x - m[INDEX_BASE].x), dy = m[INDEX_TIP].y - m[INDEX_BASE].y;
|
|
32
|
+
return Math.abs(dx) > Math.abs(dy) ? (dx > 0 ? 'Right' : 'Left') : (dy > 0 ? 'Down' : 'Up');
|
|
33
|
+
};
|
|
34
|
+
const readHand = (m, palm) => {
|
|
35
|
+
const out = {};
|
|
36
|
+
for (const [name, [base, joint, tip]] of Object.entries(FINGERS)) {
|
|
37
|
+
// BOTH halves, and each catches a hand the other lets through: a finger curled SIDEWAYS reaches away from its
|
|
38
|
+
// base without passing its joint, and one pointing AT THE CAMERA passes its joint without reaching anywhere.
|
|
39
|
+
out[name] = dist(m[tip], m[WRIST]) > dist(m[joint], m[WRIST]) * 1.1 && dist(m[tip], m[base]) > palm * 0.55;
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
out,
|
|
43
|
+
// far from the index AND leading its own joint: the second half is what tells an out thumb from one tucked
|
|
44
|
+
// across the palm, which is how a hand rests
|
|
45
|
+
thumbOut: dist(m[THUMB_TIP], m[INDEX_BASE]) > palm * 0.75
|
|
46
|
+
&& dist(m[THUMB_TIP], m[WRIST]) > dist(m[THUMB_JOINT], m[WRIST]),
|
|
47
|
+
way: wayOfTheIndex(m),
|
|
48
|
+
apart: (a, b) => dist(m[a], m[b]) / palm,
|
|
49
|
+
folded: (...fs) => fs.every((f) => !out[f]),
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
/** A fingertip this close to the thumb, in palms, is ON it. */
|
|
53
|
+
const NEAR = 0.35;
|
|
54
|
+
/*
|
|
55
|
+
* ONE ROW PER GESTURE, in the order they are answered — a table because that is what this already was: a gesture is
|
|
56
|
+
* a predicate over the hand plus the name it gives itself. The six `if`s these rows replace all reached for the same
|
|
57
|
+
* six locals, which is what made this the worst function of the tree outside the composition root (33 paths against
|
|
58
|
+
* McCabe's 10). A gesture the Dev adds is now a LINE.
|
|
59
|
+
*/
|
|
60
|
+
const RULES = [
|
|
61
|
+
{
|
|
62
|
+
name: (h) => `index${h.way}`,
|
|
63
|
+
// the thumb AWAY from the index joint is what keeps a pinch from commanding a direction — the lab dropped the
|
|
64
|
+
// pinch from the map (ADR-0206), and without this half a pinch would come back in as a direction
|
|
65
|
+
reads: (h) => h.out.index && h.folded('middle', 'ring', 'little') && h.apart(THUMB_TIP, INDEX_JOINT) >= 0.3,
|
|
66
|
+
},
|
|
67
|
+
{ name: () => 'victory', reads: (h) => h.out.index && h.out.middle && h.folded('ring', 'little') && h.way === 'Up' },
|
|
68
|
+
{ name: () => 'threeFingers', reads: (h) => h.out.index && h.out.middle && h.out.ring && !h.out.little && !h.thumbOut },
|
|
69
|
+
{ name: () => 'fourFingers', reads: (h) => h.out.index && h.out.middle && h.out.ring && h.out.little && !h.thumbOut },
|
|
70
|
+
{
|
|
71
|
+
name: () => 'dog',
|
|
72
|
+
reads: (h) => h.apart(MIDDLE_TIP, THUMB_TIP) < NEAR && h.apart(RING_TIP, THUMB_TIP) < NEAR && h.out.index && h.out.little,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: () => 'zero',
|
|
76
|
+
reads: (h) => [INDEX_TIP, MIDDLE_TIP, RING_TIP, LITTLE_TIP].every((i) => h.apart(i, THUMB_TIP) < 0.6)
|
|
77
|
+
&& h.apart(INDEX_TIP, THUMB_TIP) < NEAR,
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
/** The gestures this module reads from the landmarks (usually none or one). */
|
|
81
|
+
export function customGestures(m) {
|
|
82
|
+
if (!m || m.length < 21)
|
|
83
|
+
return [];
|
|
84
|
+
/*
|
|
85
|
+
* 🔴 A HAND WITH NO SIZE IS NOT A HAND, and the floor this line used to carry (`|| 1e-6`) got that backwards. It was
|
|
86
|
+
* there to keep the divisions safe, and it did — but it also gave every ratio an answer: 📏 measured on 2026-09-23,
|
|
87
|
+
* a frame whose 21 landmarks all collapsed onto one point read as a `zero`, because every fingertip then sits ZERO
|
|
88
|
+
* palms from the thumb. A detection that failed pressed action4. Refusing the frame is what «not readable» means.
|
|
89
|
+
*
|
|
90
|
+
* ⚠️ And the honest note about the line below: with the floor gone it is EQUIVALENT today — a palm of zero makes
|
|
91
|
+
* every ratio NaN, and `NaN < 0.6` is false, so every rule declines on its own. That is correctness by accident:
|
|
92
|
+
* it holds only while every rule compares with `<`. The line says the refusal where a reader looks for it, and
|
|
93
|
+
* the mutation that proves it is not decoration is putting the floor back, which goes red.
|
|
94
|
+
*/
|
|
95
|
+
const palm = dist(m[WRIST], m[MIDDLE_BASE]);
|
|
96
|
+
if (!(palm > 0))
|
|
97
|
+
return [];
|
|
98
|
+
const hand = readHand(m, palm);
|
|
99
|
+
return RULES.filter((r) => r.reads(hand)).map((r) => r.name(hand));
|
|
100
|
+
}
|
|
101
|
+
/** Every gesture seen in a frame: the recognizer's categories plus the landmark rules. */
|
|
102
|
+
export function gesturesSeen(landmarks, cannedNames) {
|
|
103
|
+
const seen = new Set(customGestures(landmarks));
|
|
104
|
+
for (const n of cannedNames) {
|
|
105
|
+
const g = CANNED_GESTURES[n];
|
|
106
|
+
if (g)
|
|
107
|
+
seen.add(g);
|
|
108
|
+
}
|
|
109
|
+
return seen;
|
|
110
|
+
}
|
|
111
|
+
const DOMINATES = { indexDown: 'thumbDown', openPalm: 'fourFingers', fist: 'zero' };
|
|
112
|
+
/** The whole reader: a frame's gestures in, the actions held and the ones that just started out. */
|
|
113
|
+
export function createHandMapReader({ fullMs = 600, mark = 0.5 } = {}) {
|
|
114
|
+
const since = new Map(), held = new Set();
|
|
115
|
+
return (ms, seen) => {
|
|
116
|
+
const level = (g) => {
|
|
117
|
+
if (!seen.has(g)) {
|
|
118
|
+
since.delete(g);
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
if (!since.has(g))
|
|
122
|
+
since.set(g, ms);
|
|
123
|
+
return Math.min(1, (ms - since.get(g)) / fullMs);
|
|
124
|
+
};
|
|
125
|
+
const levels = new Map(GESTURES.map((g) => [g, level(g)]));
|
|
126
|
+
for (const [strong, weak] of Object.entries(DOMINATES))
|
|
127
|
+
if (levels.get(strong) >= mark)
|
|
128
|
+
levels.set(weak, 0);
|
|
129
|
+
const started = [];
|
|
130
|
+
for (const g of GESTURES) {
|
|
131
|
+
if (levels.get(g) >= mark) {
|
|
132
|
+
if (!held.has(g)) {
|
|
133
|
+
held.add(g);
|
|
134
|
+
started.push(HAND_MAP[g]);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else
|
|
138
|
+
held.delete(g);
|
|
139
|
+
}
|
|
140
|
+
return { held: [...held].map((g) => HAND_MAP[g]), started };
|
|
141
|
+
};
|
|
142
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/** What the root does with the press: let it through, or drop it as an accident. */
|
|
3
|
+
export type CooldownDecision = 'accept' | 'refuse';
|
|
4
|
+
export interface InputCooldown {
|
|
5
|
+
/**
|
|
6
|
+
* A game key goes down. `held` is whether this same key is already down — the auto-repeat of a hand that is holding, which is
|
|
7
|
+
* one input and not a second.
|
|
8
|
+
*/
|
|
9
|
+
keydown(code: string, now: number, ms: number, held: boolean): CooldownDecision;
|
|
10
|
+
/** A game key comes up. Always accepted, and it does not start a new wait. */
|
|
11
|
+
keyup(code: string): CooldownDecision;
|
|
12
|
+
/** Forgets the wait. The root calls it when the child turns the setting off, so the next press is not refused by an old one. */
|
|
13
|
+
reset(): void;
|
|
14
|
+
}
|
|
15
|
+
/** The GAG's number, and the only one offered until somebody measures another on a real hand (ADR-0217 §3). */
|
|
16
|
+
export declare const COOLDOWN_MS = 500;
|
|
17
|
+
export declare function createInputCooldown(): InputCooldown;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// input/input-cooldown — A TREMOR IS NOT A SECOND PRESS (ADR-0217; GAG Advanced/Motor, issue #182).
|
|
3
|
+
//
|
|
4
|
+
// A hand that shakes, a spasm, a finger that bounces off a key: the same press arrives twice, the game hears two, and the child
|
|
5
|
+
// who could not avoid the second one loses the turn. After a key is accepted, this refuses a press that STARTS for as long as
|
|
6
|
+
// the cool-down runs.
|
|
7
|
+
//
|
|
8
|
+
// ⚠️ IT IS AN ACCOMMODATION AND NOT A SIMULATION, which is why it is not in `input/empathy-filter`: that module's first
|
|
9
|
+
// paragraph draws the line — a simulation makes play harder on purpose, to show an adult what a disability costs — and a rule
|
|
10
|
+
// that HELPS living beside them would blur it for whoever reads either one.
|
|
11
|
+
//
|
|
12
|
+
// WHAT IT NEVER REFUSES, and each one is a way a child would lose the game instead of being helped:
|
|
13
|
+
// · A RELEASE. A key refused on the way down is still held by a hand; if its release were refused too, a character would walk
|
|
14
|
+
// on after the child let go, and she would have no way to stop.
|
|
15
|
+
// · THE REPEAT OF A KEY SHE IS HOLDING. Holding is one input, however many times the system says so.
|
|
16
|
+
// · A PRESS ONCE THE TIME HAS PASSED — and the time is counted from the last press ACCEPTED, not from the last one seen, or a
|
|
17
|
+
// tremor of ten bounces would push the window forward ten times and the child would never be heard again.
|
|
18
|
+
//
|
|
19
|
+
// Pure: it is told the time, it answers a decision. No clock, no document, no keyboard.
|
|
20
|
+
/** The GAG's number, and the only one offered until somebody measures another on a real hand (ADR-0217 §3). */
|
|
21
|
+
export const COOLDOWN_MS = 500;
|
|
22
|
+
export function createInputCooldown() {
|
|
23
|
+
let lastAccepted = null;
|
|
24
|
+
return {
|
|
25
|
+
keydown(_code, now, ms, held) {
|
|
26
|
+
if (held)
|
|
27
|
+
return 'accept'; // the system repeating a key the hand never let go of
|
|
28
|
+
// 📌 «Off» needs no line of its own: with `ms` at 0 no elapsed time is ever less than it, so the comparison below answers
|
|
29
|
+
// «accept» for every press. A guard saying the same thing was here and was removed — a mutation proved it changed nothing,
|
|
30
|
+
// which is the definition of a line that only looks like a decision.
|
|
31
|
+
if (lastAccepted !== null && now - lastAccepted < ms)
|
|
32
|
+
return 'refuse';
|
|
33
|
+
lastAccepted = now;
|
|
34
|
+
return 'accept';
|
|
35
|
+
},
|
|
36
|
+
keyup() { return 'accept'; },
|
|
37
|
+
reset() { lastAccepted = null; },
|
|
38
|
+
};
|
|
39
|
+
}
|