Muse
Muse is a Flutter-like terminal UI framework built on OpenTUI via Dart FFI, providing declarative widgets, terminal-first layout, focus management, animations, and native buffer APIs familiar to Flutter developers.
- A declarative widget framework with
StatelessWidget,StatefulWidget,BuildContext, andsetState. - Terminal-first layout primitives such as
Row,Column,Container,Padding,SizedBox,Align,Flexible, andExpanded. - Shared framework services including focus, pointer routing, inherited dependencies, diagnostics, and animations.
- Native OpenTUI bindings, packaged binaries, and low-level buffer/renderer APIs for direct use when needed.
The repo is the development home for the framework and is preparing its first
development release on pub.dev as muse.
Current Status
Core framework work is in place:
runTuiAppis the primary application entry point and returns aTuiBindinglifecycle handle- Layout, styling, focus/input routing, inherited state, diagnostics, and animation scaffolding are implemented
- Analyzer and test coverage are in active use for framework changes
- Packaged native binaries are checked in under
native/ - Local Go parity exists for primitive scenes; widget parity is the next active lane
Quick Start
Clone the repo and install Dart dependencies:
dart pub get
Run a few representative examples:
dart run example/hello.dart
dart run example/layout_demo.dart
dart run example/focus_form.dart
dart run example/pulse_animation.dart
Run the baseline validation commands:
dart analyze
dart test
Example Apps
Static rendering and animation:
example/hello.dart— minimal renderingexample/counter.dart— stateful rebuildsexample/layout_basics.dart— core layout tourexample/layout_demo.dart— richer flex/alignment/decorationsexample/inherited_example.dart— inherited dependencies and rebuild propagationexample/bindings_validation.dart— low-level FFI smoke testexample/pulse_animation.dart—AnimationControllerand ticker usage
Interactive widgets (use these to verify keyboard/mouse work in your terminal):
example/focus_form.dart— focus manager andTextInputroutingexample/select_demo.dart—Select<T>with arrows /j/k/ Enterexample/scrollbox_demo.dart—ScrollBoxwith arrows / PgUp / PgDn / Home / Endexample/textarea_demo.dart— multi-lineTextArea, Ctrl+Enter to submitexample/widgets_tour.dart— combined tour, Tab cycles focus
Supported Keyboard and Mouse Input
The stdin parser (lib/src/core/stdin_input_driver.dart) decodes:
| Input | Result |
|---|---|
| Printable ASCII / UTF-8 | KeyEvent(key: '<char>') |
| Backspace (BS / DEL) | KeyEvent(key: 'Backspace') |
| Tab | KeyEvent(key: 'Tab') |
| Enter (CR / LF) | KeyEvent(key: 'Enter') |
| Escape | KeyEvent(key: 'Escape') |
| Ctrl + letter | KeyEvent(key: '<letter>', modifiers: KeyModifiers.ctrl) |
| Arrow keys | ArrowUp / ArrowDown / ArrowLeft / ArrowRight |
| Home / End | Home / End |
| Delete / PageUp / PageDown | Delete / PageUp / PageDown |
| Function keys | F1–F12 (both ESC O P/Q/R/S and ESC [N~) |
| Mouse SGR | MouseEvent { type, button, x, y, modifiers, scrollDelta } |
| Bracketed paste | one PasteEvent per block — subscribe via binding.inputManager.onPaste |
| Kitty CSI-u | KeyEvent with full Kitty modifiers when binding.enableKittyKeyboard() |
Signal handling: SIGINT, SIGTERM, and SIGHUP restore terminal modes and exit cleanly (POSIX). SIGWINCH triggers a buffer resize and re-layout.
Basic Framework Usage
import 'package:muse/muse.dart';
class CounterApp extends StatefulWidget {
const CounterApp({super.key});
@override
State<CounterApp> createState() => _CounterAppState();
}
class _CounterAppState extends State<CounterApp> {
int count = 0;
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
child: Text('Count: $count'),
);
}
}
void main() {
runTuiApp(const CounterApp());
}
For inspection-heavy tests and diagnostics, runTuiApp(..., headless: true)
avoids drawing while still exercising the widget and render pipelines.
Native Libraries
Native OpenTUI binaries are packaged as Dart native assets. The build hook
(hook/build.dart) verifies native_manifest.json, bundles the current
platform library for dart run, dart test, and dart build cli, and falls
back to a manifest download or Zig source build when the checked-in binary is
missing.
- Standard development flow uses the bundled native asset automatically
OPENTUI_LIBRARY_PATHis the exact development override for a custom builddart run scripts/fetch_opentui_binaries.dart --verify-onlyverifies thatnative_manifest.jsonmatches the checked-in binariesdart build cli -t bin/health_check.dartproduces a CLI bundle with the executable underbundle/bin/andlibopentuiunderbundle/lib/
Examples:
dart run scripts/fetch_opentui_binaries.dart --verify-only
dart build cli -t bin/health_check.dart
If you need to point at a custom library build:
export OPENTUI_LIBRARY_PATH=/path/to/libopentui.dylib
dart run example/hello.dart
Testing and Goldens
Detailed testing notes live in test/README.md. The short version:
dart analyze
dart test
Regenerate goldens only when the visual change is intentional:
UPDATE_GOLDENS=1 dart test test/golden
UPDATE_GOLDENS=1 dart test test/example/layout_basics_golden_test.dart
Failure artifacts are written to test/failures/ during failed golden runs and are intentionally ignored by git.
Local Go Parity
Primitive parity compares Dart-rendered snapshots against a repo-owned Go snapshot tool that uses the external/opentui git submodule bindings.
Initialize the OpenTUI submodule first if your checkout did not fetch submodules:
git submodule update --init external/opentui
Run the wrapper directly:
./scripts/run_go_snapshot.sh --scene S1 --width 20 --height 5
Run the comparator:
GO_SNAPSHOT_CMD=./scripts/run_go_snapshot.sh \
dart run bin/parity_compare.dart --scenes S1,S2,S3 --width 20 --height 5
Run the parity tests:
GO_SNAPSHOT_CMD=./scripts/run_go_snapshot.sh \
dart test test/parity
Repo References
- tasks/plan.md — canonical roadmap
- example/README.md: example catalog
- test/README.md: testing workflow
- FFIGEN.md: binding regeneration notes
For OpenTUI behavior validation, compare against:
external/opentui/packages/coreexternal/opentui/packages/goexternal/opentui/packages/react
Notes
- Alternate-screen rendering and debug logging are controlled by
TuiBindingandTERMINAL_TUI_DEBUG_LOG=1. - The current roadmap intentionally prioritizes correctness, parity, and cleanup over backward compatibility or deprecation work.
Libraries
- muse
- Muse — high-level widget and application API.
- muse_ffi
- Muse — raw FFI surface.
- muse_low_level
- Muse — advanced/internal framework API.