UNPKG

testeranto

Version:

the AI powered BDD test framework for typescript projects

257 lines (256 loc) 11.5 kB
import React, { useEffect, useState, useRef } from 'react'; const SunriseAnimation = ({ active }) => { const [position, setPosition] = useState(0); const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); const animationIdRef = useRef(null); useEffect(() => { // Set initial dimensions setDimensions({ width: window.innerWidth, height: window.innerHeight }); const handleResize = () => { setDimensions({ width: window.innerWidth, height: window.innerHeight }); }; window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); }; }, []); // Animation timing parameters const ANIMATION_DURATION = 10000; //30000; // 30 seconds for full day/night cycle const UPDATE_INTERVAL = 50; // Update every 50ms (~20fps) useEffect(() => { if (!active) { // Clean up animation frame if active becomes false if (animationIdRef.current) { cancelAnimationFrame(animationIdRef.current); animationIdRef.current = null; } return; } console.log('Starting animation with duration:', ANIMATION_DURATION, 'ms'); let startTime = performance.now(); let lastUpdateTime = 0; const animate = (timestamp) => { if (!active) return; const elapsed = (timestamp - startTime) % ANIMATION_DURATION; const progress = elapsed / ANIMATION_DURATION; // Only update if enough time has passed since last update if (timestamp - lastUpdateTime >= UPDATE_INTERVAL) { // Use cosine for smooth transition from -1 to 1 over full duration const newPos = Math.cos(progress * Math.PI * 2); setPosition(newPos); lastUpdateTime = timestamp; } animationIdRef.current = requestAnimationFrame(animate); }; // Start the animation loop animationIdRef.current = requestAnimationFrame(animate); return () => { if (animationIdRef.current) { cancelAnimationFrame(animationIdRef.current); animationIdRef.current = null; } }; }, [active]); const yPos = dimensions.height * (1 - position); const normalizedPos = (position + 1) / 2; // Convert from [-1,1] to [0,1] if (!active) return null; return (React.createElement("div", { id: "sunrise", style: { width: '100vw', height: '100vh', position: 'fixed', top: 0, left: 0, backgroundColor: 'transparent', overflow: 'hidden', pointerEvents: 'none' } }, React.createElement("div", { id: "daily-bg", style: { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', backgroundColor: 'rgba(0,0,0,0.3)', zIndex: -1001 } }), "Stars Container", React.createElement("div", { id: "starsContainer", style: { perspective: 350, perspectiveOrigin: '50% 300%', overflow: 'hidden', position: 'absolute', top: 0, left: '-50%', width: '200%', height: '50%', zIndex: -1000, opacity: Math.max(0, 0.5 - normalizedPos * 0.5) } }, React.createElement("div", { id: "stars", style: { backgroundRepeat: 'repeat', position: 'absolute', width: '200%', height: '200%', left: '-50%', bottom: 0, opacity: 0.5, transform: 'rotateX(-90deg)' } })), React.createElement("div", { id: "sun", style: { position: 'absolute', top: 0, left: '50%', transform: `translateX(-50%) translateY(${yPos}px)`, width: '100%', height: '50%', background: `radial-gradient(50% ${yPos}px, circle, rgba(242,248,247,1) 0%,rgba(249,249,28,1) 3%,rgba(247,214,46,1) 8%,rgba(248,200,95,1) 12%,rgba(201,165,132,1) 30%,rgba(115,130,133,1) 51%,rgba(46,97,122,1) 85%,rgba(24,75,106,1) 100%)`, zIndex: -900, opacity: 0.5 } }), React.createElement("div", { id: "sunDay", style: { position: 'absolute', top: 0, left: 0, width: '100%', height: '50%', background: `radial-gradient(50% ${yPos}px, circle, rgba(252,255,251,0.9) 0%,rgba(253,250,219,0.4) 30%,rgba(226,219,197,0.01) 70%,rgba(226,219,197,0.0) 70%,rgba(201,165,132,0) 100%)`, zIndex: -800, opacity: Math.max(0, 1 - yPos / dimensions.height) } }), React.createElement("div", { id: "sunSet", style: { position: 'absolute', top: 0, left: 0, width: '100%', height: '50%', background: `radial-gradient(50% ${yPos}px, circle, rgba(254,255,255,0.8) 5%,rgba(236,255,0,1) 10%,rgba(253,50,41,1) 25%,rgba(243,0,0,1) 40%,rgba(93,0,0,1) 100%)`, zIndex: -800, opacity: Math.max(0, yPos / dimensions.height - 0.2) } }), React.createElement("div", { id: "sky", style: { position: 'absolute', top: 0, left: 0, width: '100%', height: '50%', zIndex: -700, background: 'linear-gradient(to top, rgba(249,251,240,1) 10%,rgba(215,253,254,1) 20%,rgba(167,222,253,1) 40%,rgba(110,175,255,1) 100%)', opacity: Math.max(0, 1 - yPos / dimensions.height) } }), React.createElement("div", { id: "horizon", style: { position: 'absolute', top: 0, left: 0, width: '100%', height: '50%', background: 'linear-gradient(to top, rgba(212,87,43,0.9) 0%,rgba(246,149,52,0.8) 20%,rgba(24,75,106,0) 100%)', zIndex: -700, opacity: Math.max(0, yPos > dimensions.height / 2 ? (dimensions.height - yPos) / (dimensions.height / 2) + 0.2 : yPos / (dimensions.height / 2)) } }), React.createElement("div", { id: "horizonNight", style: { position: 'absolute', top: 0, left: 0, width: '100%', height: '50%', background: 'linear-gradient(to top, rgba(57,167,255,1) 0%,rgba(13,98,245,1) 20%,rgba(0,11,22,0.1) 60%)', zIndex: -600, opacity: Math.max(0, (yPos - (dimensions.height * 4 / 5)) / (dimensions.height - (dimensions.height * 4 / 5))) } }), React.createElement("div", { id: "moon", style: { position: 'absolute', top: 0, left: 0, width: '100%', height: '50%', background: 'radial-gradient(40% 55%, circle, rgba(249,249,250,1) -1%,rgba(189,255,254,1) 1%,rgba(8,49,78,1) 1%,rgba(8,26,56,1) 10%,rgba(4,16,46,1) 40%,rgba(2,8,13,1) 70%)', zIndex: -500, opacity: Math.max(0, (yPos - (dimensions.height * 9 / 10)) / (dimensions.height - (dimensions.height * 9 / 10))) } }), React.createElement("div", { id: "water", style: { overflow: 'hidden', position: 'absolute', bottom: 0, left: 0, width: '100%', height: '50%', background: 'linear-gradient(to top, rgba(0,25,45,1) 0%,rgba(14,71,117,1) 35%,rgba(26,126,174,1) 70%,rgba(62,168,220,1) 100%)', zIndex: -400 } }), React.createElement("div", { id: "waterReflectionContainer", style: { perspective: 30, perspectiveOrigin: `50% ${-15 + (normalizedPos * 30)}%`, overflow: 'hidden', position: 'absolute', top: '50%', left: '-3%', width: '103%', height: '50%', zIndex: -300, transform: `translateY(${dimensions.height - yPos}px)` } }, React.createElement("div", { id: "waterReflectionMiddle", style: { position: 'absolute', top: 0, left: '-50%', width: '200%', height: '55%', background: 'radial-gradient(50% 0px, rgba(247,177,72,1) 3%,rgba(248,175,65,1) 6%,rgba(207,62,30,0.4) 35%,rgba(176,91,48,0.1) 45%,rgba(141,88,47,0.0) 60%,rgba(116,82,63,0.0) 70%,rgba(44,65,68,0.0) 80%,rgba(7,19,31,0.0) 100%)', zIndex: -200, opacity: Math.max(0, yPos > dimensions.height / 2 ? (dimensions.height - yPos) / (dimensions.height / 2) - 0.1 : yPos / (dimensions.height / 2) - 0.1), transform: 'rotateX(45deg)' } })), React.createElement("div", { id: "waterDistance", style: { position: 'absolute', bottom: 0, left: 0, width: '100%', height: '50%', background: 'linear-gradient(90deg, rgba(0,0,0,0.0) 10%,rgba(0,0,0,0.20) 44%,rgba(0,0,0,0.65) 95%,rgba(0,0,0,0.62) 100%)', zIndex: -100, opacity: Math.max(0, yPos / dimensions.height + 0.6) } }), React.createElement("div", { id: "darknessOverlaySky", style: { backgroundColor: '#000', opacity: Math.max(0, (yPos - (dimensions.height * 7 / 10)) / (dimensions.height - (dimensions.height * 7 / 10))), position: 'absolute', top: 0, left: 0, width: '100%', height: '50%', zIndex: -50 } }), React.createElement("div", { id: "darknessOverlay", style: { backgroundColor: '#000', opacity: Math.max(0, (yPos - (dimensions.height / 2)) / (dimensions.height / 2)), position: 'absolute', bottom: 0, left: 0, width: '100%', height: '50%', zIndex: -5 } }), React.createElement("div", { id: "oceanRipple", style: { backgroundImage: 'repeating-linear-gradient(175deg, rgba(165,165,165,0.08) 43%,rgba(175,175,175,0.08) 45%,rgba(235,235,235,0.08) 49%,rgba(195,195,195,0.08) 50%,rgba(165,165,165,0.08) 54%)', opacity: 0.5, position: 'absolute', left: '0%', bottom: 0, width: '100%', height: '50%', zIndex: -10 } }))); }; export default SunriseAnimation;