TL;DR: We’ve devised a strategy to shepherd users away from archaic commands. I hope this case study shapes our thinking on UX for new terminals.

Dear Terminal Aficionados,

Excited to have the free time to summarize progress I’ve made on Twitch this year. The biggest focus was teaching new users that Terminal Click has a visual browser. My friends suggested I eliminate the cd and ls commands entirely because our alternative is superior. However, as I kept reflecting on Jes Chuhta’s fireside chat [1] (along with some private banter) this suggestion to merely chuck out the old guard didn’t sit right with me.

So what have I done instead?

Using the Old to Show You the New

After running some experiments, the solution that delighted users the most was to lull them into believing something like cd exists and then immediately violate expectations:

User feedback tells me it just seems to click (hehe) now! Notice how we’re incorporating new behavior into the old command followed by recommending the faster workflow. Running ls works similarly. Another thing I would like to implement is dissolving the command into a puff of smoke: if someone knows a quick shader trick for this please shoot me a message (I use sokol-gfx for the graphics.)

The rest of the post details what it took to ship this feature. Remember that Terminal Click is a native program with a small footprint; it’s not Electron.

Auto-Suggestion Box

The very first sign that things are different around these parts is when cd gets color-coded into pink. Now it’s possible the user didn’t notice this, so we also generate a drop-down panel with valid suggestions for cd: if that doesn’t catch their attention nothing will! As demonstrated earlier, users can filter down the auto-suggestions as they type out an argument.

We use microui as our base UI library which means we have to hand-roll plenty of custom behavior ourselves, such as smooth scrolling:

Perhaps I should clarify further: microui already supports scrolling on panels. What I’m actually demonstrating is this scenario:

  • You’re navigating the suggestions with <TAB>
  • You scroll far away with the mouse
  • You press <TAB> again to keep going through the list

In this situation you need to snap back and show the next item. The snapping used to be instant, but it turns out that smooth-scrolling is more user friendly, so that’s what I’ve added.

I’ve also been wanting to implement the Levenshtein distance so we can help users with their typos. Unfortunately this desire to assist can become rabbit hole factories, so I’m leaving it there for the time being.

Real-Time Command Analysis

Most terminal emulators have zero clue what it is you’re typing on the keyboard (that’s left up to a text-only program like zsh.) Terminal Click understands user input, but until recently it only analyzed user commands when it was time to execute them. In order to react instantaneously—like the auto-suggestion box above—we had to implement real-time command detection and analysis. Two major concerns bubbled up while programming this: (1) whether to cache results and (2) understanding the nature of these commands (built-in vs external.)

1. Premature Caching is a No No

Command detection is fancy shmantsy talk for parsing a string. So we have an analyze_user_command(...) function that takes in a user string, and inside it we ask ourselves “Hey is the user typing cd, clang, vim etc.? OK let’s react to that.” The most straightforward implementation is to run the analysis on every frame. However, the reader will realize this procedure might become very expensive down the road. On the Twitch stream I mused that I’d really like to cache prematurely, as a treat: at the very least we should only run the analysis on keystroke changes.

Turns out this impulse caused more trouble than it’s worth. The wiser move is to default to a “recompute everything on every frame” philosophy, and forget about any caching efforts for as long as possible. If you have Discord and want the nitty gritty for how I arrived at this conclusion, join the Mr. 4th server to read up on this thread [2].

2. Built-In versus External Commands

Currently we’re only detecting built-in commands – notice how we color some obvious suspects with a bit of pink as soon as they’re validated:

However, serious complications arise when we want to analyze external commands. For example if we wish to detect tar and offer visual hints/validation about the flags it can accept, we are officially talking about a binary that’s not under Terminal Click’s jurisdiction. I’m leaving this as a provoking thought exercise, because I do believe these complications can be addressed fully – which I hope to expand on in a future devlog.

P.S. Manual use of tar should be skipped entirely. If Terminal Click has a visual browser, why not support archiving files on the graphical side? Indeed, tar might very well be the next candidate to vanish into a puff of smoke!

Timed Tutorial Hints

It’s common courtesy to generate hints while the user learns the ropes of your app, but it’s critical for their appearance to be pleasant, unobstrusive, and easy to review or dismiss.

We achieve this by implementing the following properties:

  • Fade-In Effect
  • Countdown Progress Bar
  • Pause On Hover
  • Fade-Out Effect
  • Click to Dismiss

Another thing I would like to implement is rounded corners. Finally, notice how the hint is away from the action so it can be readily ignored. It really bothers me when other apps have them all up in my business and I’m forced to handle it.

A Tangent on Large Language Models

The Handmade Network often asks me whether I’ve found any use for LLMs while making this terminal. I admit to one use case.

When I was programming the progress bar for tutorial hints, I had to keep in mind that hints can be of arbitrary size and display for an arbitrary span of time. Therefore how the progress bar gets rendered and animated is variable too. There’s a simple math equation to solve this and it’s fun and quick to derive it… if you’re in a good mood. I wasn’t in a good mood, I was having a personal bad day.

Prompting an LLM for the solution and verifying it was a smart use of the tool.

Okay, What’s Next?

I am aiming to ship an alpha to users, ideally this year, so I will continue polishing the presentation and fixing the obvious known bugs.

Feel free to drop your thoughts at abner@terminal.click and don’t forget to follow on Twitch to catch some of this work live, especially as I start collabs with Mr. 4th soon!

With any luck, more devlogs will come out a little faster too.

Yours sincerely,

Abner Coimbre

Footnotes

[1] Jes is a professional UI/UX designer that joined me at Handmade Seattle 2023. She’s made me care a lot more about the onboarding story for beginners.

[2] I understand this is relevant information locked behind a login page. I’ll request permission to export this Discord thread.