phelipe@kunshan:~/research/01$ cat the-build.md ← research ← home
012026-04-24 · long read · ~12 min · kunshan, china

shipping gogrowth.me: um terminal, um jogo e uma equipe de IAs

30 minutos. do dominio vazio ao site no ar com formulario de contato seguro, jogo em canvas, email transacional funcionando, headers de segurança no nivel de quem se importa, e um visual q nao parece site generico de consultor. feito em kunshan, as 5 da manha, com codex, claude code e claude design como time de engenharia. diario de bordo da coisa toda. tudo q foi quebrado, decidido, aprendido no caminho.

o contexto

eu precisava de uma porta de entrada. 15 anos de marketing, 2 anos morando dentro do ecossistema de IA da china, e nenhum lugar na internet pra quem me procurasse entender oq eu faço. velocidade importava, nao pelo prazo, mas pelo sinal. se eu vendo velocidade com IA e demoro 3 meses pra fazer uma landing page, alguma coisa ta errada no argumento.

o briefing q eu dei pra mim mesmo foi: nada de template. nada de framework pesado. nada de stack q eu tenha q explicar antes de explicar o produto. html, css, um punhado de js. hospedagem em edge. email via api. o minimo de cola possivel entre a ideia e o deploy.

a estética: um terminal de kunshan

primeira decisao foi a mais forte: o site nao ia parecer um site. ia parecer um terminal. tipografia monoespaçada (JetBrains Mono), fundo preto, tinta vermelha saturada pro acento, scanlines sutis via ::before, vinheta radial via ::after, e uma linha de chrome no topo imitando prompt de shell: phelipe@kunshan:~$.

o sistema de cor ficou inteiro em 4 variaveis:

/* :root, tudo sai daqui */
--bg:     #000;        /* preto absoluto */
--ink:    #ededed;     /* texto principal */
--dim:    #9a9a9a;     /* metadados, legendas */
--dimmer: #6e6e6e;     /* chrome, linhas tracejadas */
--red:    #ff1a1a;     /* acento, glow, CTAs */

detalhe nao obvio: a primeira versao dos cinzas (#6a6a6a, #3a3a3a) tava brigando com o preto em monitor sem calibração. textos de meta sumindo. subi tudo em uns dois notches e as bordas tracejadas de 6% pra 12% de opacidade. ajuste em dois valores e a pagina inteira ficou legivel. a moral: contraste é regra, nao gosto.

o chrome fixo no topo com o ponto vermelho pulsando (animation: pulse 1.6s ease-in-out infinite) é o detalhe q define o tom. nao é decoração, é a promessa visual de q o site foi feito por alguem q se importa. a identidade kunshan · 昆山 · 31°N 120°E no rodapé reforça o posicionamento: brasileiro, na china, operando de dentro.

great wall runner: o jogo em canvas

consultor com landing page cheia de "vamos conversar" é ruído. eu queria algo q fizesse a pessoa ficar. resposta: um endless runner de 560x340 pixels com a muralha da china rolando em parallax. teclado space ou tap na tela, vc pula obstaculos, score sobe, game over, retry.

background parallax da muralha da china, 1536x350 pixels
bg-parallax.png · 1536×350 · a muralha em pixel art, rolando em loop atrás do corredor

o herói é um sprite em 3 estados (idle, correndo, pulando) distribuidos em 3 sheets de 130×198px por frame. motor de animação é um requestAnimationFrame simples com contador de tick dividindo frames: frame = Math.floor(tick / 6) % RUN_FRAMES. zero biblioteca.

sprite sheet idle, 3 frames
runner-idle.png · 3 frames · o corredor respirando antes do space
sprite sheet correndo, 7 frames
runner-final.png · 7 frames · ciclo de corrida completo
sprite sheet pulando, 3 frames
runner-jump.png · 3 frames · crouch, lift-off, air

a fisica cabe em 5 numeros:

const GRAVITY    = 0.62;   // puxando de volta ao chão
const JUMP_V     = -11.5;  // velocidade inicial do pulo
const JUMP_HOLD_G = 0.30;  // segurar space = pulo mais alto
const MAX_HOLD   = 14;     // teto do hold em ticks
const GROUND_Y   = H - 72; // piso fixo

o truque q dá "peso" ao pulo é o jump buffering: enquanto vc segura space, a gravidade aplicada é menor (JUMP_HOLD_G) até estourar MAX_HOLD. solta antes, pula baixo. segura, pula alto. é o mesmo truque do super mario bros de 1985. funciona pq espelha a intenção do dedo, nao o tempo do frame.

obstaculos sao gerados com gap aleatorio dentro de uma janela q encolhe conforme o score sobe. velocidade do chão acelera a cada 500 pontos. game over restaura idle e o corredor volta a respirar. o arquivo game.js tem 572 linhas. sem frameworks, sem deps, sem build step.

um jogo de 572 linhas converte melhor que uma seção "sobre mim" de 572 palavras. atenção é a moeda.

a equipe: três IAs e um humano

isso aqui é o ponto q mais pesa pro leitor q quer replicar. eu nao codei sozinho. mas tb nao fui passageiro. foi um time de 4: três modelos especializados e eu no comando, cada um fazendo aquilo q faz melhor:

codex
o rascunho rapido
primeira passada em blocos isolados: o loop do game, a funcao de escape HTML, o parser do form. quando eu precisava de "me da uma v0 disso aqui em 30 segundos", codex entregava. a regra: nunca aceitar cego. sempre ler.
claude code
o engenheiro sênior
a arquitetura, a segurança, a integracao. CSP correto, Turnstile integrado, Resend com reply_to e HTML escapado, headers do Cloudflare, fluxo de deploy via wrangler. a diferenca entre "funciona" e "funciona sem me dar dor de cabeça daqui a 6 meses" mora aqui.
claude design
o diretor de arte
sprites da muralha, do corredor em três estados, background parallax. a estética pixel-art consistente em 4 arquivos PNG, exatamente oq um freelancer cobraria dias e uns mil dolares pra entregar. preço final: 40 minutos e zero pingback.
resend
o carteiro
DNS em 15 minutos, SPF + DKIM + DMARC prontos, API limpa, HTML rico. o primeiro email do form chegou antes de eu acabar de configurar o endereço de destino. from: GOGROWTH Contact <noreply@gogrowth.me>.
cloudflare
a infra inteira
pages pra hospedar, functions pro endpoint de contato, turnstile pro anti-bot, wrangler pro deploy, e uma API de provisionamento q permitiu criar o widget de turnstile sem abrir o painel. uma conta, 5 produtos, zero vendor-specific code.

orquestração foi humana. o segredo nao é "eu usei claude". é eu sabia oq queria. prompt ruim vira codigo ruim. prompt especifico, com constraints, referencias e criterios de aceite, vira codigo q vc comita sem revisar linha por linha. aí sim vira leverage.

o endpoint de contato: /api/contact

cada form na internet é uma porta. a maior parte ta destrancada. a minha nao.

a função vive em functions/api/contact.js, hospedada no edge do cloudflare. 5 camadas antes de chegar no resend:

só depois de passar pelas 5 camadas é q o resend recebe a chamada. from é sempre o endereço configurado no dominio, nunca o input do usuario. reply_to é o email de quem mandou, entao eu aperto "responder" e falo direto com a pessoa, sem expor o endereço real do form.

turnstile via api, sem abrir o painel

esta parte foi o momento mais divertido do build. normalmente vc cria um widget de turnstile abrindo o dashboard do cloudflare, clicando em "add site", copiando sitekey e secret. eu quis fazer por API pq se eu nao consigo automatizar, eu nao controlo.

gerei um token custom com escopo Turnstile:Edit. verifiquei:

curl https://api.cloudflare.com/client/v4/user/tokens/verify \
  -H "Authorization: Bearer cfut_***"

→ { "success": true, "status": "active" }

chamei o endpoint de criação:

POST /accounts/{id}/challenges/widgets
{
  "name": "gogrowth.me",
  "domains": ["gogrowth.me", "www.gogrowth.me"],
  "mode": "managed",
  "bot_fight_mode": true
}

→ { sitekey: "0x4AAAAA...", secret: "0x4AAAAA..." }

troquei o placeholder no HTML pelo sitekey real, guardei o secret via wrangler pages secret put TURNSTILE_SECRET, deployei. pronto. widget funcionando em producao, invisivel pro usuario, e o fluxo inteiro reproduzivel, posso recriar em outro dominio com 3 comandos.

segurança: o arquivo _headers

o cloudflare pages respeita um arquivo _headers na raiz do projeto. tudo q entra ali vira header em producao. o meu:

resultado: A+ em securityheaders.com na primeira tentativa. nao é dificil. é só nao ignorar.

o deploy: uma linha

o ritual de deploy é esse aqui, inteiro:

npx wrangler pages deploy . \
  --project-name=gogrowth \
  --branch=main \
  --commit-dirty=true

✨ Deployed to https://gogrowth.pages.dev
✨ Custom domain gogrowth.me attached

30 segundos do comando até o curl gogrowth.me responder com o HTML novo. sem CI, sem github actions, sem workflow yaml. é overkill pra site estatico. wrangler + git como backup local ja resolve, complexidade só entra quando tem mais de uma pessoa no repo.

iterações: contraste, guiafreela, "hire me"

depois do primeiro deploy, duas dobras importantes. a primeira foi o ajuste de contraste q mencionei lá em cima, textos dim sumindo em monitor sem calibracao. a correcao foi cirurgica: duas variaveis CSS, duas bordas dashed subiram de opacidade, uma iteracao de deploy.

a segunda foi o callout de hire me. no lançamento eu tinha só o form generico. mas se o site é sobre consultoria, "vamos conversar" é sinal fraco. precisava da oferta: $250 USD/hora, oq é, quem é o publico. callout com borda vermelha à esquerda, gradiente suave, preço grande em vermelho, CTA outline q inverte no hover. linguagem direta:

unblock your product with AI, from china. sessões 1:1, reviews de arquitetura, estrategia de produto e growth. 15 anos de marketing, 2 anos dentro do ecossistema de IA da china.

mesma operacao pra adicionar guiafreela.com na lista de labs, um dos outros projetos q eu toco. terceira iteracao, terceiro deploy, mesmo dia.

lições em voz alta

· · ·

o site ta no ar. o jogo roda. o email chega. os headers estao apertados. a proxima pessoa q entrar em gogrowth.me às 3 da manhã vai encontrar um terminal, um corredor pulando na muralha, e uma oferta clara. foi feito em 30 min por uma pessoa num apartamento em kunshan. com IA, a ferramenta mudou, o oficio continua o mesmo.

se vc quiser conversar sobre aplicar esse mesmo tipo de velocidade e IA pro seu produto ou stack, a porta é direta: phelipe@gogrowth.me.

filed: 2026-04-24 · kunshan · 31°n 120°e
stack: html · css · js vanilla · canvas · cloudflare pages · turnstile · resend
team: codex · claude code · claude design · phelipe xavier
← back to research   ·   ← home