@the-inclusionist/engine 6.36.1
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/LICENSE +661 -0
- package/README.md +107 -0
- package/app/css/style.css +622 -0
- package/app/public/vendor/fonts/andika-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/andika-400.woff2 +0 -0
- package/app/public/vendor/fonts/andika-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/andika-700.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-400.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-700.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-mono-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-mono-400.woff2 +0 -0
- package/app/public/vendor/fonts/comicneue-400.woff2 +0 -0
- package/app/public/vendor/fonts/comicneue-700.woff2 +0 -0
- package/app/public/vendor/fonts/greatvibes-400.woff2 +0 -0
- package/app/public/vendor/fonts/inter-400.woff2 +0 -0
- package/app/public/vendor/fonts/inter-700.woff2 +0 -0
- package/app/public/vendor/fonts/lato-400.woff2 +0 -0
- package/app/public/vendor/fonts/lato-700.woff2 +0 -0
- package/app/public/vendor/fonts/lexend-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/lexend-400.woff2 +0 -0
- package/app/public/vendor/fonts/lexend-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/lexend-700.woff2 +0 -0
- package/app/public/vendor/fonts/literata-400.woff2 +0 -0
- package/app/public/vendor/fonts/literata-700.woff2 +0 -0
- package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
- package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
- package/app/public/vendor/fonts/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/quattro-400.woff2 +0 -0
- package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
- package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
- package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
- package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
- package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
- package/app/public/vendor/fonts/ufcook-700.woff2 +0 -0
- package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
- package/app/public/vendor/fonts.css +88 -0
- package/dist-pkg/boot/create-game.d.ts +159 -0
- package/dist-pkg/boot/create-game.js +266 -0
- package/dist-pkg/core/a11y-sr.d.ts +4 -0
- package/dist-pkg/core/a11y-sr.js +20 -0
- package/dist-pkg/core/actions.d.ts +100 -0
- package/dist-pkg/core/actions.js +149 -0
- package/dist-pkg/core/anel.d.ts +17 -0
- package/dist-pkg/core/anel.js +31 -0
- package/dist-pkg/core/collision.d.ts +21 -0
- package/dist-pkg/core/collision.js +62 -0
- package/dist-pkg/core/constants.d.ts +84 -0
- package/dist-pkg/core/constants.js +64 -0
- package/dist-pkg/core/contract.d.ts +227 -0
- package/dist-pkg/core/contract.js +184 -0
- package/dist-pkg/core/dom-query.d.ts +9 -0
- package/dist-pkg/core/dom-query.js +25 -0
- package/dist-pkg/core/entity.d.ts +150 -0
- package/dist-pkg/core/entity.js +38 -0
- package/dist-pkg/core/escape-html.d.ts +16 -0
- package/dist-pkg/core/escape-html.js +32 -0
- package/dist-pkg/core/i18n.d.ts +71 -0
- package/dist-pkg/core/i18n.js +236 -0
- package/dist-pkg/core/layers.d.ts +39 -0
- package/dist-pkg/core/layers.js +71 -0
- package/dist-pkg/core/letter-grid.d.ts +55 -0
- package/dist-pkg/core/letter-grid.js +116 -0
- package/dist-pkg/core/loop.d.ts +17 -0
- package/dist-pkg/core/loop.js +36 -0
- package/dist-pkg/core/password.d.ts +34 -0
- package/dist-pkg/core/password.js +205 -0
- package/dist-pkg/core/rng.d.ts +20 -0
- package/dist-pkg/core/rng.js +61 -0
- package/dist-pkg/core/rotulo-acessivel.d.ts +17 -0
- package/dist-pkg/core/rotulo-acessivel.js +41 -0
- package/dist-pkg/core/run-state.d.ts +115 -0
- package/dist-pkg/core/run-state.js +40 -0
- package/dist-pkg/core/scenes.d.ts +68 -0
- package/dist-pkg/core/scenes.js +64 -0
- package/dist-pkg/core/screens.d.ts +16 -0
- package/dist-pkg/core/screens.js +28 -0
- package/dist-pkg/core/state.d.ts +138 -0
- package/dist-pkg/core/state.js +290 -0
- package/dist-pkg/core/tiles.d.ts +12 -0
- package/dist-pkg/core/tiles.js +61 -0
- package/dist-pkg/core/world.d.ts +4 -0
- package/dist-pkg/core/world.js +58 -0
- package/dist-pkg/educational/activities-registry.d.ts +47 -0
- package/dist-pkg/educational/activities-registry.js +95 -0
- package/dist-pkg/i18n/en.d.ts +3 -0
- package/dist-pkg/i18n/en.js +560 -0
- package/dist-pkg/i18n/es.d.ts +3 -0
- package/dist-pkg/i18n/es.js +558 -0
- package/dist-pkg/i18n/pt.d.ts +3 -0
- package/dist-pkg/i18n/pt.js +618 -0
- package/dist-pkg/input/default-bindings.d.ts +24 -0
- package/dist-pkg/input/default-bindings.js +122 -0
- package/dist-pkg/input/devices.d.ts +15 -0
- package/dist-pkg/input/devices.js +31 -0
- package/dist-pkg/input/edges.d.ts +58 -0
- package/dist-pkg/input/edges.js +49 -0
- package/dist-pkg/input/gamepad.d.ts +203 -0
- package/dist-pkg/input/gamepad.js +531 -0
- package/dist-pkg/input/keyboard-runtime.d.ts +61 -0
- package/dist-pkg/input/keyboard-runtime.js +83 -0
- package/dist-pkg/input/keyboard.d.ts +45 -0
- package/dist-pkg/input/keyboard.js +80 -0
- package/dist-pkg/input/keydown.d.ts +270 -0
- package/dist-pkg/input/keydown.js +381 -0
- package/dist-pkg/input/latch.d.ts +30 -0
- package/dist-pkg/input/latch.js +63 -0
- package/dist-pkg/input/pointer-space.d.ts +40 -0
- package/dist-pkg/input/pointer-space.js +51 -0
- package/dist-pkg/input/state.d.ts +11 -0
- package/dist-pkg/input/state.js +12 -0
- package/dist-pkg/input/touch-bindings.d.ts +210 -0
- package/dist-pkg/input/touch-bindings.js +365 -0
- package/dist-pkg/input/touch.d.ts +173 -0
- package/dist-pkg/input/touch.js +314 -0
- package/dist-pkg/input/transports.d.ts +90 -0
- package/dist-pkg/input/transports.js +96 -0
- package/dist-pkg/input/vocabulary-migration.d.ts +58 -0
- package/dist-pkg/input/vocabulary-migration.js +125 -0
- package/dist-pkg/platform/audio-ambient.d.ts +27 -0
- package/dist-pkg/platform/audio-ambient.js +89 -0
- package/dist-pkg/platform/audio-earcons.d.ts +24 -0
- package/dist-pkg/platform/audio-earcons.js +62 -0
- package/dist-pkg/platform/audio-jingles.d.ts +17 -0
- package/dist-pkg/platform/audio-jingles.js +54 -0
- package/dist-pkg/platform/audio-mixer.d.ts +14 -0
- package/dist-pkg/platform/audio-mixer.js +62 -0
- package/dist-pkg/platform/audio-nav.d.ts +51 -0
- package/dist-pkg/platform/audio-nav.js +99 -0
- package/dist-pkg/platform/audio-sonar.d.ts +71 -0
- package/dist-pkg/platform/audio-sonar.js +173 -0
- package/dist-pkg/platform/audio.d.ts +32 -0
- package/dist-pkg/platform/audio.js +191 -0
- package/dist-pkg/platform/interruptible-speech.d.ts +19 -0
- package/dist-pkg/platform/interruptible-speech.js +79 -0
- package/dist-pkg/platform/speech.d.ts +2 -0
- package/dist-pkg/platform/speech.js +35 -0
- package/dist-pkg/platform/storage.d.ts +87 -0
- package/dist-pkg/platform/storage.js +148 -0
- package/dist-pkg/platform/tts.d.ts +33 -0
- package/dist-pkg/platform/tts.js +142 -0
- package/dist-pkg/render/camera.d.ts +58 -0
- package/dist-pkg/render/camera.js +105 -0
- package/dist-pkg/render/canvas.d.ts +13 -0
- package/dist-pkg/render/canvas.js +26 -0
- package/dist-pkg/render/cenario-data.d.ts +127 -0
- package/dist-pkg/render/cenario-data.js +145 -0
- package/dist-pkg/render/city-tex.d.ts +63 -0
- package/dist-pkg/render/city-tex.js +228 -0
- package/dist-pkg/render/city-tiles.d.ts +11 -0
- package/dist-pkg/render/city-tiles.js +140 -0
- package/dist-pkg/render/crt.d.ts +19 -0
- package/dist-pkg/render/crt.js +92 -0
- package/dist-pkg/render/cvd-matrices.d.ts +35 -0
- package/dist-pkg/render/cvd-matrices.js +91 -0
- package/dist-pkg/render/draw.d.ts +149 -0
- package/dist-pkg/render/draw.js +221 -0
- package/dist-pkg/render/fx.d.ts +63 -0
- package/dist-pkg/render/fx.js +123 -0
- package/dist-pkg/render/hc-role-data.d.ts +14 -0
- package/dist-pkg/render/hc-role-data.js +24 -0
- package/dist-pkg/render/high-contrast.d.ts +109 -0
- package/dist-pkg/render/high-contrast.js +254 -0
- package/dist-pkg/render/lq-filter.d.ts +37 -0
- package/dist-pkg/render/lq-filter.js +94 -0
- package/dist-pkg/render/minimap.d.ts +11 -0
- package/dist-pkg/render/minimap.js +94 -0
- package/dist-pkg/render/parallax.d.ts +85 -0
- package/dist-pkg/render/parallax.js +158 -0
- package/dist-pkg/render/player-anim.d.ts +71 -0
- package/dist-pkg/render/player-anim.js +152 -0
- package/dist-pkg/render/port.d.ts +143 -0
- package/dist-pkg/render/port.js +29 -0
- package/dist-pkg/render/recycling-tex.d.ts +48 -0
- package/dist-pkg/render/recycling-tex.js +164 -0
- package/dist-pkg/render/scene-city.d.ts +77 -0
- package/dist-pkg/render/scene-city.js +181 -0
- package/dist-pkg/render/scene-parallax.d.ts +72 -0
- package/dist-pkg/render/scene-parallax.js +426 -0
- package/dist-pkg/render/scene-sky.d.ts +126 -0
- package/dist-pkg/render/scene-sky.js +295 -0
- package/dist-pkg/render/screen-pipeline.d.ts +134 -0
- package/dist-pkg/render/screen-pipeline.js +177 -0
- package/dist-pkg/render/set-cenario.d.ts +54 -0
- package/dist-pkg/render/set-cenario.js +103 -0
- package/dist-pkg/render/sprite-fx.d.ts +3 -0
- package/dist-pkg/render/sprite-fx.js +40 -0
- package/dist-pkg/render/textures.d.ts +75 -0
- package/dist-pkg/render/textures.js +240 -0
- package/dist-pkg/render/title-scene.d.ts +46 -0
- package/dist-pkg/render/title-scene.js +75 -0
- package/dist-pkg/render/viewports.d.ts +52 -0
- package/dist-pkg/render/viewports.js +185 -0
- package/dist-pkg/render/viz-axes.d.ts +98 -0
- package/dist-pkg/render/viz-axes.js +184 -0
- package/dist-pkg/render/viz-modes.d.ts +61 -0
- package/dist-pkg/render/viz-modes.js +74 -0
- package/dist-pkg/render/viz-setters.d.ts +130 -0
- package/dist-pkg/render/viz-setters.js +244 -0
- package/dist-pkg/render/weather.d.ts +96 -0
- package/dist-pkg/render/weather.js +171 -0
- package/dist-pkg/render/wheelchair-sprites.d.ts +24 -0
- package/dist-pkg/render/wheelchair-sprites.js +63 -0
- package/dist-pkg/render/world-tex.d.ts +18 -0
- package/dist-pkg/render/world-tex.js +87 -0
- package/dist-pkg/ui/activities-menu.d.ts +258 -0
- package/dist-pkg/ui/activities-menu.js +648 -0
- package/dist-pkg/ui/caa-sets.d.ts +39 -0
- package/dist-pkg/ui/caa-sets.js +65 -0
- package/dist-pkg/ui/changed-mark.d.ts +15 -0
- package/dist-pkg/ui/changed-mark.js +96 -0
- package/dist-pkg/ui/debug-panel.d.ts +67 -0
- package/dist-pkg/ui/debug-panel.js +173 -0
- package/dist-pkg/ui/dom.d.ts +24 -0
- package/dist-pkg/ui/dom.js +47 -0
- package/dist-pkg/ui/focus-trap.d.ts +71 -0
- package/dist-pkg/ui/focus-trap.js +99 -0
- package/dist-pkg/ui/fonts.d.ts +41 -0
- package/dist-pkg/ui/fonts.js +59 -0
- package/dist-pkg/ui/hud.d.ts +137 -0
- package/dist-pkg/ui/hud.js +229 -0
- package/dist-pkg/ui/item-announcement.d.ts +19 -0
- package/dist-pkg/ui/item-announcement.js +36 -0
- package/dist-pkg/ui/layout.d.ts +6 -0
- package/dist-pkg/ui/layout.js +54 -0
- package/dist-pkg/ui/loop-crash.d.ts +19 -0
- package/dist-pkg/ui/loop-crash.js +60 -0
- package/dist-pkg/ui/map-hub.d.ts +56 -0
- package/dist-pkg/ui/map-hub.js +138 -0
- package/dist-pkg/ui/menu-nav.d.ts +141 -0
- package/dist-pkg/ui/menu-nav.js +390 -0
- package/dist-pkg/ui/pause-icons.d.ts +327 -0
- package/dist-pkg/ui/pause-icons.js +620 -0
- package/dist-pkg/ui/reach-notice.d.ts +34 -0
- package/dist-pkg/ui/reach-notice.js +71 -0
- package/dist-pkg/ui/settings-audio.d.ts +139 -0
- package/dist-pkg/ui/settings-audio.js +544 -0
- package/dist-pkg/ui/settings-caa.d.ts +45 -0
- package/dist-pkg/ui/settings-caa.js +137 -0
- package/dist-pkg/ui/settings-controls.d.ts +100 -0
- package/dist-pkg/ui/settings-controls.js +152 -0
- package/dist-pkg/ui/settings-empathy.d.ts +62 -0
- package/dist-pkg/ui/settings-empathy.js +137 -0
- package/dist-pkg/ui/settings-motion.d.ts +95 -0
- package/dist-pkg/ui/settings-motion.js +282 -0
- package/dist-pkg/ui/settings-motor.d.ts +77 -0
- package/dist-pkg/ui/settings-motor.js +215 -0
- package/dist-pkg/ui/settings-panel.d.ts +76 -0
- package/dist-pkg/ui/settings-panel.js +187 -0
- package/dist-pkg/ui/settings-typo.d.ts +74 -0
- package/dist-pkg/ui/settings-typo.js +150 -0
- package/dist-pkg/ui/settings-visual.d.ts +111 -0
- package/dist-pkg/ui/settings-visual.js +252 -0
- package/dist-pkg/ui/shell.d.ts +239 -0
- package/dist-pkg/ui/shell.js +430 -0
- package/dist-pkg/ui/title.d.ts +36 -0
- package/dist-pkg/ui/title.js +60 -0
- package/dist-pkg/ui/vlibras.d.ts +11 -0
- package/dist-pkg/ui/vlibras.js +87 -0
- package/dist-pkg/ui/webcam.d.ts +7 -0
- package/dist-pkg/ui/webcam.js +88 -0
- package/docs/CREDITS.md +64 -0
- package/docs/LICENSES.md +132 -0
- package/package.json +115 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { PlayerView } from '../core/entity.js';
|
|
3
|
+
export type MotionSceneKey = 'parallax' | 'decor' | 'items' | 'particles';
|
|
4
|
+
export type MotionCharProp = 'rmWalk' | 'rmBreath' | 'rmFlavor';
|
|
5
|
+
export interface MotionCharDef {
|
|
6
|
+
readonly prop: MotionCharProp;
|
|
7
|
+
readonly lbl: string;
|
|
8
|
+
}
|
|
9
|
+
/** As três chaves de Movimento Reduzido por personagem, derivadas de core/entity. Eram um
|
|
10
|
+
* `Partial<Record<MotionCharProp, boolean>>`, o que dizia a forma certa sem dizer que os campos são DO
|
|
11
|
+
* JOGADOR — um `Record` aceita qualquer objeto com essas chaves, inclusive um que não seja jogador nenhum. */
|
|
12
|
+
export type MotionPlayer = PlayerView<'rmWalk' | 'rmBreath' | 'rmFlavor'>;
|
|
13
|
+
export type MotionSceneFlags = Record<MotionSceneKey, boolean>;
|
|
14
|
+
export interface SettingsMotionCtx {
|
|
15
|
+
/** Quantos jogadores/telas. Estado de RODADA (ADR-0038): vem da instância que a raiz possui.
|
|
16
|
+
* Era `numPlayers`, um `let` de `core/state` importado como binding vivo — e um `let` de módulo
|
|
17
|
+
* é compartilhado por qualquer segundo jogo que a mesma página carregue (D13 do `demos`). */
|
|
18
|
+
getNumPlayers: () => number;
|
|
19
|
+
/** Os jogadores. Estado de RODADA, pelo mesmo motivo. `readonly unknown[]` porque cada consumidor
|
|
20
|
+
* estreita para a SUA fatia — o tipo real é do jogo, não da engine (ADR-0033). */
|
|
21
|
+
getPlayers: () => readonly unknown[];
|
|
22
|
+
/** Seletor DOM (ui/dom.ts `$`). */
|
|
23
|
+
$: <T extends Element = Element>(sel: string) => T | null;
|
|
24
|
+
/** Anúncio "polite" para leitor de tela (core/a11y-sr.ts). */
|
|
25
|
+
srSay: (text: string) => void;
|
|
26
|
+
/** Persistência (platform/storage.ts) — só o necessário aqui: gravar as flags por jogador. */
|
|
27
|
+
store: {
|
|
28
|
+
setBool: (key: string, on: boolean) => void;
|
|
29
|
+
};
|
|
30
|
+
/** Empilha o overlay (z-index) + liga o rodapé de explicação — compartilhado por todos os painéis "Sensibilidade". */
|
|
31
|
+
frontOverlay: (el: HTMLElement | null) => void;
|
|
32
|
+
/** Devolve o foco a quem abriu o diálogo (ui/settings-panel `restoreFocus`). Injetado, e não um `#opt-*`
|
|
33
|
+
* fixo: o id que este módulo focava não existe no documento, então fechar deixava o foco no `<body>`. */
|
|
34
|
+
restoreFocus?: (id: string) => boolean;
|
|
35
|
+
/** Reflete on/off num botão (classe is-on + aria-pressed) — helper genérico usado por vários botões-mestre. */
|
|
36
|
+
toggleBtn: (el: HTMLElement, on: boolean) => void;
|
|
37
|
+
/** Movimento reduzido de CENA (parallax/decor/items/particles) — objeto VIVO, mutado in-place. Fica em game.js:
|
|
38
|
+
* applyCalm() (modo TEA) também o usa, não é exclusivo deste painel. */
|
|
39
|
+
rm: MotionSceneFlags;
|
|
40
|
+
/** Persiste `rm` (localStorage 'inclusionist.reducedmotion.v1') — mesmo motivo, fica em game.js. */
|
|
41
|
+
saveRM: () => void;
|
|
42
|
+
/** As 4 chaves de cena — a MESMA array que applyCalm() itera. */
|
|
43
|
+
rmKeys: readonly MotionSceneKey[];
|
|
44
|
+
/** Os 3 alvos de movimento reduzido do PERSONAGEM — a MESMA array que applyCalm() itera. */
|
|
45
|
+
rmChar: readonly MotionCharDef[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Alvo → CHAVE i18n do rótulo. CHAVES, e não texto, pelo motivo de sempre: uma tabela de `const` com texto
|
|
49
|
+
* resolve UMA vez, no import, e fica congelada no idioma do boot.
|
|
50
|
+
*
|
|
51
|
+
* E é UMA tabela onde eram DUAS. A nota anterior dizia que `walk/breath/flavor` ficavam "redundantes com
|
|
52
|
+
* rmChar[].lbl" e que não haviam sido podados "por fidelidade de porte" — havia uma terceira cópia, morta, no
|
|
53
|
+
* main.js. Três tabelas dos mesmos rótulos, sem nada ligando as três: mudar um rótulo pedia três edições e
|
|
54
|
+
* esquecer uma era silencioso. Agora `rmChar[].lbl` guarda a chave DESTA tabela, e a do main.js foi apagada.
|
|
55
|
+
*/
|
|
56
|
+
export declare const RM_LABEL: Record<string, string>;
|
|
57
|
+
export declare const RM_SOON: ReadonlySet<MotionSceneKey>;
|
|
58
|
+
/** selAnimPlayer nunca aponta pra fora do nº de telas atual. */
|
|
59
|
+
export declare function clampSelectedPlayer(selected: number, total: number): number;
|
|
60
|
+
/** Uma linha de switch "Animado/Congelado" (usada tanto para o personagem quanto para a cena). */
|
|
61
|
+
export declare function motionRowHtml(label: string, frozen: boolean, attr: string, soon: boolean): string;
|
|
62
|
+
/** Linhas "Personagem" (por jogador selecionado). */
|
|
63
|
+
export declare function buildCharRowsHtml(rmChar: readonly MotionCharDef[], player: MotionPlayer | undefined): string;
|
|
64
|
+
/** Linhas "Cena" (globais, valem para todos os jogadores). */
|
|
65
|
+
export declare function buildSceneRowsHtml(rmKeys: readonly MotionSceneKey[], rm: MotionSceneFlags, labels: Record<string, string>, soon: ReadonlySet<MotionSceneKey>): string;
|
|
66
|
+
/** Toggle liga/desliga da estética CRT (scanlines/vinheta). */
|
|
67
|
+
export declare function crtToggleRowHtml(label: string, key: string, on: boolean): string;
|
|
68
|
+
/** Cantos CRT: 3 níveis (0=quadrado · 1=pequeno · 2=grande). */
|
|
69
|
+
export declare function crtRoundRowHtml(label: string, round: number): string;
|
|
70
|
+
/** true quando TUDO (cena + personagem selecionado) já está com movimento reduzido LIGADO, isto é,
|
|
71
|
+
* congelado — nome fiel ao `rm[k]`/`player[prop]` que representam "reduzido", não "animado". Controla
|
|
72
|
+
* se o botão-mestre oferece "Retomar" (true) ou "Parar" (false) — mesma variável `allOn` do game.js
|
|
73
|
+
* original, aqui renomeada por clareza (o valor/comportamento não muda). */
|
|
74
|
+
export declare function allMotionFrozen(rmKeys: readonly MotionSceneKey[], rm: MotionSceneFlags, rmChar: readonly MotionCharDef[], player: MotionPlayer | undefined): boolean;
|
|
75
|
+
/** allFrozen=true (tudo já congelado) → oferece "Retomar"; caso contrário → oferece "Parar". */
|
|
76
|
+
export declare function motionMasterLabel(allFrozen: boolean): string;
|
|
77
|
+
/** `label` chega JÁ TRADUZIDO; o que era concatenação (' congelado.') virou moldura com `{alvo}` — é o que
|
|
78
|
+
* permite a uma língua pôr o estado ANTES do alvo, coisa que uma concatenação não deixa. */
|
|
79
|
+
export declare function sceneMotionAnnouncement(label: string, frozen: boolean): string;
|
|
80
|
+
export declare function crtToggleAnnouncement(label: string, on: boolean): string;
|
|
81
|
+
export declare function crtLevelLabel(level: number): string;
|
|
82
|
+
export declare function crtRoundAnnouncement(label: string, level: number): string;
|
|
83
|
+
/** `nowFrozen` = o NOVO valor de rm[k]/player[prop] aplicado pelo botão-mestre (true = acabou de congelar
|
|
84
|
+
* tudo; false = acabou de descongelar/retomar tudo) — mesma variável `v` do game.js original. */
|
|
85
|
+
export declare function stopResumeAllAnnouncement(nowFrozen: boolean): string;
|
|
86
|
+
export declare function getSelectedPlayer(): number;
|
|
87
|
+
/** Chamado de fora (ex.: o atalho "anim" do menu de pausa) antes de open(). */
|
|
88
|
+
export declare function setSelectedPlayer(i: number): void;
|
|
89
|
+
/** Espelha `animationOpen` do game.js — só LIDO por quem despacha Escape entre os diálogos abertos. */
|
|
90
|
+
export interface SettingsMotionApi {
|
|
91
|
+
render: () => void;
|
|
92
|
+
open: () => void;
|
|
93
|
+
close: () => void;
|
|
94
|
+
}
|
|
95
|
+
export declare function initSettingsMotion(ctx: SettingsMotionCtx): SettingsMotionApi;
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// ui/settings-motion.ts — "Sensibilidade visual" → painel Movimento (#animation overlay): reduce-motion (WCAG
|
|
3
|
+
// 2.3.3 + Pause/Stop/Hide 2.2.2) por PERSONAGEM (andar/respirar/gracinhas) e por CENA (parallax/decor/itens/
|
|
4
|
+
// partículas), o botão-mestre "Parar/Retomar todas as animações", a seleção de jogador (selAnimPlayer) e a
|
|
5
|
+
// estética CRT (scanlines/vinheta/cantos) — que também mora nesta MESMA tela no game.js original (renderMotion
|
|
6
|
+
// escreve os dois blocos no mesmo #motion-list), por isso vem junto. Lógica PURA (rótulos, HTML, allMotionFrozen,
|
|
7
|
+
// anúncios) separada do DOM. INJETADO via initSettingsMotion(ctx): $ (seletor), srSay, store (persistência),
|
|
8
|
+
// frontOverlay/toggleBtn (helpers compartilhados com os painéis irmãos: visual/audio/typo/empathy/controls/
|
|
9
|
+
// motor), e rm/saveRM/RM_KEYS/RM_CHAR (estado de movimento reduzido — fica em game.js porque applyCalm(), o
|
|
10
|
+
// modo TEA, também os usa; não é exclusivo deste painel). `players`/`numPlayers` (core/state.ts) e CRT/applyCrt
|
|
11
|
+
// (render/crt.ts, já extraído) são importados DIRETO — são módulos-folha, não game.js. A API de render/fx.ts
|
|
12
|
+
// NÃO é referenciada aqui: renderMotion() nunca leu/escreveu JUICE (só o painel ?debug o faz) — ver nota no
|
|
13
|
+
// retorno da extração antes de assumir que falta wiring.
|
|
14
|
+
import { toggleLabel, toggleAria } from './dom.js';
|
|
15
|
+
import { CRT, CRT_DEFAULT, applyCrt } from '../render/crt.js';
|
|
16
|
+
import { defaultReducedMotion } from '../core/state.js';
|
|
17
|
+
import { markChanged, markMenuChanged } from './changed-mark.js';
|
|
18
|
+
import { t } from '../core/i18n.js';
|
|
19
|
+
/**
|
|
20
|
+
* Alvo → CHAVE i18n do rótulo. CHAVES, e não texto, pelo motivo de sempre: uma tabela de `const` com texto
|
|
21
|
+
* resolve UMA vez, no import, e fica congelada no idioma do boot.
|
|
22
|
+
*
|
|
23
|
+
* E é UMA tabela onde eram DUAS. A nota anterior dizia que `walk/breath/flavor` ficavam "redundantes com
|
|
24
|
+
* rmChar[].lbl" e que não haviam sido podados "por fidelidade de porte" — havia uma terceira cópia, morta, no
|
|
25
|
+
* main.js. Três tabelas dos mesmos rótulos, sem nada ligando as três: mudar um rótulo pedia três edições e
|
|
26
|
+
* esquecer uma era silencioso. Agora `rmChar[].lbl` guarda a chave DESTA tabela, e a do main.js foi apagada.
|
|
27
|
+
*/
|
|
28
|
+
export const RM_LABEL = {
|
|
29
|
+
parallax: 'rm.parallax', decor: 'rm.decor', items: 'rm.items',
|
|
30
|
+
walk: 'rm.walk', breath: 'rm.breath', flavor: 'rm.flavor', particles: 'rm.particles',
|
|
31
|
+
};
|
|
32
|
+
// Alvos de cena "em breve" (hoje nenhum — os 4 já agem).
|
|
33
|
+
export const RM_SOON = new Set([]);
|
|
34
|
+
/** Cabeçalho de seção, com a etiqueta "vale para todos os jogadores".
|
|
35
|
+
*
|
|
36
|
+
* A etiqueta estava escrita à mão em cada `<h3>` e ia ser repetida pela quarta vez quando a seção nova chegou.
|
|
37
|
+
* Reunida num ponto só, ela pôde finalmente passar por `t()` — e foi a seção nova que tornou isso urgente: com
|
|
38
|
+
* o cabeçalho traduzido ao lado de uma etiqueta em português cru, a mistura aparecia na mesma linha da tela.
|
|
39
|
+
* Os títulos das outras três seções continuam crus; é dívida anterior a esta mudança, contada pelo gate. */
|
|
40
|
+
const secao = (titulo) => `<h3 class="panel-sub">${titulo} <span class="panel-sub__tag">${t('rm.sec.all')}</span></h3>`;
|
|
41
|
+
const CRT_LBL = { scan: 'rm.crt.scan', vig: 'rm.crt.vig', round: 'rm.crt.round' }; // CHAVES i18n (ver RM_LABEL)
|
|
42
|
+
const CRT_ROUND_LEVELS = ['desligado', 'pequeno', 'grande'];
|
|
43
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
44
|
+
// Lógica PURA — testável em node, sem `document`.
|
|
45
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
46
|
+
/** selAnimPlayer nunca aponta pra fora do nº de telas atual. */
|
|
47
|
+
export function clampSelectedPlayer(selected, total) {
|
|
48
|
+
return selected >= total ? 0 : selected;
|
|
49
|
+
}
|
|
50
|
+
/** Uma linha de switch "Animado/Congelado" (usada tanto para o personagem quanto para a cena). */
|
|
51
|
+
export function motionRowHtml(label, frozen, attr, soon) {
|
|
52
|
+
const on = !frozen;
|
|
53
|
+
const soonTag = soon ? ' <em style="opacity:.7">(em breve)</em>' : '';
|
|
54
|
+
const cls = 'mode-btn switch' + (on ? ' is-on' : '');
|
|
55
|
+
const btnText = on ? '▶ Animado' : '❄ Congelado';
|
|
56
|
+
const state = on ? 'animação ligada' : 'animação congelada';
|
|
57
|
+
return `<div class="ctrl-row"><span>${label}${soonTag}</span><button class="${cls}" ${attr} type="button" aria-pressed="${on}" aria-label="${label}: ${state}">${btnText}</button></div>`;
|
|
58
|
+
}
|
|
59
|
+
/** Linhas "Personagem" (por jogador selecionado). */
|
|
60
|
+
export function buildCharRowsHtml(rmChar, player) {
|
|
61
|
+
return rmChar.map((c) => motionRowHtml(t(c.lbl), !!(player && player[c.prop]), `data-rmc="${c.prop}"`, false)).join('');
|
|
62
|
+
}
|
|
63
|
+
/** Linhas "Cena" (globais, valem para todos os jogadores). */
|
|
64
|
+
export function buildSceneRowsHtml(rmKeys, rm, labels, soon) {
|
|
65
|
+
return rmKeys.map((k) => motionRowHtml(t(labels[k]), !!rm[k], `data-rm="${k}"`, soon.has(k))).join('');
|
|
66
|
+
}
|
|
67
|
+
/** Toggle liga/desliga da estética CRT (scanlines/vinheta). */
|
|
68
|
+
export function crtToggleRowHtml(label, key, on) {
|
|
69
|
+
const cls = 'mode-btn switch' + (on ? ' is-on' : '');
|
|
70
|
+
return `<div class="ctrl-row"><span>${label}</span><button class="${cls}" data-crt-tgl="${key}" type="button" aria-pressed="${on}" aria-label="${toggleAria(label, on)}">${toggleLabel(on)}</button></div>`;
|
|
71
|
+
}
|
|
72
|
+
/** Cantos CRT: 3 níveis (0=quadrado · 1=pequeno · 2=grande). */
|
|
73
|
+
export function crtRoundRowHtml(label, round) {
|
|
74
|
+
const opt = (v, text) => `<option value="${v}"${round === v ? ' selected' : ''}>${text}</option>`;
|
|
75
|
+
return `<div class="ctrl-row"><span>${label}</span><select class="vol" data-crt="round" aria-label="${label}">${opt(0, 'Desligado (quadrado)')}${opt(1, 'Pequeno')}${opt(2, 'Grande')}</select></div>`;
|
|
76
|
+
}
|
|
77
|
+
/** true quando TUDO (cena + personagem selecionado) já está com movimento reduzido LIGADO, isto é,
|
|
78
|
+
* congelado — nome fiel ao `rm[k]`/`player[prop]` que representam "reduzido", não "animado". Controla
|
|
79
|
+
* se o botão-mestre oferece "Retomar" (true) ou "Parar" (false) — mesma variável `allOn` do game.js
|
|
80
|
+
* original, aqui renomeada por clareza (o valor/comportamento não muda). */
|
|
81
|
+
export function allMotionFrozen(rmKeys, rm, rmChar, player) {
|
|
82
|
+
return rmKeys.every((k) => rm[k]) && rmChar.every((c) => !!(player && player[c.prop]));
|
|
83
|
+
}
|
|
84
|
+
/** allFrozen=true (tudo já congelado) → oferece "Retomar"; caso contrário → oferece "Parar". */
|
|
85
|
+
export function motionMasterLabel(allFrozen) {
|
|
86
|
+
return allFrozen ? '▶ Retomar todas as animações' : '⏸ Parar todas as animações';
|
|
87
|
+
}
|
|
88
|
+
/** `label` chega JÁ TRADUZIDO; o que era concatenação (' congelado.') virou moldura com `{alvo}` — é o que
|
|
89
|
+
* permite a uma língua pôr o estado ANTES do alvo, coisa que uma concatenação não deixa. */
|
|
90
|
+
export function sceneMotionAnnouncement(label, frozen) {
|
|
91
|
+
return t(frozen ? 'sr.rm.frozen' : 'sr.rm.animated', { alvo: label });
|
|
92
|
+
}
|
|
93
|
+
export function crtToggleAnnouncement(label, on) {
|
|
94
|
+
return t(on ? 'sr.crt.on' : 'sr.crt.off', { efeito: label });
|
|
95
|
+
}
|
|
96
|
+
export function crtLevelLabel(level) {
|
|
97
|
+
return CRT_ROUND_LEVELS[level];
|
|
98
|
+
}
|
|
99
|
+
export function crtRoundAnnouncement(label, level) {
|
|
100
|
+
return t('sr.crt.round', { efeito: label, nivel: crtLevelLabel(level) });
|
|
101
|
+
}
|
|
102
|
+
/** `nowFrozen` = o NOVO valor de rm[k]/player[prop] aplicado pelo botão-mestre (true = acabou de congelar
|
|
103
|
+
* tudo; false = acabou de descongelar/retomar tudo) — mesma variável `v` do game.js original. */
|
|
104
|
+
export function stopResumeAllAnnouncement(nowFrozen) {
|
|
105
|
+
return t(nowFrozen ? 'sr.rm.allStopped' : 'sr.rm.allResumed');
|
|
106
|
+
}
|
|
107
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
108
|
+
// Estado do módulo — equivalente a `let selAnimPlayer=0` + `animationOpen=false` do game.js.
|
|
109
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
110
|
+
let selectedPlayer = 0;
|
|
111
|
+
export function getSelectedPlayer() { return selectedPlayer; }
|
|
112
|
+
/** Chamado de fora (ex.: o atalho "anim" do menu de pausa) antes de open(). */
|
|
113
|
+
export function setSelectedPlayer(i) { selectedPlayer = i; }
|
|
114
|
+
export function initSettingsMotion(ctx) {
|
|
115
|
+
function reflectMotionBtn() {
|
|
116
|
+
const b = ctx.$('#opt-animation');
|
|
117
|
+
if (b)
|
|
118
|
+
b.classList.toggle('is-on', ctx.rmKeys.some((k) => ctx.rm[k]));
|
|
119
|
+
}
|
|
120
|
+
function updateMotionMaster() {
|
|
121
|
+
reflectMotionBtn();
|
|
122
|
+
const m = ctx.$('#motion-master');
|
|
123
|
+
if (!m)
|
|
124
|
+
return;
|
|
125
|
+
const player = ctx.getPlayers()[selectedPlayer];
|
|
126
|
+
const allFrozen = allMotionFrozen(ctx.rmKeys, ctx.rm, ctx.rmChar, player);
|
|
127
|
+
m.textContent = motionMasterLabel(allFrozen);
|
|
128
|
+
ctx.toggleBtn(m, allFrozen);
|
|
129
|
+
}
|
|
130
|
+
function render() {
|
|
131
|
+
const el = ctx.$('#motion-list');
|
|
132
|
+
if (!el)
|
|
133
|
+
return;
|
|
134
|
+
selectedPlayer = clampSelectedPlayer(selectedPlayer, ctx.getNumPlayers());
|
|
135
|
+
// E3: sem abas — cada jogador edita só o seu. BUG preservado VERBATIM do game.js (não corrigido, ver
|
|
136
|
+
// retorno da extração): innerHTML='' roda ANTES do querySelectorAll, então o forEach abaixo nunca acha
|
|
137
|
+
// botões — este bloco de wiring é código morto tanto aqui quanto no original.
|
|
138
|
+
const tabs = ctx.$('#animation-players');
|
|
139
|
+
if (tabs) {
|
|
140
|
+
tabs.hidden = true;
|
|
141
|
+
tabs.innerHTML = '';
|
|
142
|
+
tabs.querySelectorAll('button[data-ap]').forEach((b) => b.addEventListener('click', () => {
|
|
143
|
+
selectedPlayer = Number(b.dataset.ap);
|
|
144
|
+
render();
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
const player = ctx.getPlayers()[selectedPlayer];
|
|
148
|
+
const charRows = buildCharRowsHtml(ctx.rmChar, player);
|
|
149
|
+
const sceneRows = buildSceneRowsHtml(ctx.rmKeys, ctx.rm, RM_LABEL, RM_SOON);
|
|
150
|
+
const crtRows = crtToggleRowHtml(t(CRT_LBL.scan), 'scan', !!CRT.scan) + crtToggleRowHtml(t(CRT_LBL.vig), 'vig', !!CRT.vig) + crtRoundRowHtml(t(CRT_LBL.round), CRT.round);
|
|
151
|
+
el.innerHTML =
|
|
152
|
+
`<h3 class="panel-sub">Personagem${ctx.getNumPlayers() > 1 ? ' · Jogador ' + (selectedPlayer + 1) : ''} <span class="panel-sub__tag">por jogador</span></h3>${charRows}` +
|
|
153
|
+
`${secao('Cena')}${sceneRows}` +
|
|
154
|
+
`${secao('Estética CRT')}${crtRows}`;
|
|
155
|
+
el.querySelectorAll('button[data-crt-tgl]').forEach((b) => b.addEventListener('click', () => {
|
|
156
|
+
const k = b.dataset.crtTgl;
|
|
157
|
+
CRT[k] = CRT[k] ? 0 : 1;
|
|
158
|
+
applyCrt();
|
|
159
|
+
render();
|
|
160
|
+
ctx.srSay(crtToggleAnnouncement(t(CRT_LBL[k]), !!CRT[k]));
|
|
161
|
+
}));
|
|
162
|
+
el.querySelectorAll('select[data-crt]').forEach((s) => s.addEventListener('change', () => {
|
|
163
|
+
const key = s.dataset.crt;
|
|
164
|
+
CRT[key] = +s.value;
|
|
165
|
+
applyCrt();
|
|
166
|
+
ctx.srSay(crtRoundAnnouncement(t(CRT_LBL[key]), CRT[key]));
|
|
167
|
+
}));
|
|
168
|
+
el.querySelectorAll('button[data-rmc]').forEach((b) => b.addEventListener('click', () => {
|
|
169
|
+
const prop = b.dataset.rmc;
|
|
170
|
+
const p = ctx.getPlayers()[selectedPlayer];
|
|
171
|
+
p[prop] = !p[prop];
|
|
172
|
+
ctx.store.setBool('incl_' + prop + '_p' + selectedPlayer, !!p[prop]);
|
|
173
|
+
render();
|
|
174
|
+
}));
|
|
175
|
+
el.querySelectorAll('button[data-rm]').forEach((b) => b.addEventListener('click', () => {
|
|
176
|
+
const k = b.dataset.rm;
|
|
177
|
+
ctx.rm[k] = !ctx.rm[k];
|
|
178
|
+
ctx.saveRM();
|
|
179
|
+
render();
|
|
180
|
+
updateMotionMaster();
|
|
181
|
+
ctx.srSay(sceneMotionAnnouncement(t(RM_LABEL[k]), ctx.rm[k]));
|
|
182
|
+
}));
|
|
183
|
+
updateMotionMaster();
|
|
184
|
+
refreshMarks();
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* A marca de "saiu do padrão" (ADR-0029), contra o padrão CALCULADO — não contra `false`.
|
|
188
|
+
*
|
|
189
|
+
* Numa máquina cujo dono pediu menos movimento, o padrão das cinco linhas de animação é CONGELADO. Marcar
|
|
190
|
+
* contra `false` acusaria "alterado" em cinco linhas que a criança nunca tocou, e mandaria justamente ela
|
|
191
|
+
* desfazer a preferência do próprio sistema. Uma marca errada é pior que marca nenhuma, e aqui ela erraria
|
|
192
|
+
* na direção mais cara.
|
|
193
|
+
*/
|
|
194
|
+
function refreshMarks() {
|
|
195
|
+
const padraoRm = defaultReducedMotion();
|
|
196
|
+
const el = ctx.$('#motion-list');
|
|
197
|
+
const player = ctx.getPlayers()[selectedPlayer];
|
|
198
|
+
const mudou = [];
|
|
199
|
+
const marcar = (sel, changed) => {
|
|
200
|
+
mudou.push(changed);
|
|
201
|
+
markChanged(el?.querySelector(sel)?.closest('.ctrl-row') ?? null, changed);
|
|
202
|
+
};
|
|
203
|
+
for (const c of ctx.rmChar)
|
|
204
|
+
marcar(`[data-rmc="${c.prop}"]`, !!(player && player[c.prop]) !== padraoRm);
|
|
205
|
+
for (const k of ctx.rmKeys)
|
|
206
|
+
marcar(`[data-rm="${k}"]`, !!ctx.rm[k] !== padraoRm);
|
|
207
|
+
marcar('[data-crt-tgl="scan"]', !!CRT.scan !== !!CRT_DEFAULT.scan);
|
|
208
|
+
marcar('[data-crt-tgl="vig"]', !!CRT.vig !== !!CRT_DEFAULT.vig);
|
|
209
|
+
marcar('[data-crt="round"]', CRT.round !== CRT_DEFAULT.round);
|
|
210
|
+
markMenuChanged(ctx.$('[data-act="anim"]'), mudou);
|
|
211
|
+
}
|
|
212
|
+
// ---- restaurar os padrões DESTE menu (ADR-0028) ----
|
|
213
|
+
//
|
|
214
|
+
// O único dos sete cujo padrão NÃO é uma constante: o das cinco linhas de animação é o que o sistema
|
|
215
|
+
// operacional pede (`prefers-reduced-motion`). Devolver `false` aqui RELIGARIA a animação na tela de quem
|
|
216
|
+
// já pediu menos movimento — o reset faria sozinho o que a WCAG 2.3.3 existe para impedir. Por isso ele
|
|
217
|
+
// chama `defaultReducedMotion()` e não escreve o valor à mão.
|
|
218
|
+
//
|
|
219
|
+
// O escopo é TODOS os jogadores, como no menu motor: o painel edita um por vez, mas o reset é do menu, e
|
|
220
|
+
// deixar o jogador 2 congelado porque a aba aberta era a do jogador 1 daria dois estados com um nome só.
|
|
221
|
+
const resetBtn = ctx.$('#animation-reset');
|
|
222
|
+
if (resetBtn)
|
|
223
|
+
resetBtn.addEventListener('click', () => {
|
|
224
|
+
const padraoRm = defaultReducedMotion();
|
|
225
|
+
for (const k of ctx.rmKeys)
|
|
226
|
+
ctx.rm[k] = padraoRm;
|
|
227
|
+
ctx.saveRM();
|
|
228
|
+
ctx.getPlayers().forEach((p, i) => {
|
|
229
|
+
for (const c of ctx.rmChar) {
|
|
230
|
+
p[c.prop] = padraoRm;
|
|
231
|
+
ctx.store.setBool('incl_' + c.prop + '_p' + i, padraoRm);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
CRT.scan = CRT_DEFAULT.scan;
|
|
235
|
+
CRT.vig = CRT_DEFAULT.vig;
|
|
236
|
+
CRT.round = CRT_DEFAULT.round;
|
|
237
|
+
applyCrt();
|
|
238
|
+
render();
|
|
239
|
+
ctx.srSay(t('sr.motion.reset'));
|
|
240
|
+
});
|
|
241
|
+
function open() {
|
|
242
|
+
const ov = ctx.$('#animation');
|
|
243
|
+
if (!ov)
|
|
244
|
+
return;
|
|
245
|
+
render();
|
|
246
|
+
ov.hidden = false;
|
|
247
|
+
ctx.frontOverlay(ov);
|
|
248
|
+
const f = ov.querySelector('button');
|
|
249
|
+
if (f)
|
|
250
|
+
f.focus();
|
|
251
|
+
}
|
|
252
|
+
function close() {
|
|
253
|
+
const ov = ctx.$('#animation');
|
|
254
|
+
if (!ov)
|
|
255
|
+
return;
|
|
256
|
+
ov.hidden = true;
|
|
257
|
+
if (ctx.restoreFocus && ctx.restoreFocus('animation'))
|
|
258
|
+
return;
|
|
259
|
+
const b = ctx.$('#opt-animation');
|
|
260
|
+
if (b)
|
|
261
|
+
b.focus(); // recuo: este id nao existe no documento hoje (gancho de uma barra futura)
|
|
262
|
+
}
|
|
263
|
+
const master = ctx.$('#motion-master');
|
|
264
|
+
if (master)
|
|
265
|
+
master.addEventListener('click', () => {
|
|
266
|
+
const player = ctx.getPlayers()[selectedPlayer];
|
|
267
|
+
const allFrozen = allMotionFrozen(ctx.rmKeys, ctx.rm, ctx.rmChar, player);
|
|
268
|
+
const next = !allFrozen;
|
|
269
|
+
for (const k of ctx.rmKeys)
|
|
270
|
+
ctx.rm[k] = next;
|
|
271
|
+
ctx.saveRM();
|
|
272
|
+
if (player)
|
|
273
|
+
for (const c of ctx.rmChar) {
|
|
274
|
+
player[c.prop] = next;
|
|
275
|
+
ctx.store.setBool('incl_' + c.prop + '_p' + selectedPlayer, next);
|
|
276
|
+
}
|
|
277
|
+
render();
|
|
278
|
+
ctx.srSay(stopResumeAllAnnouncement(next));
|
|
279
|
+
});
|
|
280
|
+
reflectMotionBtn(); // estado inicial (ex.: prefers-reduced-motion liga por padrão)
|
|
281
|
+
return { render, open, close };
|
|
282
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import { toggleLabel } from './dom.js';
|
|
3
|
+
import type { PlayerView } from '../core/entity.js';
|
|
4
|
+
import type { DomQuery } from '../core/dom-query.js';
|
|
5
|
+
/** Minimal DOM-selector shape (matches ui/dom.ts's `$`). */
|
|
6
|
+
export type { DomQuery } from '../core/dom-query.js';
|
|
7
|
+
/** Minimal platform/storage.ts shape this module needs. */
|
|
8
|
+
export interface MotorStore {
|
|
9
|
+
setBool(key: string, on: boolean): void;
|
|
10
|
+
/** Lê a chave crua. Só a marca do ADR-0029 usa, e para uma pergunta precisa: a criança ESCOLHEU isto? */
|
|
11
|
+
get(key: string): string | null;
|
|
12
|
+
}
|
|
13
|
+
/** Minimal per-player shape this module reads/writes (core/state.ts's `players` entries carry much more). */
|
|
14
|
+
/** As duas escolhas motoras por jogador: modo Fácil e teclas de alternância. */
|
|
15
|
+
export type MotorPlayer = PlayerView<'easy' | 'toggleMove' | 'toggleRun'>;
|
|
16
|
+
export interface SettingsMotorCtx {
|
|
17
|
+
/** DOM selector (querySelector), injected — never reaches `document` globally. */
|
|
18
|
+
$: DomQuery;
|
|
19
|
+
/** Screen-reader announcement (core/a11y-sr's srSay), injected. */
|
|
20
|
+
srSay: (msg: string) => void;
|
|
21
|
+
/** Persistence (platform/storage.ts), injected. */
|
|
22
|
+
store: MotorStore;
|
|
23
|
+
/** Live player list (core/state.ts's `players` — mutated in place, same reference every call). */
|
|
24
|
+
players: MotorPlayer[];
|
|
25
|
+
/** Live player count (core/state.ts's `numPlayers`); a getter because the value is reassigned over time. */
|
|
26
|
+
getNumPlayers: () => number;
|
|
27
|
+
/** SHARED setter (also used by the pause-menu quick icon `altmove`) — stays in game.js, injected. */
|
|
28
|
+
setToggleMove: (i: number, on: boolean) => void;
|
|
29
|
+
/**
|
|
30
|
+
* A ALTERNÂNCIA DO BOTÃO DE CORRER. Injetada como a irmã acima e pelo mesmo motivo: quem persiste e anuncia
|
|
31
|
+
* é a raiz de composição, que é quem conhece `players` e o armazenamento.
|
|
32
|
+
*/
|
|
33
|
+
setToggleRun: (i: number, on: boolean) => void;
|
|
34
|
+
/** Coin layout depends on any player's Modo Fácil (moedas no chão) — owned by the coin subsystem, injected. */
|
|
35
|
+
rebuildCoins: () => void;
|
|
36
|
+
}
|
|
37
|
+
export interface SettingsMotorApi {
|
|
38
|
+
/** Re-renders #movement-players (kept `hidden`, per E3 — see playerTabsHTML) and (re)wires its buttons. */
|
|
39
|
+
renderMovPlayers: () => void;
|
|
40
|
+
/** Reflects the selected player's Modo Fácil onto #opt-facil (+ the #opt-movement bar light). */
|
|
41
|
+
reflectFacil: () => void;
|
|
42
|
+
/** Reflects the selected player's alternância onto #opt-altmove (+ the #opt-movement bar light). */
|
|
43
|
+
reflectAltMove: () => void;
|
|
44
|
+
/** Idem para a alternância do botão de CORRER (#opt-togglerun). */
|
|
45
|
+
reflectToggleRun: () => void;
|
|
46
|
+
/** Sets Modo Fácil for player `i`; mirrors the old setEasy(i,on). */
|
|
47
|
+
setEasy: (i: number, on: boolean) => void;
|
|
48
|
+
/** Selects which player this panel edits (mirrors `selMovPlayer = pauseActor` before opening the panel). */
|
|
49
|
+
setSelPlayer: (i: number) => void;
|
|
50
|
+
/** Currently selected player index. */
|
|
51
|
+
getSelPlayer: () => number;
|
|
52
|
+
}
|
|
53
|
+
/** localStorage key for a player's Modo Fácil flag (== platform/storage.ts's `easy_p{i}` pattern). */
|
|
54
|
+
export declare function easyKey(i: number): string;
|
|
55
|
+
/** localStorage key da alternância do botão de CORRER (== `toggleRunP` de platform/storage). */
|
|
56
|
+
export declare function toggleRunKey(i: number): string;
|
|
57
|
+
/** Clamps the selected player back to 0 once it falls outside 0..numPlayers-1 (e.g. player count dropped). */
|
|
58
|
+
export declare function clampSelPlayer(sel: number, numPlayers: number): number;
|
|
59
|
+
/** Whether ANY player currently uses Modo Fácil or alternância — lights the #opt-movement bar button. */
|
|
60
|
+
export declare function anyMotorActive(players: MotorPlayer[]): boolean;
|
|
61
|
+
/** '❚❚ Ligado' / '▶ Desligado' para #opt-facil e #opt-altmove. Reexporta o de ui/dom, que é o único que
|
|
62
|
+
* existe desde o item 14 — o corpo daqui era uma cópia, e o comentário já dizia "shared" sem sê-lo. */
|
|
63
|
+
export declare const onOffLabel: typeof toggleLabel;
|
|
64
|
+
/**
|
|
65
|
+
* Full innerHTML for #movement-players, given the player count and the active index. Pure string building —
|
|
66
|
+
* no DOM. NOTE (verbatim from game.js, E3): the panel keeps this list `hidden` — a single player edits only
|
|
67
|
+
* their own screen (scope = pauseActor) — but the tabs/buttons are still built and wired for >1 player.
|
|
68
|
+
*/
|
|
69
|
+
export declare function playerTabsHTML(numPlayers: number, selected: number): string;
|
|
70
|
+
/**
|
|
71
|
+
* O 'Jogador N: ' que abre um anúncio quando há mais de uma tela. Uma tela só não leva prefixo — dizer
|
|
72
|
+
* "Jogador 1" para quem está sozinho é ruído, e ruído no leitor de tela custa tempo de escuta.
|
|
73
|
+
*/
|
|
74
|
+
export declare function playerPrefix(i: number, numPlayers: number): string;
|
|
75
|
+
/** srSay text for a Modo Fácil change. A frase inteira vem do dicionário — ver `sr.motor.easyOn`. */
|
|
76
|
+
export declare function easyAnnouncement(i: number, numPlayers: number, on: boolean): string;
|
|
77
|
+
export declare function initSettingsMotor(ctx: SettingsMotorCtx): SettingsMotorApi;
|