(85) 99645-7140 nelclassico@gmail.com Praça Coronel Melquiades, 124
Tecnologia

Feito com Gsap: ​​Construindo uma divertida trilha de mouse baseada na gravidade | Codrops

Para comemorar o lançamento de nossa nova coleção de efeitos, fizemos uma parceria com a Codrops para um pequeno tutorial divertido explorando uma animação interativa onde as imagens aparecem seguindo o cursor do mouse. A diferença: depois que uma imagem aparece, ela cai na parte inferior da janela de visualização, salta e depois desaparece.

Visite o link de demonstração para baixar os arquivos ZIP ou copie o componente diretamente em seu projeto Webflow. Vamos começar!

[codrops_course_ad id=”115510″]

Estrutura HTML

A estrutura aqui é bastante simples. Vamos simplesmente chamar o conjunto de imagens que queremos para nosso efeito:

<section class="codrops_mwg"> <div class="medias"> <img src="./assets/medias/01.png" alt=""> <img src="./assets/medias/02.png" alt=""> <img src="./assets/medias/03.png" alt=""> <img src="./assets/medias/04.png" alt=""> </div> </section>

Alguns CSS

Agora, vou esconder essas imagens usando um pouco de CSS.

.codrops_mwg .medias img { width: 1px; height: 1px; top: 0; left: 0; position: absolute; visibility: hidden; pointer-events: none; }

Uma explicação rápida: poderíamos ter carregado essas imagens diretamente via JavaScript para manter o DOM limpo. Então, por que não fizemos isso? Porque esta técnica permite-nos carregar as imagens imediatamente, mesmo que estejam ocultas. Dessa forma, não haverá atraso na criação de uma imagem com nosso script.

Veja como recupero todas as URLs das imagens usadas neste efeito. Esses URLs agora estão armazenados em minha matriz <section class="codrops_mwg"> <div class="medias"> <img src="./assets/medias/01.png" alt=""> <img src="./assets/medias/02.png" alt=""> <img src="./assets/medias/03.png" alt=""> <img src="./assets/medias/04.png" alt=""> </div> </section> .

const root = document.querySelector('.codrops_mwg') const images = [] root.querySelectorAll('.medias img').forEach(image => { images.push(image.getAttribute('src')) })

Iniciando a animação

Acionaremos uma função sempre que o cursor se mover uma certa distância. Aqui rastreamos os movimentos .codrops_mwg .medias img { width: 1px; height: 1px; top: 0; left: 0; position: absolute; visibility: hidden; pointer-events: none; } e images para calcular a distância total percorrida:

