Vice City no navegador

Portado por Alan Nicolas

Arquitetura da engine, carregamento da cidade, compressão 3D e processo de desenvolvimento deste port.

Publicado em 20/10/2026. Atualizado em 21/10/2026.

Ler o estudoParticipação das IAsAplicar em outro jogoConsultar as 28 técnicas

Base do port#

O trabalho começou com o estudo de conteúdo da Definitive Edition para Android. Isso gerou uma biblioteca de recursos e uma prévia 3D. Para chegar a uma experiência clássica jogável, adotamos depois a base aberta reVC Web / wasm-revc, compilada para WebAssembly, usando dados da edição PC clássica.

Jogo clássico e prévia 3D. O jogo do menu usa a engine clássica e arquivos nativos. A prévia da Definitive Edition usa modelos convertidos para Three.js. Cada rota tem formatos e otimizações próprios; os ganhos de uma não descrevem automaticamente a outra.

A comunidade já havia construído partes essenciais: a engine reVC, sua adaptação Web e um runtime de streaming. Nosso trabalho reaproveita essas bases e documenta a integração, as correções de I/O e áudio, a restauração de recursos, os perfis de carregamento, a instrumentação e a entrega no site.

Este é um estudo de um experimento em evolução. Há trechos de jogo e sistemas verificados; campanha inteira e equivalência audiovisual completa continuam abertas.

Engine, navegador e arquivos#

A engine executa a lógica clássica. O navegador fornece renderização, áudio, entrada e acesso à rede. A adaptação conecta a leitura nativa de arquivos a esse ambiente.

Página e comandos
HTML e CSS apresentam o jogo. JavaScript inicia a engine após Jogar e conecta a interface ao navegador.
Engine em WebAssembly
O código C/C++ compilado executa os sistemas nativos. Este build usa WebGL2 e áudio OpenAL.
Arquivos por demanda
O FS virtual conserva caminhos e tamanhos. O streamer resolve as leituras em blocos, cache e rede.

WebAssembly é o formato de execução do código compilado. Compilar a engine é uma parte do port. Fazer seus caminhos de áudio, arquivos, memória e atualização cooperarem com o navegador exige adaptação adicional. O Emscripten distingue arquivos embutidos e pré-carregados; escolher um pacote de dados não implementa sozinho o streaming conforme o uso. Referência de empacotamento.

Conteúdo clássico que a engine continua entendendo
FormatoPapelDecisão deste port
DFFModelos e geometria.Conservar a leitura nativa.
TXDDicionários de texturas.Preservar materiais e ligação às malhas.
IMGArquivo que reúne recursos.Buscar intervalos sem exigir o corpo inteiro.
SCMPrograma de missões e scripts.Executar pela engine clássica.
Áudio e tabelasFalas, música, efeitos e metadados.Antecipar só o necessário e conservar as amostras.

A engine pede bytes como antes; a camada Web decide como obtê-los. Essa fronteira precisa respeitar quando a engine pode esperar e quando exige uma leitura concluída.

Processo de desenvolvimento#

O projeto foi conduzido por Alan Nicolas, com assistência de IA para pesquisar fontes, ler código, implementar adaptações, investigar falhas e produzir verificações. A direção foi refinada ao jogar e revisar as entregas: primeiro a biblioteca, depois uma execução Web, os problemas de textura, desempenho, banda, controles e acesso pelo celular. Os pedidos de Alan definiram as prioridades e o acabamento que precisava ser preservado.

O port usa as bases comunitárias reVC, wasm-revc e wasm.com.br. As revisões e os créditos estão em Fontes e créditos.

Workflow de desenvolvimento

O trabalho foi dividido em rodadas, com fonte identificada, tarefa delimitada, alteração de código e verificação. Código, decisões e resultados foram registrados para a sessão seguinte.

  1. Definir o trecho a executar

    Separar os marcos: menu, partida, movimento com controles livres, rua, interior e retorno ao jogo. Na biblioteca, contar as coleções e abrir os recursos no consumidor correspondente. O plano registra a cobertura de cada trecho.

  2. Identificar a versão e as dependências

    Registrar edição, revisão de código e hashes. A fonte inicial é a Definitive Edition Android 1.90.0; a execução clássica usa dados PC e reVC Web. Essas bases têm formatos e sistemas distintos.

  3. Pesquisar a alteração

    Ler o código e a documentação do sistema afetado. Na compressão, verificar como a engine pede bytes, quais offsets espera e quando a leitura precisa terminar.

  4. Relacionar recursos aos sistemas que os usam

    Mapear modelos, texturas, animações, áudio, mapas e scripts. Rastrear o recurso desde o registro e o setor do arquivo até o carregador, o material e a instância desenhada.

  5. Integrar a engine

    Montar o sistema de arquivos, chegar ao menu e liberar o jogador. Observar posição, quadros, pausa e leituras. O visualizador de modelos fica separado da campanha para não alterar os slots usados pelos scripts.

  6. Reproduzir o defeito

    Guardar revisão, cenário, entrada e resultado. Isolar a falha em I/O, áudio, cache, material, toque ou hospedagem. Cada defeito devolvido por Alan recebe uma verificação nomeada.

  7. Preservar os dados afetados

    Definir o que deve permanecer igual: bytes, PCM, pixels, glifos, escala, física e resolução. Filas conservam ordem e cancelamento; canais pendentes conservam a identidade do som.

  8. Medir carregamento e desempenho

    Separar página, clique, menu, jogador livre e exploração. Registrar arquivos, bytes e quadros com cache frio e quente. Comparações de desempenho usam a mesma arte, percurso e pares intercalados.

  9. Conferir comportamento e aparência

    Rodar o validador principal e os cenários afetados. Comparar poses e animações no mesmo instante. Para coleções, conferir o conjunto declarado e distinguir carga técnica de inspeção visual.

  10. Registrar a rodada

    Versionar código, fontes, decisões, falhas e próximo passo. Tarefas auxiliares têm objetivo e área delimitados. As 149 sessões auxiliares identificadas na auditoria ocorreram ao longo do projeto, sem indicar execução simultânea.

  11. Publicar o build

    Comparar o manifesto de produção com o publicado e enviar os arquivos alterados. Conferir hashes, MIME, Range, cache, isolamento e versão na hospedagem. Atualizações de texto e estilo mantêm o site disponível durante o envio dos metadados.

  12. Conferir a URL entregue

    Abrir o site publicado e repetir o fluxo afetado. Registrar falhas e lacunas para a próxima rodada, como áudio ausente, material sem textura ou comando de toque perdido entre quadros.

