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',
},
});