Contexto
Feedback da persona O Iniciante (discussion #9, fricção nº2, jogado em produção): ao digitar funz no lugar de func, nada fica vermelho onde o olho está. O jogador ficou "por que travei? qual tecla errei?". O único sinal foi numérico e distante (ERROS: 1 / PRECISÃO: 75%).
Diagnóstico técnico (a red já existe, mas no lugar errado para o olhar):
- O painel do código (
CodeDisplay.tsx) já pinta o char errado de vermelho: isError = done && typed[i] !== ch → classe char-error (CodeDisplay.tsx:64).
- Mas o jogador olha para o editor onde digita — a
textarea de CodeEditor.tsx, que é um campo de texto puro e não colore caractere nenhum. Zero feedback de erro no ponto de fixação do olhar.
Race.tsx já sabe, a cada tecla, quantos chars novos vieram errados (Race.tsx:83-88, newErrors) — o sinal para disparar o feedback já existe, só não é usado visualmente.
Isto é exatamente a Parte IV · Spec — erro (docs/UI-AAA-OVERHAUL.md:779): o card do editor treme 4–6px por 80ms no erro, comunicando "erro aqui", + fallback de reduced-motion.
Escopo (1 fatia)
Feedback de erro no card do editor, dirigido pelo sinal de "última tecla foi errada" já computado em handleInput:
- Erro → screen-shake cirúrgico só no card do editor (não a tela toda):
transform na GPU, 4–6px, ~80ms, ease-out decaindo.
prefers-reduced-motion → sem movimento: flash de cor (borda/fundo do card pisca vermelho brevemente) + ícone de erro na margem. Nunca pisca > 3Hz.
- Erro nunca comunicado só por cor: cor + posição (o shake/margem) — mantendo o
char-error do painel de código.
Fora de escopo (não fazer aqui): type.error (som) depende de lib/sound.ts que ainda não existe (§IV.1 🔴); háptico navigator.vibrate pode entrar se trivial, mas é opcional. Combo (§IV.4) é outra issue.
Critérios de aceitação (verificáveis)
Dica de abordagem
handleInput (Race.tsx:74) já detecta newErrors > 0 no bloco de teclas novas — emita daí um "pulso de erro" (ex.: errorPulse timestamp em state, ou um contador) e passe ao CodeEditor, que aplica a classe de shake/flash com key/timeout curto para reprisar em erros consecutivos. Springs/durações da §I (motion tokens) quando aplicável. Testar em produção-like: erro simples, erros consecutivos, e com reduced-motion no DevTools.
Origem: feedback da persona em #9. Referência de spec: docs/UI-AAA-OVERHAUL.md §779 (Parte IV).
Contexto
Feedback da persona O Iniciante (discussion #9, fricção nº2, jogado em produção): ao digitar
funzno lugar defunc, nada fica vermelho onde o olho está. O jogador ficou "por que travei? qual tecla errei?". O único sinal foi numérico e distante (ERROS: 1 / PRECISÃO: 75%).Diagnóstico técnico (a red já existe, mas no lugar errado para o olhar):
CodeDisplay.tsx) já pinta o char errado de vermelho:isError = done && typed[i] !== ch→ classechar-error(CodeDisplay.tsx:64).textareadeCodeEditor.tsx, que é um campo de texto puro e não colore caractere nenhum. Zero feedback de erro no ponto de fixação do olhar.Race.tsxjá sabe, a cada tecla, quantos chars novos vieram errados (Race.tsx:83-88,newErrors) — o sinal para disparar o feedback já existe, só não é usado visualmente.Isto é exatamente a Parte IV · Spec — erro (
docs/UI-AAA-OVERHAUL.md:779): o card do editor treme 4–6px por 80ms no erro, comunicando "erro aqui", + fallback de reduced-motion.Escopo (1 fatia)
Feedback de erro no card do editor, dirigido pelo sinal de "última tecla foi errada" já computado em
handleInput:transformna GPU, 4–6px, ~80ms,ease-outdecaindo.prefers-reduced-motion→ sem movimento: flash de cor (borda/fundo do card pisca vermelho brevemente) + ícone de erro na margem. Nunca pisca > 3Hz.char-errordo painel de código.Fora de escopo (não fazer aqui):
type.error(som) depende delib/sound.tsque ainda não existe (§IV.1 🔴); hápticonavigator.vibratepode entrar se trivial, mas é opcional. Combo (§IV.4) é outra issue.Critérios de aceitação (verificáveis)
prefers-reduced-motion: reduceativo, não há movimento — o feedback é flash de cor + ícone, e nada pisca acima de 3Hz.transform(composited); não introduz layout/reflow nem trabalho pesado competindo com atextarea(área sagrada: latência de input a 60fps — CLAUDE.md).pnpm typecheck+pnpm buildverdes;node scripts/validate-metrics.mjsverde (não altera cálculo de WPM/erros).char-errorexistente emCodeDisplay.tsxcontinua funcionando (sem regressão).Dica de abordagem
handleInput(Race.tsx:74) já detectanewErrors > 0no bloco de teclas novas — emita daí um "pulso de erro" (ex.:errorPulsetimestamp em state, ou um contador) e passe aoCodeEditor, que aplica a classe de shake/flash comkey/timeout curto para reprisar em erros consecutivos. Springs/durações da §I (motion tokens) quando aplicável. Testar em produção-like: erro simples, erros consecutivos, e com reduced-motion no DevTools.Origem: feedback da persona em #9. Referência de spec:
docs/UI-AAA-OVERHAUL.md§779 (Parte IV).