Quais IAs participaram

GPT-6.1 Sol
gpt-6.1-sol
Pesquisa, leitura da engine, implementação, diagnóstico, testes e documentação no Codex.Identificador encontrado nos registros de turnos do projeto.
GPT-6 Astra
gpt-6-astra
Participação no trabalho técnico conduzido pelo Codex.Identificador encontrado nos registros. O histórico acumulado não permite separar com precisão os tokens entre Sol e Astra.
Claude Opus 5.5
claude-opus-5-5
Interface de abertura, menus e ajustes da bancada de modelos.A conversa do menu registra alterações nesses arquivos e 230 respostas únicas com uso contabilizado.
Gemini 4 Argon
Antigravity
Compressão e otimização dos objetos 3D, streaming e carregamento por demanda para os primeiros minutos. A etapa 3D está em Compressão dos objetos 3D.Nome do modelo informado por Alan Nicolas. Os tokens foram conferidos nos recortes locais; os registros de uso não trazem o identificador exato do modelo.

Alan definiu as prioridades e revisou as entregas. C/C++, Emscripten, JavaScript, Python e navegadores automatizados foram usados para compilar, integrar e verificar as alterações. Os menus feitos no Claude foram mantidos durante as otimizações de carregamento.

O total reúne os registros identificados de Codex, Claude e os recortes do Antigravity descritos abaixo. Cada origem conserva seu corte e sua forma de contar cache.

Tokens registrados

Os registros locais de Codex, Claude e dos recortes do Antigravity somam 7.349.836.566 tokens, incluindo leituras de contexto em cache. O levantamento cobre os recortes identificados; outras máquinas, conversas e atividade posterior podem ficar de fora.

Corte do Codex: 21/10/2026 às 01:24:05, horário de Brasília, ou 04:24:05 UTC. Última resposta do Claude contabilizada: 20/10/2026 às 22:01:32, horário de Brasília. O recorte do Antigravity termina em 21/10/2026 às 02:19:24, horário de Brasília. Atividade posterior a cada corte fica fora deste retrato.

Contadores mantidos separados por origem
ComponenteCodex · conjunto Vice CityClaude · conversa do menuGemini · recortes Antigravity
Entrada total7.186.744.10643.060.41991.487.426
Leitura de entrada em cache7.084.412.03242.583.79388.104.036
Entrada fora de leitura de cache102.332.074492 de entrada comum + 476.134 de criação de cache3.383.390
Saída registrada28.034.996157.637351.982
Total por origem7.214.779.10243.218.05691.839.408

Leituras de cache. Em uma execução longa, o contexto e os resultados de ferramentas voltam em muitas requisições. A mesma informação pode ser lida repetidamente e aparecer como entrada reutilizada. Neste agregado, cerca de 98,17% do total corresponde a leituras de cache. Isso não significa bilhões de tokens de código novo, nem mede o tamanho do jogo.

Descontadas somente as leituras de cache, restam 134.736.705 tokens no agregado: entrada fora dessas leituras, criação de cache do Claude e saída das três origens. A parcela restante também pode conter contexto repetido e não equivale a uma cobrança. Cada fornecedor usa sua própria tokenização, portanto a soma é uma contagem administrativa dos registros, não uma medida universal de texto.

Recortes do Gemini no Antigravity

A otimização de ativos 3D e de carregamento soma 597 chamadas, 3.600.971 tokens fora de leitura de cache e 90.834.850 no total bruto. Dez chamadas posteriores para apurar o consumo levam o retrato ampliado a 607 chamadas e 91.839.408 tokens brutos. O agregado do projeto usa esse retrato ampliado.

Uso conferido por etapa no Antigravity
EtapaChamadasFora de leitura de cacheLeitura de cacheTotal bruto
Ativos 3D2221.270.84330.825.89232.096.735
Streaming e demanda inicial3752.330.12856.407.98758.738.115
Contagem do consumo do GTA10134.401870.1571.004.558

