import React, { useState, useRef, useEffect } from 'react'; import { TerminalWindow } from './TerminalWindow'; import { HERO_SEQUENCE } from '../constants'; import { TypingAnimation } from './TypingAnimation'; import { BlockLogo } from './BlockLogo'; // Text-based Ghost Logo from CLI const AsciiGhost = () => { return (
{` ▐▛███▜▌
▝▜█████▛▘
  ▘▘ ▝▝`}
        
); }; const HeroSection: React.FC = () => { const [rotation, setRotation] = useState({ x: 0, y: 0 }); const [visibleLines, setVisibleLines] = useState(0); // State for status bar const [status, setStatus] = useState({ model: 'google/gemini-3-pro-preview', cost: '$0.000', context: '0%' }); const containerRef = useRef(null); const scrollRef = useRef(null); // Mouse movement for 3D effect const handleMouseMove = (e: React.MouseEvent) => { if (!containerRef.current) return; const rect = containerRef.current.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; // Calculate percentage from center (-1 to 1) const xPct = (x / rect.width - 0.5) * 2; const yPct = (y / rect.height - 0.5) * 2; // Limit rotation to 15 degrees setRotation({ x: yPct * -8, y: xPct * 8 }); }; const handleMouseLeave = () => { setRotation({ x: 0, y: 0 }); }; // Sequence Controller useEffect(() => { const timeouts: ReturnType[] = []; const runSequence = () => { setVisibleLines(0); let cumulativeDelay = 0; HERO_SEQUENCE.forEach((line, index) => { const t = setTimeout(() => { setVisibleLines(prev => Math.max(prev, index + 1)); }, line.delay); timeouts.push(t); if (line.delay && line.delay > cumulativeDelay) { cumulativeDelay = line.delay; } }); const restart = setTimeout(() => { runSequence(); }, cumulativeDelay + 4000); timeouts.push(restart); }; runSequence(); return () => timeouts.forEach(clearTimeout); }, []); // Update Status Bar based on visible lines useEffect(() => { let newStatus = { ...status }; let hasUpdates = false; // Scan visible lines to find the latest state for (let i = 0; i < visibleLines && i < HERO_SEQUENCE.length; i++) { const line = HERO_SEQUENCE[i]; if (line.data) { if (line.data.model) { newStatus.model = line.data.model; hasUpdates = true; } if (line.data.cost) { newStatus.cost = line.data.cost; hasUpdates = true; } if (line.data.context) { newStatus.context = line.data.context; hasUpdates = true; } } } if (hasUpdates) { setStatus(newStatus); } }, [visibleLines]); // Auto-scroll effect useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTo({ top: scrollRef.current.scrollHeight, behavior: 'smooth' }); } }, [visibleLines]); return (
{/* Background Gradients */}
v2.4.0 Public Beta
🎁 Top models free on OpenRouter — Grok, Gemini, DeepSeek, Llama
{/* BlockLogo */}

Claude Code. Any Model.

The most powerful AI coding agent now speaks every language.
Gemini, GPT, Grok, DeepSeek. 580+ models via OpenRouter.
Works with your Claude subscription. Or start completely free.

GET STARTED
$ npm install -g claudish
$ claudish --free
{/* 3D Container */}
{/* Terminal Flow - Scrollable Area */}
{HERO_SEQUENCE.map((line, idx) => { if (idx >= visibleLines) return null; return (
{/* System / Boot Output */} {line.type === 'system' && (
{line.content}
)} {/* Rich Welcome Screen */} {line.type === 'welcome' && (
Claudish
{/* Left Side: Logo & Info */}
Claude Code {line.data.version}
{line.data.model} • Claude Max
~/dev/claudish-landing
{/* Right Side: Activity */}
Recent activity
1m ago Tracking Real OpenRouter Cost
39m ago Refactoring Auth Middleware
What's new
Fixed duplicate message display when using Gemini.
)} {/* Rich Input (Updated to be cleaner, status moved to bottom) */} {line.type === 'rich-input' && (
{'>>'}
)} {/* Thinking Block */} {line.type === 'thinking' && (
{line.content}
)} {/* Tool Execution */} {line.type === 'tool' && (
{line.content.split('(')[0]} ({line.content.split('(')[1]}
{line.data?.details && (
{line.data.details}
)}
)} {/* Standard Output/Success/Info */} {line.type === 'info' && (
{line.content}
)} {line.type === 'progress' && (
{line.content}
)} {line.type === 'success' && (
{line.content}
)}
); })} {/* Interactive Cursor line if active */}
{'>'}
{/* Persistent Footer Status Bar */}
claudish {status.model} {status.cost} {status.context}
bypass permissions on | (shift+tab to cycle)
); }; export default HeroSection;