A página inicial de daniellocatelli.com exibida em um laptop.

Site Portfólio

Data2024-04-27
OrganizaçãoDaniel Locatelli

LocalOnline
Linkdaniellocatelli.com

Este é o site que você está lendo agora. Ele começou em abril de 2024 como um pequeno site em Astro e, desde então, virou um campo de testes para o jeito como gosto de construir as coisas: páginas estáticas rápidas, conteúdo fácil de ler tanto para pessoas quanto para ferramentas de IA, e algumas peças interativas para apimentar as coisas.

Stack Tecnológico

  • Astro com TypeScript para o site em si, React para as poucas ilhas que precisam de interatividade e Tailwind CSS para os estilos.
  • Astro Content Collections para todo o conteúdo, escrito em markdown e MDX com frontmatter tipado e validado no momento do build.
  • Claude (Anthropic) para o chat da página inicial, com o Supabase como banco vetorial para a recuperação de contexto.
  • Three.js para a esfera geodésica.
  • Cloudflare Workers com Static Assets para hospedagem, cache na borda e os endpoints voltados a agentes; as páginas pré-renderizadas são servidas direto da borda, e o Worker só roda para os endpoints de chat e MCP.

Claude Code como sistema de gestão de conteúdo

Todo o conteúdo vive como arquivos de texto simples (escritos em markdown) no mesmo lugar que o código, o repositório público no GitHub: um arquivo pequeno por projeto, entrada de pesquisa, publicação, item de ensino ou seção do currículo, com um cabeçalho curto que guarda os fatos (título, datas, tags) acima do texto da página, e uma cópia em cada um dos três idiomas. Não há banco de dados nem sistema de conteúdo separado por trás das páginas.

A pasta src/ do repositório: assets/ expandida até a imagem de capa desta página, content/ até o seu arquivo markdown, as demais pastas recolhidas.
A pasta src/ do repositório: assets/ expandida até a imagem de capa desta página, content/ até o seu arquivo markdown, as demais pastas recolhidas.

O objetivo dessa configuração é tornar o conteúdo diretamente acessível a harnesses de IA como o Claude Code. Como o conteúdo é apenas um conjunto de arquivos ao lado do código, o Claude Code consegue ler, editar, criar e cruzar entradas do mesmo jeito que trabalha com código-fonte. Na prática, isso significa que uso o Claude Code como sistema de gestão de conteúdo (CMS), a ferramenta em que normalmente se faria login para adicionar uma página ou corrigir um erro de digitação: descrevo um novo projeto ou uma correção em uma frase, e ele escreve ou atualiza os arquivos, mantém os cabeçalhos consistentes e confere as entradas relacionadas nos outros idiomas. Esta própria página foi escrita assim. Tudo neste site é cocriado, do código ao conteúdo.

Manter o conteúdo no repositório em texto puro tem um segundo ganho: é simples dividi-lo em trechos, gerar embeddings e alimentar um modelo de linguagem. É isso que torna possível o chat com IA na página inicial (mais sobre ele abaixo).

Tradução feita pelo Claude Code

O site está disponível em inglês, português e alemão. Não há nenhum serviço de tradução no pipeline: quando um arquivo de conteúdo muda em um idioma, o Claude Code o traduz e atualiza os arquivos correspondentes nos outros dois. Campos estruturais como datas, links e lugares são mantidos em sincronia, enquanto campos traduzíveis como nomes de países e cidades são localizados. O mesmo vale para os textos da interface, que vivem como objetos tipados por idioma.

Como uma mudança em um idioma chega aos outros dois: o Claude Code lê a regra do repositório e escreve os arquivos correspondentes, mantendo datas e links idênticos e traduzindo nomes e texto.
Como uma mudança em um idioma chega aos outros dois: o Claude Code lê a regra do repositório e escreve os arquivos correspondentes, mantendo datas e links idênticos e traduzindo nomes e texto.

Chat com IA na página inicial

A página inicial abre com um chat baseado no Claude. Os visitantes podem perguntar no que estou trabalhando, onde estudei, quais ferramentas uso ou qualquer outra coisa coberta pelo site, e recebem uma resposta baseada no conteúdo real, e não uma resposta genérica.

O campo de chat na página inicial: um campo de texto arredondado com "Ask me something..." e uma seta de envio, e a legenda "Powered by Claude Haiku 4.5" logo abaixo.
O campo de chat na página inicial: um campo de texto arredondado com "Ask me something..." e uma seta de envio, e a legenda "Powered by Claude Haiku 4.5" logo abaixo.

