Ficha Técnica
Zumbicho ("Ninguém Sai Sozinho") é um jogo cooperativo de sobrevivência estilo Zombicide: uma TV vira o tabuleiro, cada jogador escaneia um QR Code e controla o próprio sobrevivente pelo celular. Sem instalar nada, sem console — é um PWA que transforma a sala de estar em mesa de board game.
O problema
Jogos de tabuleiro digitais em grupo esbarram sempre no mesmo: ou todo mundo precisa instalar um app, ou alguém precisa hostear servidor, ou a sincronização de estado entre N dispositivos vira um pesadelo de conflitos. O Zumbicho resolve com uma decisão de arquitetura radical: só o host simula o jogo.
Arquitetura: host-autoritativo com motor determinístico
O motor do jogo é um reducer puro — (estado, ação) → novo estado — que roda apenas no host (a TV). Os celulares enviam intents ("quero mover", "quero atacar") e recebem de volta o GameState completo. Cliente nunca simula, só desenha. Entre eles, um relay WebSocket que não entende nada de jogo: só conhece salas e encaminha bytes opacos.
Visão de componentes e infraestrutura:
Fluxo de uma jogada:
Essa separação rende de graça três coisas difíceis: mensagens idempotentes (o próximo estado re-sincroniza qualquer cliente), reconexão trivial e zero conflito de estado — não existe "merge", existe a verdade do host.
O jogo em si
Mecânica fiel ao Zombicide Black Plague: 3 ações por turno, linha de visão realista (rua reta até parede, prédio só revela a sala), combate com dados d6, munição, armas de área, 23 skills numa trilha de XP (Azul → Amarelo → Laranja → Vermelho), 6 arquétipos de personagem, 5 tipos de zumbi com IA própria — incluindo o Necromante que foge e chama reforços — e 7 cenários declarativos com objetivos, spawns scriptados e briefing cinematográfico com câmera guiada. A horda persegue barulho acumulado (que decai pela metade a cada rodada), via BFS multi-origem no tabuleiro.
Problemas & soluções que valem a pena contar
Reconexão sem perder o personagem. O relay troca o ID de conexão a cada socket, mas o jogador precisa reatar ao mesmo sobrevivente. Solução: um token estável em localStorage mapeado contra a conexão efêmera. Quem cai fica marcado como desconectado — nunca é removido durante a partida — e o socket reconecta com backoff exponencial.
1 fps numa Smart TV. A primeira versão animava a câmera reescrevendo o viewBox do SVG — re-rasterizando o mapa vetorial inteiro a cada frame. A correção: animar com transform CSS direto no DOM (composição por GPU, sem re-render do React), desligando filtros durante o movimento, e suavização exponencial baseada em tempo (1 − e^(−k·dt)) para o glide ficar idêntico a 60 Hz ou 300 Hz.
O save que desfez uma morte. O snapshot do host era salvo com debounce — e um crash do browser engoliu exatamente o commit em que um zumbi morreu. A TV recarregou com ele vivo, desfazendo na frente de todos o que os celulares já tinham visto. O save virou síncrono de propósito, com versão e prazo de validade, omitindo o tabuleiro (que é remontado deterministicamente pelo cenário).
Determinismo como ferramenta de teste. O RNG (mulberry32) vive dentro do GameState — mesma seed, mesma partida, em qualquer processo. Isso permite um playtest headless que roda 300 partidas com bot em todos os cenários para calibrar dificuldade (taxa de vitória atual: ~11%, difícil como tem que ser).
Stack
TypeScript · React 18 + Vite · Zustand · WebSocket (ws) · PWA (service worker, Wake Lock, install) · arte 100% SVG desenhada em código · Vitest + playtest com bot · Railway (um único processo Node serve estáticos + relay na mesma origem, sem TURN/NAT drama).
Status
Jogável em zumbicho.com — conexão, lobby, os 7 cenários, combate, progressão e reconexão funcionando. Em polimento: animações do turno dos zumbis, editor de cenários e balanceamento contínuo.
Curtiu o projeto?
Se quiser conversar sobre esse projeto, arquitetura ou uma oportunidade de trabalho, é só me chamar. 🚀
contato@racoelho.com.br