Animation System Overview
Your portfolio uses two animation systems:
- Tailwind CSS Animations - Keyframe animations for glassmorphism effects and micro-interactions
- Scroll Animations - Custom React components using IntersectionObserver for scroll-triggered animations
Tailwind CSS Animations
Built-in Animations
The portfolio includes 11 custom animations defined in tailwind.config.js:
animation: {
'glass-shimmer': 'glass-shimmer 2s ease-in-out infinite alternate',
'glow-pulse': 'glow-pulse 4s ease-in-out infinite',
}
Animation Keyframes
Each animation has corresponding keyframes:
Glass Shimmer
'glass-shimmer': {
'0%': { 'background-position': '-200% 0' },
'100%': { 'background-position': '200% 0' },
}
Use with gradient backgrounds for a shimmer effect:
<div className="glass-shimmer animate-glass-shimmer">
Content here
</div>
Float Animation
'float': {
'0%, 100%': { transform: 'translateY(0px) rotate(0deg)' },
'50%': { transform: 'translateY(-20px) rotate(5deg)' },
}
Creates a gentle floating effect with slight rotation:
<div className="animate-float">
Floating element
</div>
Use animate-float-delayed for staggered floating effects on multiple elements.
Special animations for the chat button:
'chat-pulse': {
'0%, 100%': { transform: 'scale(1)', opacity: '1' },
'50%': { transform: 'scale(1.05)', opacity: '0.9' },
}
Gradient Shift
'gradient-shift': {
'0%, 100%': { 'background-position': '0% 50%' },
'50%': { 'background-position': '100% 50%' },
}
Animates gradient backgrounds. Use with background-size: 200%:
<div className="bg-gradient-to-r from-purple-500 to-blue-500
bg-[length:200%_200%] animate-gradient-shift">
Animated gradient
</div>
Custom React components for scroll-triggered animations in src/components/scroll-animations.tsx.
Fades in and slides up when scrolling into view:
src/components/scroll-animations.tsx
export function ScrollFadeIn({
children,
className = "",
delay = 0
}: ScrollAnimationProps) {
// Implementation uses IntersectionObserver
// Adds 'animate-fade-in-up' class when in viewport
}
Usage
import { ScrollFadeIn } from './components/scroll-animations'
<ScrollFadeIn delay={100}>
<h2>This will fade in</h2>
</ScrollFadeIn>
The delay prop is in milliseconds and allows you to stagger multiple animations.
Slides in from the left when scrolling into view:
src/components/scroll-animations.tsx
export function ScrollSlideIn({
children,
className = "",
delay = 0
}: ScrollAnimationProps) {
// Adds 'animate-slide-in-left' class when in viewport
}
Usage
import { ScrollSlideIn } from './components/scroll-animations'
<ScrollSlideIn delay={200}>
<div>This will slide in from left</div>
</ScrollSlideIn>
Initial State
Elements start with opacity-0 and transform classes:className="opacity-0 translate-y-8 transition-all duration-700 ease-out"
Viewport Detection
IntersectionObserver watches for element entering viewport:const observer = new IntersectionObserver(
(entries) => { /* ... */ },
{ threshold: 0.1 }
)
Animation Trigger
When visible, opacity and transform classes are removed with optional delay:setTimeout(() => {
target.classList.add(animationClass)
hiddenClasses.forEach((c) => target.classList.remove(c))
}, delay)
Scroll animations trigger once when the element enters the viewport. They don’t reverse when scrolling back up.
Creating Custom Animations
Adding Tailwind Animations
Define Keyframes
Add your keyframes in tailwind.config.js:keyframes: {
'my-animation': {
'0%': { opacity: '0', transform: 'scale(0.8)' },
'100%': { opacity: '1', transform: 'scale(1)' },
}
}
Register Animation
Add the animation configuration:animation: {
'my-animation': 'my-animation 0.5s ease-out',
}
Use in Components
Apply with the animate- prefix:<div className="animate-my-animation">
Animated content
</div>
Extend the existing pattern in scroll-animations.tsx:
src/components/scroll-animations.tsx
export function ScrollZoomIn({
children,
className = "",
delay = 0
}: ScrollAnimationProps) {
const elementRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const element = elementRef.current
if (!element) return
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setTimeout(() => {
element.classList.remove('opacity-0', 'scale-75')
element.classList.add('opacity-100', 'scale-100')
}, delay)
}
})
},
{ threshold: 0.1 }
)
observer.observe(element)
return () => observer.disconnect()
}, [delay])
return (
<div
ref={elementRef}
className={`opacity-0 scale-75 transition-all duration-700 ease-out ${className}`}
>
{children}
</div>
)
}
GPU Acceleration
The portfolio includes GPU acceleration utilities:
.transform-gpu {
backface-visibility: hidden;
transform-style: preserve-3d;
-webkit-backface-visibility: hidden;
-webkit-transform-style: preserve-3d;
}
Add this class to animated elements for better performance:
<div className="animate-float transform-gpu">
GPU-accelerated animation
</div>
Use GPU acceleration for animations involving transforms, but avoid overuse as it increases memory usage.
Animation Best Practices
- Use
will-change sparingly - Only on actively animating elements
- Prefer transforms - Use
transform over position changes
- Reduce motion - Respect user preferences with
prefers-reduced-motion
- Stagger animations - Use delay props to avoid overwhelming users
Animation Timing Reference
| Duration | Use Case | Example |
|---|
| 0.2s | Quick transitions | Button hover, fade-scale |
| 0.5-1s | UI transitions | Modal open/close |
| 2-3s | Ambient effects | Shimmer, pulse |
| 4-6s | Decorative | Float, glow-pulse |
All animations use ease-in-out or ease-out timing functions for smooth, natural motion.