Foram somados os eventos únicos dos passos 0 a 509 da frente 3D, 500 a 1356 da frente de carregamento e 1357 a 1377 da apuração. O total de 607 chamadas enviado por Alan confere até o passo 1377. Estender a seleção até 1385 inclui mais três chamadas de contagem. Os trechos sobre Casa 49 e Hades II ficaram fora.

Comparação da janela de otimização

Alan também forneceu um recorte do Codex para a otimização: 407.778.300 tokens na conversa principal e 35.730.409 em oito sessões de revisão automática, totalizando 443.508.709. Somado ao retrato ampliado do Gemini, esse comparativo registra 535.348.117 tokens brutos: 14.176.049 fora de leituras de cache e 521.172.068 em cache.

Esse comparativo é o recorte informado por Alan. Não foi adicionado ao agregado do projeto: a conversa principal se sobrepõe à contagem anterior, e a seleção das oito revisões ainda não foi conciliada por identificador. Usar um início anterior ao primeiro contador observado também muda o delta da janela.

Método de contagem

  • Codex: 150 sessões identificadas do projeto: uma conversa principal e 149 sessões auxiliares/de revisão. Há uso em 149; uma não tem contador disponível e fica fora da soma. Cada identificador entra uma vez. Da conversa longa, usamos o último contador acumulado, sem somar os eventos acumulados entre si nem adicionar páginas históricas novamente.
  • Continuidade da evidência: 23 sessões têm leitura atual do arquivo canônico; 126 reaproveitam sua medição histórica selada de 16/10, identificador por identificador. Os contadores disponíveis coincidem com o retrato do banco local. Arquivos históricos indisponíveis não foram reconstruídos por estimativa.
  • Claude: 230 respostas únicas. Os 224 registros repetidos do fluxo de respostas foram descartados. Para o mesmo identificador, a entrada precisa coincidir e conserva-se a maior saída observada. Detalhes internos de cache e iterações não são somados de novo.
  • Antigravity: somar entrada, leitura de cache e saída dos eventos selecionados, uma vez por passo. A saída registrada já inclui o consumo informado pelo exportador; não acrescentar raciocínio novamente. O nome Gemini 4 Argon vem do relato de Alan, pois estes registros não trazem o identificador do modelo.
  • Escopo: o estudo relacionado sobre Gotham e conversas que misturam outros jogos ficam fora do total principal. Revisões efêmeras sem uso salvo, atividade inacessível ou em outras máquinas e possíveis sessões não identificadas não podem ser certificadas.

Os campos dos fornecedores têm significados diferentes. No Codex, a leitura de cache já faz parte da entrada e o raciocínio registrado já faz parte da saída; somá-los novamente inflaria o total. No Claude, a entrada total desta auditoria soma entrada comum, criação de cache e leitura de cache. As fórmulas seguem as documentações de contabilidade da OpenAI e de cache da Anthropic.

Codex = entrada total + saída
Claude = entrada comum + criação de cache + leitura de cache + saída
Antigravity = entrada sem cache + leitura de cache + saída
Agregado = Codex + Claude + Antigravity

Não adicionar novamente os subconjuntos:
cache do Codex, raciocínio ou detalhes internos de cache.

Custo financeiro não apurado. O levantamento não foi conciliado com uma fatura. Plano, modelo, cache e ferramentas podem ter regras de cobrança distintas; o total de tokens, sozinho, não determina o custo.

Baixar os números e a metodologia em JSON. O arquivo público contém agregados, contagens e hashes dos recibos de auditoria. O arquivo não contém transcrições, prompts, identificadores de conversas ou credenciais.

Cronologia

As datas abaixo registram as mudanças de escopo e as etapas do projeto.

7 a 14/10 · Biblioteca e investigação da Definitive Edition

O ponto de partida foi catalogar o pacote Android, recursos e sistemas. As revisões de personagens, veículos e armas mostraram que extrair um arquivo não garante uma prévia útil: materiais, variantes, rigs e nomes também precisam ser resolvidos. A biblioteca permitiu inspecionar conteúdo; reconstruir toda a engine dessa edição continuou sendo um problema maior.

15 a 19/10 · Uma base clássica para o experimento jogável

Alan autorizou usar qualquer Vice City neste experimento. A rota passou a integrar o clássico PC com reVC Web, reaproveitando uma engine existente. O foco mudou para a execução nativa no navegador, arquivos por demanda, texturas, áudio, interiores e trechos da campanha. Esse reaproveitamento preserva sistemas já implementados e exige registrar exatamente a base usada.

20/10 · Desempenho, banda e a página de entrada

A investigação de FPS e I/O avançou junto com a compressão sem perdas. A pergunta “por que o menu baixa tanto?” revelou leitura antecipada de áudio e trabalho de engine antes da escolha de jogar. O menu criado no Claude foi preservado; imagens/fontes foram otimizadas sem cortar sua arte. O relatório de carregamento virou material público e um processo para outros ports.

20 a 21/10 · Controle e adaptação ao toque

O controle físico passou a ter orientação e detecção na entrada, usando a Gamepad API e o caminho SDL existente. A adaptação móvel estudou os widgets Android e criou um controle lógico para analógico, câmera e botões por contexto. A revisão para iPhone/tablet revelou problemas de área visível, toque curto e dependência de rede do Worker no WebKit.

21/10 · Assinatura, créditos e registros do processo

O estudo público passou a reunir assinatura, divisão de trabalho, workflow, auditoria de tokens e correções registradas durante o port.

Correções no WebKit e nos controles de toque

No WebKit, a partida parava em uma falta de dados. Mensagens entre página e Worker passavam, mas as respostas de rede do Worker só concluíam quando a página liberava execução. A espera da página impedia a conclusão da operação da qual ela dependia.

A solução atual usa leitura Range síncrona de bytes originais somente nas faltas de cache desse navegador, com checagem de status, intervalo, tamanho e SHA dos blocos mapeados. Preparação assíncrona e LRU continuam; Chromium mantém o caminho de Worker e compressão. Uma falta de cache nessa rota pode bloquear o quadro e transferir mais bytes crus.

Nos testes de toque rápido, o botão visual respondia, mas a engine podia ler o controle apenas depois de o dedo já ter soltado. O pulso de botão passou a conservar somente o restante de 100 ms para atravessar a leitura por quadro. Cancelamento, perda de foco, rotação e mudança de contexto continuam limpando a entrada imediatamente.

Etapas de carregamento#

Separamos a visita à página, o menu nativo, o jogador livre e a exploração. Cada etapa pede um conjunto de arquivos.

Marcos de uso e custo observado
MomentoO que precisa existirReferência deste caso
Apresentar a páginaInterface, fontes e arte integral.Cerca de 1,03 MB de corpos na medição histórica; nenhum recurso da engine antes de Jogar.
Abrir o menu nativoEngine, dados iniciais, tabelas e sons imediatos.36,58 → 17,10 MB no ensaio comparativo após o clique.
Liberar o jogadorTrecho de mundo, personagem, colisões e dependências.Controles livres e movimento nativo; custo depende da rota.
Continuar a partidaOutras áreas, missões, idiomas e áudio.Leituras por demanda, sem temporizador para baixar tudo.

Medições históricas de outubro de 2026 em ambiente local. MB = 1.000.000 bytes; MiB = 1.048.576 bytes. Corpo de resposta, transferência efetiva e banda faturada são medidas distintas. Os percentuais têm bases diferentes e não se somam.

Inicialização somente após Jogar

O pequeno ponto de entrada passou a importar o carregador somente na escolha de Jogar. Antes disso, não há Worker clássico, manifesto de instalação nem WASM em preparação. Revisamos também imports indiretos: outro módulo pode disparar a engine mesmo quando o botão parece leve.

A arte foi preservada. Doze imagens passaram para WebP sem perdas, incluindo transparência; três fontes passaram para WOFF2 com os glifos completos. Os 15 arquivos caíram de 1.988.974 para 1.014.742 bytes. Comparar os dados decodificados e a tela composta são provas diferentes: filtros e bordas transparentes podem produzir arredondamentos no render.

Dados dos primeiros cinco minutos#

A base clássica contém 1.445 entradas / 1.534.714.792 bytes. Antes, ser um arquivo pequeno era motivo para baixá-lo na abertura: 1.423 arquivos e mais de 121 MB, mesmo quando muitos não seriam usados.

Instrumentamos leituras reais durante menu, nova partida, introdução e um cenário curto. O perfil prepara 117 dados / 11.942.098 bytes. Outros 1.306 pequenos ficam montados no FS virtual; os 22 grandes já usavam blocos. Suplementos de textura e tabelas necessárias continuam preparados.

Arquivo montado e dados residentes. O caminho do arquivo pode existir para a engine antes de seu corpo estar na memória. O perfil inicial prevê o que antecipar; não decide quais arquivos o jogador pode usar.

Num ensaio de cinco minutos, nove dos 1.306 arquivos pequenos adiados foram pedidos e 1.297 ficaram intocados. Esse resultado pertence ao cenário e à revisão medidos. Outro idioma, save avançado ou rota pode pedir outros recursos no primeiro minuto.

A contraprova é solicitar conteúdo fora do perfil e confrontar seus bytes com a origem. Fizemos isso com áudio futuro, outro idioma e colisão de outra região. A previsão pode estar incompleta; a disponibilidade precisa sobreviver a isso.

Carregamento após o perfil inicial

Continuar seguindo as leituras do jogo. Não há um alarme que baixa o acervo inteiro. Antecipar depende de sinais de necessidade e de limites de rede e memória.

Cidade por blocos#

O arquivo gta3.img reúne muitos recursos. A engine pede intervalos de bytes. HTTP Range permite solicitar uma faixa e receber 206 Partial Content, com tamanho e posição indicados no cabeçalho. Referência de Range.

A compressão precisava conservar esse acesso. Dividimos o arquivo em 1.250 blocos lógicos de 256 KiB, comprimidos independentemente. Um índice relaciona a posição original ao intervalo comprimido em três pacotes de até 64 MiB.

Offset original
A engine pede bytes. O índice localiza os blocos correspondentes.
Range comprimido
O Worker restaura o bloco recebido e confere tamanho e SHA256.
Bytes originais
O bloco entra no cache e a engine conserva seus offsets e formatos.

O arquivo completo passou de 327.487.488 para 182.687.465 bytes no transporte, redução de 44,22%. A engine continua enxergando os mesmos 327.487.488 bytes. Não há corte de geometria, textura ou regra nativa nessa transformação.

