11 ms·
Things I've learned building a modern TUI Framework (2022)
- emrah 2y agoIn case you missed this: Casey vs Windows terminal https://news.ycombinator.com/item?id=27725559 https://news.ycombinator.com/item?id=27725559
- emrah 2y ago> The first trick is "overwrite, don't clear" This is how games were written back in the day before DirectX was a thing. You'd write directly to the frame buffer and instead of clearing and redrawing, you'd redraw what changed and what was around and under it (because there was no time to refresh the entire view in time in addition to everything else you need to do)
- Neywiny 2y agoI learned this from ComputerCraft programming. It's become applicable many times since then, occasionally professionally. But, the ability to tell the terminal when it's starting/done a frame is a lot more powerful IMO.
- moring 2y agoThere were at least two other techniques back then. The first is to write to another buffer (possibly in normal RAM, not video RAM), then when the frame is done copy the whole buffer at once, so every pixel gets changed only once. The second is to write to another buffer that must be in video RAM too, then change the registers of the graphics hardware to use that buffer to generate pixels for the monitor to show. They had different tradeoffs. Copying the whole buffer when done was expensive, changing an address register was cheap. But the details of the register were possibly hardware-dependent, and there was no real graphics driver framework in place. Also, to just "flip buffers" (as changing the address register was called), rendering to the off-screen buffer meant sending pixels to video RAM, which was (IIRC) slower to access than normal RAM (basically a NUMA architecture), so depending on how often a pixel gets overdrawn, rendering in normal RAM could be faster overall even with the final copy taken into account.
- CBarkleyU 2y ago> But the details of the register were possibly hardware-dependent, and there was no real graphics driver framework in place Did this change with 3dfx's Glide (or subsequently Direct3D once Windows got a foothold into the gaming industry)?
- eropple 2y agoIt's been a while, but as I recall, DirectX introduced a hardware abstraction layer from the get-go, but support was pretty spotty for the first few years. DirectX 7 was a pretty big step forward, and coincided with a lot of pretty important 3D features like hardware T&L and vertex buffer allocation. They got there before OpenGL, so the vendors mostly oriented around D3D7 and D3D8, but vendors' implementation was still pretty wonky and bespoke. Shaders hit for D3D9, and you had to pick between HLSL and GLSL, so the gap was widening then but I think the first time you can really describe a rigorous framework for graphics drivers, as opposed to a stack of shims of varying height, would be Windows 2000/XP bringing along XDDM (which then begat WDDM in Vista; WDDM has changed over the years, but is still recognizable in Windows 11).
- traverseda 2y agoMy big complaint with textual is that it wants to be react. I can see why it would want to be react, that's a very popular framework that a lot of people are already familiar with, but I don't think it's actually a good way of doing user interfaces. But the basic reactive design is a well trod road, and basing your system design on something that's known to work is a great way to derisk the project. Sure, we'll draw some heavy inspiration from react. Alright, so we're using some bastardization of CSS as well? That might be going a little bit too far. The react model already breaks the idea of CSS in a lot of ways, preferring standardized components. Sure, developers still use CSS to customize components, but I view that more as a side effect of how react evolved rather than as a justifiable architectural choice. But as long as you don't have to use CSS I suppose it's fine. Last I tried it, you do have to use CSS. There are no good standard components, so you will be making your own, and instead of having components be one nice self encapsulated Python class the standard docs use things like list components and then style them with an external style sheet. For those reasons textual just isn't for me yet. In python there should be one, and preferably only one, obvious way to do something. By mirroring react so closely they're also mirroring what I see as the JavaScript communities biggest vice.
- itronitron 2y agoCan you elaborate on how textual wants to be like the react framework? I don't see React (or react) mentioned anywhere in the article.
- traverseda 2y agoThey have a virtual DoM https://textual.textualize.io/api/dom_node/ https://textual.textualize.io/api/dom_node/ This includes a lot of what you'd expect from HTML, classes, CSS, etc. They have reactive attributes https://textual.textualize.io/guide/reactivity/ https://textual.textualize.io/guide/reactivity/ It has HTML (or at least a DoM), css, and you design widgets the same way.
- willm 2y ago> They have a virtual DoM https://textual.textualize.io/api/dom_node/ https://textual.textualize.io/api/dom_node/ It's not a virtual DOM. It's not technically even a DOM, because there is no Document. The name has stuck, which is why we went with that. Technically, its a tree. One of the most common data structures used to represent a UI, and predates React by decades. > This includes a lot of what you'd expect from HTML, classes, CSS, etc. It has CSS in common with HTML. classes are pretty much required for CSS. That's not "a lot". But why shouldn't a UI framework borrow concepts that work for, you know, User Interfaces? > They have reactive attributes https://textual.textualize.io/guide/reactivity/ https://textual.textualize.io/guide/reactivity/ Reactives attributes are very useful concept to manage UI complexity. And again, not exclusive to React.
- spencerchubb 2y agoInteresting that they're hiring. I'm curious how they plan to make money from a TUI framework
- itronitron 2y agothe jobs link gives a 404 error
- __float 2y agoThis post 2 years old, it seems they have filled their open roles :)
- ynniv 2y agoHe mentioned eventually running on the web, so my guess is to facilitate migrating old TUIs. There's plenty of consulting money in maintaining old enterprise software.
- tyre 2y agoYeah same question. It looks like they’re building some pretty cool software, but engineers are expensive and other frameworks exist.
- davepdotorg 2y agoThose positions were filled and then subsequently removed: https://blog.davep.org/2024/03/28/goodbye-textualize.html#goodbye-textualize https://blog.davep.org/2024/03/28/goodbye-textualize.html#go...
- rivo 2y agoIt's funny how every TUI developer eventually stumbles over Unicode and then handling international characters and emojis correctly turns into its own project close to the same scope of (or even bigger than) the original TUI project. It happened to me on rivo/tview and through the resulting rivo/uniseg package, I learned that all other TUI library maintainers deal with the same issues. Finally, everyone invents their own unique solutions to the problem because character width is not standardized and terminals are messy, as noted in the article. OP simply supports Unicode 9 only (Unicode is at version 15.1 at the moment). Sooner or later, users will complain, however, that certain emojis or international characters are not rendered correctly. So I'm not sure that this is a great solution.
- roland35 2y agoAre there any libraries in place which can normalize all emojis down to a single symbol?
- kevindamm 2y agoIt's a design decision. On one end, if I'm reading your question correctly, you could use 0xFFFD (the replacement character) for anything not recognized as language-specific characters in the BMP and SMPs (this can be done within practically all existing Unicode libraries by filtering on character class) which will inadvertantly filter some non-emoji symbols and doesn't really convey any information (it can even look unprofessional, it reminds me a lot of the early web during the pre-unicode growing pains of poorly implemented i18n/l11n). There are libraries like Unidecode[0py] [0go] [0js] which convert from unicode to ASCII text that might be easiest to include in a TUI. All the ones I looked at will convert emoji to `[?]` but many other characters are converted to that, too, including unknowns. On the other end you can keep a running list of what you mean by emoji[1] and pattern match on those characters, then substitute for a representative emoji. But it will still pose some difficulty around what to choose for the representative symbol and how to make it fit nicely within a TUI. An example of a library for pattern-matching on emoji is emoji-test-regex-pattern[2] but you can see it is based on a txt file that needs to be updated to correspond with additions to Unicode. [0py]: https://github.com/avian2/unidecode https://github.com/avian2/unidecode [0go]: (actually there are a few of these) https://pkg.go.dev/github.com/gosimple/unidecode https://pkg.go.dev/github.com/gosimple/unidecode [0js]: https://github.com/xen0n/jsunidecode https://github.com/xen0n/jsunidecode [1]: these aren't really contiguous ranges, and opinions vary, see https://en.m.wikipedia.org/wiki/Emoji#Unicode_blocks https://en.m.wikipedia.org/wiki/Emoji#Unicode_blocks [2]: https://github.com/mathiasbynens/emoji-test-regex-pattern https://github.com/mathiasbynens/emoji-test-regex-pattern
- lynx23 2y agoAnyone old and naiv enough to share this observation: Almost everything I looked at after TurboVision was inspired, but actually not really finished. Once you take the toolkit for a ride, you realize its kind of cute but unfinished. Maybe another way of looking at this is to call many of the TUI frameworks I say "opinionated", whatever that exactly means. I am likely just dense and uncreative, but the truth is, when I switched from DOS to Linux in the 90s, I was never again as productive as I happened to be with B800. Granted, it likely took me a long time to understand the need for double buffering and the difference between a local/direct text mode vs a terminal, let alone escape sequences. But still. Whenever I tried to do something directly in ncurses, I pretty much gave up due to a distinct feeling of being unhappy. Completely different to what I was able to do with the simple ideal of B800.
- thechao 2y agoI learned GUI programming using win16, then win32 — this would've been during the transition to WinXP. I must have a city-wide blind spot, but every post message pump GUI framework has left me completely befuddled. One thing I never understood was how these OO frameworks helped to really solve the multithreaded UI issues. In Win32, I just threw the main renderer into a thread, then had support renderers build models "on the side", and then updated the difference. The code never really got out of hand.
- deleted 2y ago[deleted]
- dualogy 2y agoI get what Turbo Vision is (was), but what's that B800 thing? Surely you aren't talking about a Celeron processor? Seems tricky to google, also no Wiki page on that. You got me curious, plz spill it! =)
- anothername12 2y agoOk I think he’s referring to 0xB800, the VGA text buffer segment in real mode.
- ynniv 2y agoIf you're going to run kitty it can do a lot more than that: https://m.youtube.com/watch?v=ft1Q-DwGWIs https://m.youtube.com/watch?v=ft1Q-DwGWIs https://notcurses.com/ https://notcurses.com/
- nine_k 2y agoI prefer WezTerm over Kitty, because of the Kitty's author attitude towards feature requests and even pull requests. And yes, you can do graphics on both, using the same protocols. If you really need graphics, a terminal is hardly a right solution. It's occasionally useful for tiny stuff like icons though.
- ranger_danger 2y agoDo you also prefer Windows because of Linus' attitude?
- cocodill 2y agoHumanity needs more TUI tools
- miki123211 2y agoAs a screen reader user, reading this post makes me want to scream. If you care about accessibility even one bit, for the love of god, please, don't use any of the features this post mentions. Things like animation or unicode diagrams break screen readers in horrible ways.
- willm 2y agoI would love to improve support accessibility for TUIs. Textual internally keeps a browser like DOM structure, which means it could in theory offer browser-like support for screen readers while keeping all the features offered to sighted user. But it would require a protocol to allow the app to send structured information so that the screen reader has more to work with than a matrix of characters. AFAIK this doesn't exist. The most promising way forward for accessibility is the web support for Textual. It would be possible for the app to work with the browser to make highly accessible TUIs.
- blooalien 2y ago> Textual internally keeps a browser like DOM structure, which means it could in theory offer browser-like support for screen readers while keeping all the features offered to sighted user. But it would require a protocol to allow the app to send structured information so that the screen reader has more to work with than a matrix of characters. Isn't it possible to expose this content via a publicly accessible API that screen readers could simply hook into? BTW, thank you so very much for Rich and Textual. Wonderful tools. Love 'em.
- kbouck 2y agoThis TUI discussion triggered a bit of 80s/90s programming nostalgia -- anyone remember TTT (TechnoJock's Turbo Toolkit)? Pre-gui era UI framework.
- RunSet 2y ago> I use monodraw for these diagrams. Monodraw is MacOS only unfortunately, but there are no doubt good alternatives for other platforms. https://github.com/Nokse22/ascii-draw https://github.com/Nokse22/ascii-draw
- mikkelam 2y agoWhy do software engineers care so much about TUI? I really don't get it. I love a good command line program. But TUI just doesn't appeal to me.
- willm 2y agoEach to their own. But running apps over SSH is a big plus. And some folk, like myself, enjoy the snappy keyboards focused experience that perhaps GUI apps could offer, but typically don't.
- pjmlp 2y agoI guess, mainly because of nostalgia, back from the days TUIs were the only way to interact with computers. Turbo Vision, curses and dialog were cool back in the 1990's. Having started with computers in 1986, I really don't get the TUI fetisch, not even remote access is an issue, given X Windows, VNC, RDP, Citrix,... exist for decades.
- nine_k 2y agoHaving run X programs over network connections quite a bit, I'd say that they make sense for graphics stuff, and textual interfaces over SSH are significantly more responsive. But once a fixed-width text grid stops being the right tool for the job, it's likely better to have a web UI.
- pjmlp 2y agoI used xterm for such purposes. Yes, I do agree the browser is the new X Windows / RDP client, on the modern timesharing systems.
- consteval 2y ago> X Windows, VNC, RDP, Citrix,... exist for decades. Yeah but those are all awful. I mean, okay, they work almost okay with a wired network connection and on the same network. But as soon as you hit the WAN and you throw wifi in there it's painful. Having noticeable latency and graphical artifacts does, in my opinion, hurt productivity. For those pieces of software where completing tasks as fast and accurately as possible is the most important goal, TUIs are great. Especially when you have comprehensive keyboard shortcuts. If you've ever seen an office worker rip through a TUI underwriting a loan, you'll know what I mean.
- uerioui 2y ago[flagged]
- bogdan-lab 2y agoThis TUI looks pretty, but I cannot imagine situation, when I would actually use it and be ready to pay for it. Probably I am not living in a right environment for it. But in my experience, either people are happy with something truly minimalistic or they try to please a user with GUI right away. For example, YouTube link in the article showed a possibility to display table with highlighting cells. Why would I need that as TUI? Probably if I want to navigate through table with highlighting active cell I would also need a bunch of other stuff and eventually I would need a proper GUI.
- seeknotfind 2y agoOne reason to prefer textual UIs is that you can use them from any computer anywhere fast (no slow video VNC). Also, if you are already using a terminal, then improving that experience is nice. There is a big enough market there for this company. However, I'm not sure what a "proper" GUI is. Terminals have a widely used open standard. These protocols are more standard and interoperable than any GUI framework, and they are supported on every system. Once you add video in there, close a few more gaps, I think competing with the browser, or bringing the full computer experience to the terminal is reasonable. Obviously if terminals add something like video, it's "copying" rendering pipelines from "proper" GUIs, but making the terminal experience better, which could also be viewed as bringing UNIX zen to GUIs, if it makes it big, you'll love it too! <3
- sam1r 2y agoOr what if you just prefer to not use a browser to get your information on the internet. Textualize is like the only choice I can jump to. It’s much better to hyperlink and open image and video in the browser from the terminal. In my opinion. Playing it would just block your terminal session, so it’s pretty annoying to have to open another tab with an inline video playing. I am happy with the features with textualize and haven’t even thought about needing things that play over a duration beyond a few seconds. Textualize then becomes the browser api that I build my terminal browser and render only the components I care about. None of that background or js libraries, ads. It’s well worth it.
- 2y ago
- hggh 2y ago(2022)
- Nadimakthae 2y ago[flagged]
- yoavm 2y agoI've used Textual to build a quick Swedish-English dictionary that runs in terminal but also works using touch, when using the laptop as a tablet and on my Android phone. It was a pretty smooth experience and was very fast to get something working. The TCSS layout system thing is a little strange, but only because I automatically expected it to be CSS and obviously that doesn't really work in the terminal. https://yoavmoshe.com/blog/learning-swedish-with-sway-and-an-x1-yoga-tablet/#the-swe-dictionary https://yoavmoshe.com/blog/learning-swedish-with-sway-and-an...
- troupo 2y agoOn emojis I highly recommend "Emoji under the hood" https://tonsky.me/blog/emoji/ https://tonsky.me/blog/emoji/
- lofenfew 2y ago> There is a heuristic where you write various sequences and ask the terminal for the cursor position, which should make an educated guess as the Unicode version. Unfortunately from testing we've discovered that terminals still render emoji unpredictably even if you think you know the Unicode database used. Rather than using this as a heuristic, couldn't you simply use this whenever you need to determine the width of a string? Write it to the terminal, if it ends up going farther than you expected, then you need to wrap it somewhere. I used a trick like this at one point after I got annoyed with wcwidth.
- rtpg 2y agoRE Fractions, for _many people_, decimal.Decimal will work very well. For layout concerns, fractions are probably a more natural fit (things like 1/3), but Decimal is a great floating point default for a lot of problems. They aren't exact, but a lot of the "normal" floating point weirdness goes away and your results look a lot more human. Highly recommend if you don't have a perf reason not to.
- DrMiaow 2y agoNice! I had no idea about "Synchronized output" mode. I'm adding that to my CLI project. https://youtu.be/NxsaHxON350?si=319RyQPsb5AVDQj9 https://youtu.be/NxsaHxON350?si=319RyQPsb5AVDQj9
- sam1r 2y agoWhoa! That is so cool. Thanks for the use case example.
- frontporch 2y ago> terminals are fast their slow as hell and incredibly inefficient to build graphics on top of > but many are powered by the same graphics technologies used in video games what does that mean? obviously they have to render text to graphics at some point > The first trick is "overwrite, don't clear". If you clear the "screen" and then add new content, you risk seeing a blank or partially blank frame for a brief moment. > The second trick would be to write new content in a single write to standard output. its just luck when any of these work > The third trick would be to use the Synchronized Output protocol; this could work... > With these three tricks in place you can create very smooth animation as long as you can deliver updates at regular intervals. Textual uses 60fps as a baseline. Any more than that probably isnt going to be noticeable. no, anything above 60hz will be noticeable more smooth and less laggy. also this isnt a question about bigger=better. youll notice jank even if you run 75fps on 60hz or 60fps on 75hz, and of course with unsynchronized rendering there will be jank and other artifacts even with Xfps on Xhz. > Now that you can have smooth animation in the terminal, the question becomes should you? nothing you demonstrated was smooth, just better than current broken (terminal) shit. and no, because the thing terminals miss out on is being able to scroll at just a constant pixel/time rate and actually follow the mouse precisely and without lag. as you can see in the video you cant do this because the terminal cant do this period because they can only move one font width/height per step. then if we actually explore this issue well soon find out a 125hz mouse polling rate adds tons of jank, and well discover 60hz is too slow to be smooth even with perfect sync, then that you need a CRT to have legible text at such a slow framerate. your video looks like a slightly faster windows 3.0. which is good for a terminal, but bad compared to what graphics could do even 20 years ago (at 60hz), no your not scrolling at 60hz, because thats impossible in the terminal. none of this means i want what Windows / GTK / KDE / android / ... came up with where you press a button and the program then starts slowly animating something like its (ironically) a type writer instead of just doing what i said. you lose your position in scrolling because its done wrong, the "smooth scrolling" shit in firefox or whatever is just a poor (oblivious) attempt at the solution
- efilife 2y agoThey are slow!
- sam1r 2y agoThank you so much for making this. I use this quite regularly + rigorously for my own personal tracking, scheduling and much more. Thanks to textualize, I can interact with the external world with full control in a black box.
- tuieachtheirown 2y agoFWIW, I evaluated a dozen compiled TUI libraries and found FTXUI to be the easiest to use and most reliable: https://github.com/ArthurSonzogni/FTXUI https://github.com/ArthurSonzogni/FTXUI It's a nice tool to build interactive dashboards with both keyboard and mouse support.
- theanonymousone 2y agoIsn't it written in 2022, hence requiring the year in the title?
- snthpy 2y agoI think this should include (2022) in the title.
- zokier 2y agoMany people here mention SSH as one motivating uses for TUIs. It's a shame that we don't have standardized HTTP forwarding over SSH that would work as seamlessly as X forwarding can work.
- f1refly 2y agoWe have -L though, isn't that kind of what you're looking for?
- zokier 2y agoCommon ssh (port) forwarding has lots of shortcomings that make it far less practical than X forwarding for this sort of use. Sketching out this idea, what I'd want is that ssh would set some standardized env var pointing to unix socket (analogous to $DISPLAY), and applications when starting up should pick that up. That should trigger applications to start listening on another unix socket (instead of tcp port), and notify ssh through the socket pointed by the env var. Upon that notification, ssh should set up new tunnel and open new browser window pointing to the tunnel. Nothing about that is technically particularly difficult (I'd say its almost trivial), but it'd need standardization to be truly useful.
- SoftTalker 2y ago> Common ssh (port) forwarding has lots of shortcomings What are the shortcomings? It always works very well when I use it.
- zokier 2y agoBiggest problem is that manually adding/removing forwards in a session is a hassle. There is no standard way to communicate (to user or to ssh client) that application wants something forwarded. Finally tcp sockets do not have any sort of access control, which is problem especially on server-side. Smaller problem is that because the applications all appear as localhost you lose some of the compartmentalization that browsers have, so different applications might end up seeing each others cookies/localstorage/cache/etc.
- superlopuh 2y agoWe use Textual as an interactive way to explore compilation pipelines in xDSL [0]. As our compiler is written in Python, it was the perfect tool to build a UI in the same language as the existing codebase. After starting the `xdsl-gui` project, we found Marimo [1], a reactive notebook for Python, which also lets users build apps in Python. It's been interesting to compare these two, especially in the way they handle state and propagate updates. For now we're using both tools, but it might make sense to centralise at some point. Both of these frameworks like immutable data structures, which I find is a positive incentive to use immutability throughout the code, and has been good for the rest of the project. [0]: https://xdsl.dev/ https://xdsl.dev/ [1]: https://marimo.io/ https://marimo.io/
- zelphirkalt 2y agoIs there any terminal, that throws out all the stone age terminal stuff, like weird codes for starting colored output and stopping colored output? A terminal, that instead makes use of some XML tags or so, to mark text in a readable fashion as prompt, input, output, maybe variables and such, colored and non-colored, etc., and then simply has some logic to render that XML correctly? Of course that would lead to not recognizing weird color codes and so on, but perhaps there could be a plugin system, where one could add a plugin that transforms color codes and such in the output into XML tree representation. And then one could perhaps log the whole thing in various formats: Only visible text with colors, without colors, whole XML tree, or as JSON, or whatever other format it translates well to. Also could be extended via plugin. But bare bones it merely treats everything as text.
- SoftTalker 2y ago> A terminal, that instead makes use of some XML tags or so, to mark text in a readable fashion as prompt, input, output, maybe variables and such, colored and non-colored, etc., and then simply has some logic to render that XML correctly? That would be a browser. Forgive me if you were being sarcastic and I didn't pick up on it.
- qwerty456127 2y agoHow comes we had perfect TUIs and no problems on DOS yet apparently always have some problems with TUIs on Linux?
- saulpw 2y agoUnicode, primarily.
- gudzpoz 2y ago> Emojis are terrible Not just emojis. Recently I've had some fun trying weird Unicode characters in different terminals (e.g. 𒐫): - QTerminal/Konsole: Tofu - Xfce terminal: Results in overlaps with characters that comes after it. - Alacritty: Similar to Xfce terminal, but glitches when the cursor/glyph moves. - COSMIC term: No overlapping glyphs, except that the line then wraps only after it grows out of screen. - Kitty/WezTerm: Scales the glyph to fit it into a single column. (Barely legible.) I don't even known what to expect. It is indeed a mess over there.