Todo dev tem aquele portfólio que vive "quase pronto". O meu viveu assim por um bom tempo, até que decidi parar de procurar o template perfeito e construir algo que tivesse a minha cara: um lugar pra guardar as coisas que eu construo, as coisas que eu gosto e os momentos que valem lembrar.
Esse post conta como ele saiu do papel: de onde vieram as ideias, como eu organizei o código e o que tem por baixo do capô.
Inspirações e referências
Antes de escrever qualquer linha, passei um bom tempo olhando portfólios de outros devs. Dois deles me inspiraram muito e merecem uma menção honrosa: o do Rafael Camargo e o do Shreyas Sihasane. Vale a visita.
A ideia nunca foi fazer um currículo em HTML. Eu queria que o site parecesse um caderno pessoal, com anotações à mão na margem, palavras grifadas como se fosse com marca-texto e fotos penduradas na parede. Por isso algumas escolhas se repetem pelo site todo:
- Coisas escritas à mão. As notas na margem usam uma fonte manuscrita, aparecem letra por letra e vêm até com um som de escrita (dá pra desligar no rodapé).
- Anotações desenhadas. Os grifos e sublinhados são feitos com o rough-notation, que desenha traços imperfeitos de propósito.
- Um desktop de verdade. Os projetos ficam em cima de uma área de trabalho estilo macOS, com wallpaper e tudo.
- Uma colagem de fotos. Os momentos que eu guardo viram um mural no /me, com fotos de formatos diferentes se encaixando.
Pra parte de animação, o Magic UI foi a maior referência. Vários componentes daqui nasceram de lá, como o texto digitando na home, os números que sobem nas reações, o confete e o grão de ruído no fundo. Eu não instalei a biblioteca: reescrevi cada um no projeto, cortando o que não usava e adaptando ao visual daqui.
A stack
- TanStack Start com React 19: SSR, rotas tipadas e server functions sem precisar de uma API separada.
- Vite 8 no build e no dev server.
- Tailwind CSS v4, com as cores e fontes definidas como tokens no próprio CSS.
- MDX pros posts do blog: cada post é um arquivo
.mdxcom os metadados exportados no topo. - Motion pras animações com mola e Lenis pro scroll suave.
- Supabase (Postgres) pros contadores de visualização, likes e reações.
- PostHog pra analytics, sem cookies.
- Zod validando tudo que chega do banco e das server functions.
Como eu estruturei
O código segue atomic design, com quatro níveis de componentes: átomos são as peças pequenas, moléculas combinam algumas delas, organismos são seções inteiras e templates são o esqueleto das páginas.
src/components/
atoms/ Pill, Stars, NumberTicker…
molecules/ PostCard, NavLink, LangToggle…
organisms/ Header, JobTimeline, Playlist…
templates/ SiteLayout, PageTemplate…
Cada pasta tem um index.ts que reexporta tudo, então um import fica sempre assim:
import { PostCard, SectionHeading } from '~/components/molecules'
Conteúdo separado do código
Os textos e os dados não ficam espalhados pelos componentes:
src/content/guarda o conteúdo: posts em MDX, projetos, a stack, a playlist, as recomendações.src/lib/i18n.tsconcentra todas as strings da interface em português e inglês. O site abre em pt-BR, e o idioma é resolvido já no servidor, então não existe aquele "pisca" de inglês pra português depois que a página carrega.
Assim, trocar um texto ou adicionar um projeto nunca exige mexer em componente.
Pequenos cuidados
- Tudo que é animação respeita o
prefers-reduced-motion. - O PostHog só carrega depois da hidratação e não usa cookies, por isso não tem banner de consentimento.
- As fotos da galeria passam por um script antes do build que lê as dimensões de cada imagem, então o layout não pula quando elas carregam.
E agora?
O site nunca vai estar "pronto", e essa é a graça. A ideia é que esse blog seja o lugar pra contar o que eu ando aprendendo. Se tiver algo que você quer ver por aqui, me chama.