Animation System
Relevant source files
The following files were used as context for generating this wiki page:
The animation system in the grapevine_website project is designed to add motion and visual feedback to UI elements, primarily triggered by user scrolling. It is built upon the framer-motion library, providing a flexible framework for both simple, reusable animations and complex, bespoke animated sequences.
The system's core is the AnimateOnScroll component, a wrapper that applies pre-defined animations to elements as they enter the viewport. For more intricate scenarios, such as conditional rendering or interactive effects, the project utilizes framer-motion's motion components and hooks directly. This dual approach allows for rapid implementation of common effects while retaining the power for custom-tailored animations.
Core Technology
The entire animation system is powered by the Framer Motion library, a popular and powerful animation library for React. Its inclusion is declared as a dependency in the project's configuration.
Sources: package.json
The AnimateOnScroll Component
This is the primary workhorse for scroll-triggered animations across the application. It's a reusable wrapper component that animates its children when they become visible in the viewport.
Sources: components/animations/animate-on-scroll.tsx
Component Architecture
The component leverages framer-motion's useInView hook to detect when the component is visible. A ref is attached to a motion.div element, and when useInView reports it as visible, the component's animation state transitions from initial to animate.
The following diagram illustrates the component's lifecycle and logic.
Properties (Props)
The AnimateOnScroll component accepts several props to customize its behavior.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | The content to be animated. |
animation | "fade-up" | "fade-down" | "fade-left" | "fade-right" | "fade" | "scale" | "slide-up" | "fade-up" | The pre-defined animation style to apply. |
delay | number | 0 | The delay in seconds before the animation starts. |
duration | number | 0.5 | The duration of the animation in seconds. |
once | boolean | true | If true, the animation only runs once. If false, it runs every time the element enters the viewport. |
amount | number | 0.3 | The percentage of the element that must be visible for the animation to trigger (0 to 1). |
className | string | "" | Custom CSS classes to apply to the wrapping motion.div. |
style | CSSProperties | - | Custom inline styles to apply to the wrapping motion.div. |
Sources: components/animations/animate-on-scroll.tsx:7-19
Pre-defined Animations
The component includes a set of pre-defined animations that can be selected via the animation prop.
| Name | Initial State | Animate State |
|---|---|---|
fade-up | { opacity: 0, y: 40 } | { opacity: 1, y: 0 } |
fade-down | { opacity: 0, y: -40 } | { opacity: 1, y: 0 } |
fade-left | { opacity: 0, x: -40 } | { opacity: 1, x: 0 } |
fade-right | { opacity: 0, x: 40 } | { opacity: 1, x: 0 } |
fade | { opacity: 0 } | { opacity: 1 } |
scale | { opacity: 0, scale: 0.8 } | { opacity: 1, scale: 1 } |
slide-up | { y: 60, opacity: 0 } | { y: 0, opacity: 1 } |
Sources: components/animations/animate-on-scroll.tsx:23-54
Implementation Examples
The animation system is used throughout the site in various ways, from simple content fade-ins to complex, interactive sequences.
Simple Staggered Animations
A common pattern is to apply a fade-up animation to a list or grid of items with a staggered delay. This creates a pleasant, sequential reveal effect. The StatsSection component uses this for its stat cards.
// components/stats-section.tsx:48-54
{stats.map((stat, index) => (
<AnimateOnScroll
key={index}
animation="fade-up"
delay={index * 0.1}
className="relative text-center lg:px-4"
>
{/* ... stat content ... */}
</AnimateOnScroll>
))}
Sources: components/stats-section.tsx:48-54, components/featured-resources.tsx:47-48
Conditional Rendering Animations
The ContactForm component demonstrates how to animate elements that are conditionally rendered, such as a success or error message. It uses framer-motion's <AnimatePresence> component, which detects when a child component is added to or removed from the React tree and applies animations accordingly.
The success message uses initial, animate, and exit props on a motion.div to control its appearance and disappearance.
This diagram shows the sequence for displaying the success message.
Sources: components/contact-form.tsx:210-229
Complex & Bespoke Animations
For animations that are more complex than the pre-defined effects in AnimateOnScroll, components use motion elements directly. The MarketplaceOverview component is a prime example.
- Infinite Rotation: A dotted circle is animated to rotate indefinitely.
// components/marketplace-overview.tsx:68-74 <motion.div className="border-primary/30 absolute inset-0 rounded-full border-2 border-dashed" animate={{ rotate: 360 }} transition={{ duration: 30, repeat: Infinity, ease: "linear", }} /> - Scroll-Triggered & Hover Effects: Surrounding icons animate into view using
whileInViewand scale up on hover usingwhileHover. This combines scroll-based triggers with user interaction feedback.
Sources: components/marketplace-overview.tsx:68-74, components/marketplace-overview.tsx:94-126
Animation Lifecycle & Control
Beyond simple scroll triggers, the system includes more advanced control over animation lifecycles, particularly for interactive components.
Autoplay and User Interaction
The Features component implements an auto-playing carousel that cycles through different feature steps.
- Autoplay: A
setIntervalfunction is used to automatically advance the active feature index. - Viewport Awareness: An
IntersectionObserverensures the autoplay only runs when the component is visible on screen (isInView). - Interaction Pause: When a user clicks on a feature, the autoplay is paused for 10 seconds by clearing and resetting the interval timer.
This demonstrates a stateful animation system that responds to both its visibility and direct user input.
Sources: components/features.tsx:73-81, components/features.tsx:59-71
Conclusion
The animation system in grapevine_website effectively uses framer-motion to enhance user experience. It provides a robust, two-tiered approach: the AnimateOnScroll component offers a simple, declarative way to implement common scroll-triggered animations, promoting consistency and rapid development. For more unique and complex requirements, developers can leverage the full power of framer-motion's API directly. This combination results in a visually engaging website with dynamic, responsive, and meaningful animations.