Esse percentual descreve o arquivo inteiro. No cenário de partida medido em três pares, a redução média do conjunto de corpos baixados foi de 22,83%. Uma sessão pede parte do arquivo e também baixa outros dados.

Acesso aleatório e blocos independentes

Uma compressão contínua pode exigir decodificar trechos anteriores para alcançar o ponto desejado. Blocos independentes permitem restaurar uma faixa isolada. O ganho precisa compensar índice, cabeçalhos, buscas e descompressão.

Também produzimos variantes Brotli e gzip do JS/WASM, conferidas contra os binários originais. A negociação foi verificada localmente; ter um arquivo .br no disco não certifica que a hospedagem pública o escolhe.

Leitura assíncrona e renderização#

A engine já possuía um protocolo de leitura com estados de espera. Porém, a adaptação Web terminava a leitura dentro da chamada inicial. Quando os bytes estavam frios na rede, a renderização esperava junto.

Adaptamos o caminho: a leitura enfileira; a consulta de estado verifica a residência; só então a engine copia os bytes para o buffer nativo. Enquanto o pedido adiável está pendente, o loop pode apresentar outros quadros.

Esquema conceitual da leitura:

pedirLeitura(intervalo)   → enfileirar
consultarEstado()        → pendente: próximo quadro
                          pronto: copiar bytes residentes
                          erro: tratar falha de leitura
sincronizarObrigatorio() → concluir antes do parser

Leituras obrigatoriamente síncronas continuam concluídas antes de o consumidor avançar. Retornar sucesso com um buffer incompleto seria corrupção. Flush, cancelamento, troca de canal e destruição do mundo também precisam estar corretos: um callback não pode escrever num ponteiro liberado.

Worker e sincronização

Ele busca, restaura e confere blocos. A ponte legada usa memória compartilhada e isolamento entre origens. Mas uma função que espera em Atomics na thread principal ainda pode bloquear a aba. O ganho depende dos pontos em que o consumidor realmente permite esperar até o próximo quadro.

O agendador reaproveita operações em andamento e limita a oito buscas assíncronas pendentes. Não cria outro pedido do mesmo bloco a cada quadro. A preparação inicial tem um limite separado de quatro downloads.

Com 150 ms de atraso artificial nos blocos, três pares mediram 49,909 → 59,876 FPS. Em rede local normal: 59,456 → 59,862 FPS. O ganho sob atraso pertence a essa condição.

Áudio sob demanda#

O áudio escondia dois problemas. A engine abria falas e músicas para descobrir suas durações. O consumidor de efeitos também lia seu banco inteiro, embora poucos sinais fossem necessários na abertura.

Tabela de duração do áudio

A própria engine suportava uma tabela de duração. Geramos e conferimos a tabela com a base exata: 1.224 durações / 4.896 bytes. A abertura consulta metadados sem abrir cada voz só para medi-la. Isso permitiu adiar 1.200 MP3/WAV pequenos / 96.888.249 bytes, conservando os arquivos originais.

Leitura por amostra no banco SFX

O banco SFX precisava de uma adaptação nativa. O canal agora aguarda seus bytes antes de copiar e enviar PCM ao áudio. Parar ou limpar cancela a reprodução pendente; a espera conserva a identidade e o tempo de vida do som que ainda interessa.

Os 11 sinais originais de abertura e navegação são preparados antes do menu: três blocos / 786.432 bytes, em vez de antecipar 21.233.664 bytes. Os demais efeitos chegam conforme o uso.

Adiar com qualidade exige prever o instante de tocar. Os sinais curtos aguardam os bytes sem perder a identidade do canal. Preparar sons imediatos e conservar os canais foi parte da solução. Um primeiro efeito ainda frio pode depender da rede; isso não autoriza prender a renderização.

Outra correção retirou uma espera ocupada entre canais estéreo que dependia de o navegador receber o controle de volta. O caminho Web retorna ao loop e tenta novamente depois.

Limites de quadros e medição de FPS#

Um limite nativo de 30 Hz convivia com a espera do navegador e outro bloqueio no caminho Web. A composição dessas esperas perdia oportunidades de apresentação. Investigamos o loop real, mantendo a qualidade da cena.

O caminho Web passou a seguir requestAnimationFrame, com alvo 60 quando o limitador está ligado. O prazo usa relógio monotônico e evita despejar todos os quadros vencidos após um atraso. O comportamento não Web foi preservado.

Resultado histórico e suas condições
CondiçãoAntesDepois
Mesma rua, arte final, 1280 × 720, Metal / Apple M3 Ultra, três pares intercalados.24,1619 FPS59,9530 FPS

O contador avança na apresentação nativa. Contar RAF, iterações de lógica ou tempo de download responderia a outra pergunta. Mesmo esse contador não mede diretamente o tempo de GPU ou a varredura física do monitor.

Esse resultado não promete 60 FPS em celular. Tampouco demonstra toda a física e a campanha sob outra frequência. Mudanças de cadência exigem verificar timers, animação e simulação.

Compressão dos objetos 3D#

