Communitygithub.com

shubham001312/scroll-motion-graphics

Use ao construir ou corrigir uma seção de motion graphics baseada em rolagem em uma página web, como um filme em canvas controlado pela posição da rolagem, um estágio fixo e adesivo de 'scrollytelling', capítulos vinculados à rolagem com legendas ou um carrossel/tambor 3D controlado por rolagem, arrasto e teclas de seta. Use também quando uma animação de rolagem existente apresenta travamentos, sequestra a roda, desenha sob seu texto, só toca para frente, queima a CPU enquanto ociosa ou ignora 'prefers-reduced-motion'.

O que é scroll-motion-graphics?

Esta skill define uma metodologia completa para criar animações de gráficos em movimento baseadas em rolagem que se comportam como uma linha do tempo de vídeo perfeitamente controlada pela posição da rolagem. O princípio central é que a posição da rolagem é o único relógio: ela é mapeada para um valor de progresso p (0 a 1), e cada pixel, legenda e rotação no quadro são funções puras desse p. A abordagem prioriza desempenho, acessibilidade e um controle de usuário não intrusivo, utilizando rolagem adesiva CSS pura (position: sticky) em vez de JavaScript para fixação, evitando qualquer captura de eventos de rolagem e garantindo que todo o conteúdo de texto exista no DOM para legibilidade. Cada 'reel' (cena) é uma função pura sem estado que recebe o progresso e o contexto de desenho, os laços de animação param quando a página está ociosa, o sistema respeita a preferência 'prefers-reduced-motion' e as tecnologias suportadas incluem implementações em JavaScript puro e wrappers React para os componentes de filme e tambor de história. A skill fornece um guia de construção passo a passo, listas de verificação de decisão (filme em canvas vs. transformações DOM, modo pin vs. view), uma tabela de modos de falha com correções e uma referência completa a arquivos de biblioteca e demonstração.

Funciona com✓Claude Code~Codex CLI✓Cursor✓OpenCode
npx skills add https://github.com/shubham001312/imutechz-skills/tree/HEAD/skills/scroll-motion-graphics

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Scroll motion graphics

Uma linha do tempo em canvas controlada pela posição da rolagem: um estágio fixo, reels que são funções puras do progresso e legendas que o desenho nunca pode tocar. Este método roda o tambor de história na página inicial da ImuTechz, o tambor de P&D e o filme do caminho do Fundador. Ele também alimenta a demonstração de cinco reels em assets/demo.html.

A técnica inteira cabe em uma frase. A posição da rolagem é o único relógio: mapeie-a para p ∈ [0, 1] e faça de cada pixel, legenda e rotação uma função de p.

Como é o bom resultado

  • Scruba como um vídeo. Role para frente e o filme toca. Role para trás e ele volta, quadro a quadro. Parar no meio deixa um quadro que faz sentido.
  • A página nunca é sequestrada. Roda, trackpad, toque e teclas movem a página exatamente como em qualquer outro lugar. A seção é apenas alta.
  • As palavras são sempre legíveis. As legendas são texto DOM real em um cartão. O desenho se organiza no espaço que as legendas deixam, e o canvas é recortado ao redor delas como uma rede de segurança.
  • É um controle, não apenas um show. As faces de um tambor de história são links. Sua barra, botões de seta, teclas de seta e arrasto do mouse buscam rolando a página, para que a rolagem e o tambor nunca possam discordar.
  • Uma página ociosa não custa nada. Nenhum requestAnimationFrame é executado depois que p se estabiliza ou após a seção sair da janela de visualização.
  • Movimento reduzido é respeitado. Sem suavização, sem rotação intermediária do tambor e sem animação de entrada de legenda. Todo o conteúdo ainda está lá.
  • Funciona de 360 a 1920 px de largura, em claro e escuro, em DPR 1 e 2.

