@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,24 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import { type Action } from '../core/actions.js';
|
|
3
|
+
/** `null` = este transporte NÃO alcança esta ação por padrão. Ausência declarada, nunca esquecimento. */
|
|
4
|
+
export type Binding<T> = T | null;
|
|
5
|
+
/**
|
|
6
|
+
* Teclado, esquema SOLO. Códigos de `KeyboardEvent.code` — físicos, não a letra impressa, que muda com o
|
|
7
|
+
* layout ABNT2/US e é a razão de nunca se usar `key` aqui.
|
|
8
|
+
*/
|
|
9
|
+
export declare const KEYBOARD_SOLO: Readonly<Record<Action, Binding<readonly string[]>>>;
|
|
10
|
+
/**
|
|
11
|
+
* Gamepad, mapa PADRÃO da Gamepad API (`mapping: "standard"`), que é o que um controle de Xbox reporta.
|
|
12
|
+
* O número é o índice em `gamepad.buttons`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const GAMEPAD_STANDARD: Readonly<Record<Action, Binding<number>>>;
|
|
15
|
+
/**
|
|
16
|
+
* Todos os problemas de uma tabela de binding. VAZIA quer dizer conforme.
|
|
17
|
+
*
|
|
18
|
+
* ⚠️ O QUE ISTO EXISTE PARA APANHAR É O DUPLO, e ele já aconteceu: a especificação chegou com `I` em duas
|
|
19
|
+
* ações. Um binding duplicado não dá erro em lado nenhum — as duas ações disparam juntas, e a criança vê uma
|
|
20
|
+
* ação dupla intermitente que ninguém consegue reproduzir de propósito.
|
|
21
|
+
*/
|
|
22
|
+
export declare function bindingProblems<T>(tabela: Readonly<Record<Action, Binding<T | readonly T[]>>>): string[];
|
|
23
|
+
/** As ações que este transporte NÃO alcança. É o que uma tela de seleção precisa dizer ANTES de a criança começar. */
|
|
24
|
+
export declare function unreachable<T>(tabela: Readonly<Record<Action, Binding<T | readonly T[]>>>): Action[];
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// input/default-bindings — O QUE CADA TRANSPORTE OFERECE, POR PADRÃO, PARA CADA UMA DAS QUATORZE AÇÕES.
|
|
3
|
+
//
|
|
4
|
+
// ========================= O QUE ISTO É, E ONDE ELE MORA DE PROPÓSITO =========================
|
|
5
|
+
// O ADR-0085 decidiu as quatorze POSIÇÕES (`core/actions.ts`) e disse, em tantas palavras, que os nomes
|
|
6
|
+
// físicos — L1, R2, X, A — são BINDING e vivem no transporte, não no vocabulário. Este é o ficheiro onde eles
|
|
7
|
+
// vivem. Um transporte novo (fala, olhar, toque) traz a sua tabela e não toca em `core/actions`.
|
|
8
|
+
//
|
|
9
|
+
// ⚠️ NADA AQUI ESTÁ LIGADO AINDA. `input/gamepad` e `input/keyboard` continuam a falar os oito nomes de
|
|
10
|
+
// plataforma (`jump`, `run`, `swap`, `especial`); a migração é a issue #103. Esta tabela é o destino dela,
|
|
11
|
+
// escrita agora porque o Dev especificou o padrão — e uma especificação que fica no chat é uma decisão
|
|
12
|
+
// perdida.
|
|
13
|
+
//
|
|
14
|
+
// ========================= A SIMETRIA DO TECLADO, QUE NÃO É DECORAÇÃO =========================
|
|
15
|
+
// O padrão que o Dev especificou apoia-se num bloco do QWERTY:
|
|
16
|
+
//
|
|
17
|
+
// 7 8 ← L1 sobre U, R1 sobre I
|
|
18
|
+
// Y U I O ← L2 à esquerda de U, R2 à direita de I
|
|
19
|
+
// H J K L
|
|
20
|
+
//
|
|
21
|
+
// ⚠️ E O MAPEAMENTO TECLADO↔XBOX É UMA ROTAÇÃO DE 45°, consistente nos quatro: X(oeste)→U(noroeste),
|
|
22
|
+
// Y(norte)→I(nordeste), B(leste)→K(sudeste), A(sul)→J(sudoeste). O losango do controle pousa no quadrado
|
|
23
|
+
// `U I / J K` girando um oitavo de volta. É por isso que a tabela cai bem no dedo: o que a memória muscular
|
|
24
|
+
// guarda é a POSIÇÃO RELATIVA, não a letra.
|
|
25
|
+
//
|
|
26
|
+
// ⚠️ E FOI ESSA SIMETRIA QUE DENUNCIOU UM ERRO NA ESPECIFICAÇÃO. Ela chegou com `I` atribuído DUAS vezes —
|
|
27
|
+
// para `action4` e para R2 —, e o par simétrico de `Y` (à esquerda de U) é `O` (à direita de I). Adotado `O`.
|
|
28
|
+
// O gate deste ficheiro reprova tecla repetida, então o erro não teria passado de qualquer forma; o que a
|
|
29
|
+
// simetria deu foi a tecla CERTA em vez de só a notícia de que havia uma errada.
|
|
30
|
+
import { ACTIONS } from '../core/actions.js';
|
|
31
|
+
// ⚠️ UMA TECLA QUE EXISTE HOJE E NÃO TEM LUGAR NESTA TABELA: `Space`. O esquema solo de `input/keyboard.ts`
|
|
32
|
+
// tem `jump:['KeyJ','Space']` — a barra é um segundo atalho para o pulo desde sempre. A especificação do
|
|
33
|
+
// padrão não a menciona, e pô-la em `action2` por conta própria seria decidir que o pulo mora ali: se o
|
|
34
|
+
// preset da plataforma puser o pulo noutra posição, a barra segue o verbo errado, que é pior do que ela não
|
|
35
|
+
// existir. Fica de fora, dita aqui, e é decisão do Dev — não de quem escreve a tabela.
|
|
36
|
+
/**
|
|
37
|
+
* Teclado, esquema SOLO. Códigos de `KeyboardEvent.code` — físicos, não a letra impressa, que muda com o
|
|
38
|
+
* layout ABNT2/US e é a razão de nunca se usar `key` aqui.
|
|
39
|
+
*/
|
|
40
|
+
export const KEYBOARD_SOLO = {
|
|
41
|
+
up: ['KeyW', 'ArrowUp'],
|
|
42
|
+
down: ['KeyS', 'ArrowDown'],
|
|
43
|
+
left: ['KeyA', 'ArrowLeft'],
|
|
44
|
+
right: ['KeyD', 'ArrowRight'],
|
|
45
|
+
action1: ['KeyU'],
|
|
46
|
+
action2: ['KeyJ', 'Space'],
|
|
47
|
+
action3: ['KeyK'],
|
|
48
|
+
action4: ['KeyI'],
|
|
49
|
+
leftShoulder: ['Digit7'], // L1
|
|
50
|
+
leftTrigger: ['KeyY'], // L2
|
|
51
|
+
rightShoulder: ['Digit8'], // R1
|
|
52
|
+
rightTrigger: ['KeyO'], // R2 — ver a nota da simetria acima
|
|
53
|
+
// ⚠️ E ESTAS DUAS FECHAM UMA DÍVIDA QUE O ADR-0074 §1 REGISTROU: `start` existia em dois transportes de
|
|
54
|
+
// nove e faltava no teclado. Deixa de faltar. A simetria é de MÃO: `F` fica ao lado do polegar da mão que
|
|
55
|
+
// se move (o bloco WASD), `H` ao lado da mão que age (o bloco UIJK).
|
|
56
|
+
// `Enter` acompanha `H` porque JÁ pausava — `input/keydown.ts:240` tem `PAUSE_KEYS = {Escape, Enter}` —,
|
|
57
|
+
// então declará-lo aqui descreve o que a tecla faz há muito, em vez de lhe dar um trabalho novo.
|
|
58
|
+
start: ['KeyH', 'Enter'],
|
|
59
|
+
select: ['KeyF'],
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Gamepad, mapa PADRÃO da Gamepad API (`mapping: "standard"`), que é o que um controle de Xbox reporta.
|
|
63
|
+
* O número é o índice em `gamepad.buttons`.
|
|
64
|
+
*/
|
|
65
|
+
export const GAMEPAD_STANDARD = {
|
|
66
|
+
// As direções não vêm de botões: vêm do stick 0/1 e do D-pad 12–15, em `stdDirs`. Declarar `null` aqui
|
|
67
|
+
// diria "não alcança", que é falso — por isso os índices do D-pad estão nomeados.
|
|
68
|
+
up: 12,
|
|
69
|
+
down: 13,
|
|
70
|
+
left: 14,
|
|
71
|
+
right: 15,
|
|
72
|
+
action1: 2, // X
|
|
73
|
+
action2: 0, // A
|
|
74
|
+
action3: 1, // B
|
|
75
|
+
action4: 3, // Y
|
|
76
|
+
leftShoulder: 4, // L1
|
|
77
|
+
leftTrigger: 6, // L2 — ⚠️ gatilho ANALÓGICO: a API expõe-no como botão com `.value`, e em alguns
|
|
78
|
+
// controles também como eixo. `bindActive` já trata os dois; `padActions` só lê
|
|
79
|
+
// `pressed`, o que funciona mas descarta o curso do gatilho.
|
|
80
|
+
rightShoulder: 5, // R1
|
|
81
|
+
rightTrigger: 7, // R2 — mesma ressalva analógica
|
|
82
|
+
start: 9, // Start / Menu
|
|
83
|
+
select: 8, // Select / Back / View
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Todos os problemas de uma tabela de binding. VAZIA quer dizer conforme.
|
|
87
|
+
*
|
|
88
|
+
* ⚠️ O QUE ISTO EXISTE PARA APANHAR É O DUPLO, e ele já aconteceu: a especificação chegou com `I` em duas
|
|
89
|
+
* ações. Um binding duplicado não dá erro em lado nenhum — as duas ações disparam juntas, e a criança vê uma
|
|
90
|
+
* ação dupla intermitente que ninguém consegue reproduzir de propósito.
|
|
91
|
+
*/
|
|
92
|
+
export function bindingProblems(tabela) {
|
|
93
|
+
const p = [];
|
|
94
|
+
const dono = new Map();
|
|
95
|
+
for (const acao of ACTIONS) {
|
|
96
|
+
if (!(acao in tabela)) {
|
|
97
|
+
p.push(`binding: ${acao} is not declared - write null if the transport cannot reach it`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const v = tabela[acao];
|
|
101
|
+
if (v === null)
|
|
102
|
+
continue;
|
|
103
|
+
const itens = Array.isArray(v) ? v : [v];
|
|
104
|
+
if (itens.length === 0) {
|
|
105
|
+
p.push(`binding: ${acao} has an empty list - write null instead`);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
for (const item of itens) {
|
|
109
|
+
const chave = String(item);
|
|
110
|
+
const anterior = dono.get(chave);
|
|
111
|
+
if (anterior)
|
|
112
|
+
p.push(`binding: ${chave} is bound to both ${anterior} and ${acao}`);
|
|
113
|
+
else
|
|
114
|
+
dono.set(chave, acao);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return p;
|
|
118
|
+
}
|
|
119
|
+
/** As ações que este transporte NÃO alcança. É o que uma tela de seleção precisa dizer ANTES de a criança começar. */
|
|
120
|
+
export function unreachable(tabela) {
|
|
121
|
+
return ACTIONS.filter((a) => tabela[a] === null || tabela[a] === undefined);
|
|
122
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
export declare const PAD_DESIGNS: Record<string, Record<string, string[]>>;
|
|
3
|
+
/**
|
|
4
|
+
* Glifos de controle que NÃO SE LEEM — chave i18n do nome falado de cada um (ADR-0044, item 4).
|
|
5
|
+
*
|
|
6
|
+
* Um leitor de tela lê `✕` como "sinal de multiplicação", ou não lê nada, e `△` costuma sair mudo. É por isso
|
|
7
|
+
* que a legenda da pausa carregava `aria-hidden="true"`: escondiam-se o ruído E a informação juntos. Aqui está
|
|
8
|
+
* a metade que faltava para poder tirar o atributo — o glifo continua na tela para quem o reconhece, e a
|
|
9
|
+
* PALAVRA existe para quem o escuta.
|
|
10
|
+
*
|
|
11
|
+
* Só os quatro do PlayStation entram. `A`, `B`, `X`, `Y` e `0`–`3` já se leem, e traduzi-los para "letra A"
|
|
12
|
+
* seria acrescentar ruído em nome de acessibilidade — o defeito que este item conserta pelo avesso.
|
|
13
|
+
*/
|
|
14
|
+
export declare const PAD_GLYPH_SPOKEN: Record<string, string>;
|
|
15
|
+
export declare const TOUCH_DEFAULT: Record<string, string>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// input/devices.ts — rótulos/mapeamentos de gamepad e toque (dados). Módulo-folha, ZERO deps.
|
|
3
|
+
// PAD_DESIGNS: como rotular os 4 botões de ação por modelo de controle (o navegador detecta genérico no
|
|
4
|
+
// Windows). TOUCH_DEFAULT: mapa padrão dos 9 slots de toque.
|
|
5
|
+
// A leitura de pads (pollPads) e o layout de toque ficam no game.js. (Fase 2, subsistema input)
|
|
6
|
+
//
|
|
7
|
+
// POR QUE CHAVES E NÃO TEXTO: a tabela é uma `const` de módulo, avaliada UMA vez no import. Se guardasse
|
|
8
|
+
// `t('…')` já resolvido, o idioma congelaria no boot — `dict` em core/i18n é um `let` que `setLocale`
|
|
9
|
+
// reatribui, e quem leu antes da troca nunca mais vê a troca. Guardando a chave, quem resolve é o ponto de
|
|
10
|
+
// Este módulo continua ZERO deps de propósito: chave é dado, `t` é comportamento e mora no consumidor.
|
|
11
|
+
export const PAD_DESIGNS = {
|
|
12
|
+
generic: { '0': ['0', '#3a4a6a'], '1': ['1', '#3a4a6a'], '2': ['2', '#3a4a6a'], '3': ['3', '#3a4a6a'] },
|
|
13
|
+
microsoft: { '0': ['A', '#2fae4e'], '1': ['B', '#d23b3b'], '2': ['X', '#2f6fd2'], '3': ['Y', '#d9a400'] },
|
|
14
|
+
sony: { '0': ['✕', '#4f8fd0'], '1': ['○', '#d23b3b'], '2': ['□', '#d76fae'], '3': ['△', '#2fae7e'] },
|
|
15
|
+
nintendo: { '0': ['B', '#d9a400'], '1': ['A', '#d23b3b'], '2': ['Y', '#2fae4e'], '3': ['X', '#2f6fd2'] },
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Glifos de controle que NÃO SE LEEM — chave i18n do nome falado de cada um (ADR-0044, item 4).
|
|
19
|
+
*
|
|
20
|
+
* Um leitor de tela lê `✕` como "sinal de multiplicação", ou não lê nada, e `△` costuma sair mudo. É por isso
|
|
21
|
+
* que a legenda da pausa carregava `aria-hidden="true"`: escondiam-se o ruído E a informação juntos. Aqui está
|
|
22
|
+
* a metade que faltava para poder tirar o atributo — o glifo continua na tela para quem o reconhece, e a
|
|
23
|
+
* PALAVRA existe para quem o escuta.
|
|
24
|
+
*
|
|
25
|
+
* Só os quatro do PlayStation entram. `A`, `B`, `X`, `Y` e `0`–`3` já se leem, e traduzi-los para "letra A"
|
|
26
|
+
* seria acrescentar ruído em nome de acessibilidade — o defeito que este item conserta pelo avesso.
|
|
27
|
+
*/
|
|
28
|
+
export const PAD_GLYPH_SPOKEN = {
|
|
29
|
+
'✕': 'pad.glyph.cross', '○': 'pad.glyph.circle', '□': 'pad.glyph.square', '△': 'pad.glyph.triangle',
|
|
30
|
+
};
|
|
31
|
+
export const TOUCH_DEFAULT = { up: 'up', down: 'down', left: 'left', right: 'right', start: 'start', b0: 'action2', b1: 'action3', b2: 'action1', b3: 'action4' };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/** As seis bordas de entrada, pelo nome do campo que elas levantam no jogador. */
|
|
3
|
+
export type EdgeFlag = 'jumpEdge' | 'runEdge' | 'leftEdge' | 'rightEdge' | 'swapEdge' | 'specialEdge';
|
|
4
|
+
/** As seis ações que levantam borda. Nomeado (e não `string`) para o compilador casar com o `ActionKey` de
|
|
5
|
+
* input/gamepad, que é quem lê a tabela passando a ação adiante. */
|
|
6
|
+
export type EdgeAction = 'action2' | 'action1' | 'left' | 'right' | 'action4' | 'action3';
|
|
7
|
+
/** Ação → borda, na ORDEM em que os três caminhos as levantam. */
|
|
8
|
+
export declare const EDGE_BY_ACTION: ReadonlyArray<readonly [EdgeAction, EdgeFlag]>;
|
|
9
|
+
/**
|
|
10
|
+
* Este jogador pode levantar a borda desta ação?
|
|
11
|
+
*
|
|
12
|
+
* Hoje há uma regra só, e ela é de acessibilidade: no modo Fácil o `run` não levanta borda — sem correr, e
|
|
13
|
+
* portanto sem escalada de parede. Vale para teclado, controle e toque, que é justamente o ponto.
|
|
14
|
+
* Se um dia houver uma segunda regra, ela entra AQUI e passa a valer nos três de uma vez.
|
|
15
|
+
*/
|
|
16
|
+
export declare function edgeAllowed(action: EdgeAction, easy: boolean | undefined): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* As seis intenções de navegação de menu — a mesma história das bordas, um andar acima.
|
|
19
|
+
*
|
|
20
|
+
* Estava declarada QUATRO vezes: `input/gamepad`, `ui/menu-nav`, `ui/activities-menu` e, sob o nome
|
|
21
|
+
* `TitleNav`, `input/keydown`. Três delas traziam um comentário dizendo "MESMA forma que…", que é uma cópia
|
|
22
|
+
* pedindo para ser notada. E já tinham divergido: a de `ui/activities-menu` declarava os seis campos
|
|
23
|
+
* OPCIONAIS e as outras três, obrigatórios — de modo que `navTitle` aceitava `{}` enquanto quem a alimenta
|
|
24
|
+
* sempre manda os seis.
|
|
25
|
+
*
|
|
26
|
+
* Mora em `input/` porque é uma intenção de ENTRADA: quem a produz são os tradutores (teclado, controle,
|
|
27
|
+
* toque, e amanhã voz e webcam) e quem a consome é a UI. `input/` nunca importa de `ui/`; `ui/` já importa de
|
|
28
|
+
* `input/devices`. A direção é essa.
|
|
29
|
+
*
|
|
30
|
+
* OPCIONAIS de propósito, ao contrário das bordas: um tradutor manda só o que aconteceu. `{ down: true }` é
|
|
31
|
+
* uma frase completa — "para baixo" —, e obrigar os outros cinco `false` faria cada chamada carregar cinco
|
|
32
|
+
* negações que ninguém lê. É a forma que `ui/activities-menu` já usava, e é a certa; o que estava errado era
|
|
33
|
+
* as outras três discordarem dela.
|
|
34
|
+
*/
|
|
35
|
+
export interface NavKeys {
|
|
36
|
+
up?: boolean;
|
|
37
|
+
down?: boolean;
|
|
38
|
+
left?: boolean;
|
|
39
|
+
right?: boolean;
|
|
40
|
+
/** Confirmar / entrar. */
|
|
41
|
+
yes?: boolean;
|
|
42
|
+
/** Voltar / cancelar. */
|
|
43
|
+
no?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Alguma intenção foi expressa neste quadro? Sem intenção, a tecla NÃO é consumida — nem `preventDefault`,
|
|
47
|
+
* nem `stopPropagation`, nem `navTitle`.
|
|
48
|
+
*
|
|
49
|
+
* Estava escrita DUAS vezes, com o mesmo corpo e nomes diferentes: `hasIntent` em `ui/menu-nav` e
|
|
50
|
+
* `hasTitleIntent` em `input/keydown`. Quase deixei as duas onde estavam, no raciocínio de que mover o tipo
|
|
51
|
+
* para cá e criar uma função nova seria trocar seis por meia dúzia — o raciocínio estava certo e o número,
|
|
52
|
+
* errado: não era uma cópia, eram duas, e o canônico apaga as duas. Os dois módulos reexportam com o nome
|
|
53
|
+
* que os chamadores e os testes deles já usam.
|
|
54
|
+
*
|
|
55
|
+
* O `!!` importa: com os campos opcionais, a cadeia de `||` devolve `boolean | undefined`. Foi o compilador
|
|
56
|
+
* que apontou, ao estreitar o tipo — as duas funções vinham devolvendo `undefined` como se fosse `false`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function hasNavIntent(k: NavKeys): boolean;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// input/edges — a tabela "ação → borda de entrada", e a regra de quem pode levantá-la. Módulo FOLHA: zero
|
|
3
|
+
// imports, nada de DOM, nada de estado.
|
|
4
|
+
//
|
|
5
|
+
// POR QUE ISTO EXISTE COMO MÓDULO
|
|
6
|
+
// Uma "borda" é o instante em que o jogador ACABOU de acionar algo — `jumpEdge`, `runEdge`, `leftEdge`… — em
|
|
7
|
+
// oposição a manter pressionado. Quem levanta borda são os três caminhos de entrada, e cada um tinha a sua
|
|
8
|
+
// própria cópia da mesma tabela: `input/keydown.ts`, `input/gamepad.ts` (seis `if` à mão) e
|
|
9
|
+
// `input/touch-bindings.ts`. Três cópias que precisavam concordar, e nada obrigando.
|
|
10
|
+
//
|
|
11
|
+
// Elas divergiram. A cópia do toque não tinha a guarda do modo Fácil, e como `runEdge` NÃO é a velocidade de
|
|
12
|
+
// corrida — é o gatilho que gruda e solta da parede, a escalada tipo aranha de `updateCling` em
|
|
13
|
+
// `game/physics.ts:177` e `:179` — o resultado foi que a criança em modo Fácil (que existe para dificuldade
|
|
14
|
+
// motora) não conseguia escalar com teclado nem com controle, e conseguia com o botão da tela. No tablet de
|
|
15
|
+
// escola pública, o toque não é o caminho alternativo: é o único. O sintoma foi corrigido antes deste módulo;
|
|
16
|
+
// este módulo é o que impede a divergência de voltar, porque agora só há um lugar onde ela poderia morar.
|
|
17
|
+
//
|
|
18
|
+
// A ORDEM DA TABELA É OBSERVÁVEL: `edgesFor` devolve a lista na ordem em que percorre, e há teste ancorando-a.
|
|
19
|
+
/** Ação → borda, na ORDEM em que os três caminhos as levantam. */
|
|
20
|
+
export const EDGE_BY_ACTION = Object.freeze([
|
|
21
|
+
['action2', 'jumpEdge'], ['action1', 'runEdge'], ['left', 'leftEdge'],
|
|
22
|
+
['right', 'rightEdge'], ['action4', 'swapEdge'], ['action3', 'specialEdge'],
|
|
23
|
+
]);
|
|
24
|
+
/**
|
|
25
|
+
* Este jogador pode levantar a borda desta ação?
|
|
26
|
+
*
|
|
27
|
+
* Hoje há uma regra só, e ela é de acessibilidade: no modo Fácil o `run` não levanta borda — sem correr, e
|
|
28
|
+
* portanto sem escalada de parede. Vale para teclado, controle e toque, que é justamente o ponto.
|
|
29
|
+
* Se um dia houver uma segunda regra, ela entra AQUI e passa a valer nos três de uma vez.
|
|
30
|
+
*/
|
|
31
|
+
export function edgeAllowed(action, easy) {
|
|
32
|
+
return !(action === 'action1' && !!easy);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Alguma intenção foi expressa neste quadro? Sem intenção, a tecla NÃO é consumida — nem `preventDefault`,
|
|
36
|
+
* nem `stopPropagation`, nem `navTitle`.
|
|
37
|
+
*
|
|
38
|
+
* Estava escrita DUAS vezes, com o mesmo corpo e nomes diferentes: `hasIntent` em `ui/menu-nav` e
|
|
39
|
+
* `hasTitleIntent` em `input/keydown`. Quase deixei as duas onde estavam, no raciocínio de que mover o tipo
|
|
40
|
+
* para cá e criar uma função nova seria trocar seis por meia dúzia — o raciocínio estava certo e o número,
|
|
41
|
+
* errado: não era uma cópia, eram duas, e o canônico apaga as duas. Os dois módulos reexportam com o nome
|
|
42
|
+
* que os chamadores e os testes deles já usam.
|
|
43
|
+
*
|
|
44
|
+
* O `!!` importa: com os campos opcionais, a cadeia de `||` devolve `boolean | undefined`. Foi o compilador
|
|
45
|
+
* que apontou, ao estreitar o tipo — as duas funções vinham devolvendo `undefined` como se fosse `false`.
|
|
46
|
+
*/
|
|
47
|
+
export function hasNavIntent(k) {
|
|
48
|
+
return !!(k.yes || k.no || k.up || k.down || k.left || k.right);
|
|
49
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { PlayerView } from '../core/entity.js';
|
|
3
|
+
export interface PadButtonLike {
|
|
4
|
+
pressed: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface PadLike {
|
|
7
|
+
id: string;
|
|
8
|
+
index: number;
|
|
9
|
+
mapping: string;
|
|
10
|
+
buttons: readonly (PadButtonLike | null | undefined)[];
|
|
11
|
+
axes: readonly number[];
|
|
12
|
+
}
|
|
13
|
+
/** Adapter for `navigator.getGamepads()` — the DI point that lets tests feed a fake pad without a browser. */
|
|
14
|
+
export type GetGamepads = () => readonly (PadLike | null | undefined)[] | null | undefined;
|
|
15
|
+
export type { DomQuery } from '../core/dom-query.js';
|
|
16
|
+
/** One binding captured by the wizard: a digital button, a signed analog threshold, or an exact hat/POV value.
|
|
17
|
+
* Loosely-shaped (all fields optional) rather than a strict union: bindings round-trip through JSON in
|
|
18
|
+
* localStorage, so `bindActive` must stay defensive against malformed/partial saved data, same as the original. */
|
|
19
|
+
export interface PadBinding {
|
|
20
|
+
b?: number;
|
|
21
|
+
ax?: number;
|
|
22
|
+
s?: number;
|
|
23
|
+
av?: number;
|
|
24
|
+
v?: number;
|
|
25
|
+
}
|
|
26
|
+
/** action -> binding, keyed by the 9 wizard steps (left/right/up/down/jump/run/swap/especial/start), PLUS the
|
|
27
|
+
* `_skip: true` sentinel meaning "user cancelled the wizard for this model — use the default mapping, don't
|
|
28
|
+
* ask again this session" (not persisted). A flat index signature (not `Partial<Record<..>> & {_skip}`) so the
|
|
29
|
+
* boolean `_skip` and the PadBinding action values can coexist under TS's index-signature rule; `bindingAt`
|
|
30
|
+
* narrows a lookup back down to a PadBinding for `bindActive`. */
|
|
31
|
+
export type PadMap = Record<string, PadBinding | boolean | undefined>;
|
|
32
|
+
export type ActionKey = 'left' | 'right' | 'up' | 'down' | 'action2' | 'action1' | 'action4' | 'action3';
|
|
33
|
+
export interface Dirs {
|
|
34
|
+
left: boolean;
|
|
35
|
+
right: boolean;
|
|
36
|
+
up: boolean;
|
|
37
|
+
down: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface PadActions extends Dirs {
|
|
40
|
+
[key: string]: boolean;
|
|
41
|
+
action2: boolean;
|
|
42
|
+
action1: boolean;
|
|
43
|
+
action4: boolean;
|
|
44
|
+
action3: boolean;
|
|
45
|
+
_start: boolean;
|
|
46
|
+
_pause: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** Direções pelas FONTES PADRÃO: stick 0/1 (zona morta PAD_DEAD), D-pad 12-15, e o "hat" nos eixos >=6 (POV do
|
|
49
|
+
* DirectInput). Controles com os dois direcionais mapeados ficam com ambos vivos (dedo no stick não mata o D-pad). */
|
|
50
|
+
export declare function stdDirs(gp: PadLike): Dirs;
|
|
51
|
+
/** Está o binding `bd` ativo agora neste gamepad? Digital = pressed; analógico ({ax,s}) = limiar por sinal
|
|
52
|
+
* (metade do curso); hat ({av,v}) = valor exato do passo (±0.13 — os 8 passos distam ~0.286). */
|
|
53
|
+
export declare function bindActive(gp: PadLike, bd: PadBinding | null | undefined): boolean;
|
|
54
|
+
/** Ações do frame para este gamepad. `custom` = mapa salvo pelo wizard para este `gp.id` (null/`_skip` = usa o
|
|
55
|
+
* mapa PADRÃO da Gamepad API "standard": 0=pulo · 1=especial · 2/5/7=correr · 3=troca · 9=START). Direções
|
|
56
|
+
* custom caem de volta em stdDirs quando o binding do usuário não está ativo (D-pad/stick continuam vivos). */
|
|
57
|
+
export declare function padActions(gp: PadLike, custom: PadMap | null): PadActions;
|
|
58
|
+
/**
|
|
59
|
+
* A ORDEM em que o assistente pergunta. SÓ a ordem.
|
|
60
|
+
*
|
|
61
|
+
* ⚠️ ELA CARREGAVA AS PALAVRAS, EM PORTUGUÊS CRU, DENTRO DA ENGINE: `['action2', 'PULAR']`,
|
|
62
|
+
* `['action1', 'CORRER / INTERAGIR']`. Era o defeito do ADR-0074 na sua forma mais visível — não só
|
|
63
|
+
* vocabulário de plataforma dentro do motor, mas vocabulário de plataforma NUM IDIOMA SÓ, à frente de uma
|
|
64
|
+
* criança, num ficheiro que o pilar 3 obriga a ser localizável.
|
|
65
|
+
*
|
|
66
|
+
* A palavra vem agora de `ctx.rotuloDaAcao`, que o jogo fornece pelo seu preset. Aqui fica o que é mesmo da
|
|
67
|
+
* engine: a sequência em que se pergunta — direções primeiro, ação depois, sistema no fim —, que é uma
|
|
68
|
+
* decisão de ergonomia do assistente e não do jogo.
|
|
69
|
+
*
|
|
70
|
+
* ⚠️ E UMA AÇÃO QUE O JOGO NÃO NOMEIA NÃO É PERGUNTADA. `wizPrompt` salta-a, porque um jogo que não usa a
|
|
71
|
+
* posição não tem o que mapear nela — e perguntar produziria um passo mudo, ou pior, um passo a dizer
|
|
72
|
+
* `action7` em voz alta.
|
|
73
|
+
*/
|
|
74
|
+
export declare const PADWIZ_ORDER: readonly string[];
|
|
75
|
+
export interface WizAnimDef {
|
|
76
|
+
seq?: string[];
|
|
77
|
+
hold?: number;
|
|
78
|
+
cls: string;
|
|
79
|
+
fx?: string;
|
|
80
|
+
noimg?: number;
|
|
81
|
+
flip?: number;
|
|
82
|
+
}
|
|
83
|
+
/** Demonstração animada de cada ação (frames reais do jogo) mostrada durante o passo correspondente do wizard. */
|
|
84
|
+
export declare const PADWIZ_ANIM: Record<string, WizAnimDef>;
|
|
85
|
+
interface WizBase {
|
|
86
|
+
b: boolean[];
|
|
87
|
+
a: number[];
|
|
88
|
+
}
|
|
89
|
+
interface WizAxTrack {
|
|
90
|
+
i: number;
|
|
91
|
+
v: number;
|
|
92
|
+
last: number;
|
|
93
|
+
changes: number;
|
|
94
|
+
ticks: number;
|
|
95
|
+
}
|
|
96
|
+
/** Estado do wizard em andamento; `null` = fechado. Espelha o `padWiz` do game.js. */
|
|
97
|
+
export interface WizState {
|
|
98
|
+
gi: number;
|
|
99
|
+
id: string;
|
|
100
|
+
step: number;
|
|
101
|
+
base: WizBase | null;
|
|
102
|
+
map: PadMap;
|
|
103
|
+
release: boolean;
|
|
104
|
+
baseWait: boolean;
|
|
105
|
+
axTrack: WizAxTrack | null;
|
|
106
|
+
timer: ReturnType<typeof setInterval> | null;
|
|
107
|
+
}
|
|
108
|
+
import type { NavKeys } from './edges.js';
|
|
109
|
+
import type { ModalIntent } from './keydown.js';
|
|
110
|
+
import type { DomQuery } from '../core/dom-query.js';
|
|
111
|
+
export type { NavKeys } from './edges.js';
|
|
112
|
+
/** Forma mínima de jogador que este módulo lê/escreve — DERIVADA de core/entity, não redigitada.
|
|
113
|
+
* (`quiz` SAIU em 2026-08-25 — ADR-0033. Era `{ kind: string } | null` aqui e `{ kind?: string } | null` no
|
|
114
|
+
* keydown, o mesmo objeto do JOGO com o discriminante obrigatório num módulo e opcional no outro. Hoje
|
|
115
|
+
* nenhum dos dois o lê: a pergunta é `ctx.hasModal(i)` e a resposta é uma INTENÇÃO.) */
|
|
116
|
+
export type GamepadPlayer = PlayerView<'pad' | 'quit' | 'waiting' | 'easy' | 'jumpEdge' | 'runEdge' | 'leftEdge' | 'rightEdge' | 'swapEdge' | 'specialEdge'>;
|
|
117
|
+
export interface GamepadCtx {
|
|
118
|
+
/** Adaptador da Gamepad API (substitui `navigator.getGamepads()`) — o ponto de DI para testar sem browser. */
|
|
119
|
+
getGamepads: GetGamepads;
|
|
120
|
+
/** Seletor DOM (querySelector), injetado — nunca alcança `document` global. */
|
|
121
|
+
$: DomQuery;
|
|
122
|
+
/**
|
|
123
|
+
* COMO SE CHAMA esta posição, na palavra do JOGO e no idioma vigente. `null` = o jogo não a usa.
|
|
124
|
+
*
|
|
125
|
+
* ⚠️ É a fronteira do corte de 2026-09-06 em forma de campo: a engine sabe que existe uma posição,
|
|
126
|
+
* só o jogo sabe a palavra. Antes desta linha o assistente dizia «PULAR» a partir de uma constante
|
|
127
|
+
* deste ficheiro — em português, sem passar por `t()`, dentro do motor.
|
|
128
|
+
*/
|
|
129
|
+
rotuloDaAcao: (acao: string) => string | null;
|
|
130
|
+
/** Anúncios de leitor de tela (core/a11y-sr), injetados. */
|
|
131
|
+
srSay: (msg: string) => void;
|
|
132
|
+
srAlert: (msg: string) => void;
|
|
133
|
+
/** Traz um overlay para frente + preenche o texto de ajuda (game.js's frontOverlay, compartilhado por todo overlay). */
|
|
134
|
+
frontOverlay: (el: HTMLElement | null) => void;
|
|
135
|
+
/** O mundo está rodando? (START aqui PAUSA.) */
|
|
136
|
+
mundoRodando: () => boolean;
|
|
137
|
+
/** O menu de pausa está aberto? (START aqui RETOMA.) */
|
|
138
|
+
menuDePausa: () => boolean;
|
|
139
|
+
/** Pausar e retomar. Quem empilha a cena é a raiz; daqui sai só a intenção. */
|
|
140
|
+
pausar: () => void;
|
|
141
|
+
retomar: () => void;
|
|
142
|
+
/** Modo demonstração (attract) — game.js's attractCtl. */
|
|
143
|
+
isAttractActive: () => boolean;
|
|
144
|
+
stopAttract: () => void;
|
|
145
|
+
/** Controles virtuais de toque — somem no primeiro input físico. */
|
|
146
|
+
isTouchMode: () => boolean;
|
|
147
|
+
hideTouchControls: () => void;
|
|
148
|
+
/** Estado vivo de jogadores/telas (core/state.ts, injetado como getter — nunca cacheado por este módulo). */
|
|
149
|
+
getPlayers: () => GamepadPlayer[];
|
|
150
|
+
getNumPlayers: () => number;
|
|
151
|
+
/** Navegação de menus (game.js): título, diálogo compartilhado (o de cima), e a pausa por tela. */
|
|
152
|
+
navTitle: (k: NavKeys) => void;
|
|
153
|
+
/** A tela `i` está no modo `accessibility`? (ADR-0044, item 7 — o direcional dirige a barra do HUD.) */
|
|
154
|
+
naBarraDe: (i: number) => boolean;
|
|
155
|
+
/** Um passo dentro da barra. `temStart` é a borda do botão de pausa, que é a SEGUNDA saída do modo. */
|
|
156
|
+
navBar: (i: number, k: NavKeys, temStart: boolean) => void;
|
|
157
|
+
sharedDialogOpen: () => HTMLElement | null;
|
|
158
|
+
navDialog: (dlg: HTMLElement, k: NavKeys) => void;
|
|
159
|
+
/** A tela de pausa do jogador. `HTMLElement` e não `{ hidden: boolean }`: o mínimo estrutural funciona
|
|
160
|
+
* para LER, mas este módulo REPASSA o menu para `navPause`, que precisa do elemento inteiro — e em
|
|
161
|
+
* posição de parâmetro a fatia mínima se inverte (ADR-0039). Mesma lição do `held` em audio-nav. */
|
|
162
|
+
getPauseMenu: (playerIndex: number) => HTMLElement | null | undefined;
|
|
163
|
+
navPause: (menu: HTMLElement, playerIndex: number, k: NavKeys) => void;
|
|
164
|
+
/** Qual jogador abre o submenu de a11y em seguida (game.js's `pauseActor`). */
|
|
165
|
+
setPauseActor: (playerIndex: number) => void;
|
|
166
|
+
/**
|
|
167
|
+
* MODAL do PRÓPRIO jogador: a engine entrega a INTENÇÃO, o jogo decide (ADR-0033).
|
|
168
|
+
*
|
|
169
|
+
* Eram quatro — `quizMove(p, delta)`, `quizConfirm`, `quizErase`, `announceBraille` — e as quatro existiam
|
|
170
|
+
* porque a decisão de qual chamar morava aqui, com a grade de três colunas e o desvio de Braille. O pad e
|
|
171
|
+
* o teclado tinham CÓPIAS dessa mesma decisão, o que é a pior forma de tê-la: duas para divergir.
|
|
172
|
+
*/
|
|
173
|
+
/** O ÍNDICE do jogador, não o jogador (ADR-0033/0039): a engine entrega intenção e não precisa saber o
|
|
174
|
+
* que é um jogador com desafio aberto. Quem resolve o índice é o dono do desafio. */
|
|
175
|
+
modalInput: (playerIndex: number, intent: ModalIntent) => void;
|
|
176
|
+
/** Este jogador tem um modal aberto? Uma pergunta, e não o objeto do jogo. */
|
|
177
|
+
hasModal: (playerIndex: number) => boolean;
|
|
178
|
+
/** Entra num jogo em andamento com uma tela nova (game.js's joinPlayer). */
|
|
179
|
+
joinPlayer: (padIndex: number) => boolean;
|
|
180
|
+
/** Recomeça só a tela deste jogador (game.js's respawnPlayer). */
|
|
181
|
+
respawnPlayer: (playerIndex: number) => void;
|
|
182
|
+
/** Remove o selo "aguardando" da tela quando ela ganha um controle (parte do HUD, game.js). */
|
|
183
|
+
clearWaitingBadge: (playerIndex: number) => void;
|
|
184
|
+
/**
|
|
185
|
+
* Caminho-base dos sprites usado pela demo animada do wizard. NOTA — bug encontrado, não corrigido: o
|
|
186
|
+
* game.js original referencia um identificador `SPR` que NUNCA é declarado/importado ali (só existe, sem
|
|
187
|
+
* export, em render/sprites.ts) — `padWizDemo`/`padWizDemoTick` lançam ReferenceError em runtime assim que
|
|
188
|
+
* o wizard mostra qualquer demonstração animada (inclusive ao abrir: `padWizDemo(null)` já cai no ramo que lê
|
|
189
|
+
* `SPR`). Fica como dependência EXPLÍCITA aqui em vez de reproduzir o global inexistente — ver retorno da tarefa.
|
|
190
|
+
*/
|
|
191
|
+
spriteBase: string;
|
|
192
|
+
}
|
|
193
|
+
export interface GamepadApi {
|
|
194
|
+
pollPads(): void;
|
|
195
|
+
openPadWiz(): void;
|
|
196
|
+
openPadWizFor(gp: PadLike): void;
|
|
197
|
+
closePadWiz(save: boolean): void;
|
|
198
|
+
padWizTick(): void;
|
|
199
|
+
padMapFor(id: string): PadMap | null;
|
|
200
|
+
/** Estado vivo do wizard (para expor via `get padWiz(){}` no window.__incl, como o game.js original). */
|
|
201
|
+
getPadWiz(): WizState | null;
|
|
202
|
+
}
|
|
203
|
+
export declare function initGamepad(ctx: GamepadCtx): GamepadApi;
|