artisanal 0.6.0
artisanal: ^0.6.0 copied to clipboard
A full-stack terminal toolkit for Dart featuring Lip Gloss styling, Bubble Tea TUI architecture, and Ultraviolet rendering.
Artisanal #
Build polished command-line tools and interactive terminal applications in Dart with one consistent toolkit.
Artisanal brings together high-level CLI output, Lip Gloss-inspired styling, a Bubble Tea-style runtime, reusable Bubbles, a widget framework, and the Ultraviolet cell-buffer renderer.
Table of contents #
- Overview
- Installation
- Quick start
- Toolkit
- Library entrypoints
- Examples and gallery
- Documentation and support
Overview #
| 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 #
Add Artisanal to your project:
dart pub add artisanal
Or add it to pubspec.yaml:
dependencies:
artisanal: ^0.6.0
For widget-only applications, depend on artisanal_widgets directly. Use
artisanal when you want the broader CLI, style, runtime, and rendering stack.
Quick start #
CLI output #
Minimal example
import 'package:artisanal/artisanal.dart';
void main() {
final io = Console();
io.title('Minimal Artisanal CLI');
io.info('Starting up...');
io.success('Ready to ship.');
}
Run the included example from the repository root:
dart run pkgs/artisanal/example/minimal_cli.dart

Complete CLI flow
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.');
}

Styling #
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)
Interactive TUI #
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());
}
Toolkit #
Console helpers #
| 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() |
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) async {
final runner = CommandRunner('my-cli', 'A great CLI');
runner.addCommand(HelloCommand());
await runner.run(args);
}

Bubbles #
| 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 |
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
- Reusable color, CRT, scanline, distortion, and persistence effects through
BufferRenderSink - Mouse support and focus events
- Graphics: Kitty, Sixel, iTerm2, half-block drawing
Replay and 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.
See the TUI documentation for replay and tracing details.
Library entrypoints #
Choose the smallest public library that covers your use case:
| Import | Purpose |
|---|---|
package:artisanal/artisanal.dart |
Umbrella API for CLI output, styling, charting, Markdown, hosts, and common terminal types |
package:artisanal/args.dart |
Command runner utilities (CommandRunner, Command) |
package:artisanal/bubbles.dart |
Reusable TEA widgets |
package:artisanal/catalog.dart |
Public metadata registry for Bubbles and display components |
package:artisanal/style.dart |
Styles, colors, borders, layout, and themes |
package:artisanal/tui.dart |
TEA runtime (Model, Msg, Cmd, Program) plus replay and tracing |
package:artisanal/runtime.dart |
Platform-safe TEA runtime for reusable and browser-capable packages |
package:artisanal/terminal.dart |
Terminal abstraction, ANSI helpers, keys, backends, and bridges |
package:artisanal/editor_core.dart |
Low-level text document, editor state, and viewport primitives |
package:artisanal/text_editing.dart |
Focused cursor, text input, text area, and editor-core surface |
package:artisanal/markdown.dart |
Markdown-to-ANSI renderer and options |
package:artisanal/git_diff.dart |
Git diff model, styles, and review data types |
package:artisanal/charting.dart |
Terminal chart painters and data primitives |
package:artisanal/layout.dart |
String layout, wrapping, and responsive utilities |
package:artisanal/scoring.dart |
Bayesian matching and conformal ranking utilities |
package:artisanal/glamour.dart |
High-fidelity Markdown rendering |
package:artisanal/uv.dart |
Compatibility re-export of Ultraviolet types |
package:artisanal/compat.dart |
Backward-compatible API shims |
Widget-first applications depend on and import package:artisanal_widgets/...
directly; widget APIs are not re-exported from this core package.
Renderer-level applications can import
package:ultraviolet/ultraviolet.dart directly.
Examples and gallery #
See the example/ directory for comprehensive demos:
main.dart– Full feature showcaseminimal_cli.dart– Minimal CLI output examplewidget_catalog.dart– Searchable component catalog and theme 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 layoutstui/examples/uv-effects/main.dart– Applying UV effects to a canvas buffer- Additional engine-specific demos live in
pkgs/ultraviolet/example/
Commands in this gallery assume the repository root as the working directory.
CLI walkthroughs #
The small CLI tapes focus on one interaction at a time and keep the matching command immediately beside its recording.
Tables (example/.vhs/cli_table.tape):
dart run pkgs/artisanal/example/main.dart ui:table --ansi

Prompts (example/.vhs/cli_prompts.tape):
dart run pkgs/artisanal/example/main.dart ui:prompts --defaults --no-interaction --ansi

Display components (example/.vhs/cli_components.tape):
dart run pkgs/artisanal/example/main.dart ui:components --ansi

Progress (example/.vhs/cli_progress.tape):
dart run pkgs/artisanal/example/main.dart ui:progress --count 40 --ansi

Full demo captures #
Recordings of the more consequential examples, regenerated from the VHS tapes
in example/.vhs/ with task artisanal-demos:
Markdown renderer (example/markdown_demo.dart):

Glamour themes (example/glamour_demo.dart):

CLI runner showcase (example/main.dart):

Lip Gloss TUI (example/lipgloss_tui.dart):

Spinners (example/spinner_demo.dart):

Log viewer (example/log_viewer_demo.dart):

Split dashboard (example/split_dashboard_demo.dart):

Command center (example/command_center_demo.dart):

Data table (example/data_table_demo.dart):

Sequence diagram (example/sequence_diagram_demo.dart):

Styled tables (example/lipgloss_table.dart):

Styled lists (example/lipgloss_list.dart):

Styled trees (example/lipgloss_tree.dart):

Charting (example/charting_demo.dart):

Markdown showcase (example/markdown_showcase.dart):

Theme integration (example/theme_integration_demo.dart):

Compositor images (example/compositor_image_demo.dart):

Editor core (example/editor_core_demo.dart):

Fluent style API (example/fluent_style_example.dart):

Kitty images (example/kitty_image_demo.dart):

Console tags (example/lipgloss_console_tags.dart):

Lip Gloss layout (example/lipgloss_layout.dart):

Render recorder (example/render_recorder_demo.dart):

Scanner spinner (example/scanner_demo.dart):

Inline animation (example/inline_animation_demo.dart):

DevTools counter (example/devtools_demo.dart):

Multi search (example/multi_search_demo.dart):

Artisanal Nexus (example/uv_tui_demo.dart):

Static screenshots #
Log viewer

Console tags

Layout

Documentation and support #
- Start with the documentation index.
- Browse the runnable examples in
example/. - Report bugs or outdated examples in the issue tracker.
Artisanal is a Dart port of Charm's Lip Gloss, Bubble Tea, and Bubbles. The project aims for broad parity, but some behavior may still differ from the Go originals. Reports with small reproductions are especially helpful.