Back to notes
note

Why I Built My Portfolio as a Terminal

On choosing a command-line metaphor for a personal site, and what it taught me about interface design.

·updated Aug 19, 2026·#essay#design#terminal
const{Fragment:e,jsx:t,jsxs:a}=arguments[0];function _createMdxContent(o){const n={code:"code",p:"p",...o.components};return a(e,{children:[t(n.p,{children:"Most developer portfolios look the same: a hero, a grid of project cards, a contact form. They're fine, and they're forgettable. When I sat down to redesign mine, I wanted something that would tell you more about how I think than a list of links ever could."}),"\n",t(n.p,{children:"A terminal felt like the right metaphor for a few reasons. It's the interface I actually live in — if you want to know what my work feels like, this is it. It also forces a kind of discipline: a command line has to be discoverable, predictable, and fast, or people give up. Those constraints are exactly what good interface design should impose on you anyway."}),"\n",a(n.p,{children:["The tradeoffs are real. A terminal aesthetic is hostile to casual visitors who don't want to learn a grammar just to read a paragraph. So I tried to make the common paths frictionless: ",t(n.code,{children:"help"})," lists commands, tab completion exists, and every command has a sensible default. You shouldn't need a manual to get around, but the manual is there if you want depth."]}),"\n",t(n.p,{children:"What surprised me was how much the metaphor shaped the content itself. When the surface is text, you write better copy — every paragraph has to earn its place because there's no image to hide behind. The blog reads differently, the project descriptions read differently, even the bio got tighter."}),"\n",t(n.p,{children:"A portfolio is a piece of writing as much as it is a piece of software. Treating it like a tool — something with verbs and nouns and a small grammar — made both halves better."})]})}return{default:function(e={}){const{wrapper:a}=e.components||{};return a?t(a,{...e,children:t(_createMdxContent,{...e})}):_createMdxContent(e)}};