Skip to content

API Reference

Complete reference for all public types, functions, and constants in maya.

Table of Contents


App Framework

run\<P>()

template <Program P>
void run(RunConfig cfg = {});

The primary entry point for interactive apps. P must satisfy the Program concept (see below). The runtime owns the event loop, calling P::update on each message and re-rendering via P::view.

Program concept

template <typename P>
concept Program = requires {
    typename P::Model;
    typename P::Msg;
} && (HasFullInit<P> || HasSimpleInit<P>)
  && requires(P::Model m, P::Msg msg) {
    { P::update(std::move(m), std::move(msg)) } -> std::convertible_to<std::pair<P::Model, Cmd<P::Msg>>>;
} && requires(const P::Model& m) {
    { P::view(m) } -> std::convertible_to<Element>;
};

A Program is a struct with: - Model — the app state type (plain data) - Msg — a std::variant of all possible messages - init() — returns Model (simple) or std::pair<Model, Cmd<Msg>> (full) - update(Model, Msg) — returns std::pair<Model, Cmd<Msg>> - view(const Model&) — returns Element - subscribe(const Model&) (optional) — returns Sub<Msg>

Cmd\<Msg>

template <typename Msg>
class Cmd {
    static Cmd none();
    static Cmd quit();
    static Cmd batch(std::vector<Cmd> cmds);      // also variadic
    static Cmd after(std::chrono::milliseconds delay, Msg msg);
    static Cmd task(std::function<void(std::function<void(Msg)>)> fn);
    static Cmd task_isolated(...);                // detached thread
    static Cmd set_title(std::string title);
    static Cmd write_clipboard(std::string text);
    static Cmd query_clipboard();

    // Interactive-child escape hatch (see below).
    template <std::invocable F> static Cmd suspend(F&& run);

    // Inline scrollback control (see docs/internals/witness-chain.md).
    static Cmd commit_scrollback(ScrollbackDebt debt);
    static Cmd commit_scrollback_overflow();
    static Cmd force_redraw();
    static Cmd reset_inline();
};

Commands represent side effects. Cmd<Msg>{} (or Cmd::none()) means no effect. Cmd::quit() exits the app. Cmd::batch() combines multiple commands. Cmd::after() sends a delayed message. Cmd::task() runs an async function that may produce a message.

Cmd::suspend() — hand the real terminal to an interactive child

template <std::invocable F>
    requires std::convertible_to<std::invoke_result_t<F>, Msg>
static Cmd suspend(F&& run);

