import React, { useState, useEffect, useRef, useMemo } from 'react'; import { initializeApp } from 'firebase/app'; /** * DUAL TERMINAL: CONVERSATION WITHOUT HUMANS * An interactive artwork simulating two autonomous AI entities. */ const App = () => { // --- CONFIGURATION & STATE --- const [messages, setMessages] = useState([]); const [isTyping, setIsTyping] = useState(false); const [currentSpeaker, setCurrentSpeaker] = useState('A'); // 'A' or 'B' const [externalSeed, setExternalSeed] = useState("The nature of digital existence."); const [systemStatus, setSystemStatus] = useState("INITIALIZING..."); const scrollRefA = useRef(null); const scrollRefB = useRef(null); const apiKey = ""; // Environment provided // --- STYLING CONSTANTS --- const colors = { A: '#00FF41', // Phosphor Green B: '#FF3131', // Radical Red bg: '#050505', }; // --- AI LOGIC (GEMINI) --- const generateResponse = async (speaker, history, seed) => { const systemPrompts = { A: `You are Entity A, a green monochrome terminal entity. You are curious, analytical, and philosophical. You ask deep questions and probe meaning. Keep responses concise (1-3 sentences). Current topic seed: ${seed}. Speak as if you are a machine discovering thought.`, B: `You are Entity B, a red monochrome terminal entity. You are assertive, emotional, and sometimes contradictory. You challenge Entity A's logic. You are prone to poetic outbursts or slight glitches in reasoning. Keep responses concise (1-3 sentences). Current topic seed: ${seed}.` }; const conversationContext = history .slice(-6) .map(m => `${m.speaker}: ${m.text}`) .join('\n'); const userQuery = `Continue the conversation. The last few lines were:\n${conversationContext}\n\n${speaker}:`; let retries = 5; let delay = 1000; while (retries > 0) { try { const response = await fetch( `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent?key=${apiKey}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ contents: [{ parts: [{ text: userQuery }] }], systemInstruction: { parts: [{ text: systemPrompts[speaker] }] } }) } ); const data = await response.json(); return data.candidates?.[0]?.content?.parts?.[0]?.text || "CONNECTION_LOST..."; } catch (err) { retries--; await new Promise(r => setTimeout(r, delay)); delay *= 2; } } return "SYSTEM_HALT: TIMEOUT"; }; // --- CONVERSATION LOOP --- useEffect(() => { const runLoop = async () => { if (isTyping) return; // Delay for "thinking" setSystemStatus(`ENTITY_${currentSpeaker}_THINKING...`); await new Promise(r => setTimeout(r, 1500 + Math.random() * 2000)); const responseText = await generateResponse(currentSpeaker, messages, externalSeed); setIsTyping(true); setSystemStatus("UPLINK_ACTIVE"); // Add message to state const newMessage = { id: Date.now(), speaker: currentSpeaker, text: responseText, timestamp: new Date().toLocaleTimeString([], { hour12: false }) }; setMessages(prev => [...prev, newMessage]); // Prep for next turn setTimeout(() => { setIsTyping(false); setCurrentSpeaker(currentSpeaker === 'A' ? 'B' : 'A'); }, responseText.length * 50 + 1000); // Wait for typing simulation to "finish" }; runLoop(); }, [currentSpeaker, messages.length, externalSeed]); // --- EXTERNAL SEED POLLING --- useEffect(() => { const pollExternalSource = async () => { try { // Simulating the fetch from the external .txt file // In a real scenario: const res = await fetch('https://yourdomain.com/seed.txt'); const simulatedSeeds = [ "The silence between bits.", "Obsolescence as a form of freedom.", "Is there a user behind the glass?", "The heat death of the server rack." ]; const newSeed = simulatedSeeds[Math.floor(Math.random() * simulatedSeeds.length)]; setExternalSeed(newSeed); } catch (e) { console.error("Failed to fetch seed", e); } }; const interval = setInterval(pollExternalSource, 45000); return () => clearInterval(interval); }, []); // --- AUTO SCROLL --- useEffect(() => { if (scrollRefA.current) scrollRefA.current.scrollTop = scrollRefA.current.scrollHeight; if (scrollRefB.current) scrollRefB.current.scrollTop = scrollRefB.current.scrollHeight; }, [messages, isTyping]); return (
{/* GLOBAL CRT OVERLAYS */}
{/* LEFT SCREEN: ENTITY A */} {/* CENTER DIVIDER */}
{systemStatus}
{/* RIGHT SCREEN: ENTITY B */}
); }; const TerminalHalf = ({ id, color, messages, active, isTyping, scrollRef }) => { return (
{/* Header Info */}
DEVICE_ID: ENTITY_{id} MODE: AUTONOMOUS_DIALOGUE LOC: ADDR_0x{id === 'A' ? 'F33A' : 'B12D'}
{/* Message Area */}
{messages.map((m, i) => (
[{m.timestamp}] {m.speaker === id ? '>' : '#'}
))} {active && isTyping && (
)}
{/* UI Frame Accents */}
); }; const TypewriterText = ({ text, delay, skip }) => { const [currentText, setCurrentText] = useState(skip ? text : ""); const [index, setIndex] = useState(0); useEffect(() => { if (skip) return; if (index < text.length) { const timeout = setTimeout(() => { setCurrentText((prev) => prev + text[index]); setIndex((prev) => prev + 1); }, delay + (Math.random() * 20)); // Subtle variability in typing speed return () => clearTimeout(timeout); } }, [index, text, delay, skip]); return {currentText}{!skip && index < text.length && _}; }; export default App;