O Gemini 4 Argon participou da compressão e otimização dos objetos 3D, conforme informado por Alan Nicolas. Na prévia Three.js, os recursos convertidos usam GLB e texturas separadas. O conjunto contém 428 modelos e 465 registros de textura. Seu tamanho ativo único passou de 427.886.280 para 101.351.068 bytes, redução de 76,31%.

  • Geometria compartilhada. Conservar accessors entre materiais e usar índices de 16 bits somente quando todos os valores cabem, preservando a topologia.
  • Meshopt. Comprimir buffers e quantizar apenas direções de normais/tangentes, com decodificação independente. Posições, UVs, pesos e animações conservam seus valores verificados.
  • Texturas por papel. Cor e dados lineares têm critérios próprios, com resolução preservada. Se a qualidade ou o tamanho não favorece a conversão, fica o original.
  • Reutilização e descarte. Reaproveitar operações, modelos e texturas. Descartar resultados tardios de uma cena abandonada e conservar o necessário para restauração gráfica.

Fechar um ImageBitmap logo após o upload parecia liberar memória mais cedo, mas impedia reconstruir a textura depois da perda de contexto. A liberação precisa respeitar o ciclo de vida inteiro.

A redução é do conjunto da prévia, não do download inicial nem dos DFF/TXD/IMG da campanha clássica. Preservação perceptual e direções aproximadas não significam igualdade binária de todos os recursos.

Cache, memória e banda#

O navegador pode reaproveitar o que ainda estiver no cache. Isso depende da identidade, dos cabeçalhos, do espaço e das decisões do navegador. Nova versão, cache apagado, navegação privada ou descarte podem gerar transferências. Não há promessa de armazenamento offline permanente.

Três caches com durações distintas
CamadaO que guardaLimite
HTTPRespostas reutilizáveis entre visitas.Assets com hash recebem cache longo; páginas e índices revalidam. Retenção não é garantida.
StreamerBlocos residentes durante a sessão.LRU de 400 MiB neste port. Não é a RAM total nem um teto adequado a todo aparelho.
Engine / GPUModelos, texturas, áudio e estruturas prontas.Tamanho comprimido não determina a memória após decodificar.

Corrigimos a contabilidade: uma view de 256 KiB podia manter vivo um buffer maior, apesar de contabilizar só o trecho. Guardar um bloco com armazenamento próprio pode economizar RAM mesmo exigindo uma cópia deliberada.

Uma estimativa de banda precisa separar os públicos:

banda ≈ visitas × bytes da apresentação
+ inícios de partida × bytes adicionais até jogar
+ conteúdo extra efetivamente solicitado
− reaproveitamento observado no cache

Use medições compatíveis. Cabeçalhos e transporte acrescentam custo, e a contagem do provedor pode ser outra. A revisita histórica registrou 18.314 bytes de transferência reportada num mesmo contexto; isso não garante o custo após perda de cache.

Na URL pública, conferir MIME, isolamento, Range, build e cache. no-cache exige revalidação; não significa necessariamente baixar todo o corpo novamente. Referência de cache HTTP.

Testes e limitações#

  • Fixar o objeto. Identificar engine, dados, cena, configuração e build; confrontar o servido com o medido.
  • Separar integridade e aparência. Hash prova bytes. A tela em movimento nas mesmas condições revela materiais, rig, transparência e timing.
  • Observar o consumidor. Exigir movimento nativo com controle livre, PCM correto e retorno de pausa. Uma API sem erro pode não produzir nada útil na tela.
  • Provocar falhas úteis. Testar bloco incompleto, índice divergente, atraso, cancelamento, original de reserva e restauração gráfica.
  • Medir pares. Em performance, três pares intercalados com a arte final. Uma rodada mistura rede, cache e aquecimento.
  • Contar o conjunto. Conferir 428 modelos ou 1.224 durações prova esses conjuntos, não todo recurso ou comportamento.

A rodada passou 248 verificações primárias e 18 específicas com controle virtual contra a engine real: movimento, câmera, zona morta, menus, pausa, desconexão, reconexão e teclado. O esquema original usa A/✕ para confirmar, Y/△ para voltar em submenus e Start para pausar/retomar.

Permanece aberto: campanha completa, fidelidade audiovisual integral, desempenho em aparelhos físicos e controle Bluetooth físico. Testes virtuais e celular emulado não substituem essas provas. Os números são dos cenários identificados.

Controles físicos e adaptação móvel

O controle Bluetooth/USB usa o mapeamento padrão que o navegador expõe à Gamepad API, chegando ao SDL2 já compilado na engine. A página detecta e orienta; conectar um controle não inicia o download do jogo. Os testes incluem dois analógicos, pausa, desconexão, reconexão e teclado preservado, com controle virtual. A conexão Bluetooth física ainda precisa ser confrontada em aparelhos reais.

Para toque, a pesquisa consultou os widgets da versão Android identificada e adaptou suas funções ao controle clássico. O analógico esquerdo move ou esterça; a área de olhar controla a câmera; os botões mudam em menus, cenas, a pé e em veículo. Cada dedo conserva sua identidade. Soltar um gesto não solta os outros, e perda de foco/cancelamento limpa o estado. A interface acompanha a área visível, as bordas seguras, rotação e janela dividida.

Na revisão anterior a esta edição, o validador principal passou 251 de 251 testes. A matriz de layout passou 176 de 176 casos: 22 tamanhos × quatro contextos × Chromium/WebKit. Houve ainda 66 verificações de toque no Chromium e 15 no WebKit com a engine, incluindo menus, áudio, pausa e disparo por toque rápido. Esses números descrevem a revisão 7934b4489bd7c60b147398c1fe804b085ca6b1d2, não um ensaio novo executado pelo leitor.

