Artisanal
About this project:
This library is a faithful port of Charm's TUI libraries (Lip Gloss, Bubble Tea, Bubbles) to Dart. We aim to port as much functionality as possible. In some scenarios, things may not work as expected—please report any issues you discover so we can adjust where necessary.
Many of the included examples were generated and may contain issues or not reflect the latest API. If you find a broken or outdated example, please let us know!
⚠️ Work in Progress:
This library is under active development and its API may change. Some examples may be broken or require updates to match the latest state of the package. If you discover any broken or outdated examples, please report them or open an issue. Thank you for your understanding!
A full-stack terminal toolkit for Dart, inspired by popular Go terminal libraries: Lip Gloss (styling), Bubble Tea (TUI framework), and Bubbles (reusable widgets).
Build everything from rich command-line tools to complex interactive TUI applications with a consistent, idiomatic Dart API.
Features
| Feature | Description |
|---|---|
| CLI I/O | High-level Console helpers for status lines, tables, tasks, prompts, and styled output |
| Styling | Fluent, immutable Style API with colors, borders, padding, margins, and themes |
| TUI Runtime | Elm Architecture (Model/Msg/Cmd) with a full-featured Program event loop |
| Bubbles | 20+ reusable widgets: inputs, lists, tables, spinners, progress bars, file pickers, etc. |
| Ultraviolet (UV) | High-performance cell-buffer renderer with diff-based updates and graphics support |
| Terminal + Renderer | Unified terminal abstraction, ANSI helpers, and renderer backends |
| Markdown | ANSI Markdown renderer plus Glamour high-fidelity output |
| Charting | Sparklines, line/ribbon charts, histograms, heatmaps, and pie charts |
Installation
dependencies:
artisanal: ^0.2.0
Note: This package uses workspace resolution. Use a path or git reference in standalone projects.
🖼️ Screenshots



Library Exports
| Import | Purpose |
|---|---|
package:artisanal/artisanal.dart |
Full CLI kit (Console, Style, Terminal, Layout) |
package:artisanal/args.dart |
Command runner utilities (CommandRunner, Command) |
package:artisanal/style.dart |
Styling, Layout, Colors, Borders, Themes |
package:artisanal/tui.dart |
TUI runtime: Model, Msg, Cmd, Program |
package:artisanal/bubbles.dart |
Reusable interactive widgets |
package:artisanal/terminal.dart |
Terminal abstraction, ANSI codes, Keys |
package:ultraviolet/ultraviolet.dart |
Low-level cell-buffer renderer |
package:artisanal/uv.dart |
Compatibility re-export for UV (package:ultraviolet/ultraviolet.dart) |
package:artisanal/markdown.dart |
Markdown to ANSI renderer |
package:artisanal/glamour.dart |
High-fidelity Markdown renderer |
package:artisanal/charting.dart |
Charting primitives |
Documentation
See the in-repo docs for full coverage:
docs/DOCS_INDEX.md
Quick Start: CLI Output
import 'package:artisanal/artisanal.dart';
Future<void> main() async {
final io = Console();
io.title('My App');
io.section('Setup');
io.info('Checking configuration...');
await io.task('Running migrations', run: () async {
await Future.delayed(const Duration(milliseconds: 200));
return TaskResult.success;
});
io.table(
headers: ['ID', 'Name', 'Status'],
rows: [
[1, 'users', io.style.success('DONE')],
[2, 'posts', io.style.warning('PENDING')],
],
);
final proceed = io.confirm('Continue?', defaultValue: true);
if (!proceed) return;
io.success('All good.');
}

Quick Start: Styling (Lip Gloss)
import 'package:artisanal/style.dart';
final style = Style()
.bold()
.foreground(Colors.purple)
.padding(1, 2)
.border(Border.rounded);
print(style.render('Hello, Artisanal!'));

