diff --git a/client/src/components/netflix-grid.tsx b/client/src/components/netflix-grid.tsx
index 7edd4f8..7df2b4d 100644
--- a/client/src/components/netflix-grid.tsx
+++ b/client/src/components/netflix-grid.tsx
@@ -137,17 +137,14 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
const [showLeftButton, setShowLeftButton] = useState(false);
const [showRightButton, setShowRightButton] = useState(true);
- const [currentIndex, setCurrentIndex] = useState(0);
+ const [translateX, setTranslateX] = useState(0);
+ const [isScrolling, setIsScrolling] = useState(false);
const videosToShow = 5; // Show 5 videos at a time
+ const videoWidth = 120; // Width + spacing
const scroll = (direction: 'left' | 'right') => {
- if (direction === 'right') {
- // Always move forward in the circle - perpetual motion
- setCurrentIndex(prev => prev + 1);
- } else {
- // For left arrow, also move forward but faster to create illusion of reverse
- setCurrentIndex(prev => prev + 1);
- }
+ const speed = direction === 'right' ? videoWidth : -videoWidth;
+ setTranslateX(prev => prev - speed);
};
const startAutoScroll = (direction: 'left' | 'right') => {
@@ -156,29 +153,41 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
clearInterval(scrollIntervalRef.current);
}
- // Both directions move forward - true perpetual motion carousel
- scrollIntervalRef.current = setInterval(() => {
- setCurrentIndex(prev => prev + 1);
- }, direction === 'left' ? 600 : 800); // Left moves slightly faster for effect
+ setIsScrolling(true);
+
+ // Continuous smooth flowing animation
+ const speed = direction === 'right' ? 2 : -2; // pixels per frame
+
+ const animate = () => {
+ setTranslateX(prev => {
+ const newValue = prev - speed;
+ const totalWidth = category.videos.length * videoWidth;
+
+ // Reset position for infinite loop
+ if (direction === 'right' && newValue <= -totalWidth) {
+ return 0;
+ } else if (direction === 'left' && newValue >= 0) {
+ return -totalWidth + videoWidth;
+ }
+
+ return newValue;
+ });
+
+ if (isScrolling) {
+ scrollIntervalRef.current = requestAnimationFrame(animate);
+ }
+ };
+
+ animate();
};
- // Initialize in middle section for smooth infinite scroll
+ // Initialize starting position
useEffect(() => {
if (category.videos.length > 0) {
- setCurrentIndex(category.videos.length); // Start in middle section for smooth wrapping
+ setTranslateX(-category.videos.length * videoWidth); // Start in middle section
}
}, [category.videos.length]);
- // Handle seamless infinite scroll - only forward movement
- useEffect(() => {
- const totalVideos = category.videos.length;
- if (currentIndex >= totalVideos * 2) {
- // When we reach the end, seamlessly jump back to start of middle section
- // This creates the illusion of infinite forward movement
- setCurrentIndex(currentIndex - totalVideos);
- }
- }, [currentIndex, category.videos.length]);
-
// Always show both buttons
useEffect(() => {
setShowLeftButton(true);
@@ -186,8 +195,9 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {
}, []);
const stopAutoScroll = () => {
+ setIsScrolling(false);
if (scrollIntervalRef.current) {
- clearInterval(scrollIntervalRef.current);
+ cancelAnimationFrame(scrollIntervalRef.current);
scrollIntervalRef.current = null;
}
};
@@ -281,13 +291,14 @@ function CategoryRow({ category, onVideoClick }: CategoryRowProps) {