Skip to content

Repository files navigation

tui

A Dart library for building terminal user interfaces.

What's in here

  • Widgets: Input, TextArea, Select, Confirm, Table, Spinner, ProgressBar
  • Layout: SplitView, Frame, Box
  • BigText: ASCII art banners with gradient support
  • Animations: Typewriter, glitch, matrix rain, shimmer, and more
  • Audio: Programmatic synthesis, melody DSL, SFX presets — no sound files needed
  • Focus management: Tab between focusable widgets
  • 60 FPS render loop with optional FPS meter

Quick start

import'package:tui/tui.dart';
classMyAppextendsWindow {
MyApp() {
var input =Input(placeholder:'Your name')
..onSubmit = (name) {
print('Hello, $name!');
stop();
};
children = [
Frame(title:'Welcome')..children = [input]
];
}
}
voidmain() =>MyApp().start();

Widgets

Input

var input =Input(placeholder:'Type here...')
..prompt ='> '
..onSubmit = (value) =>print(value);

Select

var select =Select<String>(
options: ['Apple', 'Banana', 'Cherry'],
header:'Pick a fruit:',
onSelect: (fruit) =>print(fruit),
);
// Multi-selectvar multi =Select<String>(
options: ['Red', 'Green', 'Blue'],
multiSelect:true,
onSelectMultiple: (colors) =>print(colors),
);

Table

var table =Table<List<String>>(
columns: [
TableColumn('Name', width:15),
TableColumn('Status', width:10),
],
rows: [
['Alice', 'Online'],
['Bob', 'Away'],
],
rowBuilder: (row) => row,
onSelect: (row) =>print(row),
);

Spinner

var spinner =Spinner(
label:'Loading...',
style:SpinnerStyle.dots, // dots, circle, line, arrow, bounce, moon, etc.
)..start();
// Later:
spinner.stop();

ProgressBar

var bar =ProgressBar()
..label ='Download'
..value =0.75; // 0.0 to 1.0

Layout

SplitView

// Horizontal split (side by side)SplitView(horizontal:true)
..children = [leftPanel, rightPanel];
// With custom ratiosSplitView(horizontal:true, ratios: [2, 1])
..children = [mainPanel, sidebar];
// Vertical splitSplitView(horizontal:false)
..children = [topPanel, bottomPanel];

Frame

Frame(title:'My Panel', color:'36', focusColor:'33')
..children = [someWidget];

The frame uses light borders normally, double borders when focused.

BigText

ASCII art text with optional gradients.

var banner =BigText('HELLO', font:BigTextFont.shadow)
..gradient =Gradients.rainbow;
children = [banner];

Fonts: block, slim, chunky, shadow

Gradients: rainbow, sunset, ocean, fire, forest, purple, cyan, gemini, matrix

Animations

var controller =AnimationController()..fps =60;
// Typewriter
controller.add(TypewriterAnimation(
text:'Hello world',
duration:Duration(seconds:2),
onUpdate: (visible) => currentText = visible,
));
// Glitch
controller.add(GlitchAnimation(
text:'ERROR',
duration:Duration(milliseconds:1500),
intensity:0.5,
onUpdate: (glitched) => currentText = glitched,
));
// Looping pulse
controller.add(ValueAnimation(
from:0,
to:1,
duration:Duration(milliseconds:500),
repeatMode:RepeatMode.pingPong,
onUpdate: (value) => opacity = value,
));

Repeat modes: once, reverse, loop, pingPong

FPS meter

classMyAppextendsWindow {
MyApp() {
showFps =true; // Shows FPS in top-right corner
}
}

Audio

Programmatic audio synthesis — generate sounds from code, no files needed.

final audio =Audio();
// Quick beep
audio.beep();
// SFX presetsSFX.success.playOn(audio.channel('sfx'));
SFX.coin.playOn(audio.channel('sfx'));

Melody builder

final melody =Melody(bpm:120, waveform:Waveform.square)
..note(Note.C4, Dur.quarter)
..note(Note.E4, Dur.quarter)
..note(Note.G4, Dur.half)
..rest(Dur.quarter)
..note(Note.C5, Dur.whole);
audio.channel('music').playMelody(melody);

Melody DSL

Compact string notation for quick melodies:

audio.channel('music').play(
'E4.q E4.q F4.q G4.q | G4.q F4.q E4.q D4.q | C4.q C4.q D4.q E4.q | E4.dq D4.e D4.h',
bpm:120,
);

Note format: {Name}{Octave}.{Duration} — e.g. C4.q, Fs5.e, R.h (rest)

Durations: w whole, h half, q quarter, e eighth, s sixteenth, t triplet, d prefix for dotted (dh, dq, de)

Waveforms and envelopes

// 5 waveform types
audio.channel('sfx').tone(
frequency:Note.A4,
waveform:Waveform.sawtooth, // sine, square, triangle, sawtooth, noise
duration:0.5,
);
// Custom ADSR envelopefinal staccato =Envelope(attack:0.005, decay:0.1, sustain:0.0, release:0.01);
audio.channel('sfx').tone(frequency:Note.C5, envelope: staccato);

Channels

Named channels — each plays one sound at a time (new replaces old):

audio.channel('sfx'); // sound effects
audio.channel('music'); // background melody
audio.channel('ui'); // UI feedback
audio.muted =true; // mute everything

SFX presets

beep, click, success, error, powerUp, explosion, coin, jump

Low-level synthesis

// Generate raw samplesfinal samples =Synthesizer.tone(frequency:440.0, duration:0.5, waveform:Waveform.sine);
// Mix multiple buffers into a chordfinal chord =Synthesizer.mix([
Synthesizer.tone(frequency:Note.C4, duration:1.0, volume:0.5),
Synthesizer.tone(frequency:Note.E4, duration:1.0, volume:0.5),
Synthesizer.tone(frequency:Note.G4, duration:1.0, volume:0.5),
]);
// Encode to WAVfinal wav =WavWriter.encode(chord);

Running the demos

dart run example/widgets_demo.dart
dart run example/animation_demo.dart
dart run example/split_view.dart
dart run example/bigtext_demo.dart
dart run example/audio_demo.dart

License

Apache 2.0

About

Text-based User Interface components for building console application.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages