Como construí tiagoholanda.tech com Astro e Three.js
Bastidores de tiagoholanda.tech: por que Astro estático, como as ilhas carregam, paleta preto e gelo e o Three.js só depois do HTML crítico.
Eu construí tiagoholanda.tech em Astro estático porque o HTML precisa sair pronto para o Google e para os LLMs, e a Hostinger serve arquivos. O Three.js entra como island, depois do título e dos botões. A paleta é só preto e gelo. Projetos e artigos vivem em collections. Não há formulário nem banco: o contato é WhatsApp e e-mail.
A restrição que escolheu a stack
O domínio aponta para um Cloud Enterprise da Hostinger no Brasil. Dá para rodar Node. Eu não quis um processo vivo para um site que vende conversa, não login.
Astro com output: 'static' gera HTML, CSS e o JavaScript das ilhas. O deploy é rsync do dist/ para public_html. Sem PM2, sem cold start, cache de CDN trivial.
Next.js faria o mesmo trabalho com mais superfície. Aqui a regra é outra: crawler, LLM e visitante leem o mesmo HTML. O React fica reservado para filtros de projeto e para a cena 3D.
Os serviços descrevem resultado para o cliente. A stack é detalhe. O site precisa se comportar do mesmo jeito: conteúdo primeiro, movimento depois.
HTML primeiro, movimento depois
A home é one-page. Hero, serviços, stack, projetos, processo, news e contato. Cada seção tem âncora, rótulo em JetBrains Mono e um h2 em Chakra Petch.
O JavaScript da página faz três coisas baratas:
- O H1 do hero “decodifica” uma vez por sessão.
- As seções revelam com GSAP e ScrollTrigger quando entram 15% na viewport.
- O menu marca a âncora ativa.
Tudo isso respeita prefers-reduced-motion. Com a opção ligada, o conteúdo já aparece e o decode não roda.
Os filtros de projeto são uma island React com client:visible. O HTML da grade existe antes da hidratação. Abrir um card usa um dialog nativo, foco preso e Esc para fechar.
Preto, gelo, sem cor de marca
A identidade cabe em duas hex: #000000 e #EEEEEE. Cinzas intermediários são opacidade do gelo, nunca uma terceira cor. Logos de stack entram em currentColor.
Três fontes, self-hosted via Fontsource:
- Chakra Petch nos títulos, caixa alta.
- IBM Plex Sans no texto.
- JetBrains Mono em rótulos, tags e metadados.
Raio 0, linhas de 1px. O movimento dura no máximo 600ms, com easing expo-out.
Essa disciplina vale para o blog. Nos artigos, H2 e H3 perdem a caixa alta para caber em texto longo. A medida fica em 65ch, line-height 1.7. Blocos de código usam as variáveis do Shiki mapeadas para gelo sobre preto. Sem tema colorido.
Projetos como dado, não como página solta
Os quatro repositórios públicos (Affiliate Tool, Agente Redator RAG, Neon Breakout e Neon Pong) vivem em src/content/projects. Zod valida capa, alt, problema, solução e links.
A home monta uma grade única, com filtro por natureza: Jogo, Aplicação, IA, Automação, Web. Jogos e software no mesmo ofício. O JSON-LD da home inclui um ItemList com SoftwareApplication ou VideoGame.
As capas dos jogos são as artes publicadas. Affiliate Tool e Agente Redator RAG usam ilustrações de capa, até existirem capturas reais das telas.
Three.js como island, não como fundo
A frase-núcleo pede um objeto no hero: partículas que convergem num icosaedro wireframe. Isso é o Idea Core.
Regras que o canvas obedece:
- HTML do hero independe do WebGL.
- Carregamento com
client:idle. - Sem WebGL2, GPU fraca ou
prefers-reduced-motion, o visitante vê o SVG estático. - Budget de 180 KB gzip para three + r3f, tree-shaken.
A ordem continua a mesma: ideia no HTML, forma 3D depois, se o aparelho aguentar.
SEO e GEO no mesmo HTML
Cada página tem um h1, canonical absoluto, title curto e description entre 120 e 160 caracteres. O grafo JSON-LD global descreve Pessoa, WebSite e ProfessionalService. A home acrescenta a lista de projetos. Cada artigo acrescenta BlogPosting, BreadcrumbList e FAQPage quando o frontmatter tem perguntas.
O feed RSS sai em /rss.xml. /llms.txt descreve serviços, projetos e artigos para LLMs. /llms-full.txt concatena o Markdown dos textos. robots.txt libera GPTBot, ClaudeBot, PerplexityBot e os demais crawlers de IA.
Este artigo abre com um parágrafo que responde o título. Os subtítulos são seções de fato. No fim, o CTA aponta para o WhatsApp, o mesmo da home.
Quem quiser ver o ofício em código abre os projetos. Quem quiser encomendar algo, fala comigo.
O que ainda falta no lançamento
O blog, o Idea Core, os testes e o pipeline de rsync já estão no repositório. Faltam os artigos dos outros clusters (jogos como software, RAG, n8n), capturas reais dos projetos e o primeiro deploy na Hostinger, com Search Console e Bing.
Nada disso muda a tese. Jogos e software são o mesmo trabalho. O site precisa se comportar como o software que eu entrego: responder, caber no aparelho e continuar claro depois do lançamento.
Perguntas frequentes
Por que Astro e não Next.js neste site?
Porque a home e os artigos são HTML estático. Crawler recebe o conteúdo pronto, a Hostinger serve arquivos em public_html, e o JavaScript pesado entra só onde há estado no cliente.
O Three.js não pesa no carregamento inicial?
O título e os CTAs do hero já saem no HTML. O canvas entra como island depois da primeira pintura. Sem JavaScript ou com movimento reduzido, fica o SVG do icosaedro.
Tem formulário de contato ou newsletter?
Não na fase 1. O contato é WhatsApp e e-mail. Sem banco, sem spam e com superfície de ataque menor.