const root = document.querySelector('.codrops_mwg') let incr = 0, oldIncrX = 0, oldIncrY = 0 root.addEventListener("mousemove", e => { const valX = e.clientX const valY = e.clientY // Add the positive difference between the last two positions (X + Y) incr += Math.abs(valX - oldIncrX) + Math.abs(valY - oldIncrY) oldIncrX = valX oldIncrY = valY })

Aqui, calculamos o delta entre a posição atual do cursor e a posição anterior em ambos os eixos. Em seguida, adicionamos essa diferença total à nossa variável const root = document.querySelector('.codrops_mwg') const images = [] root.querySelectorAll('.medias img').forEach(image => { images.push(image.getAttribute('src')) }) . Também armazenamos os deltas porque precisaremos deles mais tarde para determinar a direção em que a imagem deve se mover ao cair.

Acionando a função de criação de imagem

A seguir, chamaremos a função para criar uma imagem quando const root = document.querySelector('.codrops_mwg') const images = [] root.querySelectorAll('.medias img').forEach(image => { images.push(image.getAttribute('src')) }) exceder um limite específico. Para tornar o efeito responsivo, definiremos o limite como Y.

const root = document.querySelector('.codrops_mwg') let incr = 0, oldIncrX = 0, oldIncrY = 0, resetDist = window.innerWidth / 8 root.addEventListener("mousemove", e => { const valX = e.clientX const valY = e.clientY incr += Math.abs(valX - oldIncrX) + Math.abs(valY - oldIncrY) if(incr > resetDist) { incr = 0 createMedia(valX, valY - root.getBoundingClientRect().top, valX - oldIncrX, valY - oldIncrY) } oldIncrX = valX oldIncrY = valY })

Observe que passamos dois parâmetros extras para const root = document.querySelector('.codrops_mwg') let incr = 0, oldIncrX = 0, oldIncrY = 0 root.addEventListener("mousemove", e => { const valX = e.clientX const valY = e.clientY // Add the positive difference between the last two positions (X + Y) incr += Math.abs(valX - oldIncrX) + Math.abs(valY - oldIncrY) oldIncrX = valX oldIncrY = valY }): ###CODE_866286faad58fe 3cb052b89daf5f4c8c### e incr. Representam a direção em que o cursor estava se movendo no momento em que a imagem foi criada. Iremos usá-los para fazer a imagem flutuar na mesma direção em que cai.

Para a posição incr , ajustamos subtraindo a distância do topo do elemento raiz até o topo da janela de visualização. Isso garante que o efeito funcione corretamente mesmo se a página for rolada para baixo:

e.clientY - root.getBoundingClientRect().top

Dentro da função createMedia()

A função const root = document.querySelector('.codrops_mwg') let incr = 0, oldIncrX = 0, oldIncrY = 0 root.addEventListener("mousemove", e => { const valX = e.clientX const valY = e.clientY // Add the positive difference between the last two positions (X + Y) incr += Math.abs(valX - oldIncrX) + Math.abs(valY - oldIncrY) oldIncrX = valX oldIncrY = valY }) agora aceita quatro parâmetros: const root = document.querySelector('.codrops_mwg') let incr = 0, oldIncrX = 0, oldIncrY = 0, resetDist = window.innerWidth / 8 root.addEventListener("mousemove", e => { const valX = e.clientX const valY = e.clientY incr += Math.abs(valX - oldIncrX) + Math.abs(valY - oldIncrY) if(incr > resetDist) { incr = 0 createMedia(valX, valY - root.getBoundingClientRect().top, valX - oldIncrX, valY - oldIncrY) } oldIncrX = valX oldIncrY = valY }), ###CODE_01e14d56 691483e8b3b6841e12616c7d###, createMedia(), e incr. Começamos criando uma imagem.

const image = document.createElement("img") image.setAttribute('src', images[indexImg]) root.appendChild(image)

Também adicionamos uma pequena proteção: se o cursor estiver muito próximo da parte inferior da viewport, pulamos a criação para evitar uma queda visualmente interrompida:

const H = window.innerHeight if (y > H - 200) return

Vamos criar uma linha do tempo GSAP() simples. Quando a linha do tempo termina, a imagem é removida do DOM:

const tl = gsap.timeline({ onComplete: () => { root.removeChild(image); tl && tl.kill() } })

A primeira interpolação trata a aparência com o mesmo salto elástico, mas sem configuração const root = document.querySelector('.codrops_mwg') let incr = 0, oldIncrX = 0, oldIncrY = 0, resetDist = window.innerWidth / 8 root.addEventListener("mousemove", e => { const valX = e.clientX const valY = e.clientY incr += Math.abs(valX - oldIncrX) + Math.abs(valY - oldIncrY) if(incr > resetDist) { incr = 0 createMedia(valX, valY - root.getBoundingClientRect().top, valX - oldIncrX, valY - oldIncrY) } oldIncrX = valX oldIncrY = valY }) e incr — eles serão tratados por interpolações separadas executadas simultaneamente:

tl.fromTo(image, { xPercent: -50 + (Math.random() - 0.5) * 80, yPercent: -50 + (Math.random() - 0.5) * 10, scaleX: 1.3, scaleY: 1.3, rotation:(Math.random() - 0.5) * 20 }, { scaleX:1, scaleY:1, ease: 'elastic.out(2, 0.6)', duration: 0.4 })

A seguir, animamos a posição horizontal. A imagem se move na direção em que o cursor estava se movendo, usando createMedia(). Essa interpolação começa ao mesmo tempo que a anterior graças ao parâmetro de posição createMedia() :

tl.fromTo(image, { x, }, { x: '+=' + deltaX * 2, rotation: 0, ease: 'power1.in', duration: 0.4 }, '<')

Simultaneamente, animamos a posição vertical. A imagem cai de sua posição inicial incr até a parte inferior da janela de visualização. O y combinado com deltaX garante que a borda inferior da imagem fique precisamente na parte inferior da janela de visualização:

tl.fromTo(image, { y }, { y: '+=' + (H - y), scale: 0.9, yPercent: -95, ease: 'back.in(1.1)', duration: 0.4 }, '<')

Finalmente, o salto. Depois de atingir o fundo, a imagem volta a subir e desaparece. Continuamos flutuando horizontalmente e adicionamos uma rotação aleatória para uma sensação natural:

tl.to(image, { x: '+=' + deltaX * 1.6, rotation:(Math.random() - 0.5) * 40, ease: 'power1.in', duration: 0.3 }) tl.to(image, { yPercent: 150, ease: 'back.in(' + (1.5 + (1 - y/H)) + ')', duration: 0.3 }, '<')

Observe a dinâmica flexibilização: deltaY. Quanto mais alto a imagem começar, mais forte será o overshoot no salto, criando um efeito mais dramático para imagens que caem mais para cima.

Indo além

Ajustando os valores aleatórios ou explorando outras opções de atenuação da documentação do GSAP, você pode obter diferentes efeitos visuais. Tente ajustar a intensidade const image = document.createElement("img") image.setAttribute('src', images[indexImg]) root.appendChild(image) para saltos mais ou menos dramáticos. A página de documentação do GSAP  Easing  é um ótimo playground para isso!

Sobre Made With Gsap

Made With Gsap é uma plataforma que apresenta uma coleção cada vez maior de mais de 100 efeitos JS exclusivos e bem elaborados. Acabamos de lançar 50 novas adições, além de um efeito totalmente novo que chega a cada semana.

Para comemorar o lançamento desta nova coleção, estamos oferecendo 10% de desconto no seu primeiro período de assinatura com o código Codrops10 — disponível até o final de maio.

Obrigado mais uma vez a Manoela e Codrops pela oportunidade de compartilhar este divertido efeito saltitante e por inspirar continuamente a comunidade de desenvolvimento criativo.

Se quiser acompanhar a aventura, você pode nos encontrar em Instagram , LinkedIn , Youtube , X (Twitter) e Bluesky .

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.