import React, { useMemo, useEffect, useRef } from 'react';
import { motion, useMotionValue, useTransform, useAnimationFrame } from 'framer-motion';
// Function to generate a random number within a range
const random = (min, max) => Math.random() * (max - min) + min;
// Create a single line element
const Line = ({ width, delay }) => (
);
// Create the scrolling background component
const ScrollingTextBackground = ({ duration = 30 }) => {
const numLines = 50;
const lines = useMemo(() => {
return Array.from({ length: numLines }).map((_, i) => ({
id: i,
width: random(20, 80),
delay: random(0, 1),
}));
}, []);
// --- Manual Animation Logic ---
const yProgress = useMotionValue(0); // Tracks progress from 0 to 1
const yPercentage = useTransform(yProgress, [0, 1], ["0%", "-50%"]); // Maps progress to Y offset
const lastFrameTime = useRef(performance.now());
const animationFrameId = useRef(null); // To store the request ID
const currentDuration = useRef(duration); // Store duration in a ref
// Update the duration ref whenever the prop changes
useEffect(() => {
currentDuration.current = duration;
}, [duration]);
useAnimationFrame((timestamp) => {
const deltaTime = timestamp - lastFrameTime.current;
// Guard against potentially huge deltaTime after remount or tab backgrounding.
// Only update animation if deltaTime is reasonable (e.g., < 1 second).
// Also handle potential negative deltaTime if clocks adjust.
if (deltaTime < 0 || deltaTime > 1000) {
lastFrameTime.current = timestamp; // Reset for the next frame
return; // Skip animation update for this frame
}
lastFrameTime.current = timestamp; // Update time for the next frame calculation
// Calculate progress increment based on current duration
// duration is in seconds, deltaTime in ms. Convert duration to ms.
const progressIncrement = deltaTime / (currentDuration.current * 1000);
// Update progress, wrapping around using modulo
const newProgress = (yProgress.get() + progressIncrement) % 1;
yProgress.set(newProgress);
});
// --- End Manual Animation Logic ---
return (
{/* First block of lines */}
{lines.map(line => (
))}
{/* Second block of lines */}
{lines.map(line => (
))}
);
};
export default ScrollingTextBackground;