"use client";
import { useEffect, useRef } from "react";
export default function Projects() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// Element is in view
entry.target.classList.add("in-view");
entry.target.classList.remove("out-view");
} else {
// Element is out of view
entry.target.classList.add("out-view");
entry.target.classList.remove("in-view");
}
});
},
{
threshold: 0.5,
}
);
const projectImages = document.querySelectorAll(".project-image");
projectImages.forEach((image) => observer.observe(image));
return () => observer.disconnect();
}, []);
return (
<section className="min-h-screen py-20 dark bg-primary">
<h1 className="text-[80px] text-primary text-center mb-20 text-white">Our Work</h1>
<div className="scroll-images-main flex flex-col items-center justify-center pt-20 pb-20 h-screen sticky top-0 overflow-scroll no-scrollbar">
<div ref={containerRef} className="max-w-[1200px] mx-auto">
<div className="grid gap-16 relative">
<div className="project-image opacity-0 translate-y-full transition-all duration-1000 ease-out w-[600px] h-[400px] bg-secondary rounded-lg overflow-hidden">
<img
src="images/1.jpg"
alt="Project 1"
className="w-full h-full object-cover"
/>
</div>
<div className="project-image opacity-0 translate-y-full transition-all duration-1000 ease-out w-[600px] h-[400px] bg-secondary rounded-lg overflow-hidden">
<img
src="images/2.jpg"
alt="Project 2"
className="w-full h-full object-cover"
/>
</div>
<div className="project-image opacity-0 translate-y-full transition-all duration-1000 ease-out w-[600px] h-[400px] bg-secondary rounded-lg overflow-hidden">
<img
src="images/3.jpg"
alt="Project 3"
className="w-full h-full object-cover"
/>
</div>
<div className="project-image opacity-0 translate-y-full transition-all duration-1000 ease-out w-[600px] h-[400px] bg-secondary rounded-lg overflow-hidden">
<img
src="images/4.jpg"
alt="Project 4"
className="w-full h-full object-cover"
/>
</div>
<div className="project-image opacity-0 translate-y-full transition-all duration-1000 ease-out w-[600px] h-[400px] bg-secondary rounded-lg overflow-hidden">
<img
src="images/5.jpg"
alt="Project 5"
className="w-full h-full object-cover"
/>
</div>
</div>
</div>
</div>
<style jsx>{`
.project-image.in-view {
opacity: 1;
transform: translateY(0);
}
.project-image.out-view {
opacity: 0;
transform: translateY(100px);
}
`}</style>
</section>
);
}
First, I want it so that as soon as user's viewport reaches this section, "Our Work" is animated into view (text rolling) and appears at the center of the screen and remains there. So, keep min-h-screen
and Our Work vertically and horizontally centered. This section should then be pinned for viewports multiplied by total images
Next, as the user starts scrolling down, an image from the bottom of the screen starts moving upwards, It slowly scales up until it reaches the center. Then it keeps scaling down until it goes till the top edge and out of view. So there ae 2 animations
Other images keep following that image. Each image's animation begins below the viewprot and ends bove viewport
The first image's animation is triggered when the our work heading is in the center, and the next image's animation is triggered when previous image is in the center
To summarize, each image moves from the below the bottom of the screen to above the top of the screen one by one. As soon as the first image reaches the center the second image starts coming upwards and so on
All the images should move over the "Our Work" text that's at the center of the sceren
Each image has two animations: Below the bottom to the middle, then from the middle to the top
GSAP's ScrollSmoother is paid so find some other alternative so I can "advance" the animation on scroll. Maybe without GSAP entirely
I understand you want to create a smooth scrolling animation for your project showcase. Let's implement this using the Intersection Observer API and some custom scroll-based animations without relying on GSAP. We'll use React's useRef
and useEffect
hooks along with some CSS transitions to achieve the desired effect.
Here's the updated code that implements the animations you've described:
Let me explain the key changes and how this implementation works:
activeIndex
state.activeIndex
accordingly.Each image has three states:
globals.css
file includes an animation for the title to roll into view.This implementation creates a smooth scrolling experience where images appear to move from the bottom of the screen to the top as you scroll, with the active image always centered. The "Our Work" title remains fixed at the center of the screen throughout the scrolling.
To use this component, you would typically place it in your page file:
import Projects from './components/projects';
export default function Home() {
return (
<main>
<Projects />
{/* Other sections */}
</main>
);
}
This solution doesn't rely on GSAP and uses native browser APIs and React hooks to create the desired animation effect. You can further adjust the timing, scaling, and positioning to fine-tune the animation to your exact preferences.
Let me provide you with a complete, self-contained component that you can easily preview. I'll make sure to include all necessary code without any assumptions about existing files or components.
Here's a complete, self-contained component that implements the scrolling image showcase you described:
This component is now self-contained and should be easy to preview. Here's a breakdown of the changes and features:
To use this component in your Next.js app, you can import it into your page file:
import ImageShowcase from './components/image-showcase'
export default function Home() {
return (
<main>
<ImageShowcase />
{/* Other sections */}
</main>
)
}
This implementation should now be previewable in the v0 environment. It creates a smooth scrolling experience where images appear to move from the bottom of the screen to the top as you scroll, with the active image always centered. The "Our Work" title remains fixed at the center of the screen throughout the scrolling.
If you're still having trouble previewing the component, please let me know, and I'll be happy to make any necessary adjustments or provide further assistance.