cd ../writing
// recipe · 6 components

Building a terminal in HTML // from caret to ⌘K

Every developer portfolio wants a terminal aesthetic. Most ship a green-on-black div and call it done. A real terminal feel is six small pieces working together — blinking caret with the right timing, scramble text on hover, prompt format, command palette (⌘K), autocomplete ghost, output styling. Build them once, reuse forever.

6 components 0 dependencies ~250 lines total © use anywhere

Terminal aesthetics work because they signal seriousness. The user thinks: "this is built by someone technical, who understands tools." It's why Vercel, Linear, Stripe, and every modern dev portfolio leans on these patterns.

Below are the six building blocks. Use them as a system — not all at once, but pick the ones that fit the surface you're building. A full-page boot screen wants the caret + scramble. A search modal wants the command palette. A CLI-style input wants the prompt + autocomplete.

01 / micro

The blinking caret (with correct timing)

Real terminals blink at 1.05–1.1 seconds per cycle, not 0.5s like most CodePen examples. They use a step function, not ease — terminal carets snap on and off, they don't fade. Both details matter.

amr@iamr
Why steps(1)? A linear easing fades the caret in/out over a frame. Step easing snaps it instantly between visible and invisible — which is exactly what real terminals do. Subtle but distinguishing.
02 / motion

Scramble text — the Matrix decryption effect

The text starts as random characters and "settles" letter by letter into the final word. Used in titles, hover effects, page transitions. The trick: each character has its own settle time, weighted so earlier letters settle first.

LOVE OF CODE
The settle distribution. Each character's settle time is 0.3 + (i / n) * 0.7 of the total duration. That means even the last character starts settling at 30% of the duration. If you let everything settle linearly from start to end, the first letters look like they're stuck — the eye reads them as broken, not decrypting.
03 / layout

The prompt — three-color shell format

The classic $ user@host:path> layout. Real shells color-code each segment. Use green for the success prefix, violet for the user/host, pink for the separator. Makes scanning natural.

$ ~/writing
04 / interaction

Command palette (⌘K)

The Vercel/Linear/Raycast pattern. Press ⌘K, modal appears, search filters a list of actions in real-time. Arrow keys move selection, Enter executes. Pure JS, no library.

go home
go to writing
grep portfolio
One detail people miss: the active = 0 reset on every input event. Without it, filtering updates the list but leaves the selection index pointing at a position that no longer exists — Enter then triggers the wrong command. Tiny bug, hard to notice until users complain.
05 / interaction

Autocomplete ghost text

Zsh/Fish-style: as you type, the predicted completion appears as faded "ghost" text after the cursor. Tab accepts it. The completion comes from a history array — recent commands surface first.

cd ~/wr|iting/posts
Don't fight the browser. Set autocomplete="off" on the input or the native browser autocomplete will appear above your ghost text and cover it. Both compete for the same screen real estate; only yours should win.
06 / output

Output styling — colored exit codes

Terminal output reads as structured when each line type has a consistent color. Commands in white, success messages green, errors red, muted/debug info dim. Two-character prefixes (, , ) make scanning instant.

› deploy production
building bundle...
✓ bundle ready (4.2mb)
✓ uploaded to cdn
✗ healthcheck failed

Putting it all together.

A full terminal UI uses 3–5 of these together. A "boot sequence" page chains: scramble title → caret prompt → output styling → settled output. A search modal is: command palette + autocomplete ghost. A CLI showcase is: prompt + output styling.

Pick by surface. Don't ship all six on one screen — that's not a terminal, that's a cosplay.