Por baixo dos panos, um pipeline de conhecimento transforma as coleções de conteúdo em pequenos trechos de texto por idioma (páginas individuais, entradas do currículo, uma linha do tempo cronológica e um conjunto de respostas de FAQ pré-escritas para as perguntas mais comuns dos visitantes), gera embeddings com a Voyage AI e armazena os vetores no Supabase. Quando chega uma pergunta, o endpoint da API recupera os trechos mais parecidos e os passa ao Claude como contexto. Sempre que o conteúdo muda, um único comando regenera os arquivos de conhecimento e envia embeddings novos, e um script de benchmark roda um conjunto fixo de perguntas comuns contra o chat para garantir que ele continua respondendo todas corretamente.

Diagrama de arquitetura: no build, o conteúdo markdown do site é dividido em trechos de conhecimento, transformado em embeddings pela Voyage AI e armazenado no Supabase; em tempo de execução, a pergunta do visitante é embutida, os trechos mais próximos são recuperados e passados ao Claude, que transmite uma resposta fundamentada de volta à página.
Diagrama de arquitetura: no build, o conteúdo markdown do site é dividido em trechos de conhecimento, transformado em embeddings pela Voyage AI e armazenado no Supabase; em tempo de execução, a pergunta do visitante é embutida, os trechos mais próximos são recuperados e passados ao Claude, que transmite uma resposta fundamentada de volta à página.

A esfera geodésica

Mais abaixo na página inicial, entre as ofertas de serviços e a seção “Arquiteto + Programador”, fica uma esfera geodésica renderizada com Three.js. Ela segue a construção que Buckminster Fuller tornou famosa: partir de um icosaedro, subdividir cada face, projetar os vértices sobre uma esfera e tomar o dual, de modo que os doze vértices originais viram pentágonos e todo o resto vira hexágonos. A esfera gira conforme você rola a página, ligando o movimento da página à geometria. As arestas verdes dos polígonos são desenhadas como faixas finas no espaço da tela, e não como linhas GL brutas de um pixel, para que permaneçam suaves e com espessura uniforme em qualquer tela, e as faces são levemente recuadas em profundidade para que as arestas nunca tremulem contra a superfície. Uma leve névoa em direção ao fundo preto da página esmaece as faces do lado de trás da esfera, dando profundidade à cena.

É também uma referência à minha própria trajetória: estruturas geodésicas e leves são um tema recorrente nos projetos e pesquisas deste site, do Pavilhão O3, onde tudo começou de verdade, passando pelo Common Sky e pela minha dissertação de mestrado Building Across Scales, até o meu doutorado sobre estruturas de madeira. O Three.js é carregado logo depois que a primeira tela é desenhada, em um momento ocioso, para nunca ficar no caminho crítico do carregamento inicial da página, mas já estar pronto quando você rolar até a esfera.

Modo apresentação

Itens de conteúdo podem carregar uma apresentação de slides que vive junto do texto, na mesma pasta e no mesmo repositório. As apresentações são escritas em MDX com um pequeno atalho em YAML para os tipos de slide mais comuns (título, texto, imagem, fileira de imagens, vídeo, sobreposições) e são renderizadas no navegador com navegação por teclado, uma visão geral de todos os slides e uma janela do apresentador. Uso isso para aulas e palestras, de modo que uma aula e seus slides sejam publicados juntos, versionados juntos e traduzidos juntos.

A visão geral de slides da apresentação "Computational Architecture in Germany": uma grade de miniaturas, a primeira destacada em verde, com controles de sair, ajuda e tela cheia no canto superior direito e um contador 1 / 112 no canto inferior.
A visão geral de slides da apresentação "Computational Architecture in Germany": uma grade de miniaturas, a primeira destacada em verde, com controles de sair, ajuda e tela cheia no canto superior direito e um contador 1 / 112 no canto inferior.

Pronto para agentes na Cloudflare

Como boa parte do tráfego de um site como este virá cada vez mais de agentes de IA em vez de navegadores, o site expõe seu conteúdo nos formatos que os agentes esperam:

  • um índice llms.txt por idioma, gerado a partir das coleções de conteúdo no momento do build;
  • uma versão em markdown de cada página de conteúdo (basta acrescentar .md à URL), além de negociação de conteúdo para que uma requisição com Accept: text/markdown receba markdown diretamente;
  • um robots.txt que dá boas-vindas explícitas aos crawlers de IA, um sitemap com entradas de imagens e um catálogo de API em /.well-known/;
  • um pequeno servidor MCP somente leitura, para que agentes possam consultar o conteúdo do site como ferramentas;
  • registros de descoberta DNS-AID (registros SVCB _mcp._agents e _index._agents, assinados com DNSSEC), para que agentes encontrem o endpoint MCP apenas a partir do nome de domínio;
  • um índice de skills em /.well-known/agent-skills/, seguindo o RFC de descoberta de Agent Skills da Cloudflare, com dois arquivos SKILL.md no formato Agent Skills que ensinam um agente a consultar o site via MCP ou a lê-lo como markdown.