Os tamanhos e áreas seguras foram emulados. WebKit no Mac não certifica Safari/iOS no aparelho; a arma do ensaio foi obtida por um cheat nativo declarado no perfil de teste. Aquisição normal, desempenho físico móvel, todos os controles e campanha completa não estão certificados por esses resultados. A rota síncrona de compatibilidade pode bloquear durante uma falta de rede.

Aplicação em outros jogos#

Este roteiro reúne as etapas usadas aqui. Os parâmetros e a economia de bytes precisam ser medidos em cada jogo.

  1. Fixe a versão e meça a abertura atual.

    Registre hashes, cena, fluxo e referência visual. Separe visita, menu, primeiro controle e sessão curta.

  2. Separe apresentação e engine.

    Revise imports, preload e construtores. Prove que a simples visita não prepara uma instalação ainda não iniciada.

  3. Descubra leituras que só procuram metadados.

    Instrumente arquivos e APIs de assets. Procure duração, dimensões, cabeçalhos e dependências; produza índices vinculados à revisão.

  4. Separe disponibilidade e residência.

    Monte o conteúdo completo e antecipe o conjunto observado. Depois peça outro idioma, save avançado ou área fora da previsão.

  5. Respeite o tempo da engine.

    Use pendente/pronto/erro onde isso fizer sentido. Mantenha leitura obrigatória concluída. Revise flush, cancelamento, teardown e ponteiros.

  6. Comprima o que será transferido.

    Para acesso aleatório, avalie blocos independentes. Para JS/WASM, representações HTTP. Em malhas/texturas, preserve atributos usados e compare o resultado.

  7. Limite antecipação, concorrência e retenção.

    Guarde operações em andamento. Conte memória realmente retida. Evite download geral por tempo decorrido.

  8. Feche consumidores especiais.

    Áudio, shaders, cenas e vídeo podem ler seus pacotes inteiros. Um FS virtual não elimina sozinho esse comportamento interno.

  9. Confira o servidor na URL pública.

    Verifique MIME, encoding quando usado, Range, isolamento necessário, cache e identidade entregue.

  10. Compare resultado e qualidade.

    Repita com cache frio e revisita, mesma arte e condições. Observe em movimento e teste o aparelho alvo antes de prometer seus números.

Adaptação por arquitetura

Transferir o princípio, adaptar a implementação
PortInvestigar primeiroNão assumir
C/C++ → WASMFronteira de I/O, metadados e bloqueios.Pacotes de preload não implementam streaming por uso.
Emulador / disco virtualSeparação runtime/dados e acesso por blocos.Uma camada externa não elimina a exigência interna do arquivo completo.
Three.js / GLBDependências, geometria compartilhada e texturas por papel.Arquivo menor não demonstra menor VRAM ou menos draw calls.
Unity Web com projetoEmpacotamento, catálogos, dependências, descarte e headers.O patch nativo deste caso não se aplica diretamente à Unity.

Comece por um cenário pequeno, repetível e comparável. Prove a integração antes de reconverter o acervo inteiro.

Referência das 28 técnicas#

Abra um item para revisar o mecanismo e o cuidado ao reaplicá-lo. Use os identificadores O01 a O28 para citar uma técnica deste estudo.

O01Engine somente após Jogar

Importação dinâmica, uma única inicialização e falha visível. Antes da escolha, não preparar Worker, WASM ou instalação. Revisar imports indiretos.

O02Imagens de interface sem perdas

WebP lossless com RGBA, transparência e dimensões preservados. Conferir dados decodificados e composição final; arquivo e captura são provas distintas.

O03Fontes completas em WOFF2

Conservar glifos, contornos, métricas e kerning. Comprimir o contêiner não exige cortar caracteres ou idiomas.

O04Preparação com concorrência limitada

Quatro downloads iniciais, barreira de falha e cancelamento dos irmãos. Conferir posse do buffer antes de entregá-lo sem cópia adicional ao FS.

O05Arquivos grandes montados por blocos

Reaproveitar o FS virtual para 22 grandes. Conservar caminhos, tamanhos e offsets. Montar não significa baixar o corpo inteiro.

O06Perfil inicial de leituras reais

Antecipar 117 dados; adiar 1.306 pequenos. A previsão é vinculada à revisão e não exclui os recursos restantes.

O07Durações pré-calculadas

Tabela nativa exata de 1.224 durações / 4.896 bytes evita abrir todas as falas para medir metadados. Falhas de integridade ficam visíveis.

O08Áudio pequeno por demanda

1.200 MP3/WAV abaixo de 4 MiB usam o streamer sem transcodificação. Consumidores de leitura integral precisam de investigação própria.

O09Blocos e antecipação conforme o acesso

Blocos de 256 KiB e antecipação legada de 1, 8 ou 32 blocos conforme a sequência. Esses valores são parâmetros do caso, não um ótimo universal.

O10Worker e ponte compartilhada prontos

Preparar o Worker antes de depender dele. SharedArrayBuffer exige isolamento. A engine inteira não foi movida para um Worker.

O11Leitura nativa realmente pendente

