import { gsap } from 'gsap';
import { SplitText } from 'gsap/SplitText';
gsap.registerPlugin(SplitText);
const deepcoral_palette = [
'#1c1529', // dark purple
'#393350', // space cadet
'#895879', // chinese violet
'#838a47', // moss green
'#275d46', // castleton green
];
gsap.registerEffect({
name: 'trippyWobble',
extendTimeline: true,
defaults: {
activeCharRatio: 0.7,
durationRange: [10, 15],
xRange: [-0.8, 0.8],
yRange: [-0.8, 0.8],
rotationRange: [-2, 2],
scaleXRange: [0.97, 1.03],
scaleYRange: [0.96, 1.04],
colors: null,
glow: true,
},
effect: (
targets: gsap.DOMTarget,
config: {
activeCharRatio: 0.7;
motionPath: boolean;
glow: any;
durationRange: [number, number];
xRange: [number, number];
yRange: [number, number];
rotationRange: [number, number];
scaleXRange: [number, number];
scaleYRange: [number, number];
colors: any[];
},
) => {
const split = new SplitText(targets, {
type: 'chars',
charsClass: 'char inline-block',
});
const chars = split.chars;
(chars as HTMLElement[]).forEach((char, i) => {
char.style.willChange = 'transform, color, filter';
gsap.set(char, {
transformOrigin: '50% 50%',
scaleX: 1,
scaleY: 1,
rotation: 0,
willChange: 'transform',
});
// Subtle glow style from CSS, only blur is animated
function animateCharBlur() {
gsap.to(char, {
filter: `blur(${gsap.utils.random(0.2, 0.7)}px)`,
duration: gsap.utils.random(3, 6),
ease: 'sine.inOut',
onComplete: animateCharBlur,
});
}
animateCharBlur();
// Animate transform motion
function animateCharTransform(char: HTMLElement) {
gsap.to(char, {
x: gsap.utils.random(...config.xRange),
y: gsap.utils.random(...config.yRange),
rotation: gsap.utils.random(...config.rotationRange),
scaleX: gsap.utils.random(...config.scaleXRange),
scaleY: gsap.utils.random(...config.scaleYRange),
skewX: gsap.utils.random(-1, 1),
skewY: gsap.utils.random(-1, 1),
duration: gsap.utils.random(...config.durationRange),
ease: 'sine.inOut',
delay: gsap.utils.random(5, 8),
onComplete: () => animateCharTransform(char),
});
}
gsap.delayedCall(gsap.utils.random(0, 2.5), () => animateCharTransform(char));
// Smooth color cycling with keyframes (no recursion)
if (config.colors?.length) {
gsap.to(char, {
keyframes: config.colors.map(c => ({ color: c })),
duration: gsap.utils.random(9, 12),
repeat: -1,
yoyo: true,
ease: 'sine.inOut',
delay: gsap.utils.random(0, 3),
});
}
});
return gsap.timeline(); // enables timeline chaining if needed
},
});
gsap.effects.trippyWobble('.trippy-text', {
durationRange: [12, 15],
xRange: [-0.95, 0.95],
yRange: [-0.95, 0.95],
rotationRange: [-2, 2],
scaleXRange: [0.9, 1.3],
scaleYRange: [0.9, 1.5],
colors: deepcoral_palette,
glow: true,
});