#tui #crossterm #ascii #applications #ui #rendering-engine #command-line-interface

ascii-forge

A Minimal TUI Ascii Application Engine that simplifies the use of crossterm

22 unstable releases (3 breaking)

0.3.0 Oct 21, 2024
0.2.13 Sep 19, 2024
0.2.12 Feb 27, 2024
0.1.71 Feb 23, 2024
0.0.0 Feb 20, 2024

#271 in Game dev

33 downloads per month
Used in idex

MIT/Apache

54KB
599 lines

Ascii-Forge

An oppinionated terminal canvas rendering engine built off of crossterm with the goal of improving terminal UI/Games without adding any un-needed elements.

Why?

Although other terminal UI Engines already exist, like Ratatui, I felt there was a lot of extra elements that wasn't needed for a small application or game.

As well, there aren't many bare-bones terminal canvas engines with as much flexability as would be needed to make a fun game. In order to acomplish this, all elements of the engine are available, at all times.

But What is Different?

As said before, Ascii-Forge is oppinionated, you don't have a choice of the backend, crossterm is what you get, but it is the best, and one of the only fully cross-platform terminal engines.

To list off some big differences:

  • Keeping it as small as possible while still making things easy.
  • Absolutely everything used to make the engine available is available to you.
    • This means that if the update method doesn't work as expected, you can make your own using the other methods.
    • Want to access the stdout that the window is using, use the io() method!
  • Most of the larger engines make their own layout system, this doesn't. You use columns and rows, no extra abstraction on top of this.

Examples

Most of the examples will be found in the examples directory

Simplest Example Included Here.

use std::{io, time::Duration};

use ascii_forge::prelude::*;

fn main() -> io::Result<()> {
    // Will init the window for you, handling all required procedures.
    let mut window = Window::init()?;

    // Ask the system to handle panics for us.
    handle_panics();

    loop {
        // Ask the window to draw, handle events, and fix sizing issues.
        // Duration is the time for which to poll events before re-rendering.
        window.update(Duration::from_millis(200))?;

        // Render elements to the window
        render!(window,
            vec2(0, 0) => [ "Hello World!" ],
            vec2(0, 1) => [ "Press `Enter` to exit!".red() ],
            vec2(0, 2) => [
                "Render ".red(),
                "Multiple ".yellow(),
                "Elements ",
                "In one go!".to_string()
            ]
        );

        // Check if the Enter Key was pressed, and exit the app if it was.
        if event!(window, Event::Key(e) => e.code == KeyCode::Enter) {
            break;
        }
    }
}

Documentation

Dependencies

~3–11MB
~134K SLoC