[HN Gopher] Things I've learned building a modern TUI Framework
       ___________________________________________________________________
        
       Things I've learned building a modern TUI Framework
        
       Author : willm
       Score  : 174 points
       Date   : 2024-08-11 12:22 UTC (10 hours ago)
        
 (HTM) web link (www.textualize.io)
 (TXT) w3m dump (www.textualize.io)
        
       | emrah wrote:
       | In case you missed this: Casey vs Windows terminal
       | https://news.ycombinator.com/item?id=27725559
        
       | emrah wrote:
       | > 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 wrote:
         | I 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 wrote:
         | There 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 wrote:
           | > 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)?
        
       | traverseda wrote:
       | My 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 wrote:
         | Can 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 wrote:
           | They have a virtual DoM
           | 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/
           | 
           | It has HTML (or at least a DoM), css, and you design widgets
           | the same way.
        
             | willm wrote:
             | > They have a virtual DoM
             | 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/
             | 
             | Reactives attributes are very useful concept to manage UI
             | complexity. And again, not exclusive to React.
        
               | kragen wrote:
               | this sounds like you're elaborating on _why_ textual
               | wants to be react rather than rebutting the assertion
               | _that_ textual wants to be react. but nobody was saying
               | that wanting to be react was unreasonable
               | 
               | hmm, well, i guess traverseda was sort of saying that
               | react was bad. i doubt that's a widely shared opinion tho
        
               | willm wrote:
               | I only meant to rebut the factual claims made in the
               | previous comment. Textual is inspired by web development
               | (and I've always described it as such), but "want to be
               | react" is way overblown. It has things in common with
               | React, but equally many other web and UI frameworks. Heck
               | you could say that Textual wants to be JQuery, and that
               | would be just as apt...
        
               | kragen wrote:
               | maybe it depends on what the implicit reference class is.
               | if you're comparing it to react, angular, ncurses,
               | s-lang, jquery, vue.js, and php, then sure, things like
               | html and css are hardly react-specific. if you're
               | comparing it to ncurses, s-lang, win32, mfc, the vic in
               | the commodore 64, winforms, whiptail, dear imgui, the
               | tms9918 used in the msx, emacs lisp markers and text
               | properties, gtk, the nintendo ppu, opengl and glut, xlib,
               | xt, tcl/tk, ansi.sys, naplps, ripscrip, turbovision,
               | direct access menu.exe, and react, it's basically exactly
               | the same thing as react
               | 
               | jesus, i sure have built shitty user interfaces on a lot
               | of platforms
        
               | yunohn wrote:
               | How is it more like jQuery than React?
        
             | itronitron wrote:
             | Thanks, it seems like people tend to say react, or reactive
             | attributes, when they are describing model-view-controller
             | (MVC) patterns.
        
         | willm wrote:
         | > Last I tried it, you do have to use CSS.
         | 
         | You don't _have to_ use CSS (actually you never did). Every
         | style can be set in code, and the docs have CSS + Python
         | equivalent for every style.
         | 
         | > There are no good standard components
         | 
         | I guess its been a while since you checked
         | https://textual.textualize.io/widget_gallery/
        
           | traverseda wrote:
           | Yeah, it does seem like things have changed a lot since I
           | last used it, which I think was probably a few years ago.
           | Time flies.
        
         | actionfromafar wrote:
         | I want a way to embed a terminal (it doesn't have to support a
         | myriad terminal emulations, only one) inside a graphical
         | program. MacOS first, but other platforms would be nice.
         | 
         | So, imagine a normal GUI window, but one of the components in
         | it is a terminal window. Is there something like that?
         | 
         | Or should I just use mono font text view?
        
         | yoavm wrote:
         | I don't see how it is trying to be React; It definitely tries
         | to use concepts from HTML and CSS (and perhaps even some JS?),
         | but I actually found that it allowed me to move very quickly as
         | I didn't need to learn a whole new UI system from scratch. I
         | didn't need to create any component of my own, and CSS is
         | something I already know. If anything, like I wrote in another
         | comment, the slight layout differences and deviation from CSS
         | is what sometimes got me a little confused.
        
         | nine_k wrote:
         | If you think that react (and FRP in general) is not a good way
         | to build UIs, what is, in your opinion?
        
           | sesm wrote:
           | I don't agree that React is FRP. FRP is a generic solution
           | that builds data-UI synchronization around data, and assumes
           | that incremental UI updates will be written in UI code. React
           | puts data-UI synchronization code inside UI components and
           | provides an Immediate Mode-like API to avoid writing
           | incremental updates in UI code.
        
       | spencerchubb wrote:
       | Interesting that they're hiring. I'm curious how they plan to
       | make money from a TUI framework
        
         | itronitron wrote:
         | the jobs link gives a 404 error
        
           | __float wrote:
           | This post 2 years old, it seems they have filled their open
           | roles :)
        
         | ynniv wrote:
         | He 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 wrote:
         | Yeah same question. It looks like they're building some pretty
         | cool software, but engineers are expensive and other frameworks
         | exist.
        
       | rivo wrote:
       | It'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 wrote:
         | Are there any libraries in place which can normalize all emojis
         | down to a single symbol?
        
           | kevindamm wrote:
           | It'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
           | 
           | [0go]: (actually there are a few of these)
           | https://pkg.go.dev/github.com/gosimple/unidecode
           | 
           | [0js]: 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
           | 
           | [2]: https://github.com/mathiasbynens/emoji-test-regex-
           | pattern
        
             | estebank wrote:
             | There's a "trick" that works somewhat well for some
             | compound emoji like "family": replace ZWJs with whitespace.
             | Emoji width is not standardized because it depends on
             | platform, fonts available, shell and terminal emulator,
             | _but_ almost no terminal supports compound emoji correctly.
             | Because of how they were designed, most terminals will
             | print the emoji as its component parts. If you need to do
             | something like underline a piece of text (like rustc has
             | to) we decompose them ourselves, and then it is a more
             | tractable problem to know what the width of a char is (0, 1
             | or 2, and var width for tabs, which we just transform to a
             | hardcoded 4--incorrect but usable). This can still be
             | incorrect, on specific terminals, but works well enough on
             | most.
        
         | rockorager wrote:
         | The state of the art here is to detect mode 2027, and enable it
         | when supported. This lets you know the terminal will handle
         | graphemes properly.
         | 
         | I maintain two TUI libraries which use this technique and emoji
         | support has been (nearly) great. (One of which uses your uniseg
         | library!)
         | 
         | https://mitchellh.com/writing/grapheme-clusters-in-terminals
        
           | sweeter wrote:
           | really great read, thanks. Im a little disappointed that no
           | terminal emulator both implements the Kitty image protocol,
           | and mode 2027. I wish there would be a terminal project that
           | would just pick the best standards we have at the moment. Im
           | not a fan of sixel for a lot of reasons. Im looking forward
           | to trying Ghostty, though.
        
             | rockorager wrote:
             | Ghostty has both mode 2027 and kitty image protocol
        
             | eNV25 wrote:
             | wezterm has both according to the above article
        
       | lynx23 wrote:
       | Anyone 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 wrote:
         | I 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.
        
         | dualogy wrote:
         | I 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 wrote:
           | Ok I think he's referring to 0xB800, the VGA text buffer
           | segment in real mode.
        
           | vetinari wrote:
           | In real mode addressing and graphic card in text mode, your
           | video memory started at absolute address 0xb800:0x0000. It
           | was an two-dimensional array, where you could poke and
           | whatever you changed here, was reflected immediately on the
           | display. Each element of the array was two bytes: character
           | itself and color attributes.
        
           | lelanthran wrote:
           | 0xb800 is the address of the framebuffer for text. Simply
           | write characters to that address, using offset `((row *
           | width) + col)` and they'll appear on screen.
           | 
           | In graphics mode it was, IIRC, 0xa000. I once wrote a pacman-
           | type easter egg inside the point-of-sale system[1], because
           | doing direct graphics straight to an address is so easy and
           | simple.
           | 
           | [1] Was removed after pilot and before actual release.
        
       | ynniv wrote:
       | If you're going to run kitty it can do a lot more than that:
       | https://m.youtube.com/watch?v=ft1Q-DwGWIs
       | 
       | https://notcurses.com/
        
         | nine_k wrote:
         | I 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.
        
       | cocodill wrote:
       | Humanity needs more TUI tools
        
       | miki123211 wrote:
       | As 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 wrote:
         | I 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 wrote:
           | > 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.
        
             | willm wrote:
             | De nada!
             | 
             | > Isn't it possible to expose this content via a publicly
             | accessible API that screen readers could simply hook into?
             | 
             | Definitely possible from a technical standpoint, but I
             | don't know of anyone who has done that. Maybe one day,
             | Textual could provide that solution.
        
               | ericwood wrote:
               | It's more in the Rust ecosystem but AccessKit looks
               | really promising from this standpoint. I'm not sure if it
               | could work in the context of a TUI but it might be a
               | great starting point!
               | https://github.com/AccessKit/accesskit
        
               | miki123211 wrote:
               | > Definitely possible from a technical standpoint
               | 
               | Yes and no, it would be possible, but only if the
               | terminal emulator, the operating system's accessibility
               | API, the screen reader and the library supported it. The
               | library needs to output the right information via escape
               | codes, the terminal emulator needs to expose it via the
               | OS API, the OS API needs to have support for it, and the
               | screen reader needs to know what to do with the
               | information. I believe you could wrangle the existing
               | a11y APIs and make it work, but you'd still need to
               | implement support for it in emulators, libraries and
               | screen readers. Not to mention that you'd actually have
               | to design the standard and write a spec for it.
               | 
               | This would be slightly easier to do for terminal screen
               | readers, which run directly inside a terminal emulator
               | (kind of like Tmux) and pass most commands and keys
               | unmodified, generating speech in the meantime.
        
           | miki123211 wrote:
           | > AFAIK this doesn't exist
           | 
           | I have complained about this not existing many times and at
           | length, and have actually been thinking about how such a
           | think could work.
           | 
           | It's a great idea, but we'd need support both from screen
           | readers, TUI libraries and some terminal emulators, and I
           | don't know if we could get that to happen.
        
       | kbouck wrote:
       | This TUI discussion triggered a bit of 80s/90s programming
       | nostalgia -- anyone remember TTT (TechnoJock's Turbo Toolkit)?
       | Pre-gui era UI framework.
        
       | RunSet wrote:
       | > 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
        
       | mikkelam wrote:
       | Why 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 wrote:
         | Each 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 wrote:
         | I 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 wrote:
           | Having 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 wrote:
             | I used xterm for such purposes.
             | 
             | Yes, I do agree the browser is the new X Windows / RDP
             | client, on the modern timesharing systems.
        
         | fastasucan wrote:
         | Its great for running things in a terminal where you want more
         | of a user interface than a CLI. Sometimes a TUI is faster and
         | gives better oversight than a CLI.
        
         | habitue wrote:
         | It's the other ubiquitously installed cross-platform GUI
         | toolkit other than the web.
         | 
         | Additionally, it has a hacker aesthetic. The styling is
         | aggressively not separated from the content, and the styling
         | knobs are pretty limited, so tui apps kind of converge on a
         | single style. That style reminds us of hacker movies and cool
         | sci-fi shit :)
         | 
         | It's not loved by corporate designers. Companies don't make
         | sales based on their TUIs (to either businesses or consumers).
         | So without those commercial pressures, tuis are designed by
         | developers for developers.
         | 
         | Because of this, the meme of tuis self-reinforces. Developers
         | see and use TUIs, notice that they are usually tools built with
         | developers in mind, and then want to go on to make their own
         | TUIs.
        
         | electroly wrote:
         | There isn't much obvious benefit in using TUIs, but _writing_
         | TUIs has a big upside: it 's easier in most ways. It's
         | trivially cross-platform, you don't have to make pixel-perfect
         | GUIs (because it's impossible), you don't need icons or
         | graphics (because you can't show graphics), etc.
        
       | bogdan-lab wrote:
       | This 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 wrote:
         | One 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
        
         | mrweasel wrote:
         | It does seems niche at this point. One scenario I can see is
         | where you want something more user friendly than pure CLI and
         | where providing a web UI might be too risky for some reason. A
         | TUI could allow users to SSH in to server somewhere and just
         | have TUI app as their shell. It's a bit contrived I grant you
         | that.
         | 
         | Personally I found Textual a little weird to use, but better
         | than ncurses. Though it didn't really yield what I wanted. I
         | like the old mainframe style TUI application, those already
         | struck me as being wildly efficient.
        
         | halfcat wrote:
         | The use case is something like medical billing entry where
         | people are trained to know all of the billing codes and they
         | still use an AS400 green screen console.
         | 
         | The employees work by keyboard shortcuts and are extremely
         | efficient, and every time someone tries to replace the AS400
         | with a modern web app, their productivity drops 100x.
         | 
         | It's the same scenario as a vim/emacs wizard vs a slick looking
         | GUI that doesn't have keyboard shortcuts.
        
           | tyre wrote:
           | The solution to manual medical billing is to have computers
           | do the billing. The system can be configured via GUI with
           | rules about billing codes, payers, DX codes, etc. and then
           | the rest of the system Just Does It.
           | 
           | (I work at a company automating medical billing.)
        
       | hggh wrote:
       | (2022)
        
       | yoavm wrote:
       | I'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...
        
       | troupo wrote:
       | On emojis I highly recommend "Emoji under the hood"
       | https://tonsky.me/blog/emoji/
        
       ___________________________________________________________________
       (page generated 2024-08-11 23:00 UTC)