Tupi: reconstruindo 1554 no navegador com 32 agentes de IA
Um ataque tupinambá de 1554 recriado em 3D no navegador com Claude Opus 5.5, three.js e Blender: o pipeline, o que quebrou e quanto custou.
Tupi é um filme de três minutos e meio que roda ao vivo no navegador. Uma frota de guerra tupinambá, em igaras de casca, sobe o canal da Bertioga ao amanhecer, por volta de 1554, rumo a uma aldeia tupiniquim. O filme é um loop: perto do fim começa uma garoa, um trovão ecoa na Serra do Mar, e o amanhecer seguinte abre o céu de novo.
Eu não escrevi o código. Dirigi, numa única conversa longa com o Claude Opus 5.5 no Claude Code. Ele escreveu o dossiê de pesquisa, o código em three.js, os scripts de Blender e as ferramentas de revisão, e comandou outros 31 agentes para o trabalho em paralelo. Este post conta como foi: o pipeline, o que resistiu e a conta.

O prompt
Tudo começou com uma mensagem:
Clone o dgreenheck/tidewater. Ele fez um experimento visual muito bom com Opus 5.5 e eu quero fazer algo do mesmo nível, mas no Brasil pré-colonial: um tupinambá subindo um rio em território inimigo, ambientado em Pindorama. A ideia desta pasta é fazer várias demos retratando momentos históricos da humanidade com three.js e 3D. Acha que somos capazes não só de produzir esse nível de visual 3D no navegador, mas também de fazer a pesquisa histórica correta?
Tudo o que veio depois foi direção em rodadas, como quem revisa um corte de filme:
- “as árvores da margem direita estão iluminadas demais”;
- “a neblina está parecendo fumaça e tirando o vigor da mata”;
- “tudo que tem pedra está bem low poly”;
- “as montanhas da Serra do Mar eram pontudas assim mesmo?”;
- “coloque caranguejos e animais do mangue”.
A sequência completa de pedidos está na página de demos: o botão ✦ prompt no card da Tupi.
Pesquisa antes da geometria
A primeira pergunta que fiz foi se conseguiríamos chegar no nível visual do tidewater do dgreenheck e da Sakura River Valley, do Meng To, e, ao mesmo tempo, acertar a história. Por isso a primeira entrega não foi uma cena, foi um dossiê com fontes: Hans Staden (1557), Jean de Léry (1578), Gabriel Soares de Sousa (1587), o dicionário de tupi antigo de Eduardo Navarro, Florestan Fernandes, Carneiro da Cunha e Viveiros de Castro.
Cada escolha visual remete a ele:
- Canoas. As igaras são de casca, não troncos escavados. Staden conta que tiravam a casca da árvore numa peça só, aqueciam no fogo, dobravam as duas pontas e mantinham a canoa aberta com duas travessas. Cabiam trinta homens.
- Pintura. Jenipapo (preto) e urucum (vermelho).
- Cabelo. A tonsura: a frente da cabeça raspada, o cabelo comprido atrás.
- Adornos. O enduape, uma roseta de penas de ema amarrada na base das costas, e o tembetá no lábio.
- Fauna. Guarás cruzando o canal e tainhas saltando, porque Staden diz que os ataques vinham em agosto, “porque nesse tempo vão à caça de uma espécie de peixe”.
O dossiê também corrigiu o meu briefing, duas vezes. Eu tinha falado em “Pindorama”, que é uma invenção do século XIX. E a Serra do Mar dos primeiros renders era uma fileira de picos alpinos. Quando perguntei “as montanhas eram pontudas assim mesmo?”, a resposta foi não: é uma escarpa antiga e erodida, arredondada e coberta de mata. A serra do round 4 ao lado da final:

