Skip to content

Fleury

A fast Dart UI framework for the terminal — and the browser. One widget tree, two surfaces, and a semantic tree agents can drive.
live
You write
// A live world clock: Digits tick every second.
// Click a tab, or press ← / →, to switch zones.
Tabs(
tabs: [
TabItem(label: 'UTC', content: Digits(utcTime)),
TabItem(label: 'EST', content: Digits(estTime)),
TabItem(label: 'PST', content: Digits(pstTime)),
TabItem(label: 'CET', content: Digits(cetTime)),
TabItem(label: 'JST', content: Digits(jstTime)),
],
)
Fleury renders
Live · interactive
click & type to interact ⓘ how this demo runs
You write
DataTable(
rowCount: people.length,
selectionMode: DataTableSelectionMode.row,
columns: const [
DataTableColumn(id: 'name', title: 'NAME'),
DataTableColumn(id: 'role', title: 'ROLE'),
DataTableColumn(id: 'commits', title: 'COMMITS'),
],
cellBuilder: (row, col) => people[row][col],
)
Fleury renders
Live · interactive
click & type to interact ⓘ how this demo runs
You write
// Streamed: a timer calls setState with fresh values,
// and Fleury sends only changed cells to the target.
BarChart(
bars: [
for (final (i, jobs) in waiting.indexed) Bar('q${i + 1}', jobs),
],
showYAxis: true,
)
Fleury renders
Live

None of these are screenshots — each is a real Fleury widget tree compiled to JavaScript with dart2js, running live in your browser: the clock ticks, the bars stream, the table takes your clicks. The same trees also run native in a terminal. How that works →

Read the full case for Fleury — and how it compares →

This one is yours to change. Edit the greeting, make the button count by two, or add a widget, then press Run. Edit again and Hot reload keeps your count. For a full-page editor, open Fleury Pad.

hello_fleury.dart
You write · editable
import 'package:fleury/fleury_core.dart';
class HelloFleury extends StatefulWidget {
const HelloFleury({super.key});
@override
State<HelloFleury> createState() => _HelloFleuryState();
}
class _HelloFleuryState extends State<HelloFleury> {
int count = 0;
@override
Widget build(BuildContext context) {
final colors = context.colors;
return Container(
border: const BoxBorder(),
padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 1),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Hello, Fleury!',
style: CellStyle(foreground: colors.primary, bold: true),
),
const SizedBox(height: 1),
Text('Pressed $count ${count == 1 ? 'time' : 'times'}'),
const SizedBox(height: 1),
Button(
text: 'Press me',
autofocus: true,
onPressed: () => setState(() => count++),
),
],
),
);
}
}
Your app
Live · interactive
click & type to interact ⓘ how this demo runs

Featured apps, each built only from Fleury widgets and running live in your browser. Open one and drive it with your keyboard and mouse.

One widget tree, two surfaces rests on a retained-mode engine: it turns your widgets into cells and paints them wherever you point it — a terminal, a browser, a streamed session. These two pages walk the whole pipeline.