Skip to content

Instantly share code, notes, and snippets.

@rhcarlosweb
Last active May 24, 2025 17:40
Show Gist options
  • Save rhcarlosweb/7dd9febb0918b01333fa9cc5853ad2ea to your computer and use it in GitHub Desktop.
Save rhcarlosweb/7dd9febb0918b01333fa9cc5853ad2ea to your computer and use it in GitHub Desktop.
new animations with gsap 3
import gsap from 'gsap'
import ScrollTrigger from 'gsap/ScrollTrigger'
import {SplitText} from 'gsap/SplitText'
import CustomEase from 'gsap/CustomEase'
gsap.registerPlugin(ScrollTrigger)
gsap.registerPlugin(SplitText)
document.addEventListener('DOMContentLoaded', () => {
const animations = {
'fade-in': {from: {autoAlpha: 0}, to: {autoAlpha: 1}},
'fade-in-left': {from: {autoAlpha: 0, x: '-=30'}, to: {autoAlpha: 1, x: '+=30'}},
'fade-in-right': {from: {autoAlpha: 0, x: '+=30'}, to: {autoAlpha: 1, x: '-=30'}},
'fade-in-down': {from: {autoAlpha: 0, y: '-=30'}, to: {autoAlpha: 1, y: '+=30'}},
'fade-in-up': {from: {autoAlpha: 0, y: '+=30'}, to: {autoAlpha: 1, y: '-=30'}}
}
const applyAnimation = (selector, animation) => {
document.querySelectorAll(selector).forEach((element) => {
const delay = parseFloat(element.getAttribute('data-delay')) || 0.2
const duration = parseFloat(element.getAttribute('data-duration')) || 0.8
const start = element.getAttribute('data-start') || 'top 99%'
const end = element.getAttribute('data-end') || 'bottom 10%'
const ease = element.getAttribute('data-ease') || CustomEase.create('custom-ease', '0.33, 0.32, 0.1, 1.03')
const toggleActions = element.getAttribute('data-toggle-actions') || 'play none none reverse'
const markers = element.getAttribute('data-markers') === 'true'
const scrub = element.getAttribute('data-scrub') || false
const staggerDelay = parseFloat(element.getAttribute('data-stagger-delay')) || 0.08
gsap.set(element, {willChange: 'auto'})
if (selector.startsWith('.stagger-')) {
gsap.fromTo(element.children, animation.from, {
...animation.to,
ease: ease,
duration: duration,
delay: delay,
stagger: staggerDelay,
scrollTrigger: {
trigger: element,
start: start,
end: end,
toggleActions: toggleActions,
markers: markers,
scrub: scrub
}
})
} else {
gsap.fromTo(element, animation.from, {
...animation.to,
ease: ease,
duration: duration,
delay: delay,
scrollTrigger: {
trigger: element,
start: start,
end: end,
toggleActions: toggleActions,
markers: markers,
scrub: scrub
}
})
}
})
}
/**
* Text reveal animation with configurable SplitText types
* Supports: chars, words, lines
*/
const revealTextElements = document.querySelectorAll('.reveal-text .reveal')
if (revealTextElements.length) {
revealTextElements.forEach((text) => {
const parent = text.closest('.reveal-text')
// Configurações básicas
const delay = parseFloat(parent.getAttribute('data-delay')) || 0.2
const duration = parseFloat(parent.getAttribute('data-duration')) || 0.8
const start = parent.getAttribute('data-start') || 'top 99%'
const end = parent.getAttribute('data-end') || 'bottom 10%'
const ease = parent.getAttribute('data-ease') || CustomEase.create('custom-ease', '0.33, 0.32, 0.1, 1.03')
const toggleActions = parent.getAttribute('data-toggle-actions') || 'play none none reverse'
const markers = parent.getAttribute('data-markers') === 'true'
const scrub = parent.getAttribute('data-scrub') || false
const staggerDelay = parseFloat(parent.getAttribute('data-stagger-delay')) || 0.08
// Nova configuração: tipo de split
const splitType = parent.getAttribute('data-split-type') || 'lines' // 'chars', 'words', 'lines'
// Configurar SplitText baseado no tipo escolhido
let splitConfig = {}
let targetElements
switch (splitType.toLowerCase()) {
case 'chars':
case 'char':
splitConfig = {
type: 'chars',
charsClass: 'reveal-char'
}
break
case 'words':
case 'word':
splitConfig = {
type: 'words',
wordsClass: 'reveal-word'
}
break
case 'lines':
case 'line':
default:
splitConfig = {
type: 'lines',
linesClass: 'reveal-line'
}
break
}
// Criar o split
const split = new SplitText(text, splitConfig)
// Definir qual array usar baseado no tipo
switch (splitType.toLowerCase()) {
case 'chars':
case 'char':
case 'char':
targetElements = split.chars
break
case 'words':
case 'word':
targetElements = split.words
break
case 'lines':
case 'line':
default:
targetElements = split.lines
break
}
// Mostrar o elemento pai
gsap.set(parent, {
autoAlpha: 1
})
// Aplicar a animação
gsap.from(targetElements, {
scrollTrigger: {
trigger: text,
start: start,
end: end,
toggleActions: toggleActions,
markers: markers,
scrub: scrub
},
duration: duration,
delay: delay,
y: 50,
autoAlpha: 0,
stagger: staggerDelay,
ease: ease,
repeat: 0
})
})
}
Object.keys(animations).forEach((key) => applyAnimation(`.${key}`, animations[key]))
Object.keys(animations).forEach((key) => applyAnimation(`.stagger-${key}`, animations[key]))
})
.fade-in, .fade-in-left, .fade-in-right, .fade-in-up, .fade-in-down {
@apply invisible opacity-0;
}
.reveal-text {
@apply opacity-0 relative overflow-hidden;
.reveal {
@apply inline-block align-top pb-1;
}
.reveal-word {
@apply relative overflow-hidden align-top pb-1;
}
.reveal-line {
@apply relative overflow-hidden align-top pb-1;
}
.reveal-char {
@apply align-top pb-1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment