import React, { useState, useEffect, useRef } from 'react'; import { ChevronRight, X, Sparkles, Heart, Ghost } from 'lucide-react'; // Character data const characters = [ { id: 1, name: "Aster", tag: "the one who disappears mid-sentence", color: "#a29bfe", image: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=400", desc: "speaks softly like every word costs something. leaves rooms quietly but never without echo. knows more about me than they pretend not to.", secret: "i still look for their name in places it will never appear.", details: [ "favorite time: 3am, when the world is asleep", "always carries: a worn notebook with blank pages", "says: 'i'll be back' (never specifies when)" ] }, { id: 2, name: "Rowan", tag: "sunlight with sharp edges", color: "#ffeaa7", image: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400", desc: "laughs like nothing has ever hurt them. pretends to be simple. isn't. made me believe in warmth again.", secret: "i learned how to want better by watching them exist.", details: [ "favorite time: golden hour, obviously", "always carries: too much optimism", "says: 'it'll be fine' (and somehow it is)" ] }, { id: 3, name: "Nyx", tag: "midnight in human form", color: "#6c5ce7", image: "https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?w=400", desc: "knows the exact right things to say and chooses silence instead. always looking like they're about to leave.", secret: "they never stayed. i never asked them to. i still hoped.", details: [ "favorite time: twilight, between worlds", "always carries: secrets that aren't theirs", "says: nothing (but you hear it anyway)" ] }, { id: 4, name: "Echo", tag: "the one who remembers everything", color: "#fd79a8", image: "https://images.unsplash.com/photo-1517841905240-472988babdf9?w=400", desc: "recalls every conversation like it's scripture. makes you feel seen in ways that are both beautiful and terrifying.", secret: "sometimes being remembered feels heavier than being forgotten.", details: [ "favorite time: whenever you need them", "always carries: your words back to you", "says: 'you told me once...' (always right)" ] } ]; const OCSShowcase = () => { const [selectedChar, setSelectedChar] = useState(characters[0]); const [showSecret, setShowSecret] = useState(false); const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 }); const [sparkles, setSparkles] = useState([]); const [activeTab, setActiveTab] = useState('about'); // Cursor trail effect useEffect(() => { const handleMouseMove = (e) => { setCursorPos({ x: e.clientX, y: e.clientY }); // Add sparkle occasionally if (Math.random() > 0.95) { const newSparkle = { id: Date.now(), x: e.clientX, y: e.clientY }; setSparkles(prev => [...prev, newSparkle]); setTimeout(() => { setSparkles(prev => prev.filter(s => s.id !== newSparkle.id)); }, 1000); } }; window.addEventListener('mousemove', handleMouseMove); return () => window.removeEventListener('mousemove', handleMouseMove); }, []); const handleCharacterSelect = (char) => { setSelectedChar(char); setShowSecret(false); setActiveTab('about'); }; return (
{/* Floating cursor trail */}
{/* Sparkles */} {sparkles.map(sparkle => (
))} {/* Header */}

characters that breathe

officially, these are original characters.
unofficially… they are people who left fingerprints on me.

{/* Main layout */}
{/* Left sidebar - Character roster */}
roster
{characters.map(char => (
handleCharacterSelect(char)} style={{ padding: '1rem', marginBottom: '0.5rem', background: selectedChar.id === char.id ? `linear-gradient(135deg, ${char.color}33, transparent)` : 'transparent', border: `2px solid ${selectedChar.id === char.id ? char.color : '#2a355c'}`, borderRadius: '8px', cursor: 'pointer', transition: 'all 0.3s ease', transform: selectedChar.id === char.id ? 'translateX(5px)' : 'none' }} onMouseEnter={(e) => { e.currentTarget.style.background = `linear-gradient(135deg, ${char.color}33, transparent)`; e.currentTarget.style.borderColor = char.color; }} onMouseLeave={(e) => { if (selectedChar.id !== char.id) { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.borderColor = '#2a355c'; } }} >
{char.name}
{char.tag}
))}
{/* Right content area - Character details */}
{/* Floating card stack */}
{/* Character image card */}
{selectedChar.name}
{selectedChar.name}
{/* Floating info panels */}
{/* Windows-style tabs */}
{/* Tab headers */}
{['about', 'details', 'secret'].map(tab => (
setActiveTab(tab)} style={{ flex: 1, padding: '0.8rem', textAlign: 'center', fontFamily: "'VT323', monospace", fontSize: '1.2rem', color: activeTab === tab ? selectedChar.color : '#b8b2a7', background: activeTab === tab ? 'rgba(15, 22, 41, 0.8)' : 'transparent', borderBottom: activeTab === tab ? `3px solid ${selectedChar.color}` : 'none', cursor: 'pointer', transition: 'all 0.3s ease', textTransform: 'uppercase' }} onMouseEnter={(e) => { if (activeTab !== tab) { e.currentTarget.style.color = selectedChar.color; } }} onMouseLeave={(e) => { if (activeTab !== tab) { e.currentTarget.style.color = '#b8b2a7'; } }} > {tab}
))}
{/* Tab content */}
{activeTab === 'about' && (
{selectedChar.desc}
)} {activeTab === 'details' && (
{selectedChar.details.map((detail, i) => (
{detail}
))}
)} {activeTab === 'secret' && (
{!showSecret ? (
setShowSecret(true)} style={{ padding: '2rem', textAlign: 'center', cursor: 'pointer', background: 'rgba(42, 53, 92, 0.3)', border: `2px dashed ${selectedChar.color}`, borderRadius: '8px', color: selectedChar.color, fontFamily: "'VT323', monospace", fontSize: '1.3rem', transition: 'all 0.3s ease' }} onMouseEnter={(e) => { e.currentTarget.style.background = `${selectedChar.color}22`; }} onMouseLeave={(e) => { e.currentTarget.style.background = 'rgba(42, 53, 92, 0.3)'; }} > ▼ click to reveal ▼
(you probably shouldn't)
) : (
{selectedChar.secret}
)}
)}
{/* Quick stats card */}
signature
"{selectedChar.tag}"
~ {selectedChar.name}
); }; export default OCSShowcase;