import { router } from 'expo-router'; import { useEffect, useRef } from 'react'; import { Animated, Dimensions, Easing, Image, StyleSheet, Text, View, } from 'react-native'; const { width, height } = Dimensions.get('window'); /* -------------------------------------------------------------------------- */ /* Tokens */ /* -------------------------------------------------------------------------- */ const GREEN = '#4e8214'; const LIME = '#6fa62b'; const SPLASH_DURATION = 2800;// tempo total até navegar /* -------------------------------------------------------------------------- */ /* Helpers de animação */ /* -------------------------------------------------------------------------- */ const loopUp = ( value: Animated.Value, duration: number, delay = 0, easing: (v: number) => number = Easing.linear ) => Animated.loop( Animated.sequence([ Animated.delay(delay), Animated.timing(value, { toValue: 1, duration, easing, useNativeDriver: true, }), Animated.timing(value, { toValue: 0, duration: 0, useNativeDriver: true, }), ]) ); const loopPingPong = ( value: Animated.Value, duration: number, delay = 0 ) => Animated.loop( Animated.sequence([ Animated.delay(delay), Animated.timing(value, { toValue: 1, duration, easing: Easing.inOut(Easing.sin), useNativeDriver: true, }), Animated.timing(value, { toValue: 0, duration, easing: Easing.inOut(Easing.sin), useNativeDriver: true, }), ]) ); /* -------------------------------------------------------------------------- */ /* Configuração das partículas */ /* -------------------------------------------------------------------------- */ type BubbleConfig = { size: number; left: number; delay: number; duration: number; color: string; drift: number; outline?: boolean; }; const BUBBLES: BubbleConfig[] = [ { size: 26, left: 0.10, delay: 0, duration: 5200, color: 'rgba(78,130,20,0.22)', drift: 26, outline: true }, { size: 12, left: 0.18, delay: 900, duration: 4200, color: 'rgba(78,130,20,0.55)', drift: -18 }, { size: 34, left: 0.26, delay: 1800, duration: 6000, color: 'rgba(111,166,43,0.16)', drift: 34, outline: true }, { size: 8, left: 0.33, delay: 400, duration: 3800, color: 'rgba(8,51,24,0.45)', drift: 14 }, { size: 18, left: 0.41, delay: 2400, duration: 4800, color: 'rgba(78,130,20,0.35)', drift: -28 }, { size: 10, left: 0.49, delay: 1300, duration: 4000, color: 'rgba(111,166,43,0.60)', drift: 20 }, { size: 28, left: 0.57, delay: 200, duration: 5600, color: 'rgba(8,51,24,0.14)', drift: -22, outline: true }, { size: 14, left: 0.65, delay: 2000, duration: 4400, color: 'rgba(78,130,20,0.42)', drift: 24 }, { size: 9, left: 0.72, delay: 3000, duration: 3600, color: 'rgba(8,51,24,0.40)', drift: -16 }, { size: 22, left: 0.80, delay: 700, duration: 5000, color: 'rgba(111,166,43,0.20)', drift: 30, outline: true }, { size: 11, left: 0.88, delay: 2600, duration: 4200, color: 'rgba(78,130,20,0.50)', drift: -20 }, { size: 16, left: 0.94, delay: 1500, duration: 4600, color: 'rgba(78,130,20,0.28)', drift: 18 }, ]; type LeafConfig = { size: number; left: number; delay: number; duration: number; color: string; spin: number; drift: number; }; const LEAVES: LeafConfig[] = [ { size: 22, left: 0.14, delay: 600, duration: 6200, color: 'rgba(78,130,20,0.30)', spin: 300, drift: 40 }, { size: 15, left: 0.37, delay: 2800, duration: 5400, color: 'rgba(111,166,43,0.34)', spin: -260, drift: -34 }, { size: 26, left: 0.62, delay: 1400, duration: 6800, color: 'rgba(8,51,24,0.18)', spin: 220, drift: 46 }, { size: 18, left: 0.85, delay: 3400, duration: 5800, color: 'rgba(78,130,20,0.26)', spin: -320, drift: -28 }, ]; const RAY_COUNT = 14; /* -------------------------------------------------------------------------- */ /* Componente */ /* -------------------------------------------------------------------------- */ export default function Splash() { // entrada const logoScale = useRef(new Animated.Value(0.55)).current; const logoOpacity = useRef(new Animated.Value(0)).current; const logoSpin = useRef(new Animated.Value(0)).current; const textOpacity = useRef(new Animated.Value(0)).current; const textSlide = useRef(new Animated.Value(18)).current; const barOpacity = useRef(new Animated.Value(0)).current; const glowScale = useRef(new Animated.Value(0)).current; const progressWidth = useRef(new Animated.Value(0)).current; // ambiente (loops) const breath = useRef(new Animated.Value(0)).current; const haloPulse = useRef(new Animated.Value(0)).current; const raysSpin = useRef(new Animated.Value(0)).current; const shimmer = useRef(new Animated.Value(0)).current; const barShine = useRef(new Animated.Value(0)).current; const orbit = useRef(new Animated.Value(0)).current; const ring1 = useRef(new Animated.Value(0)).current; const ring2 = useRef(new Animated.Value(0)).current; const ring3 = useRef(new Animated.Value(0)).current; const bubbles = useRef(BUBBLES.map(() => new Animated.Value(0))).current; const leaves = useRef(LEAVES.map(() => new Animated.Value(0))).current; useEffect(() => { // --- atmosfera contínua --- loopUp(raysSpin, 34000).start(); loopPingPong(haloPulse, 2200).start(); loopPingPong(breath, 2600, 1200).start(); loopUp(orbit, 9000).start(); loopUp(shimmer, 3200, 1400).start(); loopUp(barShine, 1600, 1200).start(); loopUp(ring1, 3000, 400, Easing.out(Easing.quad)).start(); loopUp(ring2, 3000, 1400, Easing.out(Easing.quad)).start(); loopUp(ring3, 3000, 2400, Easing.out(Easing.quad)).start(); bubbles.forEach((value, i) => { const cfg = BUBBLES[i]; loopUp(value, cfg.duration, cfg.delay, Easing.out(Easing.quad)).start(); }); leaves.forEach((value, i) => { const cfg = LEAVES[i]; loopUp(value, cfg.duration, cfg.delay, Easing.linear).start(); }); // --- sequência de entrada --- Animated.sequence([ Animated.parallel([ Animated.timing(glowScale, { toValue: 1, duration: 900, easing: Easing.out(Easing.cubic), useNativeDriver: true, }), Animated.timing(logoOpacity, { toValue: 1, duration: 600, useNativeDriver: true, }), Animated.timing(logoSpin, { toValue: 1, duration: 900, easing: Easing.out(Easing.cubic), useNativeDriver: true, }), Animated.spring(logoScale, { toValue: 1, friction: 5, tension: 65, useNativeDriver: true, }), ]), Animated.parallel([ Animated.timing(textOpacity, { toValue: 1, duration: 600, useNativeDriver: true, }), Animated.timing(textSlide, { toValue: 0, duration: 600, easing: Easing.out(Easing.cubic), useNativeDriver: true, }), Animated.timing(barOpacity, { toValue: 1, duration: 400, useNativeDriver: true, }), Animated.timing(progressWidth, { toValue: 1, duration: 3600, easing: Easing.inOut(Easing.quad), useNativeDriver: false, }), ]), ]).start(); const timer = setTimeout(() => { router.replace('/menu-principal'); }, SPLASH_DURATION); return () => clearTimeout(timer); }, []); /* ---------------------------------------------------------------------- */ /* Interpolações */ /* ---------------------------------------------------------------------- */ const animatedProgress = progressWidth.interpolate({ inputRange: [0, 1], outputRange: ['0%', '100%'], }); const haloScale = haloPulse.interpolate({ inputRange: [0, 1], outputRange: [1, 1.18], }); const haloOpacity = haloPulse.interpolate({ inputRange: [0, 1], outputRange: [0.9, 0.45], }); const breathScale = breath.interpolate({ inputRange: [0, 1], outputRange: [1, 1.045], }); const raysRotate = raysSpin.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'], }); const logoRotate = logoSpin.interpolate({ inputRange: [0, 1], outputRange: ['-9deg', '0deg'], }); const shimmerX = shimmer.interpolate({ inputRange: [0, 1], outputRange: [-230, 230], }); const shimmerOpacity = shimmer.interpolate({ inputRange: [0, 0.15, 0.85, 1], outputRange: [0, 1, 1, 0], }); const barShineX = barShine.interpolate({ inputRange: [0, 1], outputRange: [-90, 230], }); const orbitRotate = orbit.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'], }); /* ---------------------------------------------------------------------- */ /* Renderizadores */ /* ---------------------------------------------------------------------- */ const renderBubble = (cfg: BubbleConfig, value: Animated.Value, key: string) => { const translateY = value.interpolate({ inputRange: [0, 1], outputRange: [0, -(height * 0.95)], }); const translateX = value.interpolate({ inputRange: [0, 0.35, 0.7, 1], outputRange: [0, cfg.drift, -cfg.drift * 0.6, cfg.drift * 0.3], }); const opacity = value.interpolate({ inputRange: [0, 0.12, 0.75, 1], outputRange: [0, 1, 0.7, 0], }); const scale = value.interpolate({ inputRange: [0, 0.4, 1], outputRange: [0.35, 1, 0.7], }); return ( ); }; const renderLeaf = (cfg: LeafConfig, value: Animated.Value, key: string) => { const translateY = value.interpolate({ inputRange: [0, 1], outputRange: [0, -(height * 1.05)], }); const translateX = value.interpolate({ inputRange: [0, 0.3, 0.65, 1], outputRange: [0, cfg.drift, -cfg.drift * 0.7, cfg.drift * 0.4], }); const rotate = value.interpolate({ inputRange: [0, 1], outputRange: ['0deg', `${cfg.spin}deg`], }); const opacity = value.interpolate({ inputRange: [0, 0.15, 0.8, 1], outputRange: [0, 1, 0.8, 0], }); return ( ); }; /* ---------------------------------------------------------------------- */ return ( {/* washes de fundo */} {/* raios girando */} {Array.from({ length: RAY_COUNT }).map((_, i) => ( ))} {/* ondas concêntricas */} {[ring1, ring2, ring3].map((value, i) => { const scale = value.interpolate({ inputRange: [0, 1], outputRange: [0.35, 2.4], }); const opacity = value.interpolate({ inputRange: [0, 0.15, 1], outputRange: [0, 0.3, 0], }); return ( ); })} {/* halos */} {/* partículas */} {BUBBLES.map((cfg, i) => renderBubble(cfg, bubbles[i], `bubble-${i}`))} {LEAVES.map((cfg, i) => renderLeaf(cfg, leaves[i], `leaf-${i}`))} {/* órbita de pontos ao redor da logo */} {/* logo */} {/* brilho que varre a logo */} {/* texto */} Bioinsumos Tecnologia Sustentabilidade {/* barra de progresso */} Preparando seu ambiente ); } /* -------------------------------------------------------------------------- */ /* Estilos */ /* -------------------------------------------------------------------------- */ const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#FFFFFF', alignItems: 'center', justifyContent: 'center', overflow: 'hidden', }, /* fundo */ wash: { position: 'absolute', width: width * 1.6, height: width * 1.6, borderRadius: width * 1.6, }, washTop: { top: -width * 1.0, left: -width * 0.5, backgroundColor: 'rgba(111, 166, 43, 0.07)', }, washBottom: { bottom: -width * 1.0, right: -width * 0.5, backgroundColor: 'rgba(8, 51, 24, 0.05)', }, /* raios */ raysBox: { position: 'absolute', width: width * 1.8, height: width * 1.8, alignItems: 'center', justifyContent: 'center', }, ray: { position: 'absolute', width: 2, height: width * 1.8, backgroundColor: 'rgba(78, 130, 20, 0.05)', }, /* ondas */ ringsBox: { position: 'absolute', width: width * 0.75, height: width * 0.75, alignItems: 'center', justifyContent: 'center', }, ring: { position: 'absolute', width: width * 0.75, height: width * 0.75, borderRadius: width, borderWidth: 1.5, borderColor: GREEN, }, /* halos */ glow: { position: 'absolute', width: width * 0.86, height: width * 0.86, borderRadius: width, backgroundColor: 'rgba(78, 130, 20, 0.11)', }, glowSoft: { position: 'absolute', width: width * 0.55, height: width * 0.55, borderRadius: width, backgroundColor: 'rgba(8, 51, 24, 0.07)', }, /* partículas */ particle: { position: 'absolute', }, leaf: { position: 'absolute', borderTopRightRadius: 3, borderBottomLeftRadius: 3, }, /* órbita */ orbitBox: { position: 'absolute', width: width * 0.78, height: width * 0.78, }, orbitDot: { position: 'absolute', width: 8, height: 8, borderRadius: 4, backgroundColor: LIME, }, orbitDotSmall: { width: 6, height: 6, borderRadius: 3, backgroundColor: 'rgba(8, 51, 24, 0.45)', }, /* logo */ logoBox: { width: 300, height: 200, alignItems: 'center', justifyContent: 'center', overflow: 'hidden', }, logo: { width: 300, height: 200, }, shimmer: { position: 'absolute', top: -60, width: 46, height: 340, backgroundColor: 'rgba(255, 255, 255, 0.55)', }, /* texto */ textBox: { marginTop: 22, alignItems: 'center', }, tagRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, tagLine: { width: 18, height: 1.5, backgroundColor: 'rgba(78, 130, 20, 0.45)', marginHorizontal: 8, }, subtitle: { fontSize: 12, color: GREEN, fontWeight: '700', letterSpacing: 0.6, textTransform: 'uppercase', }, dot: { width: 3, height: 3, borderRadius: 2, backgroundColor: LIME, marginHorizontal: 7, }, /* progresso */ progressWrap: { position: 'absolute', bottom: 68, alignItems: 'center', }, progressBar: { width: 210, height: 6, borderRadius: 10, backgroundColor: 'rgba(8, 51, 24, 0.10)', overflow: 'hidden', }, progressFill: { height: '100%', backgroundColor: GREEN, borderRadius: 10, }, progressShine: { position: 'absolute', top: -14, width: 26, height: 40, backgroundColor: 'rgba(255, 255, 255, 0.7)', }, loadingLabel: { marginTop: 12, fontSize: 11, letterSpacing: 1.2, color: 'rgba(8, 51, 24, 0.45)', fontWeight: '600', textTransform: 'uppercase', }, });