Suspends the TUI and hands the real terminal to run — the escape hatch for interactive children (sudo password prompts, $EDITOR, pagers). The runtime tears the TUI down to a clean, cooked (line-disciplined) tty, calls run() synchronously on the UI thread — the user is interacting with the child, so there is nothing else to do — then restores raw mode + the TUI escapes, re-anchors the renderer (inline: a fresh serialize below the child's output; fullscreen: a full repaint), and dispatches the Msg that run returned so update() can fold the child's result back into the model.

run returning a Msg (rather than void) is what closes the loop: the callable typically spawns the child with inherited stdio, tees its output to a buffer, and returns a completion Msg carrying the exit code + captured bytes.

return Cmd<Msg>::suspend([] {
    int rc = std::system("sudo -v");           // child owns the tty here
    return Msg{SudoDone{ .code = rc }};        // folded back after restore
});

See the Cmd::suspend demo in d726f07 and App::suspend in maya/app/app.hpp.

Sub\<Msg>

template <typename Msg>
class Sub {
    static Sub none();
    static Sub batch(std::vector<Sub> subs);   // also variadic: batch(a, b, c)
    static Sub on_key(std::function<std::optional<Msg>(const KeyEvent&)> fn);
    static Sub on_mouse(std::function<std::optional<Msg>(const MouseEvent&)> fn);
    static Sub on_resize(std::function<Msg(Size)> fn);
    static Sub on_paste(std::function<Msg(std::string)> fn);
    static Sub every(std::chrono::milliseconds interval, Msg msg);
    static Sub on_animation_frame(Msg msg);    // sugar for every(16ms, msg)
};

Subscriptions declare which external events the app listens to. Returned from the optional subscribe(const Model&) method. Subscriptions are re-evaluated when the model changes, enabling conditional subscriptions (e.g. only tick while a timer is running).

on_animation_frame() is every(16ms, msg) under one shared timer engine — there is no separate animation pump. Drop the subscription from subscribe() and the ticks stop; the loop returns to idle wait with zero bytes per frame.

Animation-frame requests

// maya/app/app.hpp
void request_animation_frame() noexcept;

The redraw-only counterpart to Sub::on_animation_frame. A widget calls it from its build() each frame it wants to keep animating; the run loop folds these requests into the same wake schedule as Sub::Every timers. The distinction is intent, not mechanism: Every delivers a Msg (drives update → model), a frame request only asks for a repaint — pure visual layer (cursor blink, scramble caret, fade) that reads wall-clock in build() and mutates nothing. A widget that stops calling drops out of the next collection and the loop idles. Idempotent within a frame.

key_map\<Msg>() and key predicates

using KeySpec = std::variant<char, SpecialKey>;

template <typename Msg>
Sub<Msg> key_map(std::initializer_list<std::pair<KeySpec, Msg>> entries);

// Pure predicates for use inside subscribe() / on_key filters:
bool key_is(const KeyEvent& k, char c) noexcept;      // also char32_t / SpecialKey
bool ctrl_is(const KeyEvent& k, char c) noexcept;     // Ctrl+c, not Ctrl+Alt+c
bool alt_is(const KeyEvent& k, char c) noexcept;      // Alt+c, not Ctrl+Alt+c

key_map() builds a Sub::on_key from a declarative key→message table:

return key_map<Msg>({
    {'q', Quit{}}, {'+', Increment{}},
    {SpecialKey::Up, Increment{}},
});

The *_is predicates are the building blocks for hand-written on_key filters where a table isn't expressive enough (modifiers, ranges).

RunConfig

struct RunConfig {
    std::string_view title      = "";
    int              fps        = 0;       // 0 = event-driven
    bool             mouse      = false;
    Mode             mode       = Mode::Fullscreen;
    Theme            theme      = theme::dark;
};

run() — Simple Convenience API

template <SimpleEventFn EventFn, SimpleRenderFn RenderFn>
void run(RunConfig cfg, EventFn&& event_fn, RenderFn&& render_fn);

template <SimpleEventFn EventFn, SimpleRenderFn RenderFn>
void run(EventFn&& event_fn, RenderFn&& render_fn); // default RunConfig

A closure-based entry point that requires no boilerplate. Suitable for most interactive apps that don't need the full Elm-architecture of run<P>().

Event function: (const Event&) -> bool (returning false quits) or (const Event&) -> void (call quit() to exit).

Render function: () -> Element or (const Ctx&) -> Element.

Global control — quit() / set_mouse()

// maya/app/quit.hpp
void quit() noexcept;            // request a clean exit from run() / live()
void set_mouse(bool on) noexcept; // toggle mouse capture at runtime

set_mouse() flips terminal mouse reporting on/off while the app runs — off hands the scroll wheel back to the terminal (native scrollback), on recaptures clicks/drag/wheel. The request is applied on the next loop iteration and keeps the runtime's mouse state in sync for a clean terminal restore on exit. Works from run() event functions and from a Program's update()/subscribe(). For Program apps Cmd<Msg>::quit() is preferred over quit(); there is no Cmd form of set_mouse() yet, so call the free function. See Events → Mouse capture vs. native terminal scroll.

Ctx

struct Ctx {
    Size  size;   // Current terminal dimensions
    Theme theme;  // Active color theme
};

The Ctx overload of the render function is useful for adaptive layouts that need to inspect the terminal size or current theme at render time.

live()

template <AnyLiveRenderFn RenderFn>
void live(LiveConfig cfg, RenderFn&& render_fn);

LiveConfig

struct LiveConfig {
    int   fps       = 30;
    int   max_width = 0;     // 0 = auto-detect
    bool  cursor    = false;
};

canvas_run()

Status canvas_run(
    CanvasConfig                                   cfg,
    std::function<void(StylePool&, int w, int h)>  on_resize,
    std::function<bool(const Event&)>              on_event,
    std::function<void(Canvas&, int w, int h)>     on_paint);

CanvasConfig

struct CanvasConfig {
    int         fps        = 60;
    bool        mouse      = false;
    Mode        mode       = Mode::Fullscreen;
    std::string title;
};

print()

void print(const Element& root);
void print(const Element& root, int width);

quit()

void quit() noexcept;  // Schedule clean exit after current frame

In Program apps, prefer Cmd<Msg>::quit() from update() instead of calling quit() directly. The free function is still available for live() and canvas_run() apps.


DSL Nodes

All nodes satisfy the Node concept:

template <typename T>
concept Node = requires(const T& n) {
    { n.build() } -> std::convertible_to<Element>;
};

template <typename T>
concept DslChild = Node<T> || ElementRange<T>;

DslChild is what v() and h() accept — either a Node (compile-time or runtime) or an ElementRange (e.g. std::vector<Element>).

TextNode

template <Str S, CTStyle Sty = CTStyle{}>
struct TextNode {
    Element build() const;
};

Created via t<"...">.

RuntimeTextNode

template <typename S>
struct RuntimeTextNode {
    S content;
    Style style{};
    TextWrap wrap{TextWrap::Wrap};

    operator Element() const;
    Element build() const;
};

Created via text(). Supports | Bold, | Fg<R,G,B>, etc.

BoxNode

template <FlexDirection Dir, BoxCfg Cfg, typename... Children>
struct BoxNode {
    std::tuple<Children...> children;
    Element build() const;
};

Created via v() and h(). Supports layout pipes.

DynNode

template <typename F>
struct DynNode {
    F fn;
    Element build() const;  // Calls fn()
};

Created via dyn().

MapNode

template <typename R, typename Proj>
struct MapNode {
    R range;
    Proj proj;
    Element build() const;  // Iterates range, applies proj
};

Created via map().

SpacerNode

struct SpacerNode {
    operator Element() const;
    Element build() const;  // BoxElement with grow=1
};

SepNode

struct SepNode {
    operator Element() const;
    Element build() const;  // Horizontal separator line
};

VSepNode

struct VSepNode {
    operator Element() const;
    Element build() const;  // Vertical separator line
};

BlankNode

struct BlankNode {
    operator Element() const;
    Element build() const;  // Empty TextElement
};

DSL Style Tags

inline constexpr StyTag<...> Bold;
inline constexpr StyTag<...> Dim;
inline constexpr StyTag<...> Italic;
inline constexpr StyTag<...> Underline;
inline constexpr StyTag<...> Strike;
inline constexpr StyTag<...> Inverse;

template <uint8_t R, uint8_t G, uint8_t B>
inline constexpr StyTag<...> Fg;

template <uint8_t R, uint8_t G, uint8_t B>
inline constexpr StyTag<...> Bg;

DSL Layout Tags

template <int T, int R = T, int B = T, int L = R>
inline constexpr PadTag<T,R,B,L> pad;

template <int G>
inline constexpr GapTag<G> gap_;

template <BorderStyle BS>
inline constexpr BorderTag<BS> border_;

template <uint8_t R, uint8_t G, uint8_t B>
inline constexpr BColTag<R,G,B> bcol;    // Requires border first

template <int G = 1>
inline constexpr GrowTag<G> grow_;

template <int W>
inline constexpr WidthTag<W> w_;        // fixed width; also wraps text nodes

template <int H>
inline constexpr HeightTag<H> h_;       // fixed height

DSL Runtime Pipes

Runtime pipe tags for dynamic values. Same | syntax as compile-time pipes.

Layout Pipes

Function Tag Type Description
padding(int) / padding(int,int) / padding(int,int,int,int) RPad Runtime padding
gap(int) RGap Gap between children
margin(int) / margin(int,int) / margin(int,int,int,int) RMargin Outer margin
grow(float g = 1.0f) RGrow Flex grow factor
width(int) RWidth Fixed width
height(int) RHeight Fixed height

Border Pipes

Function Tag Type Description
border(BorderStyle) RBorder Border style
bcolor(Color) RBCol Border color
btext(string, pos = Top, align = Start) RBText Border text label (pos/align default)

Style Pipes

Function Tag Type Description
fgc(Color) RFg Foreground color
bgc(Color) RBg Background color

Alignment Pipes

Function Tag Type Description
align(Align) RAlign Cross-axis alignment
justify(Justify) RJust Main-axis distribution
overflow(Overflow) ROvf Overflow behavior

Scroll Pipes

Wrap content in a scroll viewport backed by a caller-owned ScrollState. The renderer applies the scroll offset and writes max_x/max_y back after layout so clamping is automatic.

Function Description
scroll(ScrollState&) Scroll on both axes, viewport = allocated size
scroll(ScrollState&, int viewport_h) Vertical scroll, fixed viewport height
scroll(ScrollState&, int w, int h) Both axes, fixed viewport w×h
scrolly(ScrollState&, int h) Vertical-only scroll, fixed height
scrollx(ScrollState&, int w) Horizontal-only scroll, fixed width

Text-Wrap Tags

Tag Effect on a text(...) node
clip TextWrap::TruncateEnd — hard-truncate at the box edge
nowrap TextWrap::NoWrap — overflow past the edge, never wrap

WrappedNode

template <Node Inner>
struct WrappedNode;

Created automatically when a runtime pipe is applied to any Node. Satisfies Node. Multiple runtime pipes chain onto the same WrappedNode without extra nesting.


DSL Factory Functions

// Compile-time text
template <Str S>
inline constexpr TextNode<S> t;

// Vertical stack — accepts Nodes and ElementRanges (e.g. vector<Element>)
template <DslChild... Cs>
constexpr auto v(Cs... cs) -> BoxNode<Column, BoxCfg{}, Cs...>;

// Horizontal stack — accepts Nodes and ElementRanges (e.g. vector<Element>)
template <DslChild... Cs>
constexpr auto h(Cs... cs) -> BoxNode<Row, BoxCfg{}, Cs...>;

// Runtime builders (promoted from detail namespace)
auto box() -> BoxBuilder;      // Base builder
auto vstack() -> BoxBuilder;   // Column direction
auto hstack() -> BoxBuilder;   // Row direction
auto center() -> BoxBuilder;   // Centered, grow=1

// Z-stack — layer children on top of one another
Element zstack(std::vector<Element> layers);

// Measure-aware component: receives the (width, height) it was allotted
Element component(std::function<Element(int w, int h)> fn);

// Empty element (renders nothing, satisfies Node)
Element nothing();

// Zero-copy references (no element copy): render an externally-owned
// element vector / sealed ScrollbackLedger in place
Element list_ref(const std::vector<Element>* items);
Element ledger_ref(const ScrollbackLedger& ledger);

// Runtime text
template <typename S>
auto text(S&& content, Style s = {}) -> RuntimeTextNode<decay_t<S>>;

template <typename S>
auto text(S&& content, Style s, TextWrap w) -> RuntimeTextNode<decay_t<S>>;

// Dynamic node
template <typename F>
auto dyn(F&& fn) -> DynNode<decay_t<F>>;

// Map range
template <std::ranges::range R, typename Proj>
auto map(R&& range, Proj&& proj) -> MapNode<decay_t<R>, decay_t<Proj>>;

// each() — alias for map(), for discoverability
template <std::ranges::range R, typename Proj>
auto each(R&& range, Proj&& proj);

// Spacer/separator/blank (function forms)
constexpr auto spacer()    -> SpacerNode;
constexpr auto separator() -> SepNode;
constexpr auto blank()     -> BlankNode;

DSL Constants

inline constexpr SpacerNode space;
inline constexpr SepNode    sep;
inline constexpr VSepNode   vsep;
inline constexpr BlankNode  blank_;

inline constexpr BorderStyle Round  = BorderStyle::Round;
inline constexpr BorderStyle Single = BorderStyle::Single;
inline constexpr BorderStyle Thick  = BorderStyle::Bold;
inline constexpr BorderStyle Double = BorderStyle::Double;

Element Types

Element

struct Element {
    std::variant<BoxElement, TextElement, ElementList> inner;

    // Implicit constructors from each variant type
    Element(BoxElement);
    Element(TextElement);
    Element(ElementList);

    Element build() const;  // Returns *this (satisfies Node concept)
};

TextElement

struct TextElement {
    std::string content;
    Style       style{};
    TextWrap    wrap{TextWrap::Wrap};

    Size measure(int max_width) const;
    std::vector<std::string> format(int max_width) const;
};

BoxElement

struct BoxElement {
    FlexStyle             layout{};
    Style                 style{};
    BorderConfig          border{};
    Overflow              overflow{Overflow::Visible};
    std::vector<Element>  children;

    bool has_border() const;
    int  inner_horizontal() const;  // padding + border horizontal
    int  inner_vertical() const;    // padding + border vertical
};

ElementList

struct ElementList {
    std::vector<Element> items;
};

TextWrap

enum class TextWrap {
    Wrap,              // Word wrap at container width
    TruncateEnd,       // "Long te..."
    TruncateMiddle,    // "Lon...xt"
    TruncateStart,     // "...g text"
    NoWrap             // Overflow
};

Style System

Style

struct Style {
    std::optional<Color> fg, bg;
    bool bold = false, dim = false, italic = false;
    bool underline = false, strikethrough = false, inverse = false;

    Style with_fg(Color c) const;
    Style with_bg(Color c) const;
    Style with_bold(bool v = true) const;
    Style with_dim(bool v = true) const;
    Style with_italic(bool v = true) const;
    Style with_underline(bool v = true) const;
    Style with_strikethrough(bool v = true) const;
    Style with_inverse(bool v = true) const;

    Style merge(const Style& other) const;
    bool  empty() const;
    std::string to_sgr() const;
};

Style operator|(const Style& lhs, const Style& rhs);  // Merge

Color

class Color {
public:
    enum class Kind { Named, Indexed, Rgb };

    // Named colors (constexpr)
    static constexpr Color black();
    static constexpr Color red();
    static constexpr Color green();
    static constexpr Color yellow();
    static constexpr Color blue();
    static constexpr Color magenta();
    static constexpr Color cyan();
    static constexpr Color white();
    static constexpr Color bright_black();   // gray
    static constexpr Color bright_red();
    static constexpr Color bright_green();
    static constexpr Color bright_yellow();
    static constexpr Color bright_blue();
    static constexpr Color bright_magenta();
    static constexpr Color bright_cyan();
    static constexpr Color bright_white();
    static constexpr Color gray();

    // RGB (constexpr)
    static constexpr Color rgb(uint8_t r, uint8_t g, uint8_t b);

    // Hex (consteval — compile-time only)
    static consteval Color hex(uint32_t rgb);

    // HSL (constexpr)
    static constexpr Color hsl(float h, float s, float l);

    // Indexed (256-color)
    static Color indexed(uint8_t index);

    // Accessors
    Kind kind() const;
    uint8_t r() const, g() const, b() const;
    uint8_t index() const;

    // Adjustment (constexpr)
    Color lighten(float amount) const;
    Color darken(float amount) const;

    // SGR sequences
    std::string fg_sgr() const;
    std::string bg_sgr() const;
};

Theme

struct Theme {
    Color primary, secondary, accent;
    Color success, error, warning, info;
    Color text, inverse_text, muted;
    Color surface, background, border;
    Color diff_added, diff_removed, diff_changed;
    Color highlight, selection, cursor, link;
    Color placeholder, shadow, overlay;

    static constexpr Theme derive(Theme base, auto&& patch);
};

namespace theme {
    inline constexpr Theme dark;
    inline constexpr Theme light;
    inline constexpr Theme dark_ansi;
    inline constexpr Theme light_ansi;
}

Border

BorderStyle

enum class BorderStyle {
    None, Single, Double, Round, Bold,
    SingleDouble, DoubleSingle, Classic, Arrow
};

BorderSides

struct BorderSides {
    bool top = false, right = false, bottom = false, left = false;

    static BorderSides all();
    static BorderSides none();
    static BorderSides horizontal();  // top + bottom
    static BorderSides vertical();    // left + right
};

BorderText

struct BorderText {
    std::string    content;
    BorderTextPos  position = BorderTextPos::Top;
    BorderTextAlign align   = BorderTextAlign::Start;
    int            offset   = 0;
};

BorderColors

struct BorderColors {
    std::optional<Color> top, right, bottom, left;
    static BorderColors uniform(Color c);
};

BorderConfig

struct BorderConfig {
    BorderStyle  style = BorderStyle::None;
    BorderSides  sides{};
    BorderColors colors{};
    std::optional<BorderText> text;

    bool empty() const;
};

Layout Types

FlexDirection

enum class FlexDirection { Row, Column, RowReverse, ColumnReverse };

FlexWrap

enum class FlexWrap { NoWrap, Wrap, WrapReverse };

Align

enum class Align { Start, Center, End, Stretch, Baseline, Auto };

Justify

enum class Justify { Start, Center, End, SpaceBetween, SpaceAround, SpaceEvenly };

Overflow

enum class Overflow { Visible, Hidden, Scroll };

Dimension

struct Dimension {
    enum class Kind { Auto, Fixed, Percent };
    Kind  kind;
    float value;

    static Dimension auto_();
    static Dimension fixed(int v);
    static Dimension percent(float v);

    bool is_auto() const;
    bool is_fixed() const;
    bool is_percent() const;
    int  resolve(int parent) const;
};

Dimension operator""_pct(unsigned long long v);  // 50_pct

FlexStyle

struct FlexStyle {
    FlexDirection direction = FlexDirection::Row;
    FlexWrap      wrap      = FlexWrap::NoWrap;
    Align         align_items = Align::Stretch;
    Align         align_self  = Align::Auto;
    Justify       justify     = Justify::Start;
    float         grow   = 0;
    float         shrink = 1;
    Dimension     basis  = Dimension::auto_();
    Dimension     width  = Dimension::auto_();
    Dimension     height = Dimension::auto_();
    Dimension     min_width  = Dimension::auto_();
    Dimension     min_height = Dimension::auto_();
    Dimension     max_width  = Dimension::auto_();
    Dimension     max_height = Dimension::auto_();
    int           gap = 0;
    Edges<int>    padding{};
    Edges<int>    margin{};
};

Edges\<T>

template <typename T>
struct Edges {
    T top{}, right{}, bottom{}, left{};

    Edges() = default;
    Edges(T all);            // uniform
    Edges(T v, T h);         // vertical, horizontal
    Edges(T t, T r, T b, T l);

    T horizontal() const;    // left + right
    T vertical() const;      // top + bottom
};

Event System

Event

using Event = std::variant<KeyEvent, MouseEvent, PasteEvent, FocusEvent, ResizeEvent>;

KeyEvent

using Key = std::variant<CharKey, SpecialKey>;

struct CharKey { char32_t codepoint; };

enum class SpecialKey {
    Up, Down, Left, Right, Home, End,
    PageUp, PageDown, Tab, BackTab,
    Backspace, Delete, Insert, Enter, Escape,
    F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12
};

struct Modifiers {
    bool ctrl = false, alt = false, shift = false, super_ = false;
    bool none() const;
};

struct KeyEvent {
    Key         key;
    Modifiers   mods;
    std::string raw_sequence;
};

MouseEvent

enum class MouseButton { Left, Right, Middle, ScrollUp, ScrollDown, None };
enum class MouseEventKind { Press, Release, Move };

struct MouseEvent {
    MouseButton    button;
    MouseEventKind kind;
    Columns        x;
    Rows           y;
    Modifiers      mods;
};

Other Events

struct PasteEvent  { std::string content; };
struct FocusEvent  { bool focused; };
struct ResizeEvent { Columns width; Rows height; };

Event Predicates

// Keyboard
bool key(const Event&, char c);
bool key(const Event&, char32_t cp);
bool key(const Event&, SpecialKey sk);
bool ctrl(const Event&, char c);
bool alt(const Event&, char c);
bool shift(const Event&, SpecialKey sk);
bool any_key(const Event&);
const KeyEvent* as_key(const Event&);

// Mouse
struct MousePos { int col, row; };
bool mouse_clicked(const Event&, MouseButton = MouseButton::Left);
bool mouse_released(const Event&, MouseButton = MouseButton::Left);
bool mouse_moved(const Event&);
bool scrolled_up(const Event&);
bool scrolled_down(const Event&);
std::optional<MousePos> mouse_pos(const Event&);
const MouseEvent* as_mouse(const Event&);

// Other
bool resized(const Event&, int* w = nullptr, int* h = nullptr);
bool pasted(const Event&, std::string* out = nullptr);
bool focused(const Event&);
bool unfocused(const Event&);

// Fire-and-forget
template <typename F> bool on(const Event&, char c, F&& fn);
template <typename F> bool on(const Event&, char c1, char c2, F&& fn);
template <typename F> bool on(const Event&, SpecialKey sk, F&& fn);

Signals

Signal\<T>

template <typename T>
class Signal {
    Signal();                        // Default-construct T
    explicit Signal(U&& initial);    // Construct from value

    const T& get() const;           // Read (auto-tracks dependencies)
    const T& operator()() const;    // Shorthand for get()
    void set(const T& v);           // Write (notifies if changed)
    void set(T&& v);                // Write (move)
    void update(F&& fn);            // Mutate in-place (always notifies)
    auto map(F&& fn) const -> Computed<R>;  // Derive computed value
    uint64_t version() const;       // Change counter
};

Computed\<T>

template <typename T>
class Computed {
    const T& get() const;           // Read (recomputes if dirty)
    const T& operator()() const;
};

template <std::invocable F>
auto computed(F&& fn) -> Computed<invoke_result_t<F>>;

Effect

class Effect {
    Effect();                        // Default (inactive)
    explicit Effect(F&& fn);        // Create and run immediately
    void dispose();                  // Unsubscribe from all deps
    bool active() const;
};

template <std::invocable F>
Effect effect(F&& fn);

Batch

class Batch {
    Batch();      // Begin batch
    ~Batch();     // End batch, flush notifications
};

template <std::invocable F>
decltype(auto) batch(F&& fn);  // Run fn inside a batch scope

Canvas

Canvas

class Canvas {
    Canvas(int width, int height, StylePool* pool);

    void set(int x, int y, char32_t ch, uint16_t style_id, uint8_t width = 0);
    void write_text(int x, int y, std::string_view text, uint16_t style_id);
    void fill(Rect region, char32_t ch, uint16_t style_id);
    void clear();
    void resize(int w, int h);

    Cell get(int x, int y) const;
    int  width() const;
    int  height() const;

    void push_clip(Rect clip);
    void pop_clip();
};

Cell

struct Cell {
    char32_t character;
    uint16_t style_id;
    uint16_t hyperlink_id;
    uint8_t  width;

    uint64_t pack() const;
    static Cell unpack(uint64_t v);
};

StylePool

class StylePool {
    uint16_t intern(const Style& s);
    const Style& get(uint16_t id) const;
    void clear();
    std::size_t size() const;
};

render_tree()

void render_tree(const Element& root, Canvas& canvas,
                 StylePool& pool, const Theme& theme);

Widgets

All widgets live in maya::widget. Full documentation in 13-widgets.md.

Input

Widget Header Description
Input widget/input.hpp Single-line text input with cursor and history
TextArea widget/textarea.hpp Multi-line text editor
Checkbox widget/checkbox.hpp Toggle checkbox
ToggleSwitch widget/checkbox.hpp iOS-style toggle switch
Radio widget/radio.hpp Radio button group
Select widget/select.hpp Dropdown select menu
Slider widget/slider.hpp Numeric slider
Button widget/button.hpp Clickable button with variants
CommandPalette widget/command_palette.hpp Fuzzy-search command launcher

Data Display

Widget Header Description
Table widget/table.hpp Tabular data with column alignment
Tree widget/tree.hpp Expandable tree view
List widget/list.hpp Selectable item list
KeyHelp widget/key_help.hpp Keyboard shortcut legend
Badge widget/badge.hpp Inline status badge
Callout widget/callout.hpp Info/success/warning/error callout box
Link widget/link.hpp Hyperlink element
KeyHelp widget/key_help.hpp Keyboard shortcut legend
ShortcutRow widget/shortcut_row.hpp Width-adaptive keyboard hint row (Helix/k9s style)
ModelBadge widget/model_badge.hpp Color-coded active-model indicator
Widget Header Description
Tabs widget/tabs.hpp Tab bar navigation
Breadcrumb widget/breadcrumb.hpp Breadcrumb path navigation
Menu widget/menu.hpp Menu with selectable items
ActivityBar widget/activity_bar.hpp Vertical icon sidebar
Scrollable widget/scrollable.hpp Scrollable content region
Scrollbar widget/scrollbar.hpp Visual indicator for a ScrollState
Picker widget/picker.hpp Bordered modal picker with scrollable results
CommandPalette widget/command_palette.hpp Fuzzy-search command launcher

Display

Widget Header Description
StreamingMarkdown widget/markdown.hpp Streaming markdown renderer
Spinner widget/spinner.hpp Animated loading spinner
ProgressBar widget/progress.hpp Progress bar with percentage
Gauge widget/gauge.hpp Gauge / meter display
Divider widget/divider.hpp Horizontal or vertical divider
Image widget/image.hpp Terminal image display
gradient() widget/gradient.hpp Color gradient text builder
Disclosure widget/disclosure.hpp Collapsible disclosure section
Html widget/html.hpp Render a safe subset of HTML as styled Elements
Overlay widget/overlay.hpp Base layer + one anchored floating element

Overlay

Widget Header Description
Modal widget/modal.hpp Modal dialog with buttons
Popup widget/popup.hpp Floating popup
ToastManager widget/toast.hpp Toast notification manager

Visualization

Widget Header Description
BarChart widget/bar_chart.hpp Horizontal/vertical bar chart
LineChart widget/line_chart.hpp Line chart with series
Sparkline widget/sparkline.hpp Inline sparkline graph
Heatmap widget/heatmap.hpp Grid heatmap
Calendar widget/calendar.hpp Calendar date display
PixelCanvas widget/canvas.hpp Pixel-level drawing canvas
FlameChart widget/flame_chart.hpp Flame graph for nested execution spans
Waterfall widget/waterfall.hpp Timing waterfall chart (devtools style)
Timeline widget/timeline.hpp Vertical CI/pipeline event timeline
GitGraph widget/git_graph.hpp Commit graph with colored branch lines

Agent UI

Composable pieces of a Claude-Code / Zed-style agent conversation. Thread is the top-level viewport; the rest are the parts it (or a host) assembles.

Widget Header Description
Thread widget/thread.hpp Top-level viewport: empty → WelcomeScreen, else Conversation
WelcomeScreen widget/welcome_screen.hpp Empty-thread brand splash + starters/hints
Conversation widget/conversation.hpp Vertical list of turns with dividers + in-flight indicator
Turn widget/turn.hpp One speaker turn (rail, role, checkpoint)
TurnDivider widget/turn_divider.hpp Styled rule between conversation turns
CheckpointDivider widget/checkpoint_divider.hpp Full-width "↺ Restore checkpoint" rule above a turn
Composer widget/composer.hpp State-driven bordered input box (idle/streaming/permission)
AgentTimeline widget/agent_timeline.hpp Bordered Actions panel logging tool events for a turn
ToolBodyPreview widget/tool_body_preview.hpp Per-ToolKind body detail under a timeline event
AppLayout widget/app_layout.hpp Top-level chat-app frame (header/body/composer/overlay)
UserMessage widget/message.hpp Chat user message bubble
AssistantMessage widget/message.hpp Chat assistant message bubble
ThinkingBlock widget/thinking.hpp Collapsible AI thinking block
StreamingCursor widget/streaming_cursor.hpp Pulsing "assistant is streaming" indicator
SystemBanner widget/system_banner.hpp Severity-coloured system alert (ctx warning, rate limit)
TodoList widget/todo_list.hpp Session todo list card
PlanView widget/plan_view.hpp Task plan with status tracking
Permission widget/permission.hpp Permission approval prompt

Session / Diagnostics

Widget Header Description
DiffView widget/diff_view.hpp Side-by-side or unified diff
InlineDiff widget/inline_diff.hpp Two-line word-level LCS diff
FileChanges widget/file_changes.hpp Session file-change summary (created/modified/deleted + counts)
ChangesStrip widget/changes_strip.hpp Bordered "session has pending changes" banner
FileRef widget/file_ref.hpp File reference with icon
LogViewer widget/log_viewer.hpp Filterable log viewer
SearchResult widget/search_result.hpp Grouped search results display
ErrorBlock widget/error_block.hpp Structured error/exception card
GitStatus widget/git_status.hpp Branch + working-tree status
ContextWindow widget/context_window.hpp Segmented context-window usage meter
TokenStream widget/token_stream.hpp Live token-rate sparkline + stats (compact/full)
CostTracker widget/cost_tracker.hpp Per-turn + cumulative token/cost breakdown
ApiUsage widget/api_usage.hpp API rate-limit / request-count / latency display
ActivityIndicator widget/activity_indicator.hpp Single-row hex-dump activity tape

Status Bar

Widget Header Description
StatusBar widget/status_bar.hpp Single-line streaming status bar (composes the pieces below)
TokenStreamSparkline widget/token_stream_sparkline.hpp Live tok/s rate + sparkline chip (adaptive width)
PhaseChip widget/phase_chip.hpp Current-phase verb + elapsed, breathing
TitleChip widget/title_chip.hpp Breadcrumb / title chip
ContextGauge widget/context_gauge.hpp Context-window usage gauge
PhaseAccent widget/phase_accent.hpp Top/bottom accent rail strip
StatusBanner widget/status_banner.hpp Full-width toast that takes over the activity row

Tool Widgets

Widget Header Description
ToolCall widget/tool_call.hpp Generic tool invocation display
BashTool widget/bash_tool.hpp Shell command tool call
ReadTool widget/read_tool.hpp File read tool call
EditTool widget/edit_tool.hpp File edit tool call
WriteTool widget/write_tool.hpp File write tool call
FetchTool widget/fetch_tool.hpp HTTP fetch tool call
AgentTool widget/agent_tool.hpp Sub-agent tool call
GitCommitTool widget/git_commit_tool.hpp Git commit operation card

Core Types

Strong\<Tag, T>

template <typename Tag, typename T>
struct Strong {
    T value{};
    // Arithmetic: Strong + Strong, Strong - Strong, etc.
    // Comparison: ==, !=, <, >, <=, >=
};

Size / Position / Rect

using Columns = Strong<ColumnTag, int>;
using Rows    = Strong<RowTag, int>;

struct Size     { Columns width; Rows height; };
struct Position { Columns x; Rows y; };
struct Rect     { Position pos; Size size; };

Result / Status / Error

enum class ErrorKind {
    TerminalInit, Io, LayoutOverflow, InvalidStyle,
    InvalidUtf8, Unsupported, Signal, WouldBlock
};

struct Error {
    ErrorKind kind;
    std::string message;
    std::source_location location;

    static Error terminal(std::string msg);
    static Error io(std::string msg);
    static Error from_errno(std::string ctx);
};

template <typename T>
using Result = std::expected<T, Error>;
using Status = Result<void>;