Regras rígidas

  1. p vem da posição da rolagem, nunca de um relógio. Não use performance.now(), Date, animações CSS ou setInterval dentro de um reel. Suavização (um lerp em direção ao p alvo) é permitida porque converge para o mesmo quadro.
  2. Um reel é uma função pura draw(ctx, t, env). Ele não mantém estado entre quadros e nunca chama Math.random(); use um hash(i) com semente. O mesmo (t, env) deve pintar os mesmos pixels.
  3. Prenda com CSS, não com JS. Use uma trilha alta (position: relative; height: N×vh) segurando um estágio position: sticky; top: 0; height: 100svh. Nunca defina position: fixed no estágio, nunca bloqueie o body e nunca coloque overflow: hidden|auto|clip em um ancestral da trilha.
  4. Nunca capture entrada. Não use preventDefault na roda ou toque, nenhum overflow: hidden em html ou body e nenhum scroll snapping na trilha. Apenas um tambor focado pode lidar com teclas de seta, e ele o faz rolando a página.
  5. Busque rolando. Cada botão, item da barra, tecla e âncora altera window.scrollY. Nunca defina p ou uma rotação diretamente. Use behavior: "instant" para saltos programáticos que não devem animar, porque "auto" obedece ao CSS scroll-behavior: smooth da página.
  6. O texto vive no DOM. Legendas, títulos e links são HTML. O texto do canvas é limitado a rótulos decorativos, como anos, marcas de eixo e nomes de etapas.
  7. Meça as legendas a cada quadro e mantenha o desenho longe delas. Cada legenda e elemento HUD é uma zona de exclusão (data-keep). Os reels se distribuem dentro de env.free, e o motor recorta as zonas de exclusão com um recorte par-ímpar.
  8. Nunca mostre duas legendas ao mesmo tempo. As janelas de legenda ficam dentro de seu reel com uma lacuna em cada limite, e os reels fazem crossfade dentro dessa lacuna.
  9. O loop para quando ocioso. Inicie o rAF na rolagem ou redimensionamento apenas enquanto a seção estiver perto da janela de visualização (IntersectionObserver) e pare-o quando p for igual ao alvo.
  10. O canvas é dimensionado para o estágio em min(devicePixelRatio, 2). Chame setTransform(dpr, …) uma vez por quadro e limpe-o a cada quadro.
  11. As cores vêm de propriedades personalizadas CSS. Não codifique uma paleta de modo claro em um reel. Releia a paleta na mudança de prefers-color-scheme.
  12. Honre prefers-reduced-motion: reduce. Não use suavização, faça o tambor encaixar face a face e desligue as animações de entrada de legenda. Os quadros ainda seguem a rolagem, porque o usuário os controla.

Ordem de construção

Faça nesta ordem. Cada etapa é testável antes da próxima.

  1. Conteúdo primeiro. Escreva os capítulos: um chamariz, um título, uma ou duas frases e um link opcional para cada um. Escolha o número de reels (3 a 7) e dê a cada um cerca de 80 a 100 svh de rolagem.
  2. Trilha e estágio. Adicione a seção alta com um estágio adesivo de 100svh dentro dela e verifique se ela prende sem nenhum JS (veja layout-and-captions).
  3. O motor de scrub. Conecte ScrollMotion.scrub ou film (veja engine) e registre p. Verifique se ele lê 0 no início da fixação e 1 no final, e se move nos dois sentidos.
  4. Legendas e HUD no DOM. Coloque-as por ponto de interrupção, marque-as como data-keep e deixe o motor controlar sua opacidade a partir de p.
  5. Reels, um de cada vez. Escreva draw(ctx, t, env) dentro de env.free (veja drawing) e faça scrub para frente e para trás antes de escrever o próximo.
  6. Gramática de movimento. Adicione envelopes de entrada, manutenção e saída, escalonamentos, pausas e crossfades (veja motion-grammar).
  7. Interatividade, se for um tambor. Adicione links de face, a barra, botões anterior e próximo, teclas e arrasto, todos buscando por rolagem.
  8. Passagem de desempenho e acessibilidade. Cubra o loop ocioso, DPR, movimento reduzido, ordem de foco, texto do leitor de tela e modo escuro (veja performance-and-a11y).
  9. Verifique em 360, 390, 414, 768, 1024, 1280, 1440 e 1920 com o script headless (veja verification). Não considere concluído até que todas as verificações passem.

