Animation Engine
Relevant source files
The following files were used as context for generating this wiki page:
This project employs a sophisticated, multi-layered "Hybrid Motion Engine" to manage UI animations and interactions. The architecture is designed to use the most appropriate technology for each task, balancing performance, developer experience, and visual complexity. The engine combines declarative libraries like Framer Motion, imperative libraries like GSAP, and low-level control via direct CSS and custom requestAnimationFrame hooks.
The core philosophy is to use Framer Motion for most layout transitions and micro-interactions, GSAP for complex, timeline-based scroll choreography, and pure CSS or custom hooks for highly optimized, specific component animations. This layered approach ensures maintainability and "optical stability" throughout the application.
Sources: README.md
Core Technologies
The animation engine is built upon several key libraries and web technologies. The selection of these tools is specified in the project's dependencies and described in the README.md.
| Library / Technology | Purpose in Project | Dependencies |
|---|---|---|
| GSAP | Handles complex, timeline-based scroll choreography. | gsap |
| Framer Motion | Manages declarative layout transitions and micro-interactions. | framer-motion |
| Motion | Provides useAnimationFrame and other low-level motion primitives. | motion |
| CSS Keyframes | Used for component-specific, state-driven animations (e.g., logo). | N/A (Native CSS) |
Sources: README.md, package.json:17-33
Animation Strategies
The project utilizes several distinct strategies for implementing animations, each tailored to a specific use case.
CSS-Driven State Animations: The Logo Component
A prime example of CSS-driven animation is the Logo component, which uses a combination of React state and CSS classes to manage its appearance and behavior.
The component's animation is controlled by a simple state machine with four states: loading, intro, idle, and hovering.
This diagram illustrates the state transitions for the Logo animation.
Sources: src/shared/ui/Logo/Logo.tsx:10-33
These states correspond to specific CSS classes that trigger animations defined in index.css. The drawing effect is achieved by animating the stroke-dashoffset property of an SVG path.
| State | CSS Class | Keyframes | Behavior |
|---|---|---|---|
loading | animate-logo-loading | logo-pulse | A gentle opacity pulse to indicate a loading state. |
intro | animate-logo-intro | logo-draw-in | Draws the logo by animating stroke-dashoffset from 3500 to 0. |
hovering | animate-logo-hover-cycle | logo-cycle | On hover, the logo "undraws" and then redraws itself. |
idle | (none) | (none) | The logo is fully drawn and static, awaiting interaction. |
Sources: src/shared/ui/Logo/Logo.tsx:90-95, src/app/index.css:105-132
Declarative UI Animations with Framer Motion
Framer Motion is the primary tool for layout transitions and animating components into and out of the DOM. The Footer and ContactSection widgets are excellent examples.
In Footer.tsx, the AnimatePresence and motion.div components are used to smoothly expand and collapse the "Quick Links" section.
This sequence diagram shows the user interaction and component response for the footer animation.
Sources: src/widgets/Footer/Footer.tsx:47-53
The ContactSection uses Framer Motion's whileInView property to trigger a fade-in and slide-up animation as the user scrolls the component into the viewport.
// src/widgets/ContactSection/ContactSection.tsx:17-21
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-50px" }}
transition={{ duration: 0.6, ease: "easeOut" }}
>
Sources: src/widgets/ContactSection/ContactSection.tsx:17-21
Custom Frame-by-Frame Animation
For high-performance effects that require continuous updates, the engine uses custom hooks built around requestAnimationFrame.
ShinyText Component
The ShinyText component creates a "shine" effect that sweeps across the text. It uses the useAnimationFrame hook from the motion library to update a useMotionValue on every frame. This value is then transformed into a background-position for a CSS gradient, creating a lightweight and performant animation.
This diagram shows the data flow for the ShinyText animation loop.
The component's behavior can be configured via several props:
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | - | The text to display. |
disabled | boolean | false | Disables the animation. |
speed | number | 2 | Duration of one animation cycle in seconds. |
color | string | var(--fg-secondary) | The base color of the text. |
shineColor | string | #ffffff | The color of the sweeping shine. |
spread | number | 90 | The angle of the gradient in degrees. |
yoyo | boolean | false | If true, the animation plays forwards and then in reverse. |
pauseOnHover | boolean | true | Pauses the animation when the user hovers over the text. |
direction | "left" | "right" | "left" | The direction of the shine sweep. |
delay | number | 0 | Delay in seconds between animation cycles. |
Sources: src/shared/ui/ShinyText/ShinyText.tsx:10-26
VariableProximity Component
The VariableProximity component is a more advanced example, implementing a custom useAnimationFrame hook to create an interactive text effect. It modifies the font-variation-settings of each letter in a string based on its proximity to the user's mouse cursor.
The animation loop is optimized for performance by separating DOM reads and writes:
- Read: In each frame, it reads the mouse position and the bounding box of every letter.
- Calculate: It computes the distance between the mouse and the center of each letter.
- Write: It calculates a new
font-variation-settingsstring based on a falloff curve and applies it directly to the letter's style. This update only occurs if the value has changed.
Sources: src/shared/ui/VariableProximity/VariableProximity.tsx:100-132
Conclusion
The animation engine of this portfolio is a well-architected system that demonstrates a deep understanding of modern web animation techniques. By combining the strengths of GSAP, Framer Motion, CSS, and custom requestAnimationFrame hooks, the project achieves a rich and performant user experience. This hybrid approach provides a flexible and powerful foundation for creating everything from simple UI transitions to complex, interactive visual effects.
Sources: README.md