| | import { useRef, useEffect } from 'react'; |
| |
|
| | |
| | |
| | |
| | export const StatusIndicator = ({ handDetected }) => { |
| | return ( |
| | <div className="absolute bottom-4 left-4 flex items-center"> |
| | <div className={`w-3 h-3 rounded-full ${handDetected ? 'bg-[#217BFE]' : 'bg-gray-400'}`}></div> |
| | <span className={`ml-2 text-xs ${handDetected ? 'text-[#217BFE] font-medium' : 'text-gray-500'}`}> |
| | {handDetected ? 'Hand detected' : 'No hand detected'} |
| | </span> |
| | </div> |
| | ); |
| | }; |
| |
|
| | |
| | |
| | |
| | export const AudioEffects = ({ isThinking }) => { |
| | const bloopSoundRef = useRef(null); |
| | |
| | |
| | useEffect(() => { |
| | if (isThinking && bloopSoundRef.current) { |
| | bloopSoundRef.current.currentTime = 0; |
| | bloopSoundRef.current.play().catch(err => { |
| | |
| | console.log("Could not play sound effect:", err); |
| | }); |
| | } |
| | }, [isThinking]); |
| | |
| | return ( |
| | <audio |
| | ref={bloopSoundRef} |
| | src="/sounds/bloop.mp3" |
| | preload="auto" |
| | /> |
| | ); |
| | }; |
| |
|
| | |
| | |
| | |
| | export const AnimationStyles = () => { |
| | return ( |
| | <> |
| | <style jsx global>{` |
| | @keyframes thinking-blink { |
| | 0%, 100% { opacity: 1; transform: scale(1); } |
| | 50% { opacity: 0.7; transform: scale(0.95); } |
| | } |
| | |
| | @keyframes thinking-spin { |
| | 0% { transform: rotate(0deg); } |
| | 100% { transform: rotate(360deg); } |
| | } |
| | |
| | @keyframes spring-out { |
| | 0% { |
| | transform: scale(0) translateY(0); |
| | opacity: 0; |
| | } |
| | 20% { |
| | transform: scale(0.3) translateY(-5px); |
| | opacity: 0.7; |
| | } |
| | 40% { |
| | transform: scale(1.5) translateY(-30px); |
| | } |
| | 60% { |
| | transform: scale(0.8) translateY(15px); |
| | } |
| | 75% { |
| | transform: scale(1.2) translateY(-10px); |
| | } |
| | 90% { |
| | transform: scale(0.95) translateY(5px); |
| | } |
| | 100% { |
| | transform: scale(1) translateY(0); |
| | opacity: 1; |
| | } |
| | } |
| | |
| | @keyframes wiggle { |
| | 0% { transform: rotate(0deg); } |
| | 15% { transform: rotate(-15deg); } |
| | 30% { transform: rotate(12deg); } |
| | 45% { transform: rotate(-8deg); } |
| | 60% { transform: rotate(5deg); } |
| | 75% { transform: rotate(-2deg); } |
| | 100% { transform: rotate(0deg); } |
| | } |
| | |
| | |
| | @keyframes spring-wiggle { |
| | 0% { |
| | transform: scale(0) rotate(0deg) translateY(0); |
| | opacity: 0; |
| | } |
| | 15% { |
| | transform: scale(0.2) rotate(-5deg) translateY(-5px); |
| | opacity: 0.5; |
| | } |
| | 30% { |
| | transform: scale(1.5) rotate(12deg) translateY(-30px); |
| | opacity: 1; |
| | } |
| | 45% { |
| | transform: scale(0.8) rotate(-8deg) translateY(15px); |
| | } |
| | 60% { |
| | transform: scale(1.2) rotate(5deg) translateY(-10px); |
| | } |
| | 75% { |
| | transform: scale(0.95) rotate(-2deg) translateY(5px); |
| | } |
| | 90% { |
| | transform: scale(1.05) rotate(1deg) translateY(-2px); |
| | } |
| | 100% { |
| | transform: scale(1) rotate(0deg) translateY(0); |
| | } |
| | } |
| | |
| | |
| | @keyframes float-particle { |
| | 0% { |
| | transform: translate(0, 0) rotate(0deg); |
| | opacity: 1; |
| | } |
| | 100% { |
| | transform: translate(var(--tx), var(--ty)) rotate(var(--r)); |
| | opacity: 0; |
| | } |
| | } |
| | |
| | @keyframes pop-out { |
| | 0% { |
| | transform: scale(1); |
| | opacity: 1; |
| | } |
| | 50% { |
| | transform: scale(1.2); |
| | } |
| | 100% { |
| | transform: scale(0); |
| | opacity: 0; |
| | } |
| | } |
| | |
| | |
| | .particle { |
| | position: absolute; |
| | pointer-events: none; |
| | background: linear-gradient(135deg, #217BFE, #AC87EB); |
| | border-radius: 50%; |
| | animation: float-particle 1s ease-out forwards; |
| | } |
| | |
| | .pop-particle { |
| | position: absolute; |
| | pointer-events: none; |
| | background: linear-gradient(135deg, #217BFE, #AC87EB); |
| | border-radius: 50%; |
| | animation: float-particle 0.6s ease-out forwards; |
| | } |
| | `}</style> |
| | </> |
| | ); |
| | }; |