---
title: "Tupi: reconstruindo 1554 no navegador com 32 agentes de IA"
description: "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."
language: "pt-BR"
published: "2026-09-26T00:00:00.000Z"
tags: ["threejs", "webgpu", "ai-agents", "blender", "history"]
source: "https://www.rubenmarcus.dev/pt/blog/reconstruindo-1554-no-navegador"
translation: "https://www.rubenmarcus.dev/blog/rebuilding-1554-in-the-browser"
---

[Tupi](/demos/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.

![Uma xilogravura do livro de Hans Staden, de 1557, ao lado de um quadro do filme](/art/blog/tupi/staden-vs-render.webp)

## 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](/pt/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](https://github.com/dgreenheck/tidewater) e da [Sakura River Valley](https://valley.mengto.here.now), do [Meng To](https://x.com/MengTo), *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 round 4, com picos pontudos e um reflexo âmbar na água, ao lado da Serra do Mar arredondada da versão final](/art/blog/tupi/gauntlet-serra.webp)

O dossiê completo é público, com um nível de confiança em cada afirmação: [research.md](/demos/tupi/research.md). Para ler as fontes você mesmo:

- **Hans Staden, *Warhaftige Historia* (1557):**
  - [a edição de 1557 no Internet Archive](https://archive.org/details/staden);
  - [o texto em alemão no Projekt Gutenberg](https://www.projekt-gutenberg.org/staden/historia/historia.html);
  - [todas as xilogravuras no Wikimedia Commons](https://commons.wikimedia.org/wiki/Category:Pages_of_Wahrhaftige_Historia);
  - [a tradução de Löfgren, *Viagem ao Brasil* (PDF)](https://fundar.org.br/wp-content/uploads/2021/06/viagem-ao-brasil.pdf).
- **Jean de Léry, *Histoire d'un voyage faict en la terre du Brésil* (1578):**
  - [o texto em francês no Wikisource](https://fr.wikisource.org/wiki/Histoire_d%E2%80%99un_voyage_faict_en_la_terre_du_Br%C3%A9sil/08).
- **Gabriel Soares de Sousa, *Tratado descritivo do Brasil em 1587*:** [PDF](https://fundar.org.br/wp-content/uploads/2021/06/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:**
  - [os tupinambás](https://pt.wikipedia.org/wiki/Tupinamb%C3%A1s);
  - [a origem de "Pindorama"](https://pt.wikipedia.org/wiki/Pindorama);
  - [o forte da Bertioga da época](https://pt.wikipedia.org/wiki/Forte_de_S%C3%A3o_Filipe_da_Bertioga);
  - [o guará](https://www.wikiaves.com.br/wiki/guara).

## 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](https://valley.mengto.here.now) 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.

![Um rosto gerado por IA ao lado de um rosto do MakeHuman, e o rosto do MakeHuman com jenipapo, urucum e tonsura](/art/blog/tupi/people-faces.webp)

![Um guerreiro do MakeHuman no lookdev, com pintura corporal, cordões, adornos de penas e o tembetá](/art/blog/tupi/people-adornments.webp)

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](/blog/shipping-a-browser-fps): 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:

![O round 4, com brilho na água e névoa chapada, ao lado do quadro final](/art/blog/tupi/gauntlet-water.webp)

Três lições do loop:

1. **Um construtor dizer "corrigido" não é prova.** Várias correções estavam erradas, e só a captura A/B mostrou.
2. **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.
3. **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.

![Antes e depois: o caranguejo procedural e o novo uçá](/art/blog/tupi/fauna-uca_t80.webp)

![Antes e depois: as garças procedurais e os novos socó-grande e savacu](/art/blog/tupi/fauna-herons_t74.webp)

## 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](/demos/tupi) num computador com WebGPU e ligue o som. O prompt que a construiu está na [página de demos](/demos).
