fatui
fatui is an immediate-mode terminal ui library that aims to be flexible and cell-perfect.
less vaguely:
- "terminal ui": terminal (sometimes "textmode") uis are based on grids of formatted characters, rather than individual pixels as in a graphical ui, most commonly seen in your terminal
- "flexible": it operates on a small number of consistent principles, and beyond that, it doesn't have any strong opinions.
- "cell-perfect": the textmode equivalent of pixel-perfect -- you can control exactly, down to the individul character, where elements will be drawn.
- "immediate-mode": your ui is defined "immediately" in imperative code, rather than a declarative dsl or persistent object tree.
how do i use it?
fatui is a library for the programming language rust, so first you need to learn that, and by the time you're done with that you'll know what to do with this.
this page isn't gonna go into detail because the details will change with each version! so instead of maintaining a readme for each version in the repo and a separate page saying the same things, just go look at the crate readme.
what if there's a bug?
…fair play, that's not version-specific at all. you can email me at fatui@genderphas.ing with the usual components of a bug report:
- a pithy and mildly passive-aggressive title (feel free to use the subject line for this!)
- steps to reproduce the issue that only work on your machine, with an unsubstantiable claim that you're doing it on a totally fresh debian install and also tried it on fedora.
- some absolutely galling display of entitlement. really ham this up; act like the world is going to implode if this goofy lil terminal framework isn't fixed within seconds.
- try to work as many $5 words into it as you can. specifically, make sure you include – not a joke, this is a spamfilter – "incalculable", "involution", and "thermobaric". bonus points for including them naturally!
- the latest version of the crate you see on crates.io, even though you're actually using one released eight months ago.
once i get a report, i'll dutifully follow the standard procedure for open-source maintainers:
- ignore you for three weeks as you send increasingly agitated follow-ups
- reply with something snippy that implies it's your fault without saying how you could actually fix the problem
- after enough badgering, begrudgingly admit i may be less than perfect and write a bugfix
- out of spite, sit on it for 3 more months before releasing it to crates.io
obviously this section is mostly a joke. if you make a sincere effort to explain the issue you're having, i'll work with you to fix it. all the better if you can give me concrete steps to reproduce it, e.g. a short, self-contained, compilable example. maybe it's your code that's wrong, but hey, if nothing else i can improve the documentation!
just bear in mind: this is a hobby project. i maintain fatui for free, and if you're invested enough to send a bug report, you have already gotten the better end of the deal. if you try to turn my hobby into a second job, no matter how badly you want me to.
also, make sure you include the 3 words from above, because i'm serious about the spamfilter.
what's up next?
mentally i'm categorizing all future work into two blocks, pre-1.0 and post-1.0. everything leading up to the 1.0 release – which should hopefully be by the end of 2025, but we'll see – is about establishing the core abstractions and writing complex enough examples to stretch the apis. everything after that is refinement, improvement, and expansion.
for example: pre-1.0, i'm going to write a bunch of traits to expose a few different kinds of functionality, and a handful of essential implementations for each. post-1.0, i'm going to add a lot more.
there's also the miscellaneous category of tech debt: previous bad api decisions (i know, already) or implementation details that need to be cleaned up. i think of this as being "between" pre- and post-1.0, but in practice i'll kinda just get to them as i get to them.
so with that in mind, in no particular order:
pre-1.0
-
#![no_std]
support. the fatui crate, with no features enabled, should be fully#![no_std]
-compatible. honestly, everything except backends should be – i might just split those into separate crates, instead of wrangling features. -
trait Drawable
, for renderable components that can return data based on input, plus some supporting apis around e.g. filling areas of the frame with specific characters. -
trait Splitter
, for dividing frames into pieces in a variety of ways. 1.0 will ship with at leastrows!
andcols!
, but there are a ton of slightly sideways uses for this, most of which i probably won't implement til after 1.0. -
formatted text, in
struct Text
andtfmt!
. what it says on the tin. this will be basically just whatowo-colors
provides, but with 3 extra apis that i need for efficient handling and output. - state tracking. the naive option is just storing everything in variables, but that makes things like scrollable areas way more fiddly and probably makes it impossible (or at least a real pain) to do things like "scroll to element". it's not just scrollable areas either, but those are the big user.
-
struct Frame
, which already exists but in a half-built, nascent state. in particular: i think i need to reconsider how inputs work, so i can have my cake (immediate mode apis with complex ui elements) and eat it to (state-based rendering, like buttons doing things on click). unclear as of yet what this will actually look like, though.
tech debt
-
trait Backend
is currently just exposed and used directly, but is that the best way to do it? or should there be, like, atrait Io
andstruct Backend<I: Io>
, where you implement the former but pass the latter around? -
owo-colors
either needs some updates to work for my use-case or, way more likely, i need to stop using it. (to be clear: it works great for its intended usage, which i am distinctly not using it for, hah.) crossbeam can already do the output, so it's really just a matter of figuring out the best way to store things in a#![no_std]
and future-gui-compatible way. - clarify and (probably) re-implement the "virtual cells" concept. right now it's kinda muddled because i came up with it halfway through dev, so i need to sit down and crystallize my understanding of my own ideas, then convert that to code. and unit tests. in particular, how this will interact with inputs?
-
make sure apis are consistent where it's the same logical concept.
e.g.
Frame
andCharGrid
, which are different mostly just because i wrote the latter later, when i realized it was an abstraction contained in the frame. and relatedly, make sure apis are getting used where it makes sense, e.g. thepos
stuff.
post-1.0
(let me stress again this is in no particular order)
-
scrollable areas,
i.e. a
scroll!
splitter which lets you… scroll… i mean, you know what scrolling is. if you don't, i'm sorry, but i'm not explaining it. - themes, i.e. some way to parameterize your styles globally. not entirely sure what this would look like, to be honest – theme structures are so widely varied that it's hard to imagine. maybe just a helper macro to create your own theme struct so you can spit out styles based on the theme's colors easily.
-
guification,
i.e. a
Backend
which creates a gui window and then draws a terminal screen into it. not a builtin custom terminal emulator – though i might make a backend that opens a terminal and renders to that – because it's just rendering a grid of characters. very useful for games!