O dossiê completo é público, com um nível de confiança em cada afirmação: research.md. Para ler as fontes você mesmo:
- Hans Staden, Warhaftige Historia (1557):
- Jean de Léry, Histoire d’un voyage faict en la terre du Brésil (1578):
- Gabriel Soares de Sousa, Tratado descritivo do Brasil em 1587: PDF.
- Eduardo de Almeida Navarro, Dicionário de Tupi Antigo (Global, 2013), para as palavras em tupi antigo: igara, ypé-ygara (“canoa de casca”), tembetá.
- Contexto:
A stack
- Motor. three.js r186 em WebGPU com materiais de nós TSL, com fallback para WebGL2.
- Módulos. São 14: céu, água, terreno, mangue, mata, frota, aves, fauna, fumaça, áudio, câmera, ambiência, overlay e pós-processamento. Cada um tem um dono e o mesmo contrato:
create(ctx)devolve{ update(t, dt) }. Um módulo que quebra é registrado e pulado, então uma parte com defeito nunca apaga o filme inteiro. - Pós-processamento. TRAA, god rays próprios, bloom, exposição automática, color grade e grão.
- Câmera. Gira quando você arrasta e volta sozinha para o trilho cinematográfico quando você solta, como na Sakura River Valley do Meng To. A chuva perto do fim do loop foi a outra ideia que peguei de lá.
- Assets.
- Scans CC0 do Poly Haven para pedras, falésias, lama e raízes.
- Espécies da Mata Atlântica que não têm scan (juçara, jerivá, embaúba, ipê, figueira, aninga, caeté), geradas no Mint e reconstruídas no Blender com LODs e impostores.
- Gravações de campo, só CC0 e CC-BY. Os remadores ficam em silêncio.
As pessoas foram o mais difícil
Se alguém pergunta qual detalhe histórico deu mais trabalho, a resposta honesta é: as pessoas. As fontes são precisas, e é no ser humano que o vale da estranheza pega.
A primeira tentativa foi um gerador de modelos 3D por IA, e deu dois problemas:
- Ele recusava. Qualquer prompt que descrevesse as pessoas com precisão, e elas usavam muito pouca roupa, esbarrava na moderação.
- Detalhe. O que ele gerava servia para uma canoa a cinquenta metros e ficava ruim de perto: uma malha com cara de boneco.
Então os corpos vêm do MakeHuman, gerados por script no Blender, sem interface, pelo add-on MPFB2. Tudo o que é histórico é construído em código por cima deles:
- um shader de pele;
- máscaras procedurais de jenipapo e urucum;
- a tonsura feita com cartões de cabelo;
- o enduape, os cordões, as braçadeiras e o tembetá;
- um rig de remada.


Ainda é a parte menos convincente do filme. Na distância da remada, os remadores passam por gente; de perto, parecem manequins bem pintados.
O Gauntlet
Um agente sozinho produz um resultado razoável e para, porque é ele mesmo quem julga e conhece a razão de cada escolha que fez. Então reaproveitei o loop do meu FPS de navegador: o Gauntlet.
- Construtores. Rodam em paralelo, cada um dono dos seus arquivos.
- Críticos. Começam com contexto limpo e só veem os pixels renderizados, nunca a explicação de quem construiu.
- Classificador. Um “isso parece real?” dá nota a 42 quadros do filme a cada rodada.
- Capturas A/B. Conferem cada correção que alguém diz ter feito.
- Caçador de regressões. A única missão dele é achar o que piorou.
Rodei o loop sozinho, durante uma madrugada. A média do “parece real” subiu de 4,96 para 5,46 de 10 em 13 rodadas. É um número pequeno, e honesto. A maior parte do ganho foram defeitos que deixaram de aparecer, não notas que subiram:

