(85) 99645-7140 nelclassico@gmail.com Praça Coronel Melquiades, 124
Articles case study Tecnologia Webflow WebGL

Comércio Magnético: Construindo o Site Criativo Dash | Codrops

Uma reformulação da marca já estava prevista há algum tempo. Queríamos algo que nos ajudasse a nos destacar. Não apenas parecer diferente, mas possuir o que realmente fazemos.

Esse processo levou a um conceito simples: comércio magnético. Grandes experiências digitais fazem mais do que informar. Eles atraem as pessoas. Essa ideia moldou nosso novo logotipo, com parte do D puxada para dentro como se fosse por força magnética. O emblema tornou-se o ponto de partida para quase todas as decisões de design que se seguiram.

Depois que o ativo foi renderizado como um objeto 3D giratório, a interação do cursor ocorreu naturalmente. O logotipo deve se comportar de acordo com seu conceito. Arraste o cursor sobre ele e ele puxa. Esse detalhe deu o tom de como pensaríamos sobre o movimento no restante do site.

A outra decisão inicial foi deixar o design do iOS informar como lidamos com cartões e CTAs. Projetamos cartões de projeto como um aceno deliberado às notificações do iOS: familiares, táteis, um pouco inesperados no contexto. As diretrizes da marca eram rígidas. Essa restrição acabou sendo útil. Isso impediu que as decisões mudassem e nos empurrou para algo mais ponderado.

No total o projeto durou alguns meses. O conceito pousou relativamente rápido. Acertar o conteúdo e as animações devidamente refinadas no desenvolvimento: foi aí que o tempo passou.

Pilha e ferramentas

Figma  para design. As diretrizes da marca foram bem definidas e a Figma manteve tudo sistemático (tipo, espaçamento, componentes) sem atrapalhar a iteração.

Fluxo da Web  para a compilação. Nosso próprio site é construído em Webflow e fazia sentido usá-lo como uma prova do que é possível na plataforma para clientes em potencial. A maioria das interações reside dentro do sistema de animação do Webflow.

GSAP  para as partes que as interações nativas do Webflow não conseguiram alcançar, especialmente os comportamentos e sequências mais precisos orientados pelo cursor.

WebGL personalizado  para o plano de fundo do herói. Aquele não poderia viver em nenhum outro lugar.

O plano de fundo do herói: distorcendo uma superfície viva

O plano de fundo do herói começou com uma ideia simples: usar um vídeo em tela cheia como textura e distorcer em resposta ao movimento do cursor. O objetivo era fazer com que o fundo parecesse responsivo sem distrair.

Uma coisa foi importante desde o início. Não queríamos que o efeito se comportasse como uma simples ondulação centrada no cursor. Em vez disso, a distorção deve continuar na direção do movimento, dando a impressão de que a superfície está sendo puxada, em vez de simplesmente reagir a um estado de flutuação.

A abordagem

O efeito é implementado inteiramente em um fragment shader. Em vez de sobrepor efeitos sobre o vídeo, o shader remapeia diretamente as coordenadas de textura do vídeo. O cursor define a área de influência, enquanto a direção do movimento controla como a distorção se propaga. Uma função senoidal amortecida gera a onda que impulsiona o deslocamento.

Os valores configuráveis são definidos uma vez e passados para o renderizador:

const SETTINGS = {
  radius: 0.41,
  amplitude: 0.082,
  frequency: 13,
  speed: 0.98,
  carry: 6,
  stagger: 12,
  centerPower: 2,
  verticalDampPower: 2.2,
  motionGain: 220,
  speedDecay: 0.86,
};

A geometria consiste em um único quadrante de tela cheia:

const vertices = new Float32Array([
  -1, -1, 0, 0,
   1, -1, 1, 0,
  -1,  1, 0, 1,
  -1,  1, 0, 1,
   1, -1, 1, 0,
   1,  1, 1, 1,
]);

A distorção em si acontece no fragment shader:

float maskFn(vec2 uv) {
  vec2 d = uv - uMouseSm;
  d.x *= uAspect;
  float dist = length(d);
  return pow(smoothstep(uRadius, uRadius - uSoft, dist), uCenterPow);
}

float wave = sin(
  d.y * uFreq +
  dot(d, dir) * uCarry +
  uTime * uSpeed +
  d.y * uStagger
);

