After years of inactivity, I decided it was time for a complete overhaul of my personal portfolio. What started as a simple "let me fix this one animation" turned into a week-long intensive refactoring session that transformed the entire codebase.
🎯 The Challenge
My original portfolio stopped working because of many deprecated dependencies. The animation system was monolithic, testing was sparse, and adding new features felt like walking through a minefield.
🚀 What I Built
Complete Animation System Overhaul
The biggest change was moving from a single, monolithic animation controller to a modular scene-based system. Each section of my journey (freelance → company → ASOS) now has its own self-contained scene with dedicated animations.
// Before: One massive animation controller
const animateEverything = (progress) => {
// 500+ lines of mixed concerns
}
// After: Modular scene management
import { deskScene } from './scenes/deskScene'
import { spaceScene } from './scenes/spaceScene'
import { contactsScene } from './scenes/contactsScene'
const scenes = {
desk: deskScene,
space: spaceScene,
contacts: contactsScene
}
Brand New Visuals and Interactions
Each career chapter now tells a visual story:
- Desk Scene: My freelance days working from home
- Space Scene: The journey to London and ASOS
- Contacts Scene: Opening doors to new opportunities
Comprehensive Testing Infrastructure
Testing animations is tricky, but I managed to achieve 90%+ coverage using:
// Testing animation state changes
it('should progress through scenes correctly', () => {
const { result } = renderHook(() => useAnimation())
act(() => {
result.current.setProgress(0.5)
})
expect(result.current.currentScene).toBe('space')
})
Custom SVG Processing Pipeline
I built a custom webpack plugin to optimize and process SVG animations:
// SVG ID processor for animation targeting
class SVGIdPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync('SVGIdPlugin', (compilation, callback) => {
// Process SVG files and assign unique IDs
})
}
}
🛠️ Technical Stack
- React 18 with hooks for state management
- Custom animation system using D3 interpolation
- React Testing Library for component testing
- Webpack 5 with custom loaders and plugins
- ESLint + Prettier + Stylelint for code quality
- GitHub Copilot for enhanced development workflow
📱 Performance Optimizations
Mobile performance was crucial, especially for iOS Safari:
/* Viewport optimizations for iOS */
.animation-container {
transform: translate3d(0, 0, 0);
will-change: transform;
backface-visibility: hidden;
}
I also implemented throttled scroll handlers and IntersectionObserver for efficient animation triggers.
🧪 Testing Complex Animations
One of the biggest challenges was testing scroll-based animations. Here's how I approached it:
// Mock IntersectionObserver for testing
const mockIntersectionObserver = jest.fn()
mockIntersectionObserver.mockReturnValue({
observe: () => null,
unobserve: () => null,
disconnect: () => null
})
window.IntersectionObserver = mockIntersectionObserver
🎨 Animation Debugger
I built a timeline debugger to visualize animation states during development:
const AnimationDebugger = ({ scenes, currentProgress }) => (
<div className="debug-timeline">
{scenes.map(scene => (
<div
key={scene.name}
className={`scene-marker ${scene.active ? 'active' : ''}`}
style={{ left: `${scene.progress * 100}%` }}
>
{scene.emoji} {scene.name}
</div>
))}
</div>
)
📈 Key Metrics
After the refactor:
- 90%+ test coverage (up from ~20%)
- Modular architecture with 8 separate scene files
- Enhanced mobile performance with iOS-specific optimizations
- Custom tooling for SVG processing and animation debugging
🤔 Lessons Learned
1. Modular Architecture Pays Off
Breaking the monolithic animation system into scenes made debugging and extending much easier. Each scene can be developed and tested in isolation.
2. Testing Animations is Hard but Worth It
Finding the right abstractions for testing scroll-based animations took time, but the confidence it provides is invaluable.
3. Performance Matters on Mobile
iOS Safari has specific quirks that required targeted optimizations. Always test on real devices!
4. Developer Experience is Key
The animation debugger and GitHub Copilot integration made the development process much more enjoyable and productive.
🌟 What's Next?
The new modular system makes it easy to add new scenes and animations. I'm already planning:
- Interactive scene selection
- More detailed micro-interactions
- Performance monitoring dashboard
🔗 Check It Out
- Live site: albinotonnina.com
- Source code: github.com/albinotonnina/albinotonnina.com
The code is open source under CC BY-NC-ND 4.0 - feel free to explore and learn from it, but please don't use it as your own portfolio!
What's your approach to portfolio development? Have you tackled similar animation challenges? I'd love to hear about your experiences in the comments! 👇
Top comments (0)