Listas de verificação de decisão

Filme em canvas ou transformações DOM/CSS?

  • Muitas peças pequenas em movimento, linhas que desenham, partículas ou gráficos → filme em canvas (ScrollMotion.film).
  • Um punhado de cartões, imagens ou painéis de texto → transformações DOM controladas por scrub (o tambor é um).
  • Malhas 3D reais ou shaders → esta skill não é suficiente. Use WebGL, mas mantenha as regras 1 a 5 e 9 a 12.

Modo pin ou view?

  • A seção deve segurar a tela enquanto sua história é reproduzida → mode: "pin" (trilha alta e estágio adesivo).
  • O efeito acompanha conforme o conteúdo passa, como em marquises ou parallax → mode: "view", sem fixação.

Qual é a altura da trilha?

  • Use n × 80–100svh + 100svh para um filme e n × 70vh + 100vh para um tambor. Se um leitor de teste disser que está "muito rápido", aumente a altura. Nunca diminua a velocidade capturando a roda.

Onde colocar as legendas?

  • Desktop (≥ 760 px): ao lado do desenho (cartão esquerdo ou direito) ou como um cartão inferior largo. Telefones: sempre uma folha inferior, com o desenho acima.
  • Com um cabeçalho de site fixo, defina --sm-nav-h para que o HUD e o tambor fiquem desobstruídos.

Precisa do tambor?

  • Use o tambor quando os capítulos são coisas para as quais o usuário pode querer ir (páginas, produtos, seções). Caso contrário, use apenas o filme.

Modos de falha e correções

SintomaCausaCorreção
O estágio rola para longe em vez de prenderUm ancestral tem overflow: hidden/auto/clip, ou o estágio não tem topRemova o overflow (use overflow-x: clip no body, se necessário) e defina top: 0
A animação só toca para frente ou pula ao rolar para cimaEstado acumulado entre quadros, ou um relógio ou Math.random em um reelTorne o reel uma função pura de t; use hash(i) para aleatoriedade
O desenho passa por baixo da legendaReel distribuído em todo o estágioDistribua em env.free; mantenha data-keep na legenda; deixe o motor recortar
Caixa de legenda medida no lugar errado durante o fadeUsou getBoundingClientRect (inclui a transformação)Meça caixas de layout (offsetLeft/Top/Width/Height, veja boxIn)
Duas legendas se sobrepõem em um limiteJanelas de legenda se tocamApague as legendas em 1 − cross e acenda em cross; os reels fazem crossfade na lacuna
Ventiladores giram em uma página ociosaO loop rAF nunca paraPare quando cur === target; limite com IntersectionObserver
Canvas borrado em telefones / lento em 4KCanvas no tamanho CSS, ou DPR sem limiteUse width = W × min(dpr, 2) e setTransform(dpr, 0, 0, dpr, 0, 0)
Tambor e página discordam depois de clicar na barraO controle definiu a rotação diretamenteTodo controle chama scrollToProgress; a rotação só vem de p
O arrasto treme e depois voltaA página tem scroll-behavior: smooth, então scrollTo(x, y) animaUse scrollTo({ top, behavior: "instant" }) durante o arrasto
Clicar em uma face após um arrasto abre seu linkO clique que termina um arrasto é disparadoEngula um clique na fase de captura após um arrasto que moveu > 4 px
Salto de 100vh no celular quando a barra de URL se escondevh no estágioUse 100svh para o estágio; calcule p com a altura do próprio estágio
Modo escuro mostra um desenho do modo claroCores codificadasLeia os tokens --sm-* via readPalette; releia na mudança de esquema
As faces traseiras do tambor aparecemFalta backface-visibility: hiddenDefina-o, com o prefixo -webkit-, em cada face
Miniaturas das faces do tambor desenhadas no tamanho erradoUsou o retângulo projetado de uma face com transformação 3DDimensione por clientWidth/clientHeight

Arquivos

Comece pela demonstração: abra-a, veja o código-fonte e substitua o conteúdo. A fiação na parte inferior do arquivo tem cerca de 60 linhas.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Habilidades Relacionadas