After sharing my portfolio project on DEV, a fellow community member commented asking how I built the retro terminal panel. So, I decided to break down the logic and share the details here!
The goal was to show a series of commands and outputs, just like a real terminal, and animate them. I also wanted a blinking cursor and a “reset” effect after all lines are shown.
The State
I used React’s useState to keep track of the lines currently displayed in the terminal:
const [terminalLines, setTerminalLines] = useState([] as string[]);
The Commands
I defined the commands and outputs as an array:
const terminalCommands = [
'> whoami',
'ngawang_tenzin',
'> cat skills.txt',
'React.js | Node.js | Python | TypeScript',
'> ls projects/',
'barma-sorig-web-app/ | quiz-mobile-app/ | portfolio-website/',
'> status',
'AVAILABLE FOR HIRE',
'> echo "Let\'s build something amazing!"',
"Let's build something amazing!"
];
The Animation Logic
I used useEffect to set up an interval that adds one line at a time to the terminal. Here’s the core logic:
useEffect(() => {
let terminalInterval: ReturnType<typeof setInterval> | undefined;
let lineIndex = 0;
if (isRetroMode) {
terminalInterval = setInterval(() => {
if (lineIndex < terminalCommands.length && terminalCommands[lineIndex]) {
setTerminalLines(prev => {
const newLines = prev.slice();
newLines.push(terminalCommands[lineIndex]);
return newLines;
});
lineIndex++;
} else {
setTimeout(() => {
setTerminalLines([]);
lineIndex = 0;
}, 3000);
}
}, 800);
} else {
setTerminalLines([]);
}
return () => {
if (terminalInterval) clearInterval(terminalInterval);
};
}, [isRetroMode]);
- Every 800ms, a new line is added.
- When all lines are shown, it waits 3 seconds, then resets the terminal.
The Styling
I used CSS to get the neon green text, dark background, and blinking cursor. Here’s a snippet:
.terminal-line.command {
color: #00ff41;
}
.terminal-line.output {
color: #cccccc;
margin-left: 1rem;
}
.terminal-cursor {
color: #00ff41;
animation: blink 1s infinite;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
Result
The result is a dynamic, animated terminal panel that brings a retro vibe to my portfolio. It’s all handled with React state and effects, making it easy to customize and integrate with the rest of my site.
Top comments (1)
🔥❤️ cool