Skip to main content

How Artisanal fits together

You do not have to adopt the whole stack to use Artisanal. A command-line tool might only use Console and Style; an interactive app can add either the TEA runtime or the widget framework; a custom renderer can work directly with Ultraviolet.

This page explains where those pieces meet and helps you choose the smallest useful starting point.

Choose how to structure an interactive app​

Both approaches run on the same Program runtime and Ultraviolet renderer. Choose based on how you prefer to organize application code:

TEA modelWidget system
A good fit forSmall apps, custom event flows, and direct runtime controlScreens, forms, navigation, and reusable UI
Code shapeModel, update, and viewWidget, State, and build
Start withThe TEA runtimeThe widget framework

The two are not isolated worlds. WidgetApp is itself a Model, so advanced apps can mix widget screens with lower-level runtime features when needed.

How output reaches the terminal​

flowchart TB
subgraph application["Application layer"]
console["Console: high-level I/O"]
program["Program: TUI Elm Architecture"]
runner["CommandRunner: CLI with subcommands"]
end

subgraph presentation["Presentation layer"]
styling["Style: Lip Gloss styling"]
widgets["Widgets: declarative layouts"]
bubbles["Bubbles: reusable components"]
end

subgraph rendering["Rendering layer"]
ultraviolet["Ultraviolet cell renderer"]
canvas["Canvas"]
buffer["Buffer"]
layer["Layer"]
ultraviolet --- canvas
ultraviolet --- buffer
ultraviolet --- layer
end

subgraph terminal["Terminal layer"]
terminalApi["Terminal abstraction: raw mode, ANSI, and input parsing"]
colorProfile["Color profile detection"]
end

console --> styling
program --> widgets
program --> bubbles
runner --> console
styling --> ultraviolet
widgets --> ultraviolet
bubbles --> ultraviolet
ultraviolet --> terminalApi
colorProfile --> ultraviolet

Core Systems​

1. Style System (Lip Gloss-inspired)​

Location: pkgs/artisanal/lib/src/style/ Documentation: style.md

The Style system provides a fluent API for terminal text styling:

final style = Style()
.bold()
.foreground(Colors.cyan)
.padding(Padding.symmetric(horizontal: 2))
.border(Border.rounded);

print(style.render('Hello, World!'));

Key components:

  • Style - Fluent builder for text formatting
  • Color, AnsiColor, BasicColor, AdaptiveColor - Color types
  • Border, BorderSides - Box borders
  • Padding, Margin, Align - Layout properties
  • LipList - Styled list rendering

2. TUI System (Bubble Tea-inspired)​

Location: pkgs/artisanal/lib/src/tui/ Documentation: tui.md

The TUI system implements the Elm Architecture for interactive terminal applications:

class MyModel implements Model {

Cmd? init() => null;


(Model, Cmd?) update(Msg msg) {
return switch (msg) {
KeyMsg(key: Key(type: KeyType.runes, runes: [0x71])) => (this, Cmd.quit()),
_ => (this, null),
};
}


String view() => 'Press q to quit';
}

Key components:

  • Program - Runtime that manages event loop and rendering
  • Model - Application state with init/update/view
  • Cmd - Async side effects (quit, tick, perform, batch)
  • Msg - Events (KeyMsg, MouseMsg, WindowSizeMsg, etc.)
  • Bubbles - Pre-built components (TextInput, List, Confirm, etc.)

3. Widget System​

Location: pkgs/artisanal_widgets/lib/src/widgets/
Documentation: widgets.md

Declarative widget composition for building complex layouts:

Container(
padding: EdgeInsets.all(1),
border: Border.rounded,
child: VBox([
Label('Header', style: theme.primary),
Spacer(),
HBox([Label('Left'), Spacer(), Label('Right')]),
]),
)