Style Capabilities
- Text effects:
bold(),italic(),underline(),strikethrough(),dim(),inverse(),blink() - Colors: ANSI 16, ANSI 256, TrueColor (RGB),
AdaptiveColor(light/dark aware) - Spacing:
padding(),margin() - Borders:
rounded,thick,double,hidden, custom - Alignment:
align(),alignVertical() - Dimensions:
width(),height(),maxWidth(),maxHeight() - Themes:
ThemePalettewith presets (dark, light, ocean, nord, dracula, monokai, solarized)
Quick Start: TUI (Elm Architecture)
import 'package:artisanal/tui.dart';
class CounterModel implements Model {
final int count;
const CounterModel([this.count = 0]);
@override
Cmd? init() => null;
@override
(Model, Cmd?) update(Msg msg) {
return switch (msg) {
KeyMsg(key: Key(type: KeyType.up)) => (CounterModel(count + 1), null),
KeyMsg(key: Key(type: KeyType.down)) => (CounterModel(count - 1), null),
KeyMsg(key: Key(type: KeyType.runes, runes: [0x71])) => (this, Cmd.quit()),
_ => (this, null),
};
}
@override
String view() => 'Count: \$count\n\nUse ↑/↓ to change, q to quit';
}
Future<void> main() async {
await runProgram(CounterModel());
}
Replay + Trace Debugging
The TUI runtime supports deterministic replay (ProgramReplay) and built-in
file tracing (TuiTrace) for debugging and profiling.
Enable tracing for any TUI app:
ARTISANAL_TUI_TRACE=1 ARTISANAL_TUI_TRACE_CAPTURE=1 \
ARTISANAL_TUI_TRACE_PATH=traces/my-run.log \
dart run your_app.dart
Structured app/domain events can be emitted via TuiTrace.event(...) and are
preserved in replay conversion when they use stable typed type names.
Full replay and tracing documentation: docs/TUI.md.
Bubbles (Reusable Widgets)
| Widget | Description |
|---|---|
TextInputModel |
Single-line text input |
TextAreaModel |
Multi-line text editing |
ListModel |
Filterable list selection |
TableModel |
Interactive tables |
ViewportModel |
Scrollable content pane |
ProgressModel |
Progress bars with ETA |
SpinnerModel |
Animated loading spinners |
FilePickerModel |
File/directory browser |
AnticipateModel |
Autocomplete with suggestions |
WizardModel |
Multi-step form wizard |
SelectModel<T> |
Single-choice selection prompt |
MultiSelectModel<T> |
Multiple-choice selection |
PasswordModel |
Masked password input |
TimerModel |
Countdown timer |
StopwatchModel |
Elapsed time tracking |
PaginatorModel |
Pagination controls |
HelpModel |
Key binding help views |
Command Runner
Build CLI tools with styled help and nested commands:
import 'package:artisanal/args.dart';
class HelloCommand extends Command {
@override
String get name => 'hello';
@override
String get description => 'Say hello';
@override
void run() {
io.success('Hello, world!');
}
}
void main(List<String> args) {
final runner = CommandRunner('my-cli', 'A great CLI');
runner.addCommand(HelloCommand());
runner.run(args);
}

Ultraviolet Renderer
High-performance rendering with diff-based updates for flicker-free TUI applications:
await runProgram(
MyModel(),
options: const ProgramOptions(
useUltravioletRenderer: true,
useUltravioletInputDecoder: true,
altScreen: true,
mouse: true,
),
);
UV Features
- 2D cell buffer with styled cells
- Diff-based terminal updates (minimal redraws)
- Layer composition and hit-testing
- Mouse support and focus events
- Graphics: Kitty, Sixel, iTerm2, half-block drawing
Console Methods
| Category | Methods |
|---|---|
| Output | writeln(), write(), title(), section() |
| Messages | line(), info(), comment(), question(), warn(), error(), note(), caution(), alert(), verbose(), debug() |
| Layout | table(), tree(), listing(), twoColumnDetail(), text() |
| Interactive | ask(), confirm(), choice(), secret(), selectChoice(), multiSelectChoice(), menu(), search() |
| Progress | task(), spin(), progress(), progressIterate() |
Examples
See the example/ directory for comprehensive demos:
main.dart– Full feature showcasefluent_style_example.dart– Style API patternsspinner_demo.dart– Various spinner typeslipgloss_table.dart– Styled tableslog_viewer_demo.dart– Monitoring dashboardcommand_center_demo.dart– Multi-panel layouts- UV-specific demos now live in
pkgs/ultraviolet/example/
Libraries
- charting
- Charting primitives for terminal-native visualizations.
- glamour
- Glamour Markdown Rendering for Dart.
- liquid
- Liquid tag template adapters for Artisanal.
- markdown
- Markdown to ANSI terminal rendering.
- physics
- Physics helpers (Forge2D adapters) for Artisanal.
- widgets
- Widget system for composable TUI components.
- args Core
- Command-line argument parsing and command runners for Artisanal.
- artisanal Core
- Artisanal: A polished CLI framework for Dart.
- style Style
- Fluent styling system for terminal text (Lip Gloss for Dart).
- terminal Terminal
- Unified terminal module for artisanal.
- bubbles TUI
- Reusable interactive components for Artisanal TUI.
- tui TUI
- Interactive TUI framework (Bubble Tea for Dart).
- uv Ultraviolet
- Ultraviolet (UV): High-performance terminal rendering and input.