A React Native app for the ultimate thinking partner.
at main 87 lines 2.2 kB view raw
1/** 2 * useRainbowAnimation Hook 3 * 4 * Manages the rainbow color cycling animation for the input box. 5 * 6 * Animation triggers when ANY of these conditions are true: 7 * - Streaming in progress (agent is responding) 8 * - Input is focused (user is typing) 9 * - Reasoning blocks are expanded (user viewing agent thoughts) 10 * - No messages yet (empty state / first time experience) 11 * 12 * Returns an Animated.Value that cycles through 6 rainbow colors 13 * over 3 seconds in a continuous loop. 14 * 15 * Color sequence: Red -> Yellow -> Green -> Blue -> Purple -> Red 16 */ 17 18import { useEffect, useRef } from 'react'; 19import { Animated } from 'react-native'; 20 21interface UseRainbowAnimationParams { 22 isStreaming: boolean; 23 isInputFocused: boolean; 24 hasExpandedReasoning: boolean; 25 hasMessages: boolean; 26} 27 28export function useRainbowAnimation({ 29 isStreaming, 30 isInputFocused, 31 hasExpandedReasoning, 32 hasMessages, 33}: UseRainbowAnimationParams) { 34 const rainbowAnimValue = useRef(new Animated.Value(0)).current; 35 36 // Determine if animation should be active 37 const shouldAnimate = isStreaming || isInputFocused || hasExpandedReasoning || !hasMessages; 38 39 useEffect(() => { 40 if (shouldAnimate) { 41 // Reset to start position 42 rainbowAnimValue.setValue(0); 43 44 // Create looping animation 45 const animation = Animated.loop( 46 Animated.timing(rainbowAnimValue, { 47 toValue: 1, 48 duration: 3000, 49 useNativeDriver: false, // Color interpolation requires false 50 }) 51 ); 52 53 animation.start(); 54 55 return () => { 56 animation.stop(); 57 }; 58 } else { 59 // Stop animation when conditions no longer met 60 rainbowAnimValue.stopAnimation(); 61 } 62 }, [shouldAnimate, rainbowAnimValue]); 63 64 return { 65 rainbowAnimValue, 66 isAnimating: shouldAnimate, 67 }; 68} 69 70/** 71 * Rainbow color interpolation configuration 72 * 73 * Use with Animated.Text or Animated.View: 74 * 75 * color: rainbowAnimValue.interpolate({ 76 * inputRange: [0, 0.2, 0.4, 0.6, 0.8, 1], 77 * outputRange: RAINBOW_COLORS 78 * }) 79 */ 80export const RAINBOW_COLORS = [ 81 '#FF6B6B', // Red 82 '#FFD93D', // Yellow 83 '#6BCF7F', // Green 84 '#4D96FF', // Blue 85 '#9D4EDD', // Purple 86 '#FF6B6B', // Red (loop back) 87] as const;