molten_cauldron

Crates.iomolten_cauldron
lib.rsmolten_cauldron
version0.1.0
created_at2025-12-14 18:45:12.826717+00
updated_at2025-12-14 18:45:12.826717+00
descriptionA powerful TUI framework based on The Elm Architecture ๐Ÿ”ฎ
homepagehttps://molten.dev
repositoryhttps://github.com/moltenlabs/molten-cauldron
max_upload_size
id1984922
size58,088
Chris Mathew (chriscmathew-dorsia)

documentation

https://docs.rs/molten_cauldron

README

Cauldron

๐Ÿ”ฎ Cauldron

A powerful TUI framework based on The Elm Architecture.

Crates.io Documentation CI License

Features โ€ข Installation โ€ข Quick Start โ€ข Architecture โ€ข Ecosystem


What is Cauldron?

Cauldron is the Rust equivalent of bubbletea from Charmbracelet. It provides a simple, functional approach to building terminal user interfaces using The Elm Architecture.

use cauldron::{App, Model, Command, Event, Key};

struct Counter { count: i32 }

enum Msg { Increment, Decrement, Quit }

impl Model for Counter {
    type Message = Msg;

    fn update(&mut self, msg: Msg) -> Command<Msg> {
        match msg {
            Msg::Increment => self.count += 1,
            Msg::Decrement => self.count -= 1,
            Msg::Quit => return Command::quit(),
        }
        Command::none()
    }

    fn view(&self) -> String {
        format!(
            "๐Ÿ”ฎ Count: {}\n\n  Press +/- to change\n  Press q to quit",
            self.count
        )
    }

    fn handle_event(&self, event: Event) -> Option<Msg> {
        match event {
            Event::Key(Key::Char('+')) => Some(Msg::Increment),
            Event::Key(Key::Char('-')) => Some(Msg::Decrement),
            Event::Key(Key::Char('q')) => Some(Msg::Quit),
            Event::Key(Key::Esc) => Some(Msg::Quit),
            _ => None,
        }
    }
}

fn main() {
    App::new(Counter { count: 0 }).run().unwrap();
}

Features

๐Ÿ—๏ธ Elm Architecture

  • Model - Your application state
  • Message - Events that update state
  • Update - Pure state transitions
  • View - Render to terminal

โšก Simple API

impl Model for App {
    fn update(&mut self, msg: Msg) -> Command<Msg>;
    fn view(&self) -> String;
}

๐Ÿ–ฑ๏ธ Input Handling

  • Keyboard events
  • Mouse support (optional)
  • Bracketed paste mode
  • Focus events

๐ŸŽจ Styling Integration

use glyphs::{style, Color};

fn view(&self) -> String {
    style("Hello!")
        .fg(Color::from_hex("#F97316"))
        .bold()
        .to_string()
}

Installation

cargo add cauldron

Or add to your Cargo.toml:

[dependencies]
cauldron = "0.1"

Quick Start

1. Define Your Model

struct TodoList {
    items: Vec<String>,
    selected: usize,
}

2. Define Your Messages

enum Msg {
    MoveUp,
    MoveDown,
    Delete,
    Quit,
}

3. Implement the Model Trait

use cauldron::{Model, Command, Event, Key};

impl Model for TodoList {
    type Message = Msg;

    fn update(&mut self, msg: Msg) -> Command<Msg> {
        match msg {
            Msg::MoveUp => {
                if self.selected > 0 {
                    self.selected -= 1;
                }
            }
            Msg::MoveDown => {
                if self.selected < self.items.len().saturating_sub(1) {
                    self.selected += 1;
                }
            }
            Msg::Delete => {
                if !self.items.is_empty() {
                    self.items.remove(self.selected);
                    if self.selected >= self.items.len() {
                        self.selected = self.items.len().saturating_sub(1);
                    }
                }
            }
            Msg::Quit => return Command::quit(),
        }
        Command::none()
    }

    fn view(&self) -> String {
        let mut s = String::from("๐Ÿ“ Todo List\n\n");
        
        for (i, item) in self.items.iter().enumerate() {
            if i == self.selected {
                s.push_str(&format!("  > {}\n", item));
            } else {
                s.push_str(&format!("    {}\n", item));
            }
        }
        
        s.push_str("\nโ†‘/โ†“: navigate  d: delete  q: quit");
        s
    }

    fn handle_event(&self, event: Event) -> Option<Msg> {
        match event {
            Event::Key(Key::Up) => Some(Msg::MoveUp),
            Event::Key(Key::Down) => Some(Msg::MoveDown),
            Event::Key(Key::Char('d')) => Some(Msg::Delete),
            Event::Key(Key::Char('q')) | Event::Key(Key::Esc) => Some(Msg::Quit),
            _ => None,
        }
    }
}

4. Run It

fn main() {
    let app = TodoList {
        items: vec![
            "Build cauldron".into(),
            "Write documentation".into(),
            "Ship it!".into(),
        ],
        selected: 0,
    };
    
    cauldron::run(app).unwrap();
}

The Elm Architecture

Cauldron follows The Elm Architecture (TEA), a pattern for building interactive programs:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                                                 โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚    โ”‚  Event  โ”‚โ”€โ”€โ”€โ–ถโ”‚  Update  โ”‚โ”€โ”€โ”€โ–ถโ”‚  Model  โ”‚  โ”‚
โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                        โ”‚       โ”‚
โ”‚                                        โ–ผ       โ”‚
โ”‚                                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚                                   โ”‚  View   โ”‚  โ”‚
โ”‚                                   โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                        โ”‚       โ”‚
โ”‚                                        โ–ผ       โ”‚
โ”‚                                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚                                   โ”‚ Terminalโ”‚  โ”‚
โ”‚                                   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  1. Events come from user input (keyboard, mouse)
  2. Update transforms events into state changes
  3. Model holds your application state
  4. View renders the model to a string
  5. Terminal displays the view

Commands

Commands let you perform side effects:

// Do nothing
Command::none()

// Quit the application
Command::quit()

// Send a message
Command::message(Msg::DataLoaded(data))

// Batch multiple commands
Command::batch(vec![cmd1, cmd2, cmd3])

// Async task (coming soon)
Command::perform(|| async {
    let data = fetch_data().await;
    Msg::DataLoaded(data)
})

App Builder

Use the App builder for more control:

use cauldron::App;

App::new(my_model)
    .with_mouse()           // Enable mouse support
    .inline()               // Don't use alternate screen
    .show_cursor()          // Keep cursor visible
    .with_bracketed_paste() // Enable bracketed paste
    .run()
    .unwrap();

Ecosystem

Cauldron is part of the Molten Labs open source ecosystem:

Crate Description Status
molten_brand Design tokens & colors โœ… Published
glyphs ANSI escape sequences โœ… Published
lacquer Terminal styling โœ… Published
cauldron TUI framework (you are here) โœ… Published
sparks TUI components ๐Ÿšง Coming Soon
rune Shell glamour ๐Ÿšง Coming Soon

Why "Cauldron"?

In the forge, a cauldron is where raw materials are melted and transformed into something new. Cauldron transforms your application state through pure functions, bubbling up beautiful terminal interfaces. ๐Ÿ”ฎ


Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

git clone https://github.com/moltenlabs/cauldron
cd cauldron
cargo test

License

Licensed under either of:

at your option.


Built with ๐Ÿ”ฎ by Molten Labs

"Let them cook."

Commit count: 0

cargo fmt