Construindo um mundo aberto no navegador, parte 2: Física em Worker e o receio do atraso nos controles
Por Oleg Sidorkin, CTO e cofundador da Cinevva
Chegou agora? Consulte o guia da série. Ele explica o que é um spike e reúne links para todas as partes.
Se você trabalha com jogos multiplayer no navegador por tempo suficiente, acaba se deparando com esta discussão.
"Física em um worker é uma arquitetura limpa. Física na thread principal parece mais segura."
As duas coisas podem ser verdade. O que importa é a resposta dos controles e a latência com entradas reais.
O Spike 2 foi criado para responder a essa questão com medições, não opiniões.
Abrir o Spike 2 em uma nova aba ↗ · Ver código-fonte
Reutilizamos o terreno do Spike 1 e integramos o Rapier em um module worker dedicado. O estado das entradas era enviado ao worker a cada quadro, a simulação era executada nele e a posição autoritativa retornava ao renderizador.
As principais métricas foram a latência entre a entrada e o movimento visível, além do tempo de cada etapa da física. Também monitoramos possíveis oscilações durante o movimento normal, arrancadas em velocidade e sequências de saltos.
O resultado foi melhor do que o esperado. Com o formato e a cadência das nossas mensagens, a comunicação com o worker não foi o principal fator de latência. Os controles continuaram parecendo imediatos, que era a única coisa com a qual os jogadores se importariam.
Um desafio dessa fase foi o risco de interpretação. Após um resultado bem-sucedido, as equipes muitas vezes generalizam demais e presumem que a questão de arquitetura está resolvida para sempre. Não está. Validamos apenas um cenário concreto e um perfil de hardware. Os spikes posteriores ainda precisaram reavaliar as premissas quando a carga da GPU e do streaming mudou.
Este spike também aprimorou nosso processo. Passamos a exibir por padrão a telemetria de tempo na HUD dos spikes interativos. Isso mudou as conversas da equipe de "parece estranho" para "este caminho acrescentou 1,2 ms".
Na parte 3, abordamos os experimentos menos glamourosos que evitaram surpresas caras mais adiante: carga de transmissão, limitações de dispositivos móveis e confiabilidade da geração de comportamentos.
Tecnologias mencionadas neste capítulo
Rapier. Um motor de física escrito em Rust que é compilado para WebAssembly e usado no navegador. Ele processa corpos rígidos, colisores, articulações, controladores de personagens e raycasting com desempenho de 2 a 3 vezes superior ao nativo. Para mundos abertos, o Rapier oferece controladores de personagem do jogador (caminhar pelo terreno, subir degraus e deslizar em encostas), colisão de objetos, raycasting para interações e volumes de gatilho. Consulte a documentação do Rapier e nosso guia de tecnologias 3D para navegador sobre física.
Web Workers. Threads do navegador que executam JavaScript (ou Wasm) fora da thread principal. Executar a simulação de física em um worker significa que uma chamada pesada a world.step() não bloqueia a renderização. A thread principal envia o estado das entradas ao worker a cada quadro por meio de postMessage e recebe de volta as posições autoritativas. A penalidade de latência corresponde aos dois percursos das mensagens (cerca de 0,1 a 0,5 ms cada em computadores). O benefício é que a thread de renderização nunca fica paralisada pela detecção de colisões. Objetos transferíveis (transferência de ArrayBuffer) eliminam o custo de cópia de grandes arrays de posições.
WebAssembly (Wasm). Um formato binário de instruções executado nos navegadores com velocidade próxima à nativa. Rapier, Havok e Recast são todos compilados para Wasm. A etapa de física no Rapier-Wasm normalmente leva de 0,5 a 2 ms para algumas centenas de corpos, em comparação com 5 a 15 ms em uma implementação JavaScript equivalente. Os módulos Wasm são carregados como arquivos .wasm, obtidos junto com o código JavaScript de integração. Consulte a especificação do WebAssembly.
Latência entre entrada e resposta visual. O tempo entre o pressionamento de uma tecla e a alteração visual correspondente na tela. Para que o movimento pareça "imediato", esse valor precisa permanecer abaixo de aproximadamente 80 ms. Em uma configuração com física em um worker, a cadeia é aditiva:
evento keydown (thread principal), postMessage até o worker e de volta (
Parte 2 de 12.
Anterior: Parte 1 — Começamos tentando quebrar tudo
Próxima: Parte 3 — Os spikes pouco glamourosos que nos salvaram
Guia da série: /pt-BR/blog/2026-02-25-open-world-browser-series-guide