@the-inclusionist/engine 7.0.1 → 8.0.0-rc.2
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 +5 -3
- package/app/css/style.css +22 -5
- package/app/public/vendor/fonts/fondamento-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/fondamento-400.woff2 +0 -0
- package/app/public/vendor/fonts/opendyslexic-400.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-ar.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-br.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-ca.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-cl.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-co.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-mx.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-us-modern.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-us-trad.woff2 +0 -0
- package/app/public/vendor/fonts/pressstart-400.woff2 +0 -0
- package/app/public/vendor/fonts.css +64 -2
- package/dist-pkg/boot/create-game.d.ts +107 -4
- package/dist-pkg/boot/create-game.js +337 -18
- package/dist-pkg/core/constants.d.ts +0 -28
- package/dist-pkg/core/constants.js +34 -17
- package/dist-pkg/core/contract.d.ts +99 -0
- package/dist-pkg/core/contract.js +78 -0
- package/dist-pkg/core/entity.d.ts +47 -4
- package/dist-pkg/core/layers.d.ts +18 -0
- package/dist-pkg/core/layers.js +18 -0
- package/dist-pkg/core/rng.js +14 -4
- package/dist-pkg/core/route.d.ts +42 -0
- package/dist-pkg/core/route.js +158 -0
- package/dist-pkg/core/state.d.ts +10 -1
- package/dist-pkg/core/state.js +13 -0
- package/dist-pkg/educational/adaptive-engine.d.ts +65 -0
- package/dist-pkg/educational/adaptive-engine.js +117 -0
- package/dist-pkg/educational/segment-bar.d.ts +96 -0
- package/dist-pkg/educational/segment-bar.js +89 -0
- package/dist-pkg/i18n/en.js +44 -0
- package/dist-pkg/i18n/es.js +44 -0
- package/dist-pkg/i18n/pt.js +60 -0
- package/dist-pkg/input/default-bindings.d.ts +40 -0
- package/dist-pkg/input/default-bindings.js +151 -9
- package/dist-pkg/input/gamepad.d.ts +33 -12
- package/dist-pkg/input/gamepad.js +103 -16
- package/dist-pkg/input/keyboard-runtime.d.ts +6 -8
- package/dist-pkg/input/keyboard-runtime.js +24 -5
- package/dist-pkg/input/keyboard.d.ts +42 -0
- package/dist-pkg/input/keyboard.js +87 -17
- package/dist-pkg/input/keydown.d.ts +40 -2
- package/dist-pkg/input/keydown.js +29 -6
- package/dist-pkg/input/latch-edge.d.ts +28 -0
- package/dist-pkg/input/latch-edge.js +45 -0
- package/dist-pkg/input/latch-scope.d.ts +70 -0
- package/dist-pkg/input/latch-scope.js +110 -0
- package/dist-pkg/input/latch-store.d.ts +45 -0
- package/dist-pkg/input/latch-store.js +74 -0
- package/dist-pkg/input/latch-sync.d.ts +47 -0
- package/dist-pkg/input/latch-sync.js +43 -0
- package/dist-pkg/input/origem-sintetica.d.ts +44 -0
- package/dist-pkg/input/origem-sintetica.js +60 -0
- package/dist-pkg/input/pad-defaults.d.ts +22 -0
- package/dist-pkg/input/pad-defaults.js +34 -0
- package/dist-pkg/input/pointer.d.ts +61 -0
- package/dist-pkg/input/pointer.js +71 -0
- package/dist-pkg/input/state.d.ts +86 -1
- package/dist-pkg/input/state.js +128 -1
- package/dist-pkg/input/touch-bindings.d.ts +21 -2
- package/dist-pkg/input/touch-bindings.js +15 -3
- package/dist-pkg/input/touch.js +9 -1
- package/dist-pkg/input/transporte-em-uso.d.ts +101 -0
- package/dist-pkg/input/transporte-em-uso.js +130 -0
- package/dist-pkg/input/transports.d.ts +88 -2
- package/dist-pkg/input/transports.js +60 -5
- package/dist-pkg/input/vocabulary-migration.d.ts +18 -7
- package/dist-pkg/platform/audio-earcons.d.ts +29 -2
- package/dist-pkg/platform/audio-earcons.js +10 -0
- package/dist-pkg/platform/audio-nav.d.ts +1 -1
- package/dist-pkg/platform/audio-sonar.d.ts +149 -9
- package/dist-pkg/platform/audio-sonar.js +232 -21
- package/dist-pkg/platform/guide-intensity.d.ts +40 -0
- package/dist-pkg/platform/guide-intensity.js +73 -0
- package/dist-pkg/platform/pesados-catalogo.d.ts +14 -0
- package/dist-pkg/platform/pesados-catalogo.js +177 -0
- package/dist-pkg/platform/pesados.d.ts +31 -0
- package/dist-pkg/platform/pesados.js +75 -0
- package/dist-pkg/platform/storage.d.ts +30 -0
- package/dist-pkg/platform/storage.js +35 -0
- package/dist-pkg/platform/tts.js +16 -1
- package/dist-pkg/platform/voice-plan.d.ts +109 -0
- package/dist-pkg/platform/voice-plan.js +156 -0
- package/dist-pkg/platform/vozes-prontas.d.ts +28 -0
- package/dist-pkg/platform/vozes-prontas.js +61 -0
- package/dist-pkg/render/draw.d.ts +1 -1
- package/dist-pkg/render/draw.js +15 -5
- package/dist-pkg/render/viz-axes.d.ts +17 -0
- package/dist-pkg/render/viz-axes.js +19 -0
- package/dist-pkg/render/viz-setters.d.ts +34 -2
- package/dist-pkg/render/viz-setters.js +189 -33
- package/dist-pkg/render/wheelchair-sprites.d.ts +11 -3
- package/dist-pkg/render/wheelchair-sprites.js +10 -4
- package/dist-pkg/ui/dom.js +20 -2
- package/dist-pkg/ui/fonts.d.ts +71 -1
- package/dist-pkg/ui/fonts.js +111 -8
- package/dist-pkg/ui/latch-refusal.d.ts +32 -0
- package/dist-pkg/ui/latch-refusal.js +60 -0
- package/dist-pkg/ui/layout.d.ts +32 -0
- package/dist-pkg/ui/layout.js +64 -1
- package/dist-pkg/ui/motion-scene.d.ts +41 -0
- package/dist-pkg/ui/motion-scene.js +76 -0
- package/dist-pkg/ui/panel-shell.d.ts +53 -0
- package/dist-pkg/ui/panel-shell.js +103 -0
- package/dist-pkg/ui/pause-icons.d.ts +168 -20
- package/dist-pkg/ui/pause-icons.js +315 -45
- package/dist-pkg/ui/reach-notice.js +8 -0
- package/dist-pkg/ui/settings-audio.d.ts +14 -1
- package/dist-pkg/ui/settings-audio.js +43 -3
- package/dist-pkg/ui/settings-controls.d.ts +66 -6
- package/dist-pkg/ui/settings-controls.js +179 -17
- package/dist-pkg/ui/settings-empathy.d.ts +15 -0
- package/dist-pkg/ui/settings-empathy.js +2 -0
- package/dist-pkg/ui/settings-motion.d.ts +25 -19
- package/dist-pkg/ui/settings-motion.js +32 -19
- package/dist-pkg/ui/settings-motor.d.ts +101 -3
- package/dist-pkg/ui/settings-motor.js +136 -9
- package/dist-pkg/ui/settings-typo.d.ts +49 -5
- package/dist-pkg/ui/settings-typo.js +74 -23
- package/dist-pkg/ui/settings-visual.d.ts +21 -1
- package/dist-pkg/ui/settings-visual.js +48 -4
- package/dist-pkg/ui/shell.d.ts +13 -3
- package/dist-pkg/ui/shell.js +3 -4
- package/dist-pkg/ui/simulation-refusal.d.ts +32 -0
- package/dist-pkg/ui/simulation-refusal.js +57 -0
- package/dist-pkg/ui/visual-axes-panel.d.ts +48 -0
- package/dist-pkg/ui/visual-axes-panel.js +95 -0
- package/dist-pkg/ui/webcam.js +6 -1
- package/docs/CREDITS.md +22 -1
- package/docs/LICENSES.md +170 -132
- package/package.json +25 -4
- package/app/public/vendor/fonts/greatvibes-400.woff2 +0 -0
- package/app/public/vendor/fonts/ufcook-700.woff2 +0 -0
package/README.md
CHANGED
|
@@ -70,9 +70,11 @@ npm test # testes Vitest (node + browser via Playwright); npm run test
|
|
|
70
70
|
`allow_failure: true` e estavam vermelhos havia semanas. O histórico o guarda; o cabeçalho do `ci.yml`
|
|
71
71
|
documenta o porte linha a linha.
|
|
72
72
|
|
|
73
|
-
- **CD** —
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
- **CD** — ⚠️ **NÃO HÁ NENHUM**, hoje. Informado pelo Dev em 2026-09-07: **nenhum projeto do Cloudflare Pages
|
|
74
|
+
está conectado a repositório nenhum**. A ressalva anterior — «a conexão apontava para o GitLab, que agora
|
|
75
|
+
está arquivado» — descrevia um deploy desapontado; o estado atual é mais simples e mais grave de confundir:
|
|
76
|
+
**push não é publicação**, e `dist/` só chega a alguém por um passo manual.
|
|
77
|
+
A tabela abaixo fica como a RECEITA de quando houver conexão, e não como descrição do que existe:
|
|
76
78
|
|
|
77
79
|
| Configuração | Valor |
|
|
78
80
|
|---|---|
|
package/app/css/style.css
CHANGED
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
--z-menu:30000;
|
|
52
52
|
--z-menu-max:39999;
|
|
53
53
|
--z-transition:40000;
|
|
54
|
+
--z-skip-link:41000;
|
|
54
55
|
--z-loop-crash:45000;
|
|
55
56
|
--z-debug:90000;
|
|
56
57
|
}
|
|
@@ -178,7 +179,9 @@ html,body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--font)
|
|
|
178
179
|
(tolerância de 5px lógicos/lado) é cortado pelo .stage-wrap, e os menus rolam DENTRO dos cards. */
|
|
179
180
|
body{display:flex;flex-direction:column;height:100vh;height:100dvh;overflow:hidden}
|
|
180
181
|
.sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
|
|
181
|
-
|
|
182
|
+
/* O `z-index` ADOTOU O SLOT em 2026-09-07. Era `100`, um literal que estava CERTO e cuja tabela estava
|
|
183
|
+
errada: o `Z` punha o skip-link em CAPTIONS(26000), abaixo dos modais. Ver `SKIP_LINK` em core/layers. */
|
|
184
|
+
.skip-link{position:absolute;left:8px;top:-60px;background:var(--accent);color:var(--accent-ink);padding:.6em 1em;border-radius:0 0 10px 10px;font-weight:700;z-index:var(--z-skip-link);transition:top .15s}
|
|
182
185
|
.skip-link:focus{top:0}
|
|
183
186
|
:focus-visible{outline:4px solid var(--focus);outline-offset:2px;border-radius:6px}
|
|
184
187
|
|
|
@@ -300,10 +303,24 @@ body:not(.dbg) .topbar{display:none} /* título da PÁGINA só em ?debug=true (o
|
|
|
300
303
|
navegador, e sem esta linha as duas listas do cartão de pausa apareceriam empilhadas (ADR-0044, item 5). */
|
|
301
304
|
.pause-menu[hidden]{display:none}
|
|
302
305
|
/* 44 px NÃO é o mínimo da WCAG — o 2.5.8 pede 24×24, e o cartão já passava nisso com folga. 44 é a
|
|
303
|
-
recomendação da Apple (HIG)
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
306
|
+
recomendação da Apple (HIG). `min-height` e não `padding` porque a altura de antes (35,6 px) não estava
|
|
307
|
+
declarada em lugar nenhum: ela RESULTAVA da soma de padding, fonte e entrelinha. Um alvo que ninguém
|
|
308
|
+
escreveu é um alvo que ninguém defende.
|
|
309
|
+
|
|
310
|
+
⚠️ ESTA LINHA DIZIA TAMBÉM «e este projeto trata piso como piso», e essa metade morreu no ADR-0095: o
|
|
311
|
+
piso deixou de ser um número único e passou a ser a régua abaixo. Fica o resto, que continua a valer. */
|
|
312
|
+
/* ⚠️ O ALVO DO ITEM DE MENU SEGUE A RÉGUA DO ADR-0095, e não um literal.
|
|
313
|
+
Era `min-height:44px` cravado. O registro fixou que o alvo é função da ALTURA DA TELA — 24 px (WCAG
|
|
314
|
+
2.5.8, AA) abaixo de 540, 34 a partir de 540, 44 (2.5.5, AAA) a partir de 720 — porque um alvo grande
|
|
315
|
+
que exige ROLAGEM para ser alcançado pode custar mais dedo do que um menor que está à vista.
|
|
316
|
+
|
|
317
|
+
⚠️ E ELE USA `--alvo-min` E NÃO `--tap`, que são coisas diferentes: `--tap` é o tamanho PREFERIDO e
|
|
318
|
+
cresce com a escala do canvas (22 × k, nunca menos de 44); `--alvo-min` é o CHÃO por altura. Um botão
|
|
319
|
+
isolado pode ser o preferido; um item de LISTA, que tem de caber inteiro, usa o chão.
|
|
320
|
+
|
|
321
|
+
O `44px` do fallback é o comportamento de antes, para o caso de `layout()` não ter corrido — que era
|
|
322
|
+
exatamente o que acontecia no `quiz.html` até 07/09. */
|
|
323
|
+
.pm-btn{background:#1a2740;color:#eaf2f8;border:1px solid #3a4a6a;border-radius:10px;padding:.5rem .8rem;min-height:var(--alvo-min,44px);display:flex;align-items:center;justify-content:center;font:inherit;font-weight:700;cursor:pointer;white-space:nowrap}
|
|
307
324
|
.pm-btn:hover,.pm-btn:focus,.pm-btn.pm-sel{background:#2a3a5e;border-color:#ffd23f;outline:2px solid #ffd23f;outline-offset:1px}
|
|
308
325
|
/* Legenda sim/não: ícone do botão (conforme layout do controle) + a palavra. Sony/Nintendo invertem 0↔1. */
|
|
309
326
|
.pause-legend{display:flex;gap:1.1rem;justify-content:center;margin:.7rem 0 .1rem;font-size:.82em;color:#c3cfe0}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -80,9 +80,71 @@
|
|
|
80
80
|
@font-face{font-family:'Newsreader';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/newsreader-400.woff2') format('woff2');}
|
|
81
81
|
@font-face{font-family:'Newsreader';font-style:normal;font-weight:700;font-display:swap;src:url('fonts/newsreader-700.woff2') format('woff2');}
|
|
82
82
|
/* Manuscritas (caligráficas inglesas · blackletter alemãs · alfabetização) */
|
|
83
|
-
@font-face{font-family:'Great Vibes';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/greatvibes-400.woff2') format('woff2');}
|
|
84
83
|
@font-face{font-family:'Pinyon Script';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/pinyon-400.woff2') format('woff2');}
|
|
85
|
-
@font-face{font-family:'UnifrakturCook';font-style:normal;font-weight:700;font-display:swap;src:url('fonts/ufcook-700.woff2') format('woff2');}
|
|
86
84
|
@font-face{font-family:'UnifrakturMaguntia';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/ufmag-400.woff2') format('woff2');}
|
|
87
85
|
@font-face{font-family:'Comic Neue';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/comicneue-400.woff2') format('woff2');}
|
|
88
86
|
@font-face{font-family:'Comic Neue';font-style:normal;font-weight:700;font-display:swap;src:url('fonts/comicneue-700.woff2') format('woff2');}
|
|
87
|
+
|
|
88
|
+
/* ===== ARCADE (papel `jogo`: HUD, título, rótulos — NUNCA a face da interface) =====
|
|
89
|
+
⚠️ SEM `unicode-range`, E É DELIBERADO. O Google Fonts serve esta família em CINCO ficheiros ordenados
|
|
90
|
+
por `unicode-range` **com o latino por ÚLTIMO**, e uma vendorização que pegue no primeiro `src:` traz o
|
|
91
|
+
subconjunto cirílico — um woff2 válido, corretamente declarado, corretamente carregado, e sem uma única
|
|
92
|
+
letra latina.
|
|
93
|
+
|
|
94
|
+
Isso aconteceu de verdade, no `SP-the-inclusionist-whackwhack`: o título saiu na fonte errada durante
|
|
95
|
+
QUATRO commits e todas as verificações disponíveis diziam que estava certo —
|
|
96
|
+
`document.fonts.check()` devolvia `true`, o `status` era `loaded`, o `getComputedStyle` mostrava a
|
|
97
|
+
família certa. As três comparam o NOME da família, uma string escrita duas vezes pela mesma mão; nenhuma
|
|
98
|
+
olha para dentro do ficheiro. E o CSS resolve por CODEPOINT, então uma face sem glifo para `U+0057` é
|
|
99
|
+
ignorada para aquele caractere em silêncio.
|
|
100
|
+
|
|
101
|
+
O ficheiro aqui é o subconjunto LATINO, copiado daquele repositório já verificado, e o gate que o mede
|
|
102
|
+
é `tests/fonte-arcade.browser.test.js` — pela LARGURA DE AVANÇO, que vem do glifo e portanto do ficheiro. */
|
|
103
|
+
@font-face{font-family:'Press Start 2P';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/pressstart-400.woff2') format('woff2');}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
/* ===== OpenDyslexic (ACESSIBILIDADE — oferecida, e SEM alegação de eficácia) =====
|
|
107
|
+
SIL OFL 1.1, confirmada na API do repositório oficial (antijingoist/opendyslexic) e não de memória — a
|
|
108
|
+
licença desta face JÁ MUDOU uma vez, e afirmar de cabeça seria afirmar o estado antigo.
|
|
109
|
+
|
|
110
|
+
⚠️ ELA NÃO PROMETE LEITURA MELHOR, e isso é decisão registada. O `docs/game-design/typography.md` diz por
|
|
111
|
+
extenso: «Ofereça a Dyslexie e a OpenDyslexic apenas como escolha do usuário. A pesquisa não mostra ganho
|
|
112
|
+
de leitura com elas.» A descrição no menu fala do desenho — hastes pesadas na base —, nunca do efeito.
|
|
113
|
+
|
|
114
|
+
⚠️ E ELA NÃO É SUBCONJUNTO: 100,9 KB do ficheiro compilado do próprio projeto, contra 23 KB da Fondamento
|
|
115
|
+
latina. É a face mais pesada do roster, e entra assim porque o upstream não publica subconjuntos; quem
|
|
116
|
+
quiser cortá-la depois faz por `pyftsubset`, e o gate de precache é quem reclama se o orçamento apertar. */
|
|
117
|
+
@font-face{font-family:'OpenDyslexic';font-style:normal;font-weight:400;font-display:swap;
|
|
118
|
+
src:url('fonts/opendyslexic-400.woff2') format('woff2');}
|
|
119
|
+
|
|
120
|
+
/* ===== Fondamento (CALIGRÁFICA — fora do menu, para dentro das atividades) =====
|
|
121
|
+
SIL OFL 1.1, do Google Fonts, nos dois subconjuntos que ele serve. Mínimo de 20 px fixado pelo Dev na
|
|
122
|
+
emenda do ADR-0012: abaixo disso a face deixa de ser DIFÍCIL e passa a ser ilegível, e as duas coisas são
|
|
123
|
+
diferentes — a dificuldade é o exercício, a ilegibilidade é a criança a desistir. */
|
|
124
|
+
@font-face{font-family:'Fondamento';font-style:normal;font-weight:400;font-display:swap;
|
|
125
|
+
src:url('fonts/fondamento-400.woff2') format('woff2');
|
|
126
|
+
unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
|
|
127
|
+
@font-face{font-family:'Fondamento';font-style:normal;font-weight:400;font-display:swap;
|
|
128
|
+
src:url('fonts/fondamento-400-ext.woff2') format('woff2');
|
|
129
|
+
unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;}
|
|
130
|
+
|
|
131
|
+
/* ===== Playwrite — as OITO das Américas (ADR-0108 §2, issue #87 item 3) =====
|
|
132
|
+
* A mão que cada país ensina a escrever. Os EUA entram com AS DUAS que ensinam — escolher uma seria
|
|
133
|
+
* escolher pela criança. São variáveis no peso (100–400) e cada família é UM ficheiro: a Google não as
|
|
134
|
+
* corta por unicode-range, então não há metade `-ext` para carregar depois. SIL OFL 1.1, como as outras. */
|
|
135
|
+
@font-face{font-family:'Playwrite BR';font-style:normal;font-weight:100 400;font-display:swap;
|
|
136
|
+
src:url('fonts/playwrite-br.woff2') format('woff2');}
|
|
137
|
+
@font-face{font-family:'Playwrite US Trad';font-style:normal;font-weight:100 400;font-display:swap;
|
|
138
|
+
src:url('fonts/playwrite-us-trad.woff2') format('woff2');}
|
|
139
|
+
@font-face{font-family:'Playwrite US Modern';font-style:normal;font-weight:100 400;font-display:swap;
|
|
140
|
+
src:url('fonts/playwrite-us-modern.woff2') format('woff2');}
|
|
141
|
+
@font-face{font-family:'Playwrite CA';font-style:normal;font-weight:100 400;font-display:swap;
|
|
142
|
+
src:url('fonts/playwrite-ca.woff2') format('woff2');}
|
|
143
|
+
@font-face{font-family:'Playwrite MX';font-style:normal;font-weight:100 400;font-display:swap;
|
|
144
|
+
src:url('fonts/playwrite-mx.woff2') format('woff2');}
|
|
145
|
+
@font-face{font-family:'Playwrite AR';font-style:normal;font-weight:100 400;font-display:swap;
|
|
146
|
+
src:url('fonts/playwrite-ar.woff2') format('woff2');}
|
|
147
|
+
@font-face{font-family:'Playwrite CL';font-style:normal;font-weight:100 400;font-display:swap;
|
|
148
|
+
src:url('fonts/playwrite-cl.woff2') format('woff2');}
|
|
149
|
+
@font-face{font-family:'Playwrite CO';font-style:normal;font-weight:100 400;font-display:swap;
|
|
150
|
+
src:url('fonts/playwrite-co.woff2') format('woff2');}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
2
|
import { type Alcance, type Disponibilidade } from '../input/transports.js';
|
|
3
3
|
import { type ActionPreset } from '../core/actions.js';
|
|
4
|
+
import type { KeyScheme } from '../core/entity.js';
|
|
4
5
|
import { type GameDeclaration } from '../core/contract.js';
|
|
5
6
|
import { type SceneStack } from '../core/scenes.js';
|
|
6
7
|
import { createTts, type CarregarVozNeural } from '../platform/tts.js';
|
|
@@ -10,12 +11,49 @@ import { type SettingsPanelApi } from '../ui/settings-panel.js';
|
|
|
10
11
|
import { type MenuNavApi } from '../ui/menu-nav.js';
|
|
11
12
|
import type { NavKeys } from '../input/edges.js';
|
|
12
13
|
import { type KeyboardRuntime } from '../input/keyboard-runtime.js';
|
|
14
|
+
import { type RelatorioPesado } from '../platform/pesados.js';
|
|
13
15
|
/** O que o jogo empresta do documento. Tudo opcional menos `doc`/`win`: o que faltar vira `problems`. */
|
|
14
16
|
export interface EngineHost {
|
|
15
17
|
readonly doc: Document;
|
|
16
18
|
readonly win: Window;
|
|
17
19
|
/** Um `<svg>` vazio onde os seis filtros de daltonismo são montados em tempo de execução. */
|
|
18
20
|
readonly cvdHost?: SVGElement | Element | null;
|
|
21
|
+
/**
|
|
22
|
+
* ONDE A BARRA DE ACESSIBILIDADE ENTRA, na PRIMEIRA tela do jogo.
|
|
23
|
+
*
|
|
24
|
+
* ⚠️ PEDIDO DO DEV, 2026-09-07: «o menu de pausa, o design do menu de pausa e os ícones de acessibilidade
|
|
25
|
+
* que aparecem no jogo desde a primeira tela devem ser oferecidos pela ENGINE e não pela programação do
|
|
26
|
+
* jogo. Todo jogo da engine inclusionist deve ter o mesmo menu de pausa e ícones de acessibilidade desde a
|
|
27
|
+
* primeira.»
|
|
28
|
+
*
|
|
29
|
+
* ⚠️ E A MEDIÇÃO DE 2026-09-08 MOSTROU QUE É UM ACHADO, e não uma arrumação: dos seis jogos do catálogo
|
|
30
|
+
* local, CINCO não têm barra de acessibilidade nenhuma — nem menu de pausa. `pixi-15-puzzle`, `game-chess`,
|
|
31
|
+
* `game-soccer`, `2048` e `whackwhack` não chamam `initPauseIcons` nem montam HUD, e o `createGame` nunca
|
|
32
|
+
* os montou por eles. O comentário do `ui/pause-icons` diz porquê sem o notar: «`initPauseIcons` é chamado
|
|
33
|
+
* pela raiz de composição de CADA jogo» — ou seja, cada jogo tinha de se lembrar, e cinco não se lembraram.
|
|
34
|
+
* A criança que depende do modo cego, do TTS ou do alto contraste abre esses cinco jogos e não tem por onde.
|
|
35
|
+
*
|
|
36
|
+
* Ausente, a engine procura `#title-icons` — o id que o jogo de plataforma usa desde sempre — e, não o
|
|
37
|
+
* achando, diz-o em `problems`.
|
|
38
|
+
*
|
|
39
|
+
* ✅ E DESDE 2026-09-08 ELA TAMBÉM **MONTA** (etapa 2 do ADR-0106 §4). Este parágrafo dizia «dizer não é
|
|
40
|
+
* montar, e a montagem é o passo seguinte»; o passo seguinte aconteceu. O que a destravou foram as etapas
|
|
41
|
+
* 1 e 3: nenhuma delas era sobre montar, e sem as duas o `PauseIconsCtx` exigia sete coisas que esta raiz
|
|
42
|
+
* não sabe responder por um jogo que não conhece.
|
|
43
|
+
*
|
|
44
|
+
* ⚠️ Achando o hospedeiro, a barra é escrita e fiada aqui. Não achando, continua a ser `problems` — porque
|
|
45
|
+
* a engine pode oferecer os ícones, mas não pode adivinhar ONDE eles cabem no desenho de um jogo alheio.
|
|
46
|
+
*/
|
|
47
|
+
readonly a11yBarHost?: Element | null;
|
|
48
|
+
/**
|
|
49
|
+
* ONDE O CARTÃO DE PAUSA da primeira tela é pendurado. Ausente, a engine usa `#game-region`.
|
|
50
|
+
*
|
|
51
|
+
* ⚠️ Existe pela mesma razão do `a11yBarHost`: a engine pode OFERECER a pausa, mas não sabe onde ela cabe
|
|
52
|
+
* no desenho de um jogo alheio. 📌 E desde o ADR-0120 ONDE já não é SE: a pausa deixou de ser declinável, e
|
|
53
|
+
* o que sobra deste campo é o lugar. Um hospedeiro que não aceite filhos vira linha de `problems`, que é a
|
|
54
|
+
* diferença entre a engine não saber e a engine calar-se.
|
|
55
|
+
*/
|
|
56
|
+
readonly pauseHost?: Element | null;
|
|
19
57
|
}
|
|
20
58
|
/**
|
|
21
59
|
* O que este jogo NÃO tem. Declarado, e não deduzido de um getter que devolve null.
|
|
@@ -24,12 +62,24 @@ export interface EngineHost {
|
|
|
24
62
|
* "pausado" para navegar os próprios menus, porque a engine não tinha por onde ouvir "eu não tenho fases".
|
|
25
63
|
*/
|
|
26
64
|
export interface Declinios {
|
|
27
|
-
/** Sem menu de pausa por tela (um quiz não tem). */
|
|
28
|
-
readonly semMenuDePausa?: boolean;
|
|
29
65
|
/** Sem assistente de mapeamento de controle. */
|
|
30
66
|
readonly semAssistenteDePad?: boolean;
|
|
31
67
|
/** Sem "ator da pausa" — quem apertou o botão que abriu o menu. */
|
|
32
68
|
readonly semAtorDePausa?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Sem voz neural — este jogo não abre a porta do ADR-0094.
|
|
71
|
+
*
|
|
72
|
+
* ⚠️ EXISTE PORQUE A AUSÊNCIA ESTAVA A SER SILENCIOSA, e a medição de 2026-09-08 diz quanto: dos SEIS jogos
|
|
73
|
+
* do catálogo local, TRÊS declaram `carregarVozNeural` (platformer, 15-puzzle, 2048) e TRÊS não
|
|
74
|
+
* (`game-soccer`, `whackwhack`, `game-chess`). Nos três últimos não há voz neural nenhuma, e nada o dizia.
|
|
75
|
+
*
|
|
76
|
+
* ⚠️ E ISSO CONTRADIZ UMA PROMESSA ESCRITA. O ADR-0065 §3 diz que as vozes «fazem parte da engine, e não do
|
|
77
|
+
* jogo em si» e que um cartucho «não tem de saber que existe»; o ADR-0094 — com razão, e por 135 MB de WASM
|
|
78
|
+
* — passou a exigir UMA LINHA do jogo. As duas coisas podem ser verdade ao mesmo tempo (a engine é dona das
|
|
79
|
+
* VOZES, o jogo nomeia o FORNECEDOR), mas só se quem esquece a linha for avisado. Declinar é escolha; não
|
|
80
|
+
* declarar era omissão.
|
|
81
|
+
*/
|
|
82
|
+
readonly semVozNeural?: boolean;
|
|
33
83
|
}
|
|
34
84
|
export interface CreateGameOptions {
|
|
35
85
|
/** Os SETE CAMPOS (core/contract). É o que a pilha de acessibilidade lê, e a única coisa que ela lê. */
|
|
@@ -51,9 +101,12 @@ export interface CreateGameOptions {
|
|
|
51
101
|
readonly comIndice?: () => boolean;
|
|
52
102
|
readonly naBarraDe?: (i: number) => boolean;
|
|
53
103
|
readonly navBar?: (i: number, k: NavKeys) => void;
|
|
54
|
-
/** Jogadores para o teclado remapeável. `Pick<ControlledPlayer,'ctrl'>` — esquema de teclas e nada mais.
|
|
104
|
+
/** Jogadores para o teclado remapeável. `Pick<ControlledPlayer,'ctrl'>` — esquema de teclas e nada mais.
|
|
105
|
+
* ⚠️ `KeyScheme` e não `Record<string, string[]>` desde a #118: era uma CÓPIA ESTRUTURAL do tipo, e uma
|
|
106
|
+
* cópia que ninguém obriga a concordar diverge — é a lição que o próprio `core/entity` abre a dizer, com
|
|
107
|
+
* o `DomQuery` (dezasseis cópias) e o `KeyScheme` (seis) como as contas já pagas. */
|
|
55
108
|
readonly players?: {
|
|
56
|
-
ctrl:
|
|
109
|
+
ctrl: KeyScheme;
|
|
57
110
|
}[];
|
|
58
111
|
/** Troca de fase, para quem tem fases. Ausente = não faz nada (o jogo sem fases não perde nada). */
|
|
59
112
|
readonly setPhase?: (p: 'title' | 'playing' | 'paused') => void;
|
|
@@ -91,6 +144,35 @@ export interface CreateGameOptions {
|
|
|
91
144
|
* painel de áudio deixa de OFERECER o motor neural, em vez de o oferecer e nunca o carregar.
|
|
92
145
|
*/
|
|
93
146
|
readonly carregarVozNeural?: CarregarVozNeural;
|
|
147
|
+
/**
|
|
148
|
+
* BAIXAR AS COISAS PESADAS NO PRIMEIRO CARREGAMENTO? Padrão **sim** (ADR-0110 (b), ADR-0116, ADR-0119).
|
|
149
|
+
*
|
|
150
|
+
* As quatro vozes neurais são ~241 MB e descem em SEGUNDO PLANO, uma de cada vez, sem bloquear o jogo: a
|
|
151
|
+
* criança joga enquanto elas chegam, e o que não pode acontecer é ela voltar no segundo dia, sem rede, e
|
|
152
|
+
* descobrir que a voz nunca foi buscada. O pilar 8 é «primeiro dia ONLINE, depois offline-first», e o
|
|
153
|
+
* ADR-0116 tirou a contradição que travava isto — instalar já é um acto de rede.
|
|
154
|
+
*
|
|
155
|
+
* ⚠️ PÔR `false` É PARA QUEM TEM RAZÃO PARA O FAZER, e a razão que já existe é um TESTE: um caso que monte
|
|
156
|
+
* o arranque num navegador de verdade não pode disparar 241 MB contra o Hugging Face. Um jogo em produção
|
|
157
|
+
* que o desligue está a decidir que a criança dele fica sem voz neural offline.
|
|
158
|
+
*
|
|
159
|
+
* 📌 E o ADR-0117 diz que quem devia pagar isto uma vez é a PLATAFORMA, não cada cartucho — a Cache Storage
|
|
160
|
+
* é particionada por origem, e num site só os 241 MB descem uma vez para todos os jogos. Enquanto a
|
|
161
|
+
* plataforma não os pede, é o jogo que os pede: melhor descer duas vezes do que nunca.
|
|
162
|
+
*/
|
|
163
|
+
readonly baixarPesados?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* O QUE ACONTECEU COM CADA COISA PESADA, à medida que acontece. Ausente = ninguém está a ver.
|
|
166
|
+
*
|
|
167
|
+
* ⚠️ É AQUI E NÃO EM `problems` porque a descarga é de FUNDO: `problems` é devolvido sincronamente pelo
|
|
168
|
+
* `createGame`, e uma linha que chegue depois disso entra num vector que o leitor já leu. O ADR-0110 pede
|
|
169
|
+
* que uma busca falhada seja REPORTADA — reportar é ter um canal que existe quando a notícia chega, e não
|
|
170
|
+
* empurrar para uma lista que já foi entregue.
|
|
171
|
+
*
|
|
172
|
+
* 📌 A engine não inventa superfície nenhuma com isto: quem sabe onde cabe «faltam 241 MB» na tela de um
|
|
173
|
+
* jogo é o jogo. `pesoPorBaixar(relatorio)` dá o número para a frase.
|
|
174
|
+
*/
|
|
175
|
+
readonly aoProgredirPesados?: (r: RelatorioPesado) => void;
|
|
94
176
|
/**
|
|
95
177
|
* Como se descobre que cada transporte está aqui. Ausente = a engine pergunta ao aparelho.
|
|
96
178
|
*
|
|
@@ -101,6 +183,27 @@ export interface CreateGameOptions {
|
|
|
101
183
|
}
|
|
102
184
|
export interface Engine {
|
|
103
185
|
readonly declaration: GameDeclaration;
|
|
186
|
+
/**
|
|
187
|
+
* A PAUSA QUE ESTA RAIZ MONTOU — mostrar e esconder, sem o consumidor caçar id nenhum.
|
|
188
|
+
*
|
|
189
|
+
* ⚠️ EXISTE PORQUE MONTAR NÃO É MOSTRAR, e a etapa 2 do ADR-0106 tinha ficado a meio sem que nada o
|
|
190
|
+
* dissesse. O cartão nasce `hidden` (é assim que o `buildScreenPause` o entrega, e tem de ser: a pausa
|
|
191
|
+
* abre-se, não está aberta) e QUEM O REVELA é o `ui/shell`, por fase — que esta raiz **não monta**, de
|
|
192
|
+
* propósito: «não substitui o boot do main.js, que tem catorze anos de ordem própria».
|
|
193
|
+
*
|
|
194
|
+
* ⚠️ Sem estas duas, um jogo montado por `createGame` ficava com um cartão de pausa que NADA mostrava. Não
|
|
195
|
+
* é «o consumidor esqueceu-se»: não havia por onde, a não ser procurar `#vp-pause-0` no documento — que é
|
|
196
|
+
* exactamente o tipo de conhecimento que este ficheiro existe para não exigir.
|
|
197
|
+
*
|
|
198
|
+
* 📌 A engine OFERECE o mecanismo e não toma a fase. Quando abrir a pausa continua a ser do jogo, porque só
|
|
199
|
+
* ele sabe o que é estar a jogar; o que deixa de ser dele é saber COMO.
|
|
200
|
+
*/
|
|
201
|
+
readonly pausa: {
|
|
202
|
+
/** Revela o cartão da tela `i` e refaz os itens — o §5 avaliado no instante em que ela abre. */
|
|
203
|
+
readonly mostrar: (i: number) => void;
|
|
204
|
+
/** Esconde-o outra vez. */
|
|
205
|
+
readonly esconder: (i: number) => void;
|
|
206
|
+
};
|
|
104
207
|
readonly tts: ReturnType<typeof createTts>;
|
|
105
208
|
readonly overlays: SettingsPanelApi;
|
|
106
209
|
readonly nav: MenuNavApi;
|