pudcaster / prompts.txt
Fuckingbase's picture
Add 3 files
2c02f13 verified
import React, { useEffect, useRef, useState } from 'react'; import * as THREE from 'three'; const PersianAudioGalaxy: React.FC = () => { const [activeStage, setActiveStage] = useState<'google' | 'video' | 'main'>('google'); const [typingText, setTypingText] = useState(''); const [isTypingComplete, setIsTypingComplete] = useState(false); const [isTransitioning, setIsTransitioning] = useState(false); const [isPlaying, setIsPlaying] = useState(false); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [volume, setVolume] = useState(1); const searchInputRef = useRef<HTMLInputElement>(null); const videoRef = useRef<HTMLVideoElement>(null); const audioRef = useRef<HTMLAudioElement>(null); const canvasRef = useRef<HTMLCanvasElement>(null); const eqCanvasRef = useRef<HTMLCanvasElement>(null); const threeCanvasRef = useRef<HTMLCanvasElement>(null); const sceneRef = useRef<THREE.Scene | null>(null); const cameraRef = useRef<THREE.PerspectiveCamera | null>(null); const rendererRef = useRef<THREE.WebGLRenderer | null>(null); const starsRef = useRef<THREE.Points | null>(null); const animationRef = useRef<number>(0); const audioContextRef = useRef<AudioContext | null>(null); const analyserRef = useRef<AnalyserNode | null>(null); const frequencyDataRef = useRef<Uint8Array | null>(null); const fullText = "دیگه کجا میتونم اطلاعات به این مفیدی پیدا کنم!؟"; // Typing animation effect useEffect(() => { if (activeStage !== 'google') return; let index = 0; const typingInterval = setInterval(() => { if (index < fullText.length) { setTypingText(fullText.substring(0, index + 1)); index++; } else { clearInterval(typingInterval); setIsTypingComplete(true); if (searchInputRef.current) { searchInputRef.current.focus(); } } }, 100); return () => clearInterval(typingInterval); }, [activeStage]); // Handle keyboard events for the search input useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (activeStage === 'google' && isTypingComplete) { if (e.key === 'Enter') { handleTransitionToVideo(); } } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [activeStage, isTypingComplete]); // Initialize Three.js scene useEffect(() => { if (activeStage !== 'main' || !threeCanvasRef.current) return; const init3D = () => { const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.z = 50; const renderer = new THREE.WebGLRenderer({ canvas: threeCanvasRef.current as HTMLCanvasElement, antialias: true, alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight); const starGeo = new THREE.BufferGeometry(); const starVertices = []; for (let i = 0; i < 15000; i++) { starVertices.push( (Math.random() - 0.5) * 2000, (Math.random() - 0.5) * 2000, (Math.random() - 0.5) * 2000 ); } starGeo.setAttribute('position', new THREE.Float32BufferAttribute(starVertices, 3)); const stars = new THREE.Points( starGeo, new THREE.PointsMaterial({ color: 0xaaaaaa, size: 0.7 }) ); scene.add(stars); sceneRef.current = scene; cameraRef.current = camera; rendererRef.current = renderer; starsRef.current = stars; const handleResize = () => { if (cameraRef.current && rendererRef.current) { cameraRef.current.aspect = window.innerWidth / window.innerHeight; cameraRef.current.updateProjectionMatrix(); rendererRef.current.setSize(window.innerWidth, window.innerHeight); } }; window.addEventListener('resize', handleResize); // Start animation animate(); return () => { window.removeEventListener('resize', handleResize); if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }; init3D(); }, [activeStage]); // Animation loop const animate = () => { if (sceneRef.current && cameraRef.current && rendererRef.current && starsRef.current) { starsRef.current.rotation.y += 0.00015; cameraRef.current.position.z -= 0.03; if (cameraRef.current.position.z < -200) { cameraRef.current.position.z = 200; } // Draw equalizer if audio is playing if (analyserRef.current && audioRef.current && !audioRef.current.paused) { drawEqualizer(); } rendererRef.current.render(sceneRef.current, cameraRef.current); animationRef.current = requestAnimationFrame(animate); } }; // Setup audio analysis const setupAudioAnalysis = async () => { if (audioContextRef.current) return; try { const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)(); audioContextRef.current = audioContext; if (audioContext.state === 'suspended') { await audioContext.resume(); } if (audioRef.current) { const source = audioContext.createMediaElementSource(audioRef.current); const analyser = audioContext.createAnalyser(); analyser.fftSize = 256; source.connect(analyser); analyser.connect(audioContext.destination); analyserRef.current = analyser; frequencyDataRef.current = new Uint8Array(analyser.frequencyBinCount); } } catch (error) { console.error('Audio analysis setup failed:', error); } }; // Draw equalizer visualization const drawEqualizer = () => { if (!analyserRef.current || !frequencyDataRef.current || !eqCanvasRef.current) return; const eqCtx = eqCanvasRef.current.getContext('2d'); if (!eqCtx) return; analyserRef.current.getByteFrequencyData(frequencyDataRef.current); eqCtx.clearRect(0, 0, eqCanvasRef.current.width, eqCanvasRef.current.height); const barCount = 64; const barWidth = (eqCanvasRef.current.width / barCount); let x = 0; const gradient = eqCtx.createLinearGradient(0, 0, eqCanvasRef.current.width, 0); gradient.addColorStop(0, '#8ab4f8'); gradient.addColorStop(0.5, '#6ea8ff'); gradient.addColorStop(1, '#d1e3ff'); for (let i = 0; i < barCount; i++) { const barHeight = (frequencyDataRef.current[i * 2] / 255) * eqCanvasRef.current.height; eqCtx.fillStyle = gradient; eqCtx.fillRect(x, (eqCanvasRef.current.height - barHeight) / 2, barWidth, barHeight); x += barWidth; } }; // Handle transition to video stage const handleTransitionToVideo = async () => { if (isTransitioning) return; setIsTransitioning(true); try { await setupAudioAnalysis(); if (videoRef.current) { await videoRef.current.play(); setActiveStage('video'); } } catch (error) { console.error('Video playback failed:', error); setIsTransitioning(false); } }; // Handle video end to transition to main stage useEffect(() => { const video = videoRef.current; if (!video) return; const handleVideoEnd = () => setActiveStage('main'); video.addEventListener('ended', handleVideoEnd); return () => video.removeEventListener('ended', handleVideoEnd); }, []); // Audio player controls const togglePlayPause = () => { if (audioRef.current) { if (audioRef.current.paused) { audioRef.current.play(); setIsPlaying(true); } else { audioRef.current.pause(); setIsPlaying(false); } } }; const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => { if (audioRef.current) { audioRef.current.currentTime = parseFloat(e.target.value); setCurrentTime(parseFloat(e.target.value)); } }; const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => { const newVolume = parseFloat(e.target.value); setVolume(newVolume); if (audioRef.current) { audioRef.current.volume = newVolume; } }; // Format time for display const formatTime = (seconds: number) => { const minutes = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${minutes}:${secs < 10 ? '0' : ''}${secs}`; }; // Update current time as audio plays useEffect(() => { const audio = audioRef.current; if (!audio) return; const updateTime = () => setCurrentTime(audio.currentTime); const updateDuration = () => setDuration(audio.duration); audio.addEventListener('timeupdate', updateTime); audio.addEventListener('loadedmetadata', updateDuration); return () => { audio.removeEventListener('timeupdate', updateTime); audio.removeEventListener('loadedmetadata', updateDuration); }; }, []); return ( <div className="h-screen w-full overflow-hidden bg-black font-sans" dir="rtl"> {/* Google Page Stage */} <div className={`fixed inset-0 flex justify-center items-center transition-opacity duration-1000 ease-in-out ${ activeStage === 'google' ? 'opacity-100 visible z-50' : 'opacity-0 invisible' }`} style={{ backgroundColor: '#fff' }} > <div className="flex flex-col items-center justify-center flex-grow w-full p-5 box-border"> {/* Google Logo */} <svg className="google-logo max-w-[272px] w-[60%] mb-7" aria-label="Google" viewBox="0 0 272 92" xmlns="http://www.w3.org/2000/svg" > <path d="M115.75 47.18c0 12.77-9.99 22.18-22.25 22.18s-22.25-9.41-22.25-22.18C71.25 34.32 81.24 25 93.5 25s22.25 9.32 22.25 22.18zm-9.74 0c0-7.98-5.79-13.44-12.51-13.44S80.99 39.2 80.99 47.18c0 7.9 5.79 13.44 12.51 13.44s12.51-5.55 12.51-13.44z" fill="#EA4335"></path> <path d="M163.75 47.18c0 12.77-9.99 22.18-22.25 22.18s-22.25-9.41-22.25-22.18c0-12.85 9.99-22.18 22.25-22.18s22.25 9.32 22.25 22.18zm-9.74 0c0-7.98-5.79-13.44-12.51-13.44s-12.51 5.46-12.51 13.44c0 7.9 5.79 13.44 12.51 13.44s12.51-5.55 12.51-13.44z" fill="#FBBC05"></path> <path d="M209.75 26.34v39.82c0 16.38-9.66 23.07-21.08 23.07-10.75 0-17.22-7.19-19.66-13.07l8.48-3.53c1.51 3.61 5.21 7.87 11.17 7.87 7.31 0 11.84-4.51 11.84-13v-3.19h-.34c-2.18 2.69-6.38 5.04-11.68 5.04-11.09 0-21.25-9.66-21.25-22.09 0-12.52 10.16-22.26 21.25-22.26 5.29 0 9.49 2.35 11.68 4.96h.34v-3.61h9.25zm-8.56 20.92c0-7.81-5.21-13.52-11.84-13.52-6.72 0-12.35 5.71-12.35 13.52 0 7.73 5.63 13.36 12.35 13.36 6.63 0 11.84-5.63 11.84-13.36z" fill="#4285F4"></path> <path d="M225 3v65h-9.5V3h9.5z" fill="#34A853"></path> <path d="M262.02 54.48l7.56 5.04c-2.44 3.61-8.32 9.83-18.48 9.83-12.6 0-22.01-9.74-22.01-22.18 0-13.19 9.49-22.18 20.92-22.18 11.51 0 17.14 9.16 18.98 14.11l1.01 2.52-29.65 12.28c2.27 4.45 5.8 6.72 10.75 6.72 4.96 0 8.4-2.44 10.92-6.14zm-23.27-7.98l19.82-8.23c-1.09-2.77-4.37-4.7-8.23-4.7-4.95 0-11.84 4.37-11.59 12.93z" fill="#EA4335"></path> <path d="M35.29 41.41V32H67c.31 1.64.47 3.58.47 5.68 0 7.06-1.93 15.79-8.15 22.01-6.05 6.3-13.78 9.66-24.02 9.66C16.32 69.35.36 53.89.36 34.91.36 15.93 16.32.47 35.3.47c10.5 0 17.98 4.12 23.6 9.49l-6.64 6.64c-4.03-3.78-9.49-6.72-16.97-6.72-13.86 0-24.7 11.17-24.7 25.03 0 13.86 10.84 25.03 24.7 25.03 8.99 0 14.11-3.61 17.39-6.89 2.66-2.66 4.41-6.46 5.1-11.65l-22.49.01z" fill="#4285F4"></path> </svg> {/* Search Form */} <form className="search-form w-full max-w-[584px]" onSubmit={(e) => e.preventDefault()}> <div className="search-container flex z-30 h-[46px] bg-white border border-[#dfe1e5] rounded-[24px] mx-auto hover:shadow hover:border-transparent transition-shadow"> <div className="search-input-wrapper flex flex-1 items-center px-3 overflow-hidden"> <span className="flex-grow whitespace-nowrap overflow-hidden text-base" dir="ltr"> {typingText} {isTypingComplete && ( <span className="inline-block bg-[#222] w-px h-5 align-middle animate-blink"></span> )} </span> <input ref={searchInputRef} id="search-input" type="text" autoComplete="off" className="hidden" /> </div> <div className={`search-icon-wrapper flex items-center pl-3 cursor-pointer ${ isTypingComplete ? '' : 'pointer-events-none' }`} onClick={handleTransitionToVideo} > <svg className={`search-icon w-6 h-6 fill-[#4285f4] transition-all ${ isTypingComplete ? 'animate-attention-pulse' : '' }`} focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" > <path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path> </svg> </div> </div> <div className="google-buttons mt-4 text-center"> <button className="bg-[#f8f9fa] border border-[#f8f9fa] rounded text-[#3c4043] font-inherit text-sm mx-1 px-4 h-9 min-w-[54px] text-center cursor-not-allowed opacity-70" disabled > Google Search </button> <button className="bg-[#f8f9fa] border border-[#f8f9fa] rounded text-[#3c4043] font-inherit text-sm mx-1 px-4 h-9 min-w-[54px] text-center cursor-not-allowed opacity-70" disabled > I'm Feeling Lucky </button> </div> </form> </div> </div> {/* Video Intro Stage */} <div className={`fixed inset-0 flex justify-center items-center transition-opacity duration-1000 ease-in-out ${ activeStage === 'video' ? 'opacity-100 visible z-40' : 'opacity-0 invisible' }`} > <video ref={videoRef} id="intro-video" className="w-full h-full object-cover" src="https://github.com/Shervinuri/Telbot/raw/refs/heads/main/lv_0_20250907111724.mp4" playsInline /> </div> {/* Main Experience Stage */} <div className={`fixed inset-0 flex justify-center items-center transition-opacity duration-1000 ease-in-out ${ activeStage === 'main' ? 'opacity-100 visible z-30' : 'opacity-0 invisible' }`} > <audio ref={audioRef} src="https://raw.githubusercontent.com/Shervinuri/Telbot/89a6ba05e0e67d37b917d488749324d909480d23/POD.mp3" loop crossOrigin="anonymous" /> {/* Three.js Canvas for Starfield */} <canvas ref={threeCanvasRef} id="starfield" className="fixed top-0 left-0 w-full h-full z-10" /> {/* Audio Player */} <div id="audio-player-container" className={`fixed bottom-8 left-1/2 transform -translate-x-1/2 w-[90%] max-w-[500px] bg-[rgba(25,25,25,0.7)] backdrop-blur-xl rounded-xl p-4 shadow-xl border border-[rgba(255,255,255,0.18)] z-50 transition-opacity duration-1000 ease-in-out ${ activeStage === 'main' ? 'opacity-100 delay-1000' : 'opacity-0' }`} > <div className="player-top-row flex items-center gap-4 mb-2"> <canvas ref={eqCanvasRef} id="equalizer-canvas" className="flex-grow h-[50px]" /> <div className="volume-container relative flex items-center"> <button id="volume-btn" className="bg-transparent border-none cursor-pointer p-1"> <svg className="w-[22px] h-[22px] fill-[#e8eaed]" viewBox="0 0 24 24" > <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"></path> </svg> </button> <input type="range" id="volume-slider" min="0" max="1" step="0.01" value={volume} orient="vertical" onChange={handleVolumeChange} className="volume-slider absolute bottom-[150%] left-1/2 transform -translate-x-1/2 w-2 h-[100px] bg-[rgba(255,255,255,0.2)] rounded outline-none transition-opacity opacity-0 invisible appearance-none p-0 m-0 hover:opacity-100 hover:visible" /> </div> </div> <div className="player-bottom-row flex items-center gap-4 text-[#e8eaed] text-sm font-mono" dir="ltr"> <span id="current-time">{formatTime(currentTime)}</span> <input type="range" id="seek-bar" min="0" max={duration || 100} step="1" value={currentTime} onChange={handleSeek} className="seek-bar flex-grow h-1 bg-[rgba(255,255,255,0.2)] rounded cursor-pointer appearance-none bg-gradient-to-r from-[#6ea8ff] to-[#6ea8ff] bg-no-repeat bg-left" style={{ backgroundSize: `${duration ? (currentTime / duration) * 100 : 0}% 100%` }} /> <span id="duration">{formatTime(duration)}</span> <button id="play-pause-btn" onClick={togglePlayPause} className="bg-transparent border-none cursor-pointer p-0 w-10 h-10 flex justify-center items-center flex-shrink-0" > {isPlaying ? ( <svg className="w-7 h-7 fill-[#e8eaed] transition-transform hover:scale-110" viewBox="0 0 24 24" > <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/> </svg> ) : ( <svg className="w-7 h-7 fill-[#e8eaed] transition-transform hover:scale-110" viewBox="0 0 24 24" > <path d="M8 5v14l11-7z"/> </svg> )} </button> </div> </div> </div> {/* CSS for animations */} <style>{` @keyframes blink { from, to { opacity: 1; } 50% { opacity: 0; } } @keyframes attention-pulse { 0% { transform: scale(1); filter: drop-shadow(0 0 0px #4285f4); } 50% { transform: scale(1.2); filter: drop-shadow(0 0 8px #8ab4f8); } 100% { transform: scale(1); filter: drop-shadow(0 0 0px #4285f4); } } .animate-blink { animation: blink 1s step-end infinite; } .animate-attention-pulse { animation: attention-pulse 1.5s infinite; } .seek-bar::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; height: 16px; width: 16px; border-radius: 50%; background: #e8eaed; border: 2px solid #191919; margin-top: -6px; } .seek-bar::-moz-range-tra