- Gallery
- Creative & Unique
- RetroTerminal
New
RetroTerminal
Terminal-style component with green phosphor text, blinking cursor, scan lines, and typed output effect.
Creative & Uniqueterminalretrohackertypingconsole
Dependencies
No additional dependencies needed.
How to use this component
Copy the code below into your project. Make sure you have the required shadcn/ui dependencies installed. Then import and use the component in your pages or layouts.
Code
1"use client";23import { useState, useEffect, useRef } from "react";45const lines = [6 "$ initializing system...",7 "> Loading modules: [OK]",8 "> Connecting to mainframe: [OK]",9 "> Authenticating user: admin",10 "> Access granted.",11 "",12 "$ fetch --status",13 "> Uptime: 99.97%",14 "> Memory: 4.2GB / 16GB",15 "> CPU: 23% utilization",16 "> All systems nominal.",17 "",18 "$ _",19];2021export default function RetroTerminal() {22 const [displayedLines, setDisplayedLines] = useState<string[]>([]);23 const [currentLine, setCurrentLine] = useState(0);24 const [currentChar, setCurrentChar] = useState(0);25 const containerRef = useRef<HTMLDivElement>(null);2627 useEffect(() => {28 if (currentLine >= lines.length) return;29 const line = lines[currentLine];3031 if (currentChar <= line.length) {32 const timeout = setTimeout(() => {33 setDisplayedLines((prev) => {34 const next = [...prev];35 next[currentLine] = line.slice(0, currentChar);36 return next;37 });38 setCurrentChar(currentChar + 1);39 }, 30 + Math.random() * 40);40 return () => clearTimeout(timeout);41 } else {42 const timeout = setTimeout(() => {43 setCurrentLine(currentLine + 1);44 setCurrentChar(0);45 }, 200);46 return () => clearTimeout(timeout);47 }48 }, [currentLine, currentChar]);4950 useEffect(() => {51 containerRef.current?.scrollTo(0, containerRef.current.scrollHeight);52 }, [displayedLines]);5354 return (55 <div className="mx-auto w-full max-w-lg overflow-hidden rounded-2xl border border-zinc-800 bg-zinc-950 shadow-2xl shadow-green-500/5">56 {/* Title bar */}57 <div className="flex items-center gap-2 border-b border-zinc-800 bg-zinc-900 px-4 py-3">58 <div className="h-3 w-3 rounded-full bg-red-500" />59 <div className="h-3 w-3 rounded-full bg-yellow-500" />60 <div className="h-3 w-3 rounded-full bg-green-500" />61 <span className="ml-2 font-mono text-xs text-zinc-500">terminal@ui-anvil ~ %</span>62 </div>6364 {/* Terminal body */}65 <div ref={containerRef} className="relative h-72 overflow-y-auto p-4 font-mono text-sm leading-relaxed">66 {/* Scan lines overlay */}67 <div className="pointer-events-none absolute inset-0 bg-[repeating-linear-gradient(0deg,transparent,transparent_2px,rgba(0,0,0,0.1)_2px,rgba(0,0,0,0.1)_4px)]" />6869 {displayedLines.map((line, i) => (70 <div key={i} className="whitespace-pre-wrap">71 <span className={line.startsWith("$") ? "text-green-400" : line.startsWith(">") ? "text-green-300/80" : "text-green-200/60"}>72 {line}73 </span>74 {i === currentLine && currentLine < lines.length && (75 <span className="ml-0.5 inline-block h-4 w-2 animate-pulse bg-green-400" />76 )}77 </div>78 ))}79 {currentLine >= lines.length && (80 <span className="ml-0.5 inline-block h-4 w-2 animate-pulse bg-green-400" />81 )}82 </div>83 </div>84 );85}