CretezyCretezy × Technology & Programming
UnreleasedDeveloper Tools

Cretty: A New Terminal Emulator

My journey with using the command line started when I started using computers more seriously, likely around the time I discovered Linux. I was probably around 10 years old, and figuring out I can control the computer by writing text was eye opening. A year or two later, I started hosting Minecraft server for my friends, the public, and I. This is when I started using this skill on a daily basis; SSHing into servers, running Linux on my desktop, and eventually learning programming.

I’ve always been particular with my tools. Over the years, I used IntelliJ/WebStorm for many years (due in part to developing Minecraft server plugins, then websites), and in the last ~5 years, switched to Neovim, followed by Zed. For terminal emulators, I remember using iTerm2 on macOS for over 15 years, while on Linux I used (one of the many evolutions) of the GNOME terminal, Guake, and Kitty.

All these terminal emulators have allowed me to work how I want to work, but with the birth of AI and their many CLI tools, I find myself in my terminal more than I ever was. In my day-to-day, I find myself juggling between many tickets and agents and worktrees and projects, something that traditional terminal emulators aren’t great at.

Many terminal emulators support tabs (I don’t like using tiling within my terminals) and multiple windows, but this wasn’t enough for me, and I found cmux for macOS to be a very good solution to this. With it’s sidebar of sessions/workspaces, it made it easy to group multiple tabs (e.g. an agent + a runner) within a session, making it easy to switch between multiple active tasks. It’s a very nice piece of (macOS) software.

Alas, although I use macOS daily, I use Linux outside of work, and cmux is macOS only. This made me think: Could I build my own terminal emulator?

The Journey To Working

I knew what I wanted: cmux, but on Linux, and with my own preferences and taste. And I knew how I didn’t want to build it: web technologies (i.e. Electron, Tauri). Although I wanted to build a cross-platform application, and I have tons of experience working with the web, I wanted to build a proper desktop application.

I settled on using Rust, primarily for my familiarity and it’s performance/safety. Within the Rust ecosystem, I choose Iced as the GUI framework for it’s ergonomics, flexibility, and (nascent) community. With this toolkit, Windows + macOS + Linux support should be relatively straightforward.

Once my choices were done, I got started writing code, with the help of AI. Most of the project was indeed written by AI, with some strong steering and guidance. The release of GPT 5.6 couldn’t have came at a better time.

I first started with a basic terminal emulator implementation, backed by Alacritty’s terminal parsing crate (thank you!). I got a very naive implementation done, which could spawn a shell, render it’s output within a grid of Iced widgets, and accept inputs. Look ’ma, my first terminal emulator! Once this was implemented, I moved on to basic session and tabs within the sidebar.

This is how the first working version looked:

[INSERT IMAGE]

Simple, Correct, Fast

Next, I focused on adding a bunch of features. Hyperlinks? Check. Search? You got it. Bell/notifications? Sure thing. Themes? In all the colors.

Once I implemented line height, I noticed gaps in ASCII art between rows. I inspired myself from other terminals (namely Alacritty again), and implemented custom drawing for certain glyphs, such as █ and ━/┃, so that they extended all the way to the cell’s edge. And needed to implement anti-aliasing. Luckily for text I was already using cryoglyph – Iced’s wgpu text renderer based on glyphon, which uses cosmic-text – for sharp anti-aliased high performance text.

I also took the time to implement some features I’ve wanted from other terminals but haven’t found, such as “gapless margin”. For example, when running Neovim (which sets it’s own background color using cells’ background) within Kitty (with), a gap appeared around if the background color didn’t match.

[INSERT IMAGE: kitty nvim]

The same was visible when using codex:

[INSERT IMAGE: kitty codex]

I implemented 2 fixes/features: First, cells are “stretched” to fit the viewport, instead of being snapped to a fixed number of rows and columns. This fixed the gap around, which make it look seamless. Second, I implemented margin/padding within the terminal viewport, as I find it prettier when text isn’t stuck to the edges. Together, they give us “gapless margin”:

[INSERT IMAGES: cretty nvim/codex]

Design Design

As you can see from the first screenshot of Cretty above, it was quite ugly. I extensively reworked the design, first settling on a flat look, then a more rounded look. I also implemented application themes separate from terminal themes (and added a bunch of built-in terminal themes too), with the ability to override any value or even import custom app or terminal themes.

While using the terminal to develop itself, I also noticed that always having the sidebar open takes up a lot of space when I’m focused on one tab. So I implemented an option to switch between displaying the tabs in the sidebar or in the top tab bar. I then followed this up with another option to have the sidebar automatically collapse and show on hover, moving it out of the way when not needed. And by dog-feeding it more, I realized I also needed a way to access the sidebar using the keyboard, so I implemented a “focus sidebar” keymapping with keyboard navigation.

[INSERT IMAGE: top bar tabs]

And although I preferred the new round styling, I did like the appeal of the flat style I had originally implemented. So I also added an option to toggle between them.

[INSERT IMAGE: flat styling]

What Else Is In A Terminal?

Next up, I knew I needed to focus on 3 aspects:

  • Performance
  • Terminal support
  • Cross-platform support

Performance

I rebuilt the naive renderer with a custom wgpu-backed GPU renderer. This significately increased the performance and smoothness of the terminal. Many iterations were made here to get the right balance.

Terminal support

Did you know that terminal can render images? And there’s 3 protocols to render images (Kitty, iTerm, Sixel, probably more)? Well Cretty support those.

There’s also 3 ways for processes to report notifications: Bells (\a) and OSC 9/777 (which can support title and body).

There’s also another OSC protocol for shells to report a title and which commands are currently running. And another for the working directory. And progress reporting. And cursor shape. And clipboard. And many more for colors.

There’s also alt mode, which let’s a process take over the entire screen (such as Neovim and recent versions of Claude), which required a .terminfo file installed on the system to report the terminal emulator’s capabilities (strangely, running jj was failing without this). There’s also ligatures, wide cells (where some Unicode characters such as Japanese characters or emojis take up 2 cells instead of 1).

I believe I’m now implemented the majority of the commonly supported features (at least looking at this feature matrix).

Cross-platform support

As this project was coming along, most of the testing was done on Linux. I booted up my Mac and implemented platform-specific features, such as the traffic lights (the close/minimize/maximize red/yellow/green buttons), which was difficult to get right (especially with fullscreen mode and a sliding sidebar).

[TODO: WINDOWS]

What Do We Have Now?

Well, I now have built a terminal emulator, (hopefully) capable of supporting most common features, with a custom paradim inspired by cmux. Luckily, a few friends were able to test it themselves.

A lot of work has been put into polishing the application, including having every setting editable within the application, having great documentation, and ensuring stability. Memory usage is low, and the terminal performance is flawless.

You can view the website and documentation [here] and install it from [here].

Avatar

Who am I?

Hello! My name is Cretezy and I am a software developer. I write about programming, personal projects, and more.

See more posts here.