A much better alternative to this would be to for more terminal emulators to implement overstrike mode (DECSET 20, as available on the VK100). That way you could just draw border characters over existing text cells to achieve the same thing.
Unfortunately mintty is the only terminal emulator I'm aware of which supports overstrike [0], as this would open up a world of new possibilities for TUI apps if more widely supported.
A considerably less archaic and more generally useful way would be for Unicode to add border-drawing given that the concept of composing several codepoints to the same glyph is already there and ubiquitous. You’d just need 2^4=16 new codepoints.
Ages ago I had found a software that would convert an image to ascii-art, and then used another tool called posteriza to split the large image into several A4s, which I then taped together and hung on my wall. Would love to do something similar but with better tools.
I’m not against overstrike, but I can think of one drawback of that solution: it becomes significantly harder to have rounded corners with a filled interior.
But I’m not trying to argue for nor against either solution.
There's some downsides to this - I can't recall where I called this out off the top of my head, but this also adds a bunch more things that that wouldn't do that are covered in the spec.
If you mean your proposal adds more things, that sounds like it might be over-complicated. To solve the problem of tightly-fitting boxes around terminal text -- if you consider that to be a real problem -- overstrike sounds like a really elegant solution.
Which things do you consider in your experience of writing tuis that are mentioned as being wanted in the blog post / rationale doc linked to be unnecessary?
If you want those things then overstrike is insufficient.
cell borders sound even more elegant imo, they are a targeted, precise fix for a useful feature. overstrike sounds messy to me though I can see where it has a lot of uses.
The better alternative to most of this is to use a different display protocol, one that gives you pixel-level control, if you want pixel-level control.
This protocol would still be used for user interfaces, but it would use a completely different approach to rendering them, I guess we could call this approach "graphical"?
If it's not obvious how this could be achieved with overstrike, basically the idea is that you could draw text on a cell then overstrike the cell with 1/8 block characters for the 4 edges characters (U+2581 & friends) to create a border around the cell.
Edit: HN stripped the characters in question from my comment
I love this work and everything else Ratatui does but I have to ask: if you're changing the terminal protocol and the terminal itself to do this, why not do something more ambitious; a full monospaced information-dense UI framework, a terminal designed for user interfaces, rather than one designed to replicate the limitations of dumb terminals?
I've written about it before, but in brief the mountain of standards is worth ripping out wholesale and doing write as a semantic protocol. It's needed to solve several things that work really poorly in terminals because their unit of compatibility is cells rather than a higher primitive. It's hard to bake something on top that works well.
The need is most strong in Accessibility, Text wrapping, Scrollback handling (i.e. making the scrollback editable and not dead text), and various other bits that make writing highly functional TUIs. Coding agents tend to find all those edge cases.
This often gets push back that it's easy, to which I can point nay sayers at the various many months long issues on things in Codex, Gemini, Claude etc. on flickering, scrolling, key handline, IME, ... doing anything moderately complex involves modeling a terminal in a terminal app effectively.
Ghostty and Rex sort of do the opposite bit. If you think of it like a stack, they write a new layer underneath that transports the cells on a better multiplexer layer 0. I think a new semantic layer 2 is an approach that would be neat to work with.
I think I mostly just want to see someone do it so I can see what it looks like; it just feels like something that should exist. You're taking baby steps towards it! :)
I kinda keep talking about it in the hopes that someone will be nerd sniped enough to throw tokens at it as an idea. Sort of what you're probably doing too I guess. ;)
... Write up a more complete spec of the problem and I could be tempted to throw some tokens at it. But before I do, can you write up a more complete description of the problem with existing terminal protocols? I don't think I understand the issues well enough to make a good solution. Eg, can you give some examples of what apps are hard to build now? What prior art is worth looking at? Etc.
I've been working on one version of this, if you want to see what it
looks like: https://bateri.dev/pens
It's narrower than replacing the cell grid. A program asks for a view
the way vim takes the alternate screen. If the terminal answers, the
program hands it the view's files once, and from then on the two
exchange six small messages inside the normal byte stream (APC frames,
the same trick kitty graphics uses). No port and no extra connection,
so it works over plain ssh to a box with no GPU. When the program exits
you get your terminal back, and in a terminal that doesn't answer the
program can fall back to plain text.
A view is either a Lua script the terminal draws itself, in its own
font and theme, or a sandboxed web page. The second one is exactly the
"terminals are becoming browsers" worry from upthread, and I don't
think that worry is wrong, which is why the native kind exists. Going
through tmux is a non-goal: a multiplexer that doesn't pass the stream
through untouched just means the program sees no host and falls back.
> a full monospaced information-dense UI framework, a terminal designed for user interfaces, rather than one designed to replicate the limitations of dumb terminals?
I can only speak for myself but I use the CLI and TUIs specifically because of the limitations those modalities impose on software that uses them as the primary method for interfacing with the end user. If you want a full featured UI and all that comes with it why not just use QT or GTK or modern HTML or etc?
I think the only "improvements" I'd like to see are thing such as metadata regarding what the different streams are for, an official way to communicate using structured data as opposed to raw bytes, that sort of thing. Spiritually in the same ballpark as the difference between HTML before and after CSS.
I actually am exploring exactly this. Ironically from the perspective of someone that was trying to leave the Terminal.
How i got here i find kinda interesting. Originally i was trying to leave the terminal. Using GPUI/etc frameworks. I kept running into the terminal though, because no matter how nice the UI is - the terminal still needs to work excellently.
Eventually i decided to try an abomination. To use a custom terminal which, not unlike Kitty images, allows generic apps to pass escape codes to control the UI components. Where the UI components have no restriction on "dumb terminals". So my text editor is a two part app, an editor and a tty to render the actual custom UI APC codes.
This paved the way for true smooth scrolling from within a terminal editor, as the editor effectively paginates but the tty scrolls within the buffered pages. It allows for different UI components to mix fonts and font sizes, eg popup docs being a different size than the other text, and .. well, anything i suppose.
I have to say it's working excellently and is slowly becoming my daily driver. I won't link it though, it's a fully vibe coded and even claude designed horror.
I'm surprised i've not seen more of this in the past to be honest.
I am running ewm (not exwm) which makes emacs into a wayland compositor and it's fantastic, most of the primitives dissolve and you script it with elisp, wayland windows are just a special buffer and where applicable normal windowing and buffering rules can be applied.
The developer seems to have used AI heavily in the elisp code and it works very well.
> To use a custom terminal which, not unlike Kitty images, allows generic apps to pass escape codes to control the UI components.
> I'm surprised i've not seen more of this in the past to be honest.
This is what emacs is. It's a text buffer, but text can have properties like how to render, and custom values. then a bunch of commands to manipulate the buffer and it's contents.
Whenever I use dumb terminals, I have the same feeling. I am also actively looking for a way to get a good developer experience while keeping more ownership of what gets generated with the new tools. My specific bottleneck is working in remote environments and not being able to have it , now that we have tools like Claude, Codex, and Gemini. (I find them safer to run them in virtual environments and working on them remotely is better than doing it locally.)
I also don't like the fact that each TUI application (btop, for instance) comes with its own color palette. So, a friend of mine developed a terminal (https://bateri.dev, macOS only for now, but the plan is to port it to Linux later) and yet another protocol where terminal SPAs can communicate over standard SSH (inspired by X over SSH, but we didn't like its drawbacks). The SPA itself is a set of Lua scripts that runs in a sandbox inside the terminal. The application on the host that communicates with the SPA can be implemented in any language (preferably Lua to keep it simple). With this approach, all SPAs (plugins) adhere to the user's color palette preferences. (There are more details that can share if you are interested.)
So far, to stress test it and help with devex, he has built a text editor (https://github.com/bateri/textpen) and a Docker/task monitor (https://github.com/bateri/dockerpen). I am also working on a plan document viewer that works within the terminal. We'd love some feedback if you are interested.
Because it will turn into the kitchen-sink mess that the Web is.
Terminals work so well because there's a huge frictional cost to adding to the protocol. That's what keeps the protocol simple, which is what keeps multiple implementations feasible. Unlike the web, where unless you have GoogleBux you can't afford to implement it properly.
You can save all that effort and instead come up with a CSS framework that enforces monospaced fonts, uniform font sizes, encourage information-dense layouts, have borders that don’t take up a cell (border: solid 0.1rem black; padding: 0.5rem;). Pair it up with a small JavaScript framework that listens to keypresses and buffers them. Furthermore, the framework makes the user decide on fonts, whether to allow images, whether to adhere to a strict character grid etc.
For a while in the 2000s I tried programming with Verdana in my IDE at the time. It wasn't all that bad. It would be in a terminal however - fun idea regardless.
Text terminal with every keystroke round-tripped through the server is not a design that makes sense for any reason other than backwards compatibility. It's kind of annoying to design for and atrocious for performance.
For some reason the page has very few examples of left/right zero width borders. The only ones I could find were a checkbox and as a highlight to show a selected row in a list.
This is pretty cool but this does feel like we are just reinventing another GUI display at this point.
I don't generally like TUI's and think one gets more flexibility with raw text interfaces and being able to glue things together is more important then them looking nice. I think less fancy out put is better to be honest.
I have vibe coded a remote X/Wayland solution that actually works really well for this, at least as long as you are mainly interested in one machine (so good for people with remote work machines, not so good for network/infra engineers).
You just run `mycommand connect host` and it will connect via SSH, start a Wayland server with X support, set up the appropriate environment variables, and also automatically reconnect, so you only have to do this once.
After that you can just run GUI commands via SSH and appear locally like you always wished they would. It uses a VNC-like image data protocol so the client works on any OS. And windows are seamless - no windows within windows nonsense. I haven't put much effort into the video protocol tbh but it's already better than Xpra and very usable with 100ms latency (London to NY) so that's good enough for me.
I'll try to open source it.
I think a better solution would be if SSH itself supported some GUI channel, but the only thing is the Kitty graphics protocol which kind of sucks tbh. I did try writing some tools using that for the GUI a while back but it's awkward because you have to use PNG, you're still stuck with the character grid for text, etc.
100ms sounds good, but how about the consistency of the GUI (remote vs local) and HiDPI issues when it comes to this approach? (I assume latency would be higher when there are many applications running in many windows?)
To be clear I meant the experience is fine when running on a 100ms link. I haven't measured the actual latency. That said it uses QUIC and sends the data as tiles, which are displayed immediately, so I suspect it is basically as low latency as possible. It does lead to fun mosaic style tearing which half of me finds cool and half wishes it didn't do that, but side-by-side with Xpra it's much faster and less annoying than waiting for a whole frame which is what Xpra does.
I'm running an old Qt X11 app with a modern retina MacBook with multiple different density screens and it works fine. There were some minor issues with that to start with but I pretty much just said "this happens, please fix it" and Claude figured it out without even having access to a Mac, which is impressive.
Honestly the thing that was hardest was keyboard layout. That kind of stuff never worked well for me in any remote desktop app, and now I can see why! You might never notice if you only use the US layout tbf. It works pretty well now though - I got it to query your local layout and the dynamically build an X keyboard layout and send it to the server.
I've run it with up to about 4 large windows and it seems to work fine. It doesn't send anything when nothing is changing so lots of windows won't matter unless they're playing videos or whatever - it's more designed for old Windows/Qt/Gtk style apps. I suspect you could do better with a traditional video codec but unfortunately the server I use has no GPU so that wasn't really an option.
ssh -X (or -Y) forwards your X11 connection automagically. It doesn't work for Wayland because Wayland was designed to be impossible to forward.
However, most X11 apps will have utterly abysmal performance on WAN SSH connections. Ancient apps will be slow because they block waiting for every response (this is unavoidable in Xlib) and less than ancient apps will be slow because they send full pixel data. It is possible to write a reasonably performant remote X11 app (using XCB instead of Xlib and always being aware of latency), but there are very few such apps. This is why Wayland dropped the requirement.
ssh -Y worked well for me. That usecase should be revived in a bandwidth efficient manner (eg. RDP does bearable over crappy links, eg. over the ocean) instead.
What worries me is that TUI used to mean light on your hardware unless it's doing actual work that you demanded.
What's the reality with these new frameworks? Whenever I see one i worry that it renders at 144 Hz in a loop instead of redrawing only when something changes, for one. And let's not mention redrawing only the areas that have changed [1].
Should I ask about ram consumption too?
[1] ... which is why vi is the best editor to use over slow, unreliable links.
I don't really see how these terminal borders would make any of these issues worse? You can build a wasteful 144Hz TUI using only dots and spaces. There's a tiny bit of overhead for the extra commands, but everything else seems to be an implementation detail, no?
What I'd really love to see instead of all of this is an OS that has composable areas that can interact and have event loops of their own. E.g. ditch the app boundary and compose. We're getting there sorta with AI Canvas type things (e.g. github copilot app, some of the stuff in chatgpt visualizations), but all of this sort of work tends to devolve to browser type things instead of simpler components. This is mostly unrelated to the terminal side of things though from my perspective on this. But it's a fun thought experiment.
Exactly. Any GUI element is a "window" and composed of other sub-areas, also windows. You could create windows in the "root window", then the WM would manage then and draw window decorations, but in theory you could also just render a window in a certain area within another window (e.g. a full application, or even just a single view or editor of an application).
I'm not too familiar with higher level frameworks like Qt or gtk, but I suspect since they just draw the whole thing, that they only use single X windows and don't compose them, so you wouldn't be able to render a subview of them inside a different context.
It's actually unusual for X11 apps to create a window per widget as it comes with a bunch of overhead. Only very old ones do that. However, it does work - windows can be used as widgets and they can cross-embed from other processes. This is very cool but rarely used. It allows you to run a casually sandboxed subprocess with GUI I/O.
They can also just draw on each other's windows and get input events on each other's windows. The connection between a window and its creator process is very weak: the window is automatically destroyed when the creator disconnects. And that's all. You can even turn that off, too. For every request that includes a window (or other resource) ID, nothing says that it has to be your window.
It is! OLE has to be one of my favourite abandoned technologies.
It does require a lot of deep coupling which is probably why it was abandoned, but also why it worked so well. You had things like passing menu subtree handles back and forth, so the host app and the embedded app could merge together their menus. This only worked because everyone on Windows was using the same menu subsystem, until Office 2007.
1. The AI disclosure up front is very useful for cutting my blog filter time from 10 seconds down to 1, which is significant in the age of content overload. Hopefully disclosure becomes a point of pride for vibebloggers and they'll add it more often.
2. While it makes sense that the popularity of TUIs (driven mostly by CLI coding agents) sees maintainers try and push more spec into emulators, I'm hoping this doesn't become the standard. The whole TUI mentality just runs counter to what makes terminals such sticky tech in the first place.
Compatibility will always be the hard part with new standards like this. Given that most terminals already have some special handling of box drawing characters, I don't know if it's completely dead on arrival for implementors, but I don't love as an application author with ratatui, not knowing how the padding on my app will look. I might honestly rather disable this and know it'll be more consistent, than enable it and fragment my UI.
The ratatui change was a pure PoC, isolated branch, my own fork, not the ratatui repo even. This would likely never ship as a default approach as it would be way too breaking. I haven't really spent any time on making it hook into the current block border approaches - it's just at the cell level where this is opted in. That will never merge without much much more though into things.
I used ratatui there mostly so that I could prove that it would work in real looking apps that do panels and similar stuff that benefits from borders.
But yeah, compat is key. It would probably go out to ghostty, rio, kitty pretty easily, terminal.app never, other terminals much slower. IDK about the windows / linux side of things.
I appreciate the innovation happening with TUIs in these modern times. But, aesthetically, I have to say, I like my borders to have some breathing room, which gets lost in this particular treatment.
My thoughts exactly. Borders costing a cell means you are forced to be frugal with them, lest you run out of space or have to do ugly and clumsy "pwease make ur window biggr :3" messages
One of the top 5 "smells" of LLM generated websites that I can't stand is everything has to have its own round-rect. Everything in a box. Every button, label, header, subheader, so much fucking noise everywhere. You shouldn't need that many.
Another, of course, is the phrase "The wire format", included in this post. Oh yeah, its the format on the wire? What wire? The wire between my psuedo terminal and my kernel? What garbage. Cool exploration but, come on: "The common path is a pen, held in the cursor like the current background color. Set it, print some text, and the printed cells get the borders:" shit is not OK to post
I like this a lot, especially the ability to draw lines through graphs like in `btop`.
Somthing I think could be intresting to go along with this is for the terminal to be able to distinguish sub-windows using these border, so if you've got a popup and try to select multiple lines in it, you'll actually select only the text in thr popup rather than the whole terminal-wide line.
That would be awesome! IIRC zellij supports this, but that only works as long as it intercepts all selection inputs. Having a more universal standard that terminal emulators can support would be great.
Interesting. All I wish I could do in a terminal is moving the cursor by clicking. And maybe selecting some text and replacing it with a single key stroke. Why is that not a thing?
Because a terminal emulator is emulating 1970s technology and the mouse hadn't been invented yet. We do have a way for apps to accept mouse input, believe it or not, but it's usually done by avoiding the 1970s emulation layer. As a bonus, you get full control over your screen pixels too!
This is true for all the other magic things I'm always reading about with the newest, hottest, terminal emulator tech XYZ, as in this article. People do amazing stuff with those tools. I'd already be very happy if the current line I'm writing in would have the convenience of a 1993 Mosaic input-element.
Also, selecting and replacing could be done without a a mouse. Quite often I want to select, copy, replace, paste somewhere else. Not possible without a mouse.
I am in general against the big push to fit GUI interfaces into the tty, but I have to say that this feature looks genuinely good. Vim will look great with this.
I love this idea. I HATE looking at rounded corners in the terminal window. Hate. I had no idea I would feel so strongly about such a thing. Also, easily fixable. But, wow.
The big thing to note on this is one last caveat. I don't care about the actual spec on this - happy for that to be whatever works. I care more about the capability than how it's done / implemented.
There's some bits that feel like they probably make sense to consider doing other ways, like how border placement works (inside, outside, on the border, etc.), and how the filling works - to make borders incorporate external or internal padding.
Why wouldn’t this work over tmux? The authors claims don’t make a whole lot of sense because if this were a cell property, like any other CSI, then it’ll get rendered in the terminal emulator exactly as intended. And we know this because none of the other CSI sequences get garbled over multiplextors.
But for there to be a dedicated section on how multiplexors wouldn’t work suggests to me that the authors already tried this via tmux.
So I’m left wondering what they’ve done with the implementation of this to make that a problem.
I spotted they are using DCS sequences. But even that shouldn’t be an issue itself.
Tmux drops DCS that it doesn't know like this. That aside, this is extra state per cell that needs to be tracked, handled, understood from a rendering perspective etc. It can work, but would require maybe a thousand lines of code or so to support storing and handling state, redraw etc. and all the various edge cases.
Really? That surprises me. Not saying it’s untrue, just that I’m surprised. I’ve found tmux doesn’t drop CSI, OSC nor APC.
I wouldn’t recommend APC because Apple Terminal doesn’t follow spec with APC parsing (one of the reasons I switched some of my custom sequences from APC to OSC).
Regarding the extra state to be tracked, tmux wouldn’t handle that cell state. That would be down to the terminal emulator.
Since these are cell properties, it does feel like CSI would be the right place (like Kittys undercurl).
I like this idea! Of course I might be biased, since it’s similar enough to one I’ve had myself. Good job getting an implementation going; I never did.
I upvote naysayers comments there as I don't think votes should be used to indicate (dis)agreement at least not without commenting why, more an indication that this is a useful thing to discuss. So if you see my comments not getting votes while every other one has a bump, that's my vote on them :)
It's kind of funny, I posted this here and there at similar times. Expected to be spam flagged there due to the anti-AI brigade, but my submission here was the one that actually got hit (likely because I disclosed AI use in the post body is my guess).
I think that's a fair question. It seems that people want more keyboard navigation and (sometimes) monospace UIs, but that should be perfectly feasible in a web UI.
Thanks for that slop warning, on a general point: wondering whether there might be enough momentum to finally ditch the whole terminal garbage and use proper GUIs in spite of what the card-punching devils intended?
Sure - I use GUIs most of the time despite maintaining Ratatui. I much prefer them for coding agents as the amount of interactions and various things I want out of the interface are not handled by TUI well. GUIs are a vastly superior interface (I worked on the Codex TUI at OpenAI btw).
This funny to read! I drive Codex TUI daily. In the past, I paired it with VSCode for better code navigation and file reading; seems similar to what you are saying or do you also mean Source Level Debuggers, etc.? But, I eventually worked on Kitty terminal typesetting instead and now reading the files with my gloss tool [1]; combined with Rex blocks it's really nice, easier on my eyes.
Thanks for Ratatui, which certainly has a top tier name, and also has had tons of great software written with it! I've been inspired by much of that ecosystem, especially the charting libs. The weird GUI stuff I'm doing with Kitty+Bubbletea, can certainly be done on Ratatui, in the spirit of Makepad. IMO, Golang needs this more than Rust.
Nothing really - Ghostty has a bit of padding that's unused per cell - 16 bits. The implementation stores an ID into a lookup table with border combinations. If all of those were used and never cleaned up, 65535 at around 100 for each combination used, order of magnitude 25MB absolute worst case assuming no real optimization in place for this.
I think the other side of things is why have the graphic program run over ssh, just have raw text cli tools to manipulate what ever then have a program driving it. This for me is where emacs excels and some programs already fit well with this model and the fantastic (albeit hacky) tramp.
Doing it through port forwarding is kinda bad though because generally access to network ports is not very well access controlled. Doing it through unix sockets (like x) would be much better but annoyingly browsers do not support http over uds
Afraid that’s a contradiction. In this role, HTML is a pile of hacks upon hacks that was not originally intended for UIs.
But, yeah, people are trying to reinvent GUIs. By layering hacks over TTYs. If only there’d be some protocol for widgets and events over a stream connection…
the thing with X and wayland etc is, that they are low level. which is fine if you want full control over the presentation. what HTML was trying to do is to go higher level, send over some data and let the browser figure out how to present it. but it went wrong and people are abusing it as a low level presentation interface like X or wayland.
what we are missing is a really high level protocol/system that takes really high level data and figures out the presentation on its own.
take a list of files for example. you can run ls -l in a terminal and it will attempt a crude text based formatting of the output. or you can run a full gui filemanager.
what if there was a command that would produce ls output as a table data structure, run in a sort of terminal that knows how to format a table nicely without the ls command having to include any formatting instructions? this terminal would have support for all sorts of data types and structures to display all of them nicely.
> Take a list of files for example. you can run ls -l in a terminal and it will attempt a crude text based formatting of the output. or you can run a full gui filemanager.
ls's output (and a few other programs') are human facing. They're not meant to be machine readable.
> what if there was a command that would produce ls output as a table data structure, run in a sort of terminal that knows how to format a table nicely without the ls command having to include any formatting instructions? this terminal would have support for all sorts of data types and structures to display all of them nicely.
Because that's just complexity for its own sake. What's simpler is to just create a shell alias for a particular view you want. The shell is for interactive usage, with some capabilities for automation. If something better is needed, you write a real program for it.
> what if there was a command that would produce ls output as a table data structure, run in a sort of terminal that knows how to format a table nicely without the ls command having to include any formatting instructions? this terminal would have support for all sorts of data types and structures to display all of them nicely.
So, powershell? For some reason only IT jockeys on Microsoft's death grip remember and use its full capability after learning it.
> In this role, HTML is a pile of hacks upon hacks that was not originally intended for UIs.
I get where you're going and am genuinely curious, what does a "better" system designed to do what HTML/JS have become actually look like? (or what would one look like?)
There has to be markup of some sort, and there has to be scriptable interactions of some sort, right? If not, how else would it work?
Well, yea, that was a remark about HTML's legacy. In pre-AI era, I preferred QML or GtkBuilder (when viable, of course) to HTML any time. Nowadays, to be honest, I don't know.
That said, yes: NeWS, XForms, rio, and many others have tried with arguably cleaner designs. Not without their own issues, but in comparison to HTML, driving GUIs was a design goal from day zero (not a direction shift), and they're a lot smaller and simpler (which has its pros and cons).
UI in a browser is a massive hack in itself, a clean design would be better. For example a compact semantic remote access protocol to use with UIs, something like SPICE but better optimized for networks, fully presentation-independent, and less janky. This would let everyone use a GUI framework of their choice with an adapter. But people building terminal GUIs are culturally not ready for this, they'd rather continue reinventing the wheel and piling up hacks in terminals. I wonder when they realize that proportional fonts are more readable when vertical alignment is handled separately, and introduce terminals with variable-width fonts. And the presentation layer (I suggest calling it CSS).
Having markdown tables render with zero-cell spacing (use underlines for horizontal and different background shades for vertical) is just one of the billion reasons I will never, ever, ever go back to closed-source coding agents.
A pet peeve of mine is that most people / WM get "useless gaps" wrong. You do want a gap between two terminals because otherwise there are times where things can get really confusing (where you don't know what belong to which terminal / window).
So the "borderless" (0 pixels) / zero "useless gaps" simply are confusing and... Wrong.
But then people who do use useless gap, as in TFA, get it wrong too: they typically add gaps near the monitor's edges.
Yeah. But no. Sorry but my monitor's edge is a perfectly fine gap. I don't risk mistaking it for anything.
So I modified my WM (the Awesome WM) to do proper "useless gaps" computation and remove the ones that really are useless: and that'd be those near the monitor's physical border.
I mean: nearly everybody gets it wrong, but it's not complicated to get it right, is it?
P.S: even the terminology is wrong... People calling those "useless gaps" haven't got a clue: they are useful. The only useless ones are the one on the monitor's edge (if your monitor has physical edges, which it probably does).
The side gaps were for for making it feel balanced in the screenshots and visualizations to be able to show where the borders line up with cells easily etc. It wouldn't be what I'd use in a real app.
One thing to note though is that some things which are "wrong" can be aesthetically pleasing to look at and may be the actual best UX in certain situations. There's a lot of new design principle work (especially in macOS / iOS) that is about things going past the edge, or being overlaid with floating things. Some of this is "wrong" some of it is wrong, and some of it sitting in in the useless gap beteen the two. ;)
Man, I’d really like a monitor with no edges. One that just keeps going and going, past my window and the tree outside until it’s completely out of sight. 100% useful area.
One benefit worth calling out: the box-drawing fallback is worse than it looks for CJK users. U+2500-257F and the half/full block elements are East Asian "Ambiguous" in UAX #11, so in a terminal configured to render ambiguous as double width (xterm's cjkWidth, iTerm2's checkbox) every line glyph takes two cells and the whole frame lands in the wrong place. Cell borders aren't text, so that failure class just disappears.
The part I'd want specced early: borders are per-cell, but cells aren't per-grapheme. A CJK char owns two cells plus a continuation placeholder, and combining marks or ZWJ emoji sequences own zero-or-more depending on whose wcwidth table you ask, so app and terminal routinely disagree across Unicode versions. Today that shows up as a vertical bar one column off; with cell borders it becomes a line that stops short of the corner. Does the border attach to the cell or to the grapheme cluster?
Unfortunately mintty is the only terminal emulator I'm aware of which supports overstrike [0], as this would open up a world of new possibilities for TUI apps if more widely supported.
[0] https://github.com/mintty/mintty/wiki/CtrlSeqs#overstrike
I've really enjoyed using it on paper: https://hughpyle.com/ASR33/
Ages ago I had found a software that would convert an image to ascii-art, and then used another tool called posteriza to split the large image into several A4s, which I then taped together and hung on my wall. Would love to do something similar but with better tools.
Damn, that's one from back in the day.
But I’m not trying to argue for nor against either solution.
This isn’t an issue if you want square borders. But the screenshots in the article showed fancy rounded corners.
The syntax is:
CSI 53 m SGR 53 — Overlined CSI 55 m SGR 55 — Not overlined
which is much more different than mitty's Control Sequence, but supports much more emulators
If you want those things then overstrike is insufficient.
Edit: HN stripped the characters in question from my comment
I've written about it before, but in brief the mountain of standards is worth ripping out wholesale and doing write as a semantic protocol. It's needed to solve several things that work really poorly in terminals because their unit of compatibility is cells rather than a higher primitive. It's hard to bake something on top that works well.
The need is most strong in Accessibility, Text wrapping, Scrollback handling (i.e. making the scrollback editable and not dead text), and various other bits that make writing highly functional TUIs. Coding agents tend to find all those edge cases.
This often gets push back that it's easy, to which I can point nay sayers at the various many months long issues on things in Codex, Gemini, Claude etc. on flickering, scrolling, key handline, IME, ... doing anything moderately complex involves modeling a terminal in a terminal app effectively.
Ghostty and Rex sort of do the opposite bit. If you think of it like a stack, they write a new layer underneath that transports the cells on a better multiplexer layer 0. I think a new semantic layer 2 is an approach that would be neat to work with.
It's narrower than replacing the cell grid. A program asks for a view the way vim takes the alternate screen. If the terminal answers, the program hands it the view's files once, and from then on the two exchange six small messages inside the normal byte stream (APC frames, the same trick kitty graphics uses). No port and no extra connection, so it works over plain ssh to a box with no GPU. When the program exits you get your terminal back, and in a terminal that doesn't answer the program can fall back to plain text.
A view is either a Lua script the terminal draws itself, in its own font and theme, or a sandboxed web page. The second one is exactly the "terminals are becoming browsers" worry from upthread, and I don't think that worry is wrong, which is why the native kind exists. Going through tmux is a non-goal: a multiplexer that doesn't pass the stream through untouched just means the program sees no host and falls back.
The only host so far is bateri, the macOS terminal I'm building, and the spec is an early Apache-2.0 draft: https://github.com/bateri/pencere/blob/main/spec/draft/pence...
Do they? Last time I checked you still couldn't select text via the keyboard in the Claude Code TUI.
I can only speak for myself but I use the CLI and TUIs specifically because of the limitations those modalities impose on software that uses them as the primary method for interfacing with the end user. If you want a full featured UI and all that comes with it why not just use QT or GTK or modern HTML or etc?
I think the only "improvements" I'd like to see are thing such as metadata regarding what the different streams are for, an official way to communicate using structured data as opposed to raw bytes, that sort of thing. Spiritually in the same ballpark as the difference between HTML before and after CSS.
How i got here i find kinda interesting. Originally i was trying to leave the terminal. Using GPUI/etc frameworks. I kept running into the terminal though, because no matter how nice the UI is - the terminal still needs to work excellently.
Eventually i decided to try an abomination. To use a custom terminal which, not unlike Kitty images, allows generic apps to pass escape codes to control the UI components. Where the UI components have no restriction on "dumb terminals". So my text editor is a two part app, an editor and a tty to render the actual custom UI APC codes.
This paved the way for true smooth scrolling from within a terminal editor, as the editor effectively paginates but the tty scrolls within the buffered pages. It allows for different UI components to mix fonts and font sizes, eg popup docs being a different size than the other text, and .. well, anything i suppose.
I have to say it's working excellently and is slowly becoming my daily driver. I won't link it though, it's a fully vibe coded and even claude designed horror.
I'm surprised i've not seen more of this in the past to be honest.
The developer seems to have used AI heavily in the elisp code and it works very well.
> I'm surprised i've not seen more of this in the past to be honest.
This is what emacs is. It's a text buffer, but text can have properties like how to render, and custom values. then a bunch of commands to manipulate the buffer and it's contents.
I also don't like the fact that each TUI application (btop, for instance) comes with its own color palette. So, a friend of mine developed a terminal (https://bateri.dev, macOS only for now, but the plan is to port it to Linux later) and yet another protocol where terminal SPAs can communicate over standard SSH (inspired by X over SSH, but we didn't like its drawbacks). The SPA itself is a set of Lua scripts that runs in a sandbox inside the terminal. The application on the host that communicates with the SPA can be implemented in any language (preferably Lua to keep it simple). With this approach, all SPAs (plugins) adhere to the user's color palette preferences. (There are more details that can share if you are interested.)
So far, to stress test it and help with devex, he has built a text editor (https://github.com/bateri/textpen) and a Docker/task monitor (https://github.com/bateri/dockerpen). I am also working on a plan document viewer that works within the terminal. We'd love some feedback if you are interested.
Terminals work so well because there's a huge frictional cost to adding to the protocol. That's what keeps the protocol simple, which is what keeps multiple implementations feasible. Unlike the web, where unless you have GoogleBux you can't afford to implement it properly.
Is it because it looks visually crowded?
I don't generally like TUI's and think one gets more flexibility with raw text interfaces and being able to glue things together is more important then them looking nice. I think less fancy out put is better to be honest.
If we must embed 2D interfaces in terminals, I feel like we'd be better off putting in iframes or canvases that occupy a dedicated rectangle of cells.
You just run `mycommand connect host` and it will connect via SSH, start a Wayland server with X support, set up the appropriate environment variables, and also automatically reconnect, so you only have to do this once.
After that you can just run GUI commands via SSH and appear locally like you always wished they would. It uses a VNC-like image data protocol so the client works on any OS. And windows are seamless - no windows within windows nonsense. I haven't put much effort into the video protocol tbh but it's already better than Xpra and very usable with 100ms latency (London to NY) so that's good enough for me.
I'll try to open source it.
I think a better solution would be if SSH itself supported some GUI channel, but the only thing is the Kitty graphics protocol which kind of sucks tbh. I did try writing some tools using that for the GUI a while back but it's awkward because you have to use PNG, you're still stuck with the character grid for text, etc.
I'm running an old Qt X11 app with a modern retina MacBook with multiple different density screens and it works fine. There were some minor issues with that to start with but I pretty much just said "this happens, please fix it" and Claude figured it out without even having access to a Mac, which is impressive.
Honestly the thing that was hardest was keyboard layout. That kind of stuff never worked well for me in any remote desktop app, and now I can see why! You might never notice if you only use the US layout tbf. It works pretty well now though - I got it to query your local layout and the dynamically build an X keyboard layout and send it to the server.
I've run it with up to about 4 large windows and it seems to work fine. It doesn't send anything when nothing is changing so lots of windows won't matter unless they're playing videos or whatever - it's more designed for old Windows/Qt/Gtk style apps. I suspect you could do better with a traditional video codec but unfortunately the server I use has no GPU so that wasn't really an option.
However, most X11 apps will have utterly abysmal performance on WAN SSH connections. Ancient apps will be slow because they block waiting for every response (this is unavoidable in Xlib) and less than ancient apps will be slow because they send full pixel data. It is possible to write a reasonably performant remote X11 app (using XCB instead of Xlib and always being aware of latency), but there are very few such apps. This is why Wayland dropped the requirement.
There used to be one. It was called X forwarding. You'd run ash -X or ssh -Y and it magically worked.
What's the reality with these new frameworks? Whenever I see one i worry that it renders at 144 Hz in a loop instead of redrawing only when something changes, for one. And let's not mention redrawing only the areas that have changed [1].
Should I ask about ram consumption too?
[1] ... which is why vi is the best editor to use over slow, unreliable links.
https://en.wikipedia.org/wiki/Framework_(office_suite)
I'm not too familiar with higher level frameworks like Qt or gtk, but I suspect since they just draw the whole thing, that they only use single X windows and don't compose them, so you wouldn't be able to render a subview of them inside a different context.
They can also just draw on each other's windows and get input events on each other's windows. The connection between a window and its creator process is very weak: the window is automatically destroyed when the creator disconnects. And that's all. You can even turn that off, too. For every request that includes a window (or other resource) ID, nothing says that it has to be your window.
It does require a lot of deep coupling which is probably why it was abandoned, but also why it worked so well. You had things like passing menu subtree handles back and forth, so the host app and the embedded app could merge together their menus. This only worked because everyone on Windows was using the same menu subsystem, until Office 2007.
1. The AI disclosure up front is very useful for cutting my blog filter time from 10 seconds down to 1, which is significant in the age of content overload. Hopefully disclosure becomes a point of pride for vibebloggers and they'll add it more often.
2. While it makes sense that the popularity of TUIs (driven mostly by CLI coding agents) sees maintainers try and push more spec into emulators, I'm hoping this doesn't become the standard. The whole TUI mentality just runs counter to what makes terminals such sticky tech in the first place.
I used ratatui there mostly so that I could prove that it would work in real looking apps that do panels and similar stuff that benefits from borders.
But yeah, compat is key. It would probably go out to ghostty, rio, kitty pretty easily, terminal.app never, other terminals much slower. IDK about the windows / linux side of things.
BTW, love ratatui. I've been building ratmark lately, for markdown rendering. But I really need link support ;)
One of the top 5 "smells" of LLM generated websites that I can't stand is everything has to have its own round-rect. Everything in a box. Every button, label, header, subheader, so much fucking noise everywhere. You shouldn't need that many.
Another, of course, is the phrase "The wire format", included in this post. Oh yeah, its the format on the wire? What wire? The wire between my psuedo terminal and my kernel? What garbage. Cool exploration but, come on: "The common path is a pen, held in the cursor like the current background color. Set it, print some text, and the printed cells get the borders:" shit is not OK to post
Somthing I think could be intresting to go along with this is for the terminal to be able to distinguish sub-windows using these border, so if you've got a popup and try to select multiple lines in it, you'll actually select only the text in thr popup rather than the whole terminal-wide line.
[background color, top, left, bottom]B[top, bottom only]UTTO[top, bottom, right]N[reset]
https://github.com/microsoft/terminal
Also, selecting and replacing could be done without a a mouse. Quite often I want to select, copy, replace, paste somewhere else. Not possible without a mouse.
It reminds me of video games overlays / layers (like the gameboy window layer) used to display HUDs.
There's some bits that feel like they probably make sense to consider doing other ways, like how border placement works (inside, outside, on the border, etc.), and how the filling works - to make borders incorporate external or internal padding.
The charm of the terminal is that you can do whatever you want, as long as it fits in one cell.
But for there to be a dedicated section on how multiplexors wouldn’t work suggests to me that the authors already tried this via tmux.
So I’m left wondering what they’ve done with the implementation of this to make that a problem.
I spotted they are using DCS sequences. But even that shouldn’t be an issue itself.
I wouldn’t recommend APC because Apple Terminal doesn’t follow spec with APC parsing (one of the reasons I switched some of my custom sequences from APC to OSC).
Regarding the extra state to be tracked, tmux wouldn’t handle that cell state. That would be down to the terminal emulator.
Since these are cell properties, it does feel like CSI would be the right place (like Kittys undercurl).
I like simple, predictable TUIs which i can operate with keyboard input only. I don’t like ui chrome or complex ux in TUI, i prefer GUI for that.
It's kind of funny, I posted this here and there at similar times. Expected to be spam flagged there due to the anti-AI brigade, but my submission here was the one that actually got hit (likely because I disclosed AI use in the post body is my guess).
I like seeing different points of view, and maybe controversial topics should be discussed () more than others, not less.
and discussed means fact-based, civil discourse, not piling on
Thanks for Ratatui, which certainly has a top tier name, and also has had tons of great software written with it! I've been inspired by much of that ecosystem, especially the charting libs. The weird GUI stuff I'm doing with Kitty+Bubbletea, can certainly be done on Ratatui, in the spirit of Makepad. IMO, Golang needs this more than Rust.
[1] Viewing the gloss README in the Gloss web viewer (Golang WASM in a Ghostty frame), press 't' to typeset it. Alpha release quality. https://nimbleterminal.github.io/gloss/app.html?src=https%3A...
In fact it just makes it less secure.
It can already port forward so you can basically already do this, I don’t think that’s insecure per se.
https://bugzilla.mozilla.org/show_bug.cgi?id=1688774 etc
> instead of hacks on top of hacks
Afraid that’s a contradiction. In this role, HTML is a pile of hacks upon hacks that was not originally intended for UIs.
But, yeah, people are trying to reinvent GUIs. By layering hacks over TTYs. If only there’d be some protocol for widgets and events over a stream connection…
what we are missing is a really high level protocol/system that takes really high level data and figures out the presentation on its own.
take a list of files for example. you can run ls -l in a terminal and it will attempt a crude text based formatting of the output. or you can run a full gui filemanager.
what if there was a command that would produce ls output as a table data structure, run in a sort of terminal that knows how to format a table nicely without the ls command having to include any formatting instructions? this terminal would have support for all sorts of data types and structures to display all of them nicely.
ls's output (and a few other programs') are human facing. They're not meant to be machine readable.
> what if there was a command that would produce ls output as a table data structure, run in a sort of terminal that knows how to format a table nicely without the ls command having to include any formatting instructions? this terminal would have support for all sorts of data types and structures to display all of them nicely.
Because that's just complexity for its own sake. What's simpler is to just create a shell alias for a particular view you want. The shell is for interactive usage, with some capabilities for automation. If something better is needed, you write a real program for it.
So, powershell? For some reason only IT jockeys on Microsoft's death grip remember and use its full capability after learning it.
I get where you're going and am genuinely curious, what does a "better" system designed to do what HTML/JS have become actually look like? (or what would one look like?) There has to be markup of some sort, and there has to be scriptable interactions of some sort, right? If not, how else would it work?
That said, yes: NeWS, XForms, rio, and many others have tried with arguably cleaner designs. Not without their own issues, but in comparison to HTML, driving GUIs was a design goal from day zero (not a direction shift), and they're a lot smaller and simpler (which has its pros and cons).
So the "borderless" (0 pixels) / zero "useless gaps" simply are confusing and... Wrong.
But then people who do use useless gap, as in TFA, get it wrong too: they typically add gaps near the monitor's edges.
Yeah. But no. Sorry but my monitor's edge is a perfectly fine gap. I don't risk mistaking it for anything.
So I modified my WM (the Awesome WM) to do proper "useless gaps" computation and remove the ones that really are useless: and that'd be those near the monitor's physical border.
I mean: nearly everybody gets it wrong, but it's not complicated to get it right, is it?
P.S: even the terminology is wrong... People calling those "useless gaps" haven't got a clue: they are useful. The only useless ones are the one on the monitor's edge (if your monitor has physical edges, which it probably does).
The test app has a key to turn that off see https://github.com/joshka/ratatui/blob/joshka/cell-borders/C...
The side gaps were for for making it feel balanced in the screenshots and visualizations to be able to show where the borders line up with cells easily etc. It wouldn't be what I'd use in a real app.
One thing to note though is that some things which are "wrong" can be aesthetically pleasing to look at and may be the actual best UX in certain situations. There's a lot of new design principle work (especially in macOS / iOS) that is about things going past the edge, or being overlaid with floating things. Some of this is "wrong" some of it is wrong, and some of it sitting in in the useless gap beteen the two. ;)
The part I'd want specced early: borders are per-cell, but cells aren't per-grapheme. A CJK char owns two cells plus a continuation placeholder, and combining marks or ZWJ emoji sequences own zero-or-more depending on whose wcwidth table you ask, so app and terminal routinely disagree across Unicode versions. Today that shows up as a vertical bar one column off; with cell borders it becomes a line that stops short of the corner. Does the border attach to the cell or to the grapheme cluster?
I probably missed on something, but I stopped there
Whatever the author is doing works reasonably well to be readable and inoffensive.