From c85660e5294657838184318a2c2028bf50c2ad20 Mon Sep 17 00:00:00 2001
From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com>
Date: Fri, 29 Aug 2025 15:05:04 +0000
Subject: [PATCH] Make video rows flow continuously and smoothly like water
Update the Netflix grid component to use CSS transforms for smooth, continuous scrolling animations instead of incremental index changes, improving the visual experience of video rows.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 2eb1084e-b728-4449-9231-f1665924c8d5
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/2eb1084e-b728-4449-9231-f1665924c8d5/QCN70f2
---
client/src/components/netflix-grid.tsx | 69 +++++++++++++++-----------
1 file changed, 40 insertions(+), 29 deletions(-)
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) {