Files
portifolio-evandrodevbr/specs/2026-11-10-jogo-zumbis-etapa-1.md
evandro 67b32fcab3
CI / audit (push) Successful in 10m48s
CI / verify (push) Successful in 19m2s
CI / deploy (push) Successful in 2m14s
CI / e2e (push) Failing after 36m15s
feat(jogo): expediente dos mortos, jogo de zumbis em primeira pessoa
Etapa 1 inteira (logica com 100% de cobertura, cena 3D, toque, sons, bancada de desempenho, e2e) e a base da etapa 2 (mapa novo no Tiled, texturas, imagens dos itens, sons conferidos, golpe recortado e medido). Pagina /jogo fora do menu e do sitemap ate a medicao no celular.
2026-11-10 19:37:10 -03:00

30 KiB
Raw Permalink Blame History

Jogo de zumbis do portfólio: etapa 1, trecho jogável

Autor: Evandro · Data: 2026-11-10 · Porte: grande · Status: em execução

1. Objetivo

Uma página /jogo com um jogo de tiro em primeira pessoa em que cada horda de zumbis é um problema de empresa que eu resolvo; horda eliminada vira um aliado com o nome da solução. A etapa 1 entrega um trecho jogável e medido no computador e no S26 Ultra, para decidir com número quanto o jogo pode crescer.

2. Escopo

  • Dentro: rota /jogo (tela inicial, partida, relatório final) e /jogo/bancada (medição); um mapa (escritório à noite); um modelo de zumbi realista com 3 variações de textura; 3 comportamentos (comum, rápido, blindado) e o chefão; pistola, automática e faca; 3 drones aliados; feed de eliminações; sangue; efeitos sonoros; controles de teclado e mouse e de toque; a lista dos 27 problemas; créditos dos arquivos.
  • Fora (não fazer): botão na entrada do site (etapa 2, depois da medição); outros mapas; comportamentos "divide", "invisível" e "atira de longe"; multiplayer e placar online; música; braços em primeira pessoa; opção sem sangue; arquivos que pedem login (Mixamo, Sketchfab); dependência nova; cartão que cite cliente.

