Build Reactive UIs with Dataflow

A statically-typed functional language where changes propagate automatically

Unlike React or Vue where reactivity is a library bolted onto the language, Graphix is reactive at the language level. Every expression compiles to a node in a live dataflow graph — change any input and updates flow through automatically.

overview_first.gx
use tui;
use tui::block;
use tui::text;

let counter = 0;
let clock = time::timer(duration:1.s, true);
counter <- clock ~ (counter + 1);

block(
  #border: &`All,
  #title: &line("My First TUI"),
  #style: &style(#fg: `Green),
  &text(&"Counter: [counter]")
)
Reactive counter demo

Key Features

Reactive Dataflow

Changes propagate automatically through the dataflow graph. No manual state management or update logic needed.

🔒

Strong Static Typing

Type inference with structural type discipline catches errors at compile time. Parametric polymorphism for flexible, type-safe code.

📊

Rich UI Frameworks

Terminal UIs with ratatui and graphical UIs with iced. Charts, tables, widgets, theming, and more — all with reactive updates.

λ

First-Class Functions

Closures, higher-order functions, and pattern matching. Functional programming meets reactive dataflow.

See It In Action

Terminal and graphical UIs built with Graphix

Code Examples

use tui;
use tui::block;
use tui::text;

let counter = 0;
let clock = time::timer(duration:1.s, true);
counter <- clock ~ (counter + 1);

block(
  #border: &`All,
  #title: &line("My First TUI"),
  #style: &style(#fg: `Green),
  &text(&"Counter: [counter]")
)

The <- operator sets up a reactive binding. When clock fires, counter automatically updates with the new value. The block widget wraps the content with borders, a title, and styling.

let status: [i64, string, null] = 42;

select status {
  i64 as n if n > 0 => "positive number: [n]",
  i64 as n => "non positive number: [n]",
  string as s => "got string: [s]",
  null as _ => "no value"
}

Pattern matching on types with guards. The select statement matches on which type the variant currently holds. The type system ensures all cases are covered.

let value = cast<i64>(net::subscribe("/sensor/temperature")?)?;
let fahrenheit = value * ((9 / 5) + 32);

text(&"Temperature: [fahrenheit]°F")

Subscribe to network data streams with net::subscribe. Values update reactively as new data arrives.

Getting Started

1

Install Graphix

cargo install graphix-shell
2

Start the REPL

graphix
3

Try an Example

let x = 5; x * 2

Requires Rust and some Linux dependencies. See the installation guide for full details.

Read Full Documentation