Três lições do loop:
- Um construtor dizer “corrigido” não é prova. Várias correções estavam erradas, e só a captura A/B mostrou.
- Bug de captura se disfarça de bug de cena. Por um tempo os remadores pareciam transparentes. Não era bug de renderização: a exposição automática, a névoa e o contraste juntos estavam apagando os corpos. Outra vez, um detector de “quadro ladrilhado” estava lendo um canvas WebGPU vazio em vez do screenshot. Meça primeiro a ferramenta de medir.
- A causa raiz raramente está onde parece.
- As “pedras low poly” eram scans de verdade descartados em silêncio por um bug de temporal dead zone. O que aparecia na tela eram malhas de falésia esticadas na vertical.
- As “golas de espuma” nas pedras eram a névoa rasteira.
- Uma cruz amarela no céu era uma libélula a um centímetro da lente.
”Travou na tela de carregamento”
O primeiro relato do mundo real veio de um amigo, num PC de casa mais simples: o navegador travou na tela de carregamento. Medi:
- Onde ia o tempo. O primeiro quadro montava quase todos os shaders da cena numa tarefa só, 5,2 s de thread principal bloqueada até num Mac M-series.
- Por que travava. Num PC com Windows, onde o driver compila shaders bem mais devagar, isso dura o bastante para parecer travado.
- Onde estava a barra de progresso. Já em 100%.
As correções, todas medidas antes e depois:
-
Aquecimento dos shaders. Os objetos entram poucos por vez atrás da tela de carregamento, e cada passo espera a GPU. Nenhuma tarefa dura o suficiente para travar o navegador.
-
Pré-cálculo no build. O ruído do terreno, o skinning dos adornos dos remadores e a busca de posições dos bichos eram determinísticos, mas rodavam no navegador de cada visitante. Agora são calculados uma vez no build e vão como arquivos binários.
O quê No carregamento, antes Depois Dados pré-calculados Terreno 2,8 s 0,18 s 6,8 MB Skinning dos adornos 1,67 s 0,39 s 0,6 MB Posicionamento dos bichos uma trava de 3 s 0,09 s 0,1 MB Pré-calculado contra calculado na hora: diferença média de 0,00 nos pixels de 12 quadros.
-
Níveis por aparelho.
- GPU integrada, até 4 GB de RAM ou até 4 núcleos, e celulares recebem uma versão leve.
- Renderização por software recebe o filme gravado no lugar da cena ao vivo.
- Um carregamento que travou de verdade faz a visita seguinte cair um nível.
-
Abertura com a cena. A tela de carregamento mostra um loop curto da canoa atrás do título, então há o que ver enquanto os shaders compilam.
Uma ideia deu errado, e deixo aqui porque é a parte útil. Tentei carregar a mata e o mangue depois que o filme começava. O carregamento ficou mais rápido, mas no site no ar o filme passou a engasgar por uns 20 s enquanto os shaders compilavam no meio das cenas. Compilar de forma assíncrona acabou com o engasgo, mas aí as árvores apareciam 40 s atrasadas. A melhor troca foi a menos esperta: a mata compila antes, atrás da tela de carregamento, e só os bichos, os guarás e a fumaça, que aparecem depois do primeiro minuto, carregam em segundo plano.
Resultado num Mac M-series: carregar os módulos caiu de 4,9 s para 1,5 s, e o filme começa em ~7,7 s, sem engasgos depois. Antes eram 11–16 s, seguidos de 20 s engasgando.
Caranguejos e garças
Depois que a parte de desempenho entrou no ar, veio a revisão seguinte: “no close dos caranguejos eles estão totalmente low poly, e tem uma ave branca de cabeça preta que não dá para identificar”. As duas coisas eram provisórias: um caranguejo procedural com casco de oito lados e pernas de palito, e um savacu montado como uma bola branca com uma bola preta em cima. As espécies estavam certas; os modelos, não.
Foram trocados por gerações do Mint, recortadas no Blender:
- Um script divide cada caranguejo em casco, garras e pernas, então eles andam com pernas articuladas.
- A garra grande do chama-maré acena de verdade. As fêmeas, com duas garras pequenas, são novas.
- O savacu vira a cabeça e muda o peso de perna.


Quanto custou
| Modelo | Claude Opus 5.5, 1 orquestrador + 31 subagentes |
| Chamadas | ~3.770 |
| Tokens | ~1,29 bilhão processados, a maioria leitura de cache; ~0,7 milhão gerados |
| Preço equivalente na API | ≈ US$ 516 a preço de tabela |
| Outras IAs | ~US$ 6 em créditos do Mint para as espécies de árvores |
| Tempo de relógio | ~22 horas do primeiro prompt ao primeiro build público, com uma madrugada rodando sozinho |
O trabalho de desempenho e dos bichos, depois, somou mais cinco agentes. O custo é dominado pela leitura de cache: 32 agentes relendo um projeto grande muitas vezes. Em tokens, gerar o código foi a parte barata. Conferir foi a parte cara, e foi também o que tornou o resultado confiável.
O que ainda está fraco
- Os remadores. Corpos com cara de real e adornos históricos são o problema mais difícil daqui. Se eu for além, o próximo passo é um pipeline de MetaHuman ou fotogrametria.
- Taxa de quadros. Não é 60 fps cravado. Num Mac M-series ocupado fica em uns 40–45 fps, com a resolução dinâmica trabalhando bastante.
- Compilação dos shaders. Ainda é a maior parte do carregamento. O próximo passo é juntar em shaders compartilhados os materiais que só mudam nos parâmetros.
Abra a Tupi num computador com WebGPU e ligue o som. O prompt que a construiu está na página de demos.