3. Critérios de aceite

  • CA1 (laço): no Fácil, 3 hordas e o chefão. Ao cair cada horda aparece "Resolvido: ", nasce um drone com o nome da solução e o feed mostra "<solução> eliminou ". O relatório final mostra eliminações da pessoa e dos drones, o link do serviço de cada problema e o WhatsApp com mensagem que cita o problema escolhido → pnpm test:e2e -- jogo com piloto automático e semente fixa.
  • CA2 (dificuldade): a partida abre no Fácil; Fácil, Normal e Difícil aplicam a tabela da seção 5 → pnpm test -- lib/jogo/dificuldade.
  • CA3 (armas): pistola com munição infinita; automática gasta e recolhe munição caída; faca só acerta a até 1,5 m → pnpm test -- lib/jogo/armas.
  • CA4 (celular): em aparelho de toque aparecem direcional, área de mira, troca de arma e faca; a automática atira sozinha com a mira no zumbi; em retrato a página pede para virar o aparelho; nenhum controle fica fora da área visível em 915×412 e 640×360 → e2e com toque emulado e inspeção no S26 Ultra.
  • CA5 (desempenho no computador): bancada com 16 zumbis animados à vista, 3 drones e sangue: p95 do quadro ≤ 16,7 ms em 1440×900 no Chromium com GPU; com CPU 4× mais lenta, p95 ≤ 33 ms → pnpm test:e2e -- jogo-bancada (local, com GPU).
  • CA6 (desempenho no S26 Ultra): mesma bancada no aparelho: p95 ≤ 16,7 ms; em 5 minutos de partida, a média do último minuto fica em até 1,2× a do primeiro → a bancada mostra o resultado na tela e ele vai para o Registro. Bloqueada por P1.
  • CA7 (regulador): com p95 > 20 ms por 2 s o jogo reduz, nesta ordem, resolução, sombras e zumbis à vista (mínimo 8); com folga por 10 s, sobe um degrau → pnpm test -- lib/jogo/regulador e bancada com CPU lenta.
  • CA8 (peso): tudo que baixa antes de jogar soma ≤ 6 MB; cada modelo ≤ 1,5 MB; o zumbi tem ≤ 12 mil triângulos; texturas com lado ≤ 1024 px; abrir / não baixa nenhum arquivo de /jogo e o LCP da home continua sendo o h1 → pnpm test -- lib/jogo/orcamento e e2e de rede.
  • CA9 (memória): 3 partidas seguidas sem recarregar: geometrias e texturas vivas (renderer.info.memory) iguais às da primeira e heap JS em até 1,1× → e2e na bancada.
  • CA10 (caminhos): toda função de lib/jogo/** tem complexidade ciclomática ≤ 10 e a cobertura de linhas e de ramos de lib/jogo/** é 100% → pnpm test -- lib/jogo --coverage.
  • CA11 (acesso): sem JavaScript, sem WebGL ou com movimento reduzido a página mostra os 27 problemas em texto com link para o serviço (com movimento reduzido há também "jogar mesmo assim", sem tremor de câmera); aviso de sangue antes de começar; pausa no Esc e ao sair da aba; botão de mudo; axe sem violação na tela inicial e no relatório → e2e.
  • CA12 (conteúdo e licença): cada problema aponta para um serviço que existe; nenhum texto do jogo cita cliente; cada arquivo de public/jogo/ consta em public/jogo/CREDITOS.json com origem, autor e licença (CC0-1.0 para o que foi baixado, propria para o que foi gerado aqui) → pnpm test -- lib/jogo/problemas lib/jogo/creditos.
  • CA13: Biome, typecheck, pnpm test, build e e2e verdes; /jogo e /jogo/bancada com noindex e fora do sitemap nesta etapa.

4. Contexto verificado

  • Cena 3D carregada sob demanda: app/components/cinematic/HeroField.tsx:109 (await import("./BlocosScene")). GLTFLoader vem de three/examples/jsm (BlocosScene.tsx:25); SkeletonUtils, PointerLockControls, DRACOLoader e meshopt_decoder existem na mesma pasta do three 0.182.
  • Orçamento de quadro que já existe: createFrameBudget(limitMs = 28, frames = 60) em lib/blocos.ts:315. Bloco da marca: public/3d/bloco.glb (2,7 KB).
  • WhatsApp: buildWhatsAppUrl(message) em lib/whatsapp.ts:17. Serviços e slugs: lib/site-content.ts:120-613. noindex de referência: app/not-found.tsx:21.
  • Jest: roots em app e lib, coverageProvider: "v8", sem coverageThreshold (jest.config.ts:4-6). O Biome não tem regra de complexidade (biome.json). e2e em e2e/, sobre a porta 3001 (playwright.config.ts:10).
  • Blender 5.2.2 instalado; os scripts de modelo ficam em 3d/*.py.
  • Zumbi candidato: "Male City Zombie", de Rikindle3D, CC0, 4,4 MB em .7z, baixa sem login (https://opengameart.org/content/male-city-zombie-ready-for-use-in-game-engines); a página lista andar, atacar, morrer, parado, correr e reação. Formato interno e triângulos não conferidos. Não foi achado outro zumbi realista com esqueleto que baixe sem login.
  • Texturas e sons CC0 sem conta: Poly Haven, ambientCG, Kenney, OpenGameArt (licenças lidas pelos agentes de pesquisa, não conferidas arquivo a arquivo).
  • Não há número medido de quantos personagens animados um celular aguenta no three.js; um relato viu queda acima de uns 20.

5. Desenho

  • Lógica separada da tela. lib/jogo/ não importa three nem DOM, avança em passo fixo de 1/60 s e sorteia por semente; por isso é testável caminho a caminho e o piloto repete a mesma partida. Interface comum: criarPartida({ semente, dificuldade, problemaId }), avancar(estado, entrada) e Entrada = { mover: [x, y], olhar: [dx, dy], atirar: boolean, arma: 0 | 1 | 2 }.
  • Módulos: tipos e valores (contrato e números, abaixo), mapa (grade de 1 m escrita em texto, de onde saem as paredes da lógica e as da tela), partida (inicio → horda → pausa → chefão → vitória ou derrota), hordas, zumbis (campo de fluxo em grade, colisão por círculo), armas (tiro por raio contra cápsulas), drones, feed, dificuldade, regulador, problemas, piloto, orcamento, creditos.
  • Contrato da lógica: plano XZ em metros, Y para cima; rumo em radianos, com direção (sin(rumo), cos(rumo)). O estado é um objeto só, alterado no lugar por avancar; cada passo deixa em eventos o que a tela precisa desenhar (tiro, acerto, morte, drone novo, horda resolvida).
  • Valores iniciais: zumbi comum (vida 100, 1,2 m/s, dano 10), rápido (50, 2,4 m/s, 6), blindado (250, 0,9 m/s, 15), chefão (1500, 1,0 m/s, 25); ataque a 1 m, um por segundo. Pistola (dano 34, 3 tiros/s, munição infinita), automática (20, 10 tiros/s, 90 balas, caixa caída dá 30), faca (100, 2 golpes/s, 1,5 m). Acerto acima de 1,55 m de altura dobra o dano. Drone (dano 25, 2 tiros/s, 15 m, precisa de linha de visão). Pausa de 5 s entre hordas, com +25 de vida.
  • Hordas: a 1 só tem comuns; a 2, comuns e rápidos; a 3, comuns, rápidos e blindados; o chefão vem com 6 comuns. As três hordas levam o nome de três outros problemas da mesma área do problema escolhido.
  • Feed: só registra eliminação feita por drone e horda resolvida.
  • Tela: app/jogo/ com o canvas three e a interface em HTML por cima. Sem motor de física e sem biblioteca nova.
  • Zumbis: um GLB clonado com SkeletonUtils.clone, com teto de zumbis à vista (16 no nível alto, 8 no baixo); o resto da horda espera na fila. Animação assada em textura com instâncias só entra se a bancada reprovar: não construir antes de medir.
  • Drones: blocos verdes da marca (bloco.glb) agrupados, com o nome da solução por cima. Sem esqueleto, custam pouco.
  • Partida: hordas de 12, 16 e 20 zumbis e o chefão; o problema escolhido é o chefão e a área dele dá os nomes das hordas. Vida 100.
Dificuldade Velocidade Dano Quantidade
Fácil (padrão) 0,6× 0,4× 0,7×
Normal 1× 1× 1×
Difícil 1,3× 1,5× 1,3×
  • Problemas (27) e o serviço de cada área:
    • Vender e ser encontrado → criacao-de-sites: site que ninguém acha no Google; site que não abre direito no celular; site lento; catálogo desatualizado; pedido perdido no WhatsApp; pagamento que falha.
    • Atender → atendimento-whatsapp-ia: atraso no atendimento; mesma pergunta respondida cem vezes; agenda com horário duplicado; cliente sem retorno.
    • Operar → engenharia-de-software: planilha duplicada; digitar a mesma coisa em dois lugares; estoque furado; processo que só uma pessoa sabe fazer; controle no papel.
    • Fiscal e financeiro → nota-fiscal-reforma-tributaria: nota fiscal rejeitada; fechamento do mês que não bate; cobrança esquecida; relatório que demora dias.
    • Sistemas e integrações → arquitetura-de-software (a máquina vai para integracao-hardware-software-iot): sistemas que não conversam; máquina que não conversa com o sistema; sistema antigo em que ninguém mexe; sistema que cai na hora do pico.
    • Segurança e dados → arquitetura-de-software (o app vai para /ia): senha compartilhada; dados sem backup; acesso de ex-funcionário; app feito por IA cheio de falha.
  • Arquivos 3D: 3d/jogo.py (Blender sem janela) baixa as fontes para 3d/fontes/ (fora do git), reduz, troca as texturas e exporta para public/jogo/. Compressão Draco só se o peso passar do CA8. Variações de textura do zumbi e cartazes do cenário saem da geração de imagem.
  • Bancada: /jogo/bancada?zumbis=16&seg=20 roda o piloto, mostra na tela e expõe window.__bancada = { p50, p95, max, quadros, chamadas, triangulos, heapMB }.

6. Restrições, riscos, suposições

  • Restrições: sem dependência nova; nenhum byte do jogo na home; só arquivos CC0 que baixam sem login; sem commit nem push sem pedido.
  • R1: só há um zumbi realista sem login, de aparência mediana e formato não conferido. T1 abre e mede antes de tudo; se não servir, o trabalho para e a decisão volta ao Evandro (zumbi simplificado do Quaternius ou liberar login).
  • R2: o S26 Ultra é topo de linha; passar nele não garante aparelho médio. Por isso o CA5 mede com CPU 4× mais lenta e o CA7 exige o regulador.
  • R3: sangue e zumbi realista num site que vende para dono de empresa. O jogo fica em página própria, com aviso antes de começar e noindex nesta etapa.
  • R4: Safari no iPhone não será testado (sem aparelho).
  • Suposições: S1 no celular o jogo roda em paisagem; S2 nome provisório "Expediente dos Mortos"; S3 o CI não tem GPU, então a bancada roda só local e no aparelho; S4 "testes ciclomáticos" é o CA10; S5 valores da tabela e das hordas são iniciais e se ajustam jogando.
  • Perguntas abertas: P1: para o S26 Ultra abrir a bancada é preciso publicar a branch como prévia (push de feat/jogo-zumbis, que o CI publica fora de produção). Depende do ok do Evandro.

7. Microtasks

T1 · preparar o zumbi · sênior

  • Serve: CA8, CA12 · Depende de: nenhuma · Arquivos: criar 3d/jogo.py, public/jogo/zumbi.glb, public/jogo/CREDITOS.json
  • Fazer: baixar o candidato, abrir no Blender, relatar formato, triângulos e clipes; reduzir para ≤ 12 mil triângulos e textura de 1024 px; exportar com os clipes parado, andar, atacar, morrer. Parar e relatar se o arquivo não servir (R1).
  • Pronto quando: blender -b -P 3d/jogo.py termina com OK zumbi; o GLB tem ≤ 1,5 MB; um render de frente e um de perto estão em 3d/out/.
  • feito

T2 · bancada de desempenho · sênior

  • Serve: CA5, CA6 · Depende de: T1 · Arquivos: criar app/jogo/bancada/page.tsx, app/jogo/Bancada.tsx, e2e/jogo-bancada.spec.ts
  • Fazer: cena com N zumbis clonados andando em círculo, 3 drones e luz do mapa; medir o tempo de quadro por seg segundos e publicar window.__bancada; noindex.
  • Pronto quando: o e2e lê p95 com 16 zumbis; o resultado aparece na tela.
  • feito

CP1 · após T1–T2 · direto

  • Verificar: CA5 no computador e, com P1 resolvida, CA6 no S26 Ultra. O teto de zumbis à vista sai desta medida e vai para o Registro. Reprovou: parar e rever o desenho com o Evandro.

T3 · partida, hordas e dificuldade · implementador

  • Serve: CA1, CA2 · Depende de: CP1 · Arquivos: criar lib/jogo/partida.ts, lib/jogo/hordas.ts, lib/jogo/dificuldade.ts e os testes
  • Fazer: teste primeiro; máquina de estados e tabela da seção 5; criarPartida e avancar com a interface da seção 5.
  • Pronto quando: pnpm test -- lib/jogo/partida lib/jogo/hordas lib/jogo/dificuldade verde, com um teste por caminho.
  • feito

T4 · zumbis · implementador [P]

  • Serve: CA1 · Depende de: T3 · Arquivos: criar lib/jogo/zumbis.ts e o teste
  • Fazer: campo de fluxo em grade até o jogador, colisão por círculo, comportamentos comum, rápido, blindado e chefão, teto de zumbis à vista e fila.
  • Pronto quando: pnpm test -- lib/jogo/zumbis verde.
  • feito

T5 · armas · implementador [P]

  • Serve: CA3 · Depende de: T3 · Arquivos: criar lib/jogo/armas.ts e o teste
  • Fazer: pistola, automática e faca; tiro por raio contra cápsula; munição caída e recolhida.
  • Pronto quando: pnpm test -- lib/jogo/armas verde.
  • feito

T6 · drones e feed · implementador [P]

  • Serve: CA1 · Depende de: T3 · Arquivos: criar lib/jogo/drones.ts, lib/jogo/feed.ts e os testes
  • Fazer: drone nasce quando a horda cai, escolhe o alvo mais próximo, atira em ritmo fixo; o feed guarda as últimas 5 linhas "<solução> eliminou ".
  • Pronto quando: pnpm test -- lib/jogo/drones lib/jogo/feed verde.
  • feito

T7 · problemas e créditos · implementador [P]

  • Serve: CA12 · Depende de: nenhuma · Arquivos: criar lib/jogo/problemas.ts, lib/jogo/creditos.ts e os testes
  • Fazer: os 27 problemas com área, solução e serviço da seção 5; o teste confere cada slug em lib/site-content.ts e cada arquivo de public/jogo/ no CREDITOS.json.
  • Pronto quando: pnpm test -- lib/jogo/problemas lib/jogo/creditos verde.
  • feito

T8 · complexidade e cobertura · implementador

  • Serve: CA10 · Depende de: T3–T7 · Arquivos: criar lib/jogo/complexidade.test.ts; modificar jest.config.ts
  • Fazer: teste que percorre lib/jogo/** com a API do TypeScript e conta decisões por função (if, laços, case, catch, ?:, &&, ||, ??), falhando acima de 10; coverageThreshold de 100% em linhas e ramos para lib/jogo/**.
  • Pronto quando: pnpm test -- lib/jogo --coverage verde; uma função de 11 decisões posta de propósito faz o teste falhar.
  • feito

CP2 · após T3–T8 · direto

  • Verificar: Biome, typecheck e pnpm test; uma partida inteira do piloto termina em vitória no Fácil só com a lógica.

T9 · cena jogável no computador · sênior

  • Serve: CA1 · Depende de: CP2 · Arquivos: criar app/jogo/page.tsx, app/jogo/Jogo.tsx, app/jogo/cena.ts
  • Fazer: mapa do escritório, zumbis e drones ligados ao estado da lógica, arma na tela, mira, vida, munição, feed; mouse com PointerLockControls, WASD, 1 2 3, Esc pausa.
  • Pronto quando: uma partida completa é jogável em 1440×900 sem erro no console.
  • feito

T10 · controles de toque · sênior

  • Serve: CA4 · Depende de: T9 · Arquivos: criar app/jogo/toque.ts, app/jogo/jogo.css
  • Fazer: direcional à esquerda, arrastar à direita para mirar, tiro automático com a mira no zumbi, botões de arma e faca, aviso de virar o aparelho.
  • Pronto quando: o e2e com toque emulado elimina um zumbi; os controles cabem em 915×412 e 640×360.
  • feito

T11 · telas de início e de fim · implementador

  • Serve: CA1, CA11 · Depende de: T9 · Arquivos: criar app/jogo/Inicio.tsx, app/jogo/Relatorio.tsx; modificar app/jogo/page.tsx
  • Fazer: escolha do problema e da dificuldade, aviso de sangue, mudo; cartão "Resolvido" entre hordas; relatório com links e WhatsApp por buildWhatsAppUrl; lista em texto para quem não tem JavaScript, WebGL ou pediu menos movimento.
  • Pronto quando: a mensagem do WhatsApp cita o problema escolhido; a lista em texto aparece sem JavaScript.
  • feito

T12 · sangue, som e regulador · sênior

  • Serve: CA7, CA9 · Depende de: T9 · Arquivos: criar lib/jogo/regulador.ts e o teste; modificar app/jogo/cena.ts
  • Fazer: partículas e marcas de sangue com teto de 64; sons CC0 liberados no primeiro toque; regulador do CA7; descarte de geometrias e texturas ao fim da partida.
  • Pronto quando: pnpm test -- lib/jogo/regulador verde; a bancada com CPU lenta desce de nível sozinha.
  • feito

T13 · testes de ponta a ponta · implementador

  • Serve: CA1, CA4, CA8, CA9, CA11, CA13 · Depende de: T10–T12 · Arquivos: criar e2e/jogo.spec.ts, lib/jogo/orcamento.test.ts; modificar app/sitemap.test.ts
  • Fazer: partida com piloto e semente fixa; toque; rede da home sem arquivo de /jogo; 3 partidas e memória; axe; pesos de public/jogo/; /jogo fora do sitemap.
  • Pronto quando: pnpm test:e2e -- jogo e pnpm test -- lib/jogo/orcamento verdes.
  • feito

CP3 · após T9–T13 · direto

  • Verificar: todos os CAs; parecer do fable-critico sobre o laço de renderização e o descarte de memória; partida no S26 Ultra pelo Evandro.

8. Registro

2026-11-10 — spec escrita a partir das decisões do Evandro: primeira pessoa, jogável no celular desde o início, zumbi realista com sangue, só arquivos sem login, drones como aliados, Fácil por padrão, chefão escolhido pela pessoa, S26 Ultra como aparelho de teste. 2026-11-10 — a licença aceita em CREDITOS.json passou a ser CC0-1.0 ou propria, porque texturas e cartazes gerados aqui não têm origem externa. 2026-11-10 — aprovada pelo Evandro ("pode"), incluindo o push da branch como prévia quando a bancada estiver pronta (P1). 2026-11-10 — ordem da lógica revista: ela não depende do resultado da bancada (se a medição reprovar, muda a tela, não as regras), então corre em paralelo com T1 e T2. O contrato (lib/jogo/tipos.ts, lib/jogo/valores.ts) foi escrito antes; a base (mapa, rng) e hordas com feed saem primeiro, depois zumbis com dificuldade, depois armas e drones, e por último partida com piloto. O nascimento dos zumbis fica em zumbis, não em hordas. 2026-11-10 — T7 entregue: 27 problemas e a conferência de créditos, 17 testes, 100% de linhas e ramos. O teste roda no jsdom (o jest.setup.ts não carrega no ambiente node). 2026-11-10 — T1 entregue: public/jogo/zumbi.glb com 11.950 triângulos, 1.459.472 bytes, 66 ossos, 1,80 m, clipes parado, andar, atacar, morrer, correr, reacao; texturas de cor e normal em JPEG 1024. Aparência (R1): proporção humana boa, mas a textura original é uma crosta ruidosa igual na pele e na roupa; não passa por realista de perto. Tentativa de conserto dentro do combinado: repintar com texturas geradas pela assinatura GPT (T1b), que também dá as 3 variações. Se não ficar bom, a decisão volta para o Evandro (liberar download com login ou trocar de estilo). 2026-11-10 — os ossos do zumbi têm o prefixo mixamorig:, ou seja, o autor montou esqueleto e animações no Mixamo antes de publicar como CC0. A Adobe permite usar personagens e animações do Mixamo em projetos comerciais, jogos incluídos (helpx.adobe.com/creative-cloud/faq/mixamo-faq.html); o uso aqui (embutido no jogo, não redistribuído solto) cabe nisso. O arquivo foi baixado do OpenGameArt sem login. 2026-11-10 — T4, T5, T6 e T8 entregues. pnpm test:jogo (script novo, com limite de 100% de cobertura) entrou no job verify do CI. O regulador de qualidade (parte de lógica da T12) saiu antes como lib/jogo/regulador.ts, com os degraus em valores.ts. 2026-11-10 — a partida inteira do piloto pegou um defeito do desenho: a regra "com linha de visão o zumbi anda reto" prendia o zumbi atrás das mesas, que são sólidas mas deixam ver por cima. Correção: andar reto só com caminho livre de sólidos; senão, campo de fluxo mirando o centro da próxima célula, sem cortar quina. 2026-11-10 — contrato da tela escrito em app/jogo/contrato.ts (Escolha, Retrato, Resultado, Controle); controles e telas correm em paralelo com a bancada. T10 ganhou lib/jogo/alavanca.ts e alvoNaMira em armas.ts (o tiro automático do toque do CA4 precisa saber se a mira está num zumbi). Nomes de arquivo mudaram em relação à seção 7: app/jogo/controle.ts e Toque.tsx no lugar de toque.ts; Hud.tsx e ListaDeProblemas.tsx a mais. 2026-11-10 — causa real dos zumbis presos: seguindo o campo de fluxo, o corpo (raio 0,35) raspava a quina da mesa. direcaoNoCampo passou a mirar o centro da próxima célula e o zumbi só anda reto com caminhoLivre. Partida do piloto com semente 1 no Fácil: vitória no passo 6.703 (cerca de 1 min 52 s), placar 23 × 17, vida 100. O piloto mira sem errar, então uma pessoa leva mais tempo; a duração e o dano ficam para ajustar depois de jogar de verdade. 2026-11-10 — o chefão (raio 0,6) nascia encostado na parede e não andava. Decisão: para andar, todo zumbi usa no máximo RAIO_DE_PASSAGEM (0,45 m); para levar tiro e atacar, vale o raio do tipo. 2026-11-10 — a cena saiu em duas partes com interface fixa: T9a (cena.ts, ambiente.ts, atores.ts) e T9b (page.tsx, Jogo.tsx); a parte de sangue e som da T12 virou efeitos.ts e som.ts. Acréscimo ao desenho: cada zumbi leva o nome do problema acima da cabeça e cada drone o nome da solução, para a ideia ficar legível sem depender só do feed. 2026-11-10 — T2 entregue. Bancada no computador (RTX 5060 Ti, next dev, 1440×900, Chromium com GPU): 16 zumbis p50/p95/máx 16,7/16,7/16,8 ms, 50 chamadas, 85 mil triângulos; 24 zumbis 16,7/16,7/16,8 ms; com CPU 4× mais lenta, 16 zumbis 16,7/16,8/33,4 ms e 24 zumbis 16,7/33,4/100 ms. CA5 atendido no computador. O tempo entre quadros trava nos 60 Hz do monitor e não mostra a folga; a bancada vai ganhar a medida do trabalho por quadro. Desvio: o Playwright não aceita launchOptions por bloco, então o caso com GPU abre o próprio Chromium. 2026-11-10 — CP2: pnpm test:jogo com 253 testes, 100% de linhas e ramos, nenhuma função acima de 10 decisões. Piloto com semente 1: Fácil vitória no passo 5.988 (24 × 16), Normal 5.003 (37 × 18), Difícil 4.662 (46 × 24), sempre com vida 100. O piloto não erra e recua sempre; não serve de medida de dificuldade para gente. 2026-11-10 — sons: 10 arquivos MP3 mono (1,7 a 18 KB cada) de pacotes CC0 da Kenney e do OpenGameArt (kurt, EZduzziteh, AntumDeluge), todos em CREDITOS.json. Um pacote foi recusado porque a página dizia CC0 e o zip trazia CC-BY. Ninguém ouviu os sons ainda: foram escolhidos por nome, duração e pico. 2026-11-10 — efeitos.ts e som.ts entregues (22 testes): arma feita de caixas, clarão, traçantes, 64 gotas e 64 marcas de sangue em reserva fixa, 5 chamadas de desenho. page.tsx e Jogo.tsx entregues (16 testes), página sem h1 próprio (o h1 é da tela inicial e do relatório). 2026-11-10 — a primeira versão da tela inicial ficou fraca (27 opções numa coluna só, botão "Começar" 1.600 px abaixo, sem imagem). Redesenho em andamento: duas colunas no computador, barra fixa com "Começar" no celular, imagem de abertura renderizada do próprio zumbi (public/jogo/capa.jpg). 2026-11-10 — T1b entregue: cor refeita por bake no Blender com as 4 texturas geradas (pele, camisa, calça, máscara de sangue), normal original a 0,3, sem KHR_materials_specular, materiais roupa, corpo, olhos; três roupas (A no GLB, roupa-b.jpg 111 KB, roupa-c.jpg 64 KB); capa.jpg 83 KB. zumbi.glb com 1.465.268 bytes e 11.950 triângulos. Aparência: passa por zumbi crível a 2–3 m no escuro, não por fotorrealista; o molde original ainda aparece na calça curta, nos pés descalços, na barriga à mostra e na costura do ombro. R1 fica aberto para o Evandro decidir depois de ver no jogo. 2026-11-10 — bancada com a medida de trabalho por quadro: 16 zumbis p95 2,8 ms (10,9 ms com CPU 4× mais lenta); 24 zumbis 4,5 ms (10,5 ms). Memória da bancada: geometrias 5 e texturas 55 iguais na 1ª e na 3ª medição. capa.jpg (1600 × 900) ficou fora do limite de 1024 px do CA8, que vale para textura; ganhou limite próprio de 1600 px e 220 KB. 2026-11-10 — T9 entregue: cena.ts, ambiente.ts, atores.ts. No navegador com GPU, o piloto vence no Fácil (passo 5.988) sem erro no console; p95 de 16,7 ms e 26 chamadas de desenho no meio da horda (máximo medido 36 no Fácil e 49 no Difícil). Desvio da interface: criarAmbiente recebe { camera, movimentoReduzido } e expõe atualizar. Conferência estática do conjunto: tsc rc=0, Biome limpo em 357 arquivos, 363 testes de app/jogo e lib/jogo passando. 2026-11-10 — primeira olhada na cena: funciona, mas a arma é um bloco preto com faces brancas, os rótulos dos drones tomam a tela de perto, os dos zumbis se empilham e fora da lanterna fica escuro demais. Polimento em andamento, junto com o parecer do fable-critico e os testes de ponta a ponta. 2026-11-10 — parecer do fable-critico (só leitura, CP3): sem vazamento achado em 3 partidas; passo fixo correto (teto de 5 passos, sem salto na volta da pausa). Um defeito que bloqueia: o regulador media o intervalo entre quadros, que a 60 Hz nunca fica abaixo de 16,7 ms, então nunca voltava a subir, e numa tela limitada a 30 quadros desceria até o fim sem ganho. Decisão: o regulador passa a receber também o tempo de trabalho do quadro; desce pelo intervalo (p95 > 20 ms, como no CA7), sobe quando o intervalo está dentro do limite e o trabalho tem p95 abaixo de 6 ms por 10 s, e duas descidas seguidas sem ganho de 10% fazem voltar e travar. Outros achados em conserto: perda de contexto WebGL sem tratamento, um esqueleto por malha em cada zumbi (3 vezes o custo de ossos), interpolação com 2 passos no mesmo quadro, som que não volta no iOS ao sair da aba, clique rápido perdido entre dois passos, alocação por quadro. O CA9 media renderer.info.memory entre renderers diferentes, o que não prova nada: a cena passa a publicar o que sobrou depois do descarte (esperado 0 geometrias e 0 texturas). 2026-11-10 — consertos do parecer, parte 1: as 3 malhas de cada zumbi passaram a dividir um esqueleto (com 16 zumbis e CPU 4× mais lenta, o trabalho por quadro caiu de 20,9 para 12,4 ms no p95 e as texturas de 56 para 24); clone reaproveitado começa do zero; liberar() retoma o som sempre que o contexto não está rodando; clique ou toque inteiro entre dois passos vira um tiro. 106 testes de app/jogo, tsc e bancada (4 casos) verdes. 2026-11-10 — polimento visual entregue e conferido nas capturas: armas refeitas (0,8% a 3,2% da tela), rótulos de tamanho fixo e só nos 3 zumbis mais próximos e no chefão, drones a 2,3 m, sala visível a 12 m, portas com luz vermelha nos nascedouros. Ainda feio: pilares lisos e armas feitas de caixas. Em 915 × 412 as eliminações cobrem os botões e o aviso cobre a mira (a corrigir no HUD). 2026-11-10 — o Evandro pediu o refino (ferramentas abertas por CLI, mapa novo, itens, golpe sincronizado, ataque mais rápido): virou a spec 2026-11-10-jogo-zumbis-etapa-2-refino.md, com execução autônoma. Esta etapa fecha antes de a lógica nova entrar. 2026-11-10 — T13b entregue: e2e/jogo.spec.ts com 12 casos; 11 passam (CA1, CA4 em 915 × 412, 640 × 360 e retrato, CA8, CA11, CA13). O caso do CA9 falha por dois defeitos do jogo: heap em 1,113× e 1,117× entre a 1ª e a 3ª partida (limite 1,1×) e, com semente aleatória, o piloto fica mais de 5 minutos na horda 3 com "faltam 2". Os dois estão em conserto (o segundo com varredura de 300 sementes por dificuldade). Decisões do teste: no CA8, "arquivo do jogo" é o bloco que contém __jogo (a home já baixa o three pelo fundo 3D); no CA11 a pausa é conferida com exitPointerLock, porque o Esc simulado não solta a trava do mouse. 2026-11-10 — Partida que empacava: achada e consertada. Causa: dois zumbis chegavam juntos a uma passagem de 1 m entre mesas e a separação empurrava cada um metade da sobreposição, um contra cada mesa; nenhum passava e o jogador, sem linha de visão, esperava (Fácil, semente 4, horda 3, "faltam 2" correto). Conserto em separarPar (lib/jogo/zumbis.ts): só o zumbi mais longe do jogador recua, e recua a sobreposição inteira. Varredura de 300 sementes × 3 dificuldades: 900 partidas terminam, todas em vitória, com vida média do piloto de 100 (o piloto não apanha; não diz nada sobre a dificuldade para uma pessoa, S5). Teste permanente novo com 40 sementes por dificuldade (leva de 19 a 23 s; reduzir na etapa 2). pnpm test:jogo: 277 testes, 100% nas quatro colunas. 2026-11-10 — Consertos do parecer crítico, parte 2, feitos: regulador mede intervalo e trabalho (duas descidas sem ganho voltam os degraus e travam; nível inicial pelo pixelRatio do aparelho); contexto WebGL perdido pausa a partida e "Continuar" volta a valer depois de restaurar; guardarPasso a cada passo; sem vetor novo por passo; carga cancelada não cria renderer; sobras = 0 geometrias e 0 texturas nas 3 partidas (faltava soltar a textura DFG_LUT, que o three não liberava); "Continuar" chama som.liberar(). Heap entre a 1ª e a 3ª partida: 1,096× (limite 1,1×), medido com coleta forçada. Playwright: 16 passaram (bancada e jogo). Observado com CPU 4× mais lenta: o nível desceu, não houve ganho, voltou e travou, como desenhado; não foi visto subir de volta. 2026-11-10 — Ponto de controle antes da lógica da etapa 2: Biome limpo (386 arquivos), typecheck rc=0, pnpm test 2071 testes, pnpm test:jogo 278 testes com 100% nas quatro colunas, build rc=0. Commit e push da prévia feitos neste estado. Desvio: o impeccable critique e o audit da etapa 1 passam para o fechamento da etapa 2, sobre a tela final, porque o refino já mudou HUD, sons e clipe de ataque.