MilWebWhatsApp
Voltar aos projetos

Site-experiência sobre Rock · motion design de ponta a ponta

ROCKVERSE

Lighthouse 99 · A11y 100 · motion 60fpsProjeto autoral · demo

Problema

Marcas de música e cultura disputam atenção em segundos, e sites institucionais comuns não geram desejo, memória nem compartilhamento.

Solução

Experiência imersiva pela história do rock: headline cinética letra a letra, scroll com inércia (Lenis), cursor contextual, vinis interativos com modal, timeline com scrub e seção editorial em papel. O projeto foi auditado como se eu fosse jurado de premiação e refinado em 5 fases, mantendo Lighthouse 99/100/100/100 no desktop.

Como foi construído

O motion do ROCKVERSE não é biblioteca-padrão ligada no automático. O scroll passa por Lenis (lerp 0.1, smoothWheel) e o scroll-behavior: smooth nativo do CSS fica desligado, pra evitar que os dois sistemas disputem o mesmo frame. É um conflito sutil: só aparece quando alguém clica num link âncora e a página "engasga" no meio do scroll. O cursor customizado (CustomCursor.tsx) só ativa em pointer: fine, então telas touch nunca pagam o custo. Ele usa um anel com física de spring (stiffness 250, damping 25) seguindo um ponto rígido, e um atributo data-cursor nos elementos interativos troca o rótulo conforme o contexto, tipo "GIRAR" sobre um vinil. Sem re-render desnecessário, porque o estado só muda quando o valor realmente muda (bail-out do React via Object.is). A headline do hero é revelada letra a letra com máscara (overflow-hidden + translateY por motion.span, stagger de 35ms por caractere) e reage à posição do mouse com paralaxe em três camadas: fundo, título e luz radial, via useMotionValue + useSpring + useTransform. Tudo com fallback estático completo quando prefers-reduced-motion está ativo.

O que separa isso de "mais um site com fadeUp" são as cenas ligadas ao próprio scroll, não só disparadas por ele. A timeline de décadas (History.tsx) tem uma barra de progresso em gradiente cuja escala Y vem de useScroll + useSpring do progresso da seção inteira, enquanto cada card roda seu próprio useScroll local pra dar paralaxe à imagem (-8% a 8%) e deslocar o ano lateralmente. No desktop a imagem fica sticky, o que cria profundidade sem precisar de WebGL. Na seção de álbuns, os vinis por trás das capas giram conforme o usuário rola a grade inteira (useTransform de 0 a 180 graus sobre o scrollYProgress da seção), e só ganham animate-spin-slow de verdade quando abertos no modal. O divisor de marquee vai além: em vez de rolar em velocidade fixa, aplica um skewX calculado a partir da velocidade instantânea do scroll (useVelocity sobre scrollY, mapeada pra -5°/5° com spring). O texto se inclina mais quanto mais rápido o visitante rola. É o tipo de detalhe que só existe em site que trata o scroll como instrumento, não como gatilho de fade-in.

Manter Lighthouse 99/100/100/100 com esse volume de efeito exigiu decisões de arquitetura, não sorte. O app/page.tsx carrega Hero, History, Navbar e a barra de progresso de forma eager, que é o que aparece na primeira dobra, e faz next/dynamic de todas as outras nove seções abaixo dela (Bands, Instruments, Genres, Festivals, Albums, HallOfFame, Curiosities, Stats, Gallery, Newsletter, Footer). Assim o bundle inicial não paga o custo de código que o usuário talvez nunca role até ver. As partículas de brasa do hero (EmberCanvas.tsx) não são componentes Framer Motion. São um canvas 2D cru desenhado a mão, com IntersectionObserver pausando o requestAnimationFrame fora da viewport e um listener de visibilitychange pausando quando a aba perde foco, além de devicePixelRatio limitado a 2 e densidade de partículas cortada pela metade no mobile. O next/image usa qualidades customizadas (qualities: [60, 75], hero explicitamente em 60) pra cortar payload de LCP sem borrar a imagem de forma perceptível. E o prefers-reduced-motion é tratado em duas camadas: um kill-switch global no CSS, que zera todas as animation-duration e transition-duration, mais checagens pontuais via useReducedMotion() nos componentes que fazem cálculo de física (parallax do hero, timeline, rotação dos vinis). Sem a segunda camada, a query CSS mataria a transition mas deixaria os cálculos de useTransform rodando a cada frame.

O que mais diferencia o processo está documentado em docs/DESIGN-AUDIT.md: uma auto-auditoria de 20 problemas, escrita como se fosse um jurado de premiação avaliando o site ("veredito geral: 7.2/10"), cobrindo hero, paleta, tipografia, espaçamento, componentes e imagens, com um roadmap de 5 fases explícito. A Fase 4 desse roadmap, "Motion Design", listava exatamente o que faltava: Lenis, headline cinética, timeline com scrub, skew no marquee por velocidade. É literalmente o que está implementado no código hoje. Tratar o próprio projeto autoral como se fosse um cliente exigente, com auditoria escrita, tabela de prioridade (P0 a P3) e reavaliação de Lighthouse a cada fase, é o que separa "fizemos um site bonito" de um processo de design repetível.

Scroll com física real

Lenis com lerp 0.1 substitui o scroll nativo, com âncoras recalculadas via offset de navbar em vez de saltos secos.

Headline letra a letra

Reveal por máscara com stagger de 35ms por caractere, mais paralaxe de mouse em três camadas independentes.

Cenas ligadas ao scroll

Vinil que gira com o progresso da seção e marquee que se inclina conforme a velocidade instantânea do scroll.

99/100/100/100 sem atalho

Code-splitting por seção, partículas em canvas cru pausadas fora da viewport e reduced-motion tratado em duas camadas.

Mais telas

Hero do ROCKVERSE com headline cinéticaGrade de vinis (Discoteca)

Stack

  • Next.js 16
  • TypeScript
  • Tailwind v4
  • Framer Motion
  • Lenis

Pronto para transformar sua ideia em um produto digital?

Me conta o que você precisa. Respondo rápido e te passo um orçamento gratuito, sem compromisso.

  • Contrato de garantia
  • Suporte pós-entrega
  • O código é seu
  • Orçamento gratuito