Enfileirar e copiar só bytes residentes. Manter Sync, flush, troca de canal e teardown corretos; sucesso exige dados disponíveis.

O12Reutilizar pedidos em andamento

Guardar a operação por arquivo/bloco, além do resultado. Limitar background e evitar clonar o índice inteiro em cada pedido.

O13LRU e memória realmente retida

Teto de 400 MiB neste cache, com descarte de blocos antigos e armazenamento próprio. Uma view pequena pode reter um backing buffer enorme.

O14Compressão independente da cidade

1.250 blocos gzip em três pacotes, com índice, tamanho e hash. 327.487.488 → 182.687.465 bytes, restaurando o conteúdo nativo.

O15Brotli e gzip para a engine

Conferir restauração e negociar com MIME e Vary corretos. Preservar a representação de Range. Negociação local não certifica a pública.

O16Identidade por conteúdo e cache

Nomes com hash permitem cache longo de corpos estáveis. Páginas e índices mutáveis revalidam; identidade nova não pode apontar para corpo incompatível.

O17Integridade, prazos e original de reserva

Conferir tamanho e hash, coordenar prazos e recuperar pela origem quando necessário. Cancelamento impede efeitos tardios.

O18Banco SFX no consumidor nativo

Conservar alocação e estado, lendo PCM por amostra. Canais pendentes mantêm identidade; Stop, Reset e limpeza cancelam o interesse perdido.

O19Preparar sons imediatos

Onze sinais precisam estar residentes antes da primeira pausa. Três blocos / 786.432 bytes preparados, mantendo o restante por demanda.

O20Cadência Web e quadros reais

Investigar limitadores duplicados, seguir RAF e medir a apresentação nativa. Mudanças de cadência exigem verificar a simulação.

O21Devolver controle para o áudio avançar

Evitar espera ocupada por uma condição dependente da próxima tarefa do navegador. Retornar ao loop quando canais estéreo desencontram.

O22Payload sem dados que não são desenhadosPrévia 3D

O consumidor da prévia não usa os atributos de diagnóstico já omitidos na conversão. Demonstrar o não uso; o nome do campo não autoriza apagá-lo em outro jogo.

O23Geometria compartilhada e índices adequadosPrévia 3D

Converter accessors únicos; índices de 16 bits só quando todos cabem. Preservar topologia e LODs existentes, sem corte automático de triângulos.

O24Meshopt e quantização limitadaPrévia 3D

Comprimir buffers e aproximar só direções conforme a régua. Decodificar e conferir os demais atributos; aproximação não é igualdade bit a bit.

O25Texturas por papel e qualidade medidaPrévia 3D

Preservar resolução, distinguir cor de dados lineares e manter PNG quando qualidade ou tamanho não favorecem conversão. Medir e observar.

O26Coleções por uso e recursos compartilhadosPrévia 3D

Reutilizar índices, promessas, modelos e materiais. Clonar transformações não exige duplicar geometria nem prova redução de draw calls.

O27Descarte e restauração gráficaPrévia 3D

Definir dono e duração. Descartar resultados tardios e manter ImageBitmap até o descarte para restaurar texturas após perda de contexto.

O28Publicação como parte do funcionamento

Conferir status, MIME, Range, cache, isolamento e build na URL real. Enviar diferenças economiza publicação, medida distinta da banda dos jogadores.

Glossário#

Engine
Sistemas que executam mundo, lógica, desenho, áudio e outros comportamentos do jogo.
WebAssembly / WASM
Formato de código compilado executável no navegador, integrado às APIs do ambiente.
FS virtual
Arquivos apresentados à engine mesmo quando seus dados vêm de memória ou rede.
Streaming
Trazer conteúdo conforme a necessidade, aqui inclusive por intervalos de bytes.
Residente
Dado disponível numa camada de memória para consumo. Um arquivo comprimido ainda pode precisar de preparo.
Worker
Contexto separado usado para buscar, restaurar e conferir dados.
Cache frio / quente
Dados ausentes ou presentes na camada de cache observada.
LRU
Remover primeiro os itens usados há mais tempo quando o cache ultrapassa seu limite.
SHA256
Resumo do conteúdo usado para confrontar identidade e integridade dos bytes.
RAM / VRAM
Memória do sistema e associada à GPU; o download não mede nenhuma diretamente.
PCM
Amostras de áudio usadas no caminho de reprodução.
Build
Conjunto produzido para executar e publicar, identificado por commit e manifesto.

Fontes e créditos#

As medidas vêm dos manifestos e dos testes registrados do projeto. Cada comparação conserva a revisão e o cenário em que foi feita. O roteiro para outros jogos reúne procedimentos derivados deste port.

Referência da publicação do relatório de carregamento: build ff25461b8a718a73ae26dfe4d0b8d85c68eec2653ff33c6fd23fef0ef36b85d5, com cenários comparativos de revisões anteriores identificados no texto. Controle: commit c19fd1db097dbc2c807c34031fc342a509377219. Uma regressão nativa mais ampla permaneceu parcial; testes primários ou específicos não a substituem.

Créditos: Rockstar Games pelo jogo original; comunidades reVC, wasm-revc e wasm.com.br pelas bases; Emscripten, librw, SDL, OpenAL, Three.js e ferramentas de compressão pelos componentes. Este material documenta a integração e suas medições.