Pular para o conteúdo
Uma flor azul dissolvida em dither ordenado: a fotografia sobrevive apenas como malha de pontos, densa nas pétalas e aberta no fundo

Um portfólio sem páginas: como o site da FREITAG é feito

A Leal construiu o portfólio da FREITAG como um documento só: uma cena WebGL, quatro sobreposições e nenhum carregamento de página. Projetos são lugares dentro de um domo que se atravessa. Cada estado empurra a própria URL, então dá para mandar um projeto a um cliente e o voltar funciona.

Publicado · 4 min de leitura

Em resumo

  • A cena monta uma vez e nunca é descarregada. As quatro seções são sobreposições por cima dela, e é por isso que o movimento entre elas parece contínuo.
  • Não ter carregamento de página não obriga a não ter endereço. pushState e popstate dão URL real a cada estado, então link, refresh e botão voltar continuam funcionando.
  • Cada efeito de superfície usa uma ferramenta diferente por um motivo: um canvas de 132 por 165 pixels para o dither ordenado, um shader GLSL na GPU para o halftone sobre imagem em movimento.
  • O site não tem etapa de build. Os módulos carregam por importmap, então o que você escreve é o que roda.
  • A abertura parecia lenta por causa de um atraso que nós escrevemos, e não por peso. Medir encontrou três segundos que não carregavam nada.

A FREITAG é um braço de produção audiovisual AI-driven, e o portfólio deles não tem home. Tem um domo.

O estúdio inteiro é um espaço navegável. Projetos são lugares dentro dele, e você atravessa de um para o outro. Não existe transição entre páginas porque o site não tem páginas: são quatro sobreposições sobre uma cena que nunca é descarregada.

É assim que ele é montado.

Um documento, quatro sobreposições

A cena é um canvas WebGL feito com three.js. Ela monta uma vez e fica montada. Studio, Index e Contact são camadas desenhadas por cima, e um projeto abre como mais uma, então o domo continua lá embaixo, guardando posição e inércia.

É isso que faz o movimento parecer contínuo. Nada é destruído e reconstruído, então nada precisa ser reencontrado. O custo de uma troca de página normal, que é jogar tudo fora e começar de novo, simplesmente não acontece.

E ela sustenta 60 fps enquanto você atravessa, sem perder quadro, numa passagem contínua que abre um projeto atrás do outro. É o número que decide uma cena dessas: portfólio que se atravessa só é agradável enquanto continua fluido.

URL sem página

Site sem carregamento de página costuma perder justamente aquilo para que serve um link. Este não perde.

Cada estado empurra o próprio endereço com a History API, e o lê de volta no popstate:

const target = "/" + routeForState() + location.search; if (location.pathname !== target) history.pushState({}, "", target);

Então um projeto tem uma URL que dá para mandar a um cliente específico, atualizar a página devolve você ao mesmo lugar, e o botão voltar do navegador funciona como as pessoas esperam. A experiência é contínua e os endereços continuam reais.

A superfície é calculada, e não filtrada

A linguagem visual se apoia em efeitos calculados em tempo de execução, e cada um usa a ferramenta certa por um motivo diferente.

A tela de entrada é um dither ordenado de Bayer desenhado num canvas 2D. O buffer é minúsculo de propósito, 132 por 165 pixels, e depois é ampliado: a grossura do ponto é o efeito, e calcular pequeno é o que deixa isso barato.

A página About usa um halftone escrito como shader GLSL, rodando na GPU, porque ele precisa aguentar imagem em movimento e não um still.

A tipografia embaralha antes de assentar, e a quebra de linha passa pelo SplitType para cada linha poder ser animada sozinha. O GSAP conduz as timelines que amarram tudo isso.

Sem etapa de build

Não há bundler nem package.json. O navegador carrega módulos ES por um importmap, direto de um CDN: three.js, GSAP, SplitType.

Para um site desse tamanho isso é simplificação de verdade, e não pirotecnia. São 2.420 linhas de JavaScript e 1.149 de CSS em 122 arquivos. O que você escreve é o que roda, e não existe etapa de compilação entre mudar e ver.

O gate é escolha

O site abre numa soleira: um retrato em dither, os logos dos clientes e um botão escrito Enter. Você chega em algum lugar antes de chegar ao trabalho.

Isso é deliberado. Um portfólio que todo mundo alcança por um link que a agência manda pode se dar ao luxo de ter porta de entrada, e a porta faz uma coisa que grid nenhum faz: ela ajusta o registro antes do primeiro projeto aparecer.

O que ela não custa é a parte de baixo. A cena é legível para máquina mesmo sendo pixel, porque o canvas declara o que carrega e a linha da marca existe na marcação além de existir em 3D. Acessibilidade, boas práticas e SEO voltam todas em 100.

Quem publica é o time

Cases, imagens, o filme de abertura e os logos de cliente saem do Sanity. Acrescentar projeto é preencher um formulário, e não fazer deploy.

É essa parte que decide se um site assim sobrevive ao primeiro ano. Portfólio que ninguém consegue atualizar vira a captura de tela do dia em que foi lançado.

O que medimos

Fluidez ao atravessar a cena 3D, sem queda de quadro
60 fps
Sustentado numa passagem contínua pelo domo, abrindo projetos no caminho, em navegador de desktop.
Notas do Lighthouse em acessibilidade, boas práticas e SEO
100 out of 100, on all three
Lighthouse no site publicado. Três auditorias distintas, todas com nota cheia, num portfólio cuja superfície principal é uma cena WebGL.
Tamanho do site, sem etapa de build
2420 lines of JavaScript, plus 1,149 of CSS across 122 files
Contado no repositório, sem as dependências, que carregam de um CDN e nunca são copiadas para dentro.

Perguntas

Por que não usar um framework?
O site é uma cena e quatro sobreposições, sem estado compartilhado relevante e sem transição de página para orquestrar. Um framework acrescentaria etapa de build e árvore de dependências para resolver problemas que este site não tem.
Um site de documento único ainda funciona com link e botão voltar?
Sim, quando ele empurra o próprio estado. Este escreve o endereço a cada mudança e o lê de volta no popstate, então a URL de um projeto pode ser compartilhada, o refresh volta ao mesmo lugar e o voltar faz o que parece que faz.
Por que calcular o dither num canvas minúsculo em vez de usar uma imagem?
Porque a grossura do ponto é o efeito. Trabalhar em 132 por 165 e ampliar dá pontos grandes e regulares, custa quase nada para calcular, e continua nítido em qualquer tamanho de tela, em vez de ser um arquivo fixo que precisa ser exportado de novo a cada recorte.

Os projetos por trás disso

  • FREITAG® · Uma agência construída do jeito que ela cria.

Ler em texto puro