Key components:

  • Widget - Base class with lifecycle (init, update, view)
  • Container - Box with padding, borders, backgrounds
  • Label - Styled text
  • HBox, VBox - Horizontal/vertical layouts
  • GestureDetector - Typed gesture recognition (tap, double-tap, long-press, drag)
  • Theme - Color theming with adaptive support
  • Flutter-style ports - Chip, DropdownButton, PopupMenuButton, Slider, RangeSlider, LinearProgressIndicator, CircularProgressIndicator

4. UV System (Ultraviolet)​

Location: pkgs/ultraviolet/lib/src/uv/ Documentation: uv.md

Low-level cell-based terminal rendering:

final canvas = Canvas(80, 24);
canvas.setString(10, 5, 'Hello');
canvas.drawBorder(roundedBorder(), rect(5, 3, 20, 5));
final output = canvas.render();

Key components:

  • Cell, UvStyle, UvColor - Cell representation
  • Buffer - 2D grid of cells
  • Screen - Abstract drawing surface
  • Canvas - Compositing with drawables
  • Layer - Z-ordered composition
  • UvTerminalRenderer - Diff-based terminal output

Two Color Systems​

Artisanal has two color systems serving different purposes:

SystemLocationPurpose
Style Colorspkgs/artisanal/lib/src/style/color.dartHigh-level API producing ANSI strings
UV Colorspkgs/ultraviolet/lib/src/uv/cell.dartLow-level cell storage for deferred rendering

Style Colors​

// Used with Style fluent API
Style().foreground(Colors.red) // BasicColor
Style().foreground(AnsiColor(196)) // Explicit ANSI code
Style().foreground(AdaptiveColor( // Auto light/dark
light: Colors.black,
dark: Colors.white,
))

UV Colors​

// Used with Cell/Canvas API
final cell = Cell(
content: 'A',
style: UvStyle(fg: UvColor.rgb(255, 0, 0)),
);

Bridge Code​

The widget system bridges these two systems:

// In layout_widgets.dart
UvColor? colorToUvColor(Color? color) {
if (color is AdaptiveColor) {
resolved = hasDarkBackground ? color.dark : color.light;
}
// Convert Style Color → UV Color
}

Import Structure​

// Core CLI utilities (Console, Verbosity, Terminal)
import 'package:artisanal/artisanal.dart';

// Just the styling system
import 'package:artisanal/style.dart';

// TUI framework (Model, Program, Cmd, Msg)
import 'package:artisanal/tui.dart';

// Pre-built TUI components
import 'package:artisanal/bubbles.dart';

// Low-level cell renderer (prefer dedicated package in new code)
import 'package:ultraviolet/ultraviolet.dart';
// Compatibility: `package:artisanal/uv.dart` continues to re-export these UV types.

// CLI command runner
import 'package:artisanal/args.dart';

// Terminal abstraction
import 'package:artisanal/terminal.dart';

// Umbrella API: Console, Markdown, charting, and Liquid
import 'package:artisanal/artisanal.dart';

// Focused high-fidelity Markdown renderer
import 'package:artisanal/glamour.dart';

Satellite Libraries​

  • Charting: Terminal-native charts rendered into UV buffers.
  • Markdown: Lightweight ANSI renderer for inline docs.
  • Glamour: High-fidelity Markdown renderer with themes.
  • Liquid: Templating adapters for UI blocks (experimental).

Data Flow​

Console (High-level I/O)​

flowchart LR
user["User code"] --> console["Console"]
console --> styling["Style.render()"]
styling --> terminal["Terminal"]
terminal --> stdout["stdout"]

TUI (Interactive)​

flowchart LR
stdin["stdin"] --> parser["KeyParser"]
parser --> message["Msg"]
message --> update["Model.update()"]
update --> model["Model"]
model --> view["Model.view()"]
view --> renderer["Renderer"]
renderer --> stdout["stdout"]
update --> command["Cmd"]
command --> operation["Async operation"]
operation --> message

UV Rendering​

There are two separate rendering paths depending on which programming model is in use:

TEA model path (bare Model, no widget tree):