d += dir * (wave * amp * maskFn(uv) * damp);

O resultado é um efeito que responde ao movimento do cursor sem se comportar como uma simples interação flutuante. A distorção carrega impulso na direção do deslocamento antes de se estabilizar gradualmente.

Direção e persistência do movimento

Antes que os valores sejam passados para o shader, o estado de interação é suavizado e decaído no lado do JavaScript:

motionTarget *= SETTINGS.speedDecay;
const mappedMotion = Math.min(motionTarget * SETTINGS.motionGain, 1);

motion += (mappedMotion - motion) * SETTINGS.momentum;
dirSm.x += (dirTarget.x - dirSm.x) * SETTINGS.dirSmooth;
dirSm.y += (dirTarget.y - dirSm.y) * SETTINGS.dirSmooth;

Essa persistência evita que o efeito pare assim que o cursor para. Em vez disso, a distorção perde gradualmente o impulso antes de retornar ao seu estado de repouso, fazendo com que a interação pareça mais contínua e menos mecânica.

Restrição Visual

O objetivo era adicionar movimento ao herói sem competir com o conteúdo. O efeito fica por trás da tipografia, adicionando profundidade e mantendo o texto fácil de ler.

O campo de influência usa um enfraquecimento suave em vez de uma borda rígida, evitando a aparência de um holofote ao redor do cursor. O amortecimento vertical também limita a extensão da propagação da onda, dando à distorção uma forma mais direcional em vez de se expandir uniformemente em todas as direções.

O resto do herói é deliberadamente simples: um fundo preto, um vídeo sem margens e o shader aplicado diretamente na textura. Manter todo o resto mínimo ajuda a manter o foco na interação em si.

Arquitetura

A estrutura é bastante simples.

<section id="us-sine-bg" class="hero-sine-bg">
  <video id="bgvid" class="hero-sine-bg__video" muted playsinline autoplay loop></video>
</section>

A configuração consiste em um contêiner hero, um elemento de vídeo oculto usado como fonte de textura e uma tela WebGL em camadas acima dele.

A partir daí, o renderizador executa cinco tarefas principais:

  1. Prepare a fonte de vídeo e aguarde a reprodução.
  2. Inicialize o renderizador WebGL e compile os shaders.
  3. Rastreie o movimento do ponteiro e suavize o estado da interação.
  4. Carregue o quadro de vídeo atual para a GPU de cada quadro.
  5. Renderize uma única passagem em tela cheia.

O renderizador não depende de um gráfico de cena, pipeline de pós-processamento ou geometria adicional. Ele funciona com uma única textura, um quad de tela cheia e um par de shaders, facilitando a integração em um site de produção.

Os uploads de quadros só são realizados quando o vídeo estiver pronto:

if (video.readyState >= 2) {
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);
}

rafId = requestAnimationFrame(renderFrame);

A implementação mantém o loop de renderização leve. Os valores de interação são suavizados ao longo do tempo, o sombreador apenas remapeia as coordenadas UV, a tela é limitada à seção principal e a renderização não começa até que o vídeo esteja pronto.

A mesma abordagem pode ser reutilizada com diferentes fontes de vídeo, perfis de distorção ou seções de um site sem alterar a estrutura geral.

Reflexões

O resultado final parece muito mais próximo do que queríamos que o site comunicasse. A implementação técnica ocorreu de forma relativamente rápida. A maior parte do tempo foi gasta refinando o movimento, editando o conteúdo e garantindo que ambos funcionassem juntos.

Um dos maiores desafios foi saber quando parar de adicionar. Pequenos ajustes no tempo, na flexibilização e na cópia muitas vezes tiveram mais impacto do que a introdução de novos efeitos.

Olhando para trás, a principal coisa que abordaríamos de forma diferente é a dependência da interação do cursor. A experiência muda significativamente em dispositivos sensíveis ao toque, então isso é algo que consideraríamos mais cedo no processo de design, em vez de adaptarmos mais tarde.

No geral, o projeto reforçou uma ideia que moldou a reformulação da marca desde o início: a interação funciona melhor quando apoia o conceito, em vez de chamar a atenção para si mesma.

Deixe um comentário

Seu email não será publicado. Campos obrigatórios marcados com *

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.