Fazer a negociação de conteúdo funcionar em páginas pré-renderizadas exigiu investigar como o pipeline de requisições da Cloudflare, o Workers Static Assets e o middleware de build do Astro interagem; a solução é um Snippet da Cloudflare no nível da zona que reescreve a URL antes de ela chegar ao Worker. No isitagentready.com, o verificador que acompanha o guia de prontidão para agentes da Cloudflare, o site saiu de uma pontuação de 25% para 71/100, “Nível 5, Agent-Native”, com nota máxima em descoberta, conteúdo e controle de acesso de bots. Os pontos restantes estão na categoria de API e autenticação e ficam deliberadamente em aberto: descoberta OAuth, metadados de recurso protegido e um auth.md só fazem sentido quando há algo em que fazer login, um agent card A2A descreve um agente que oferece serviços a outros agentes, e o WebMCP expõe ações dentro da página, como formulários ou checkouts. Um portfólio somente leitura não tem nada disso, então o verificador continua listando esses itens e o site continua dispensando-os.

Resultado do Is It Agent Ready?: 71/100, Nível 5, Agent-Native
Resultado do Is It Agent Ready?: 71/100, Nível 5, Agent-Native

Desempenho e Lighthouse

O Astro renderiza o site em HTML majoritariamente estático, o que já lhe dá uma vantagem inicial. As pontuações de 100 no Lighthouse em desempenho, acessibilidade, boas práticas e SEO vêm então de não carregar o que o visitante ainda não precisa:

  • As imagens chegam em tamanhos responsivos com dimensões explícitas, carregadas sob demanda pouco antes de entrarem na área visível; as fontes são reduzidas ao subconjunto necessário e pré-carregadas.
  • O Three.js carrega num momento ocioso e só redesenha a esfera enquanto ela está em movimento.
  • A janela do chat só é baixada quando o visitante começa a digitar, de modo que o campo de entrada da abertura carrega apenas alguns kilobytes de JavaScript.
  • Os logotipos do mapa de competências são imagens separadas carregadas sob demanda, em vez de SVG embutido, o que reduziu o HTML da página inicial de cerca de 350 KB para menos de 70 KB.
Resultado do Lighthouse: 100 em desempenho, acessibilidade, boas práticas e SEO
Resultado do Lighthouse: 100 em desempenho, acessibilidade, boas práticas e SEO

Uma caixa de ferramentas pessoal por trás das páginas públicas

O site também hospeda páginas que não são linkadas de lugar nenhum e existem sobretudo para meu próprio uso. O currículo resumido, o currículo completo e o currículo voltado ao doutorado ficam em URLs não listadas, são renderizados a partir das mesmas coleções de conteúdo que o resto do site (de modo que uma experiência ou publicação só precisa ser cadastrada uma vez) e trazem estilos de impressão, para que salvar a página como PDF gere um documento limpo e atualizado sempre que for preciso. Algumas páginas igualmente não listadas servem de cartões de abertura para aulas gravadas. Assim, o site funciona também como um pequeno espaço de trabalho, e não apenas como vitrine para visitantes.

A caixa de diálogo de impressão do navegador sobre a página do currículo: a pré-visualização mostra o currículo como um documento branco e limpo, com foto, nome, "PhD Candidate at ETH Zurich", resumo, habilidades e experiência profissional, pronto para ser salvo como PDF.
A caixa de diálogo de impressão do navegador sobre a página do currículo: a pré-visualização mostra o currículo como um documento branco e limpo, com foto, nome, "PhD Candidate at ETH Zurich", resumo, habilidades e experiência profissional, pronto para ser salvo como PDF.

Detalhes menores

  • Prévias de links no build. Links externos listados em uma página são exibidos como cartões de prévia. Títulos, descrições, imagens e favicons são buscados uma única vez e guardados em cache no repositório, de modo que o build é reprodutível e nenhuma requisição a terceiros acontece ao carregar a página.
  • Tooltips em toda parte. Um único sistema de tooltip (um painel popover com seta, posicionado e invertido por poucas linhas de JavaScript) atende todos os tooltips do site: notas de rodapé em markdown mostram a nota no próprio lugar ao passar o mouse, para que o leitor não precise pular até o fim da página; cada ferramenta do Mapa de Conhecimento na página inicial explica onde e como eu a uso; os ícones sociais do rodapé, da seção de contato e do cabeçalho do CV indicam seu destino; e os controles das apresentações de slides mostram seu atalho de teclado. Não resta nenhum tooltip nativo do navegador.