flowchart LR
view["Model.view()"] --> value["String or View"]
value --> renderer["UvTerminalRenderer"]
renderer --> diff["Cell diff"]
diff --> stdout["stdout"]

Widget system path (WidgetApp wraps a widget tree):

flowchart TB
view["WidgetApp.view()"] --> elements["ElementTree.render()"]
elements --> renderObjects["RenderObject tree"]
renderObjects --> canvas["Canvas"]
canvas --> buffer["Buffer"]
buffer --> renderer["UvTerminalRenderer"]
renderer --> diff["Cell diff"]
diff --> stdout["stdout"]

In both cases the Program runtime calls model.view() — the difference is that WidgetApp.view() triggers a full element-tree traversal before producing a string.

Terminal Capabilities​

Artisanal automatically detects terminal capabilities:

  • Color Profile: ASCII, ANSI (16), ANSI256, TrueColor
  • Background: Light/Dark detection via OSC 11
  • Graphics: Sixel, Kitty, iTerm2 image protocols (auto-selected by priority: Kitty > iTerm2 > Sixel > HalfBlock fallback)
  • Features: Mouse tracking, bracketed paste, focus events
  • Gesture System: Recognizer-based gesture processing with typed detail objects for tap, double-tap, long-press, and drag
// Automatic degradation
final style = Style().foreground(BasicColor('#ff5500'));
// TrueColor terminal: \x1b[38;2;255;85;0m
// ANSI256 terminal: \x1b[38;5;208m
// ANSI16 terminal: \x1b[91m

Performance Considerations​

  1. Diff-based Rendering: UV only redraws changed cells
  2. Synchronized Output: Uses DEC synchronized-output mode where supported
  3. Frame Rate Control: Configurable FPS with automatic throttling
  4. Lazy Evaluation: Style rendering is deferred until needed

File Organization​

pkgs/artisanal/lib/
├── artisanal.dart # Main entry point
├── style.dart # Style system exports
├── tui.dart # TUI framework exports
├── runtime.dart # Platform-safe core TUI runtime
├── bubbles.dart # Bubble components exports
├── compat.dart # Compatibility helpers
├── editor_core.dart # Low-level editor primitives
├── text_editing.dart # Focused editor and text-input models
├── markdown.dart # Focused Markdown-to-ANSI renderer
├── git_diff.dart # Focused Git diff model and data types
├── charting.dart # Focused chart painters and data types
├── layout.dart # Focused string layout utilities
├── scoring.dart # Focused matching and ranking utilities
├── glamour.dart # Focused high-fidelity Markdown renderer
├── args.dart # CLI argument parser exports
├── terminal.dart # Terminal abstraction exports
├── uv.dart # UV compatibility re-export
├── web.dart # Browser program runner
└── src/
├── charting/ # Charting renderers
├── web/ # Browser renderer/runner support
├── style/ # Lip Gloss-inspired styling
├── tui/ # Bubble Tea-inspired TUI
│ └── bubbles/ # Pre-built TEA components
│
├── uv/ # Ultraviolet cell renderer
├── io/ # Console I/O utilities
├── terminal/ # Terminal abstraction
├── colorprofile/ # Color capability detection
├── unicode/ # Unicode width/grapheme handling
├── layout/ # Layout utilities
├── renderer/ # Renderer abstraction
├── runner/ # Command runner
├── tui/markdown/ # Markdown to ANSI
├── glamour/ # Glamour renderer
└── liquid/ # Liquid adapters

Widget shells, runners, and testing utilities live under pkgs/artisanal_widgets/lib/. Artisanal Widgets depends on this core package; core does not re-export the widget package.

Standalone UV users can import the focused package:ultraviolet/core.dart, input.dart, rendering.dart, terminal.dart, or unicode.dart entrypoint, or use package:ultraviolet/ultraviolet.dart for the umbrella surface. package:ultraviolet/uv.dart is the complete low-level compatibility surface; package:artisanal/uv.dart delegates to it.