Tip
☕ Support TUIkit Development
If you enjoy TUIkit and find it useful, consider supporting its development! Your donations help cover ongoing costs like hosting, tooling, and the countless cups of coffee that fuel late-night coding sessions. Every contribution, big or small, is greatly appreciated and keeps this project alive. Thank you! 💙
Important
This project is currently a WORK IN PROGRESS! I strongly advise against using it in a production environment because APIs are subject to change at any time.
See Production Readiness Plan for the roadmap toward a first-class production TUI framework. See API Stability Policy for current pre-1.0 API compatibility and migration rules. See Known Limitations, Terminal Compatibility, and the Release Validation Checklist before evaluating production use.
A SwiftUI-like framework for building Terminal User Interfaces in Swift: no ncurses, no C dependencies, just pure Swift.
TUIkit lets you build TUI apps using the same declarative syntax you already know from SwiftUI. Define your UI with View, compose views with VStack, HStack, and ZStack, style text with modifiers like .bold() and .foregroundColor(.red), and run it all in your terminal.
import TUIkit
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@State var count = 0
var body: some View {
VStack(spacing: 1) {
Text("Hello, TUIkit!")
.bold()
.foregroundStyle(.cyan)
Text("Count: \(count)")
Button("Increment") {
count += 1
}
}
.statusBarItems {
StatusBarItem(shortcut: "q", label: "quit")
}
}
}Viewprotocol: the core building block, mirroring SwiftUI'sView@ViewBuilder: result builder for declarative view composition@State: reactive state management with automatic re-rendering@Environment: dependency injection for theme, focus manager, status barAppprotocol: app lifecycle with signal handling and run loop
- Primitive views:
Text,EmptyView,Spacer,Divider,Image(ASCII art rendering, multiple color modes, async loading) - Layout containers:
VStack,HStack,ZStack,LazyVStack,LazyHStackwith alignment and spacing - Interactive:
Button,ButtonRow,Toggle(default, checkbox, switch styles),Menu,TextField,SecureField,Slider,Stepper,RadioButtonGroupwith keyboard navigation - Data views:
List,Table,Section,ForEach,NavigationSplitView,ContentUnavailableView - Containers:
Alert,Dialog,Panel,Box,Card - Feedback:
ProgressView(5 bar styles),Spinner(animated) StatusBar: context-sensitive keyboard shortcuts with.compactand.borderedstyles
- Text styling: bold, italic, underline, strikethrough, dim, blink, inverted
- Full color support: ANSI colors, 256-color palette, 24-bit RGB, hex values, HSL
- Theming: 6 predefined palettes (Green, Amber, Red, Violet, Blue, White)
- Border styles:
line,rounded,doubleLine,heavy,none - List styles:
PlainListStyle,InsetGroupedListStylewith alternating rows - Badges:
.badge()modifier for counts and labels on list rows
- Toast-style notifications: transient alerts via
.notificationHost()modifier
- 5 languages built-in: English, German, French, Italian, Spanish
- Type-safe string constants: Compile-time verified
LocalizationKeyenum - Persistent language selection: Automatic storage with XDG paths
- Fallback chain: Current language → English → key itself
- Thread-safe operations: Safe language switching at runtime
- Lifecycle modifiers:
.onAppear(),.onDisappear(),.task() - Key handling:
.onKeyPress()with modifier keys (ctrl, alt, shift) and function keys F1–F12 - Storage:
@AppStoragewith JSON file backend (XDG paths) andUserDefaultsbackend - Preferences: bottom-up data flow with
PreferenceKey - Focus system: Tab/Shift+Tab navigation,
.focusSection()for grouped areas - Render caching:
.equatable()for subtree memoization
TUIkit includes a preview workflow for fast visual iteration without launching a full app. Previews are regular Swift executable targets, so they compile with your app code, run in the terminal, and can be watched from an editor or Xcode scheme.
Create a preview executable target that depends on TUIkit, TUIkitPreview, and your app module, then declare previews with TUIkitPreviewApp:
import TUIkit
import TUIkitPreview
@main
struct MyPreviews: TUIkitPreviewApp {
static var previews: [TUIPreview] {
TUIPreview("Dashboard", size: .desktop) {
DashboardView()
}
TUIPreview("Narrow Empty State", size: .narrow) {
DashboardView(items: [])
}
}
}Run a single preview directly, or use the package-level live preview runner:
swift run MyPreviews
swift run MyPreviews -- --list
swift run MyPreviews -- --preview dashboard --size 100x30
swift run tuikit-preview -- --target MyPreviews --preview dashboard --size 100x30
swift run tuikit-preview -- list --target MyPreviews
swift package plugin tuikit-preview --target MyPreviews --preview dashboardAdd .tuikit-preview.yml to persist defaults (target, defaultPreview, theme, and size). Pass --no-watch for a one-shot build/render; by default the runner rebuilds and rerenders when Swift package files change.
Use --snapshot when you want plain rendered output for fixtures, demos, or documentation generation:
swift run MyPreviews -- --preview dashboard --snapshotSee docs/Previews.md for the full setup, target configuration, and recommended preview patterns.
make exampleThis runs swift run TUIkitExample. Press q, ESC, or Ctrl+C to exit. During production-readiness validation, confirm the header shows platform information plus live FPS (for example, macOS 27.0 · arm64 · 60.0 FPS) and that resize, focus/cursor animations, async responsiveness, and terminal cleanup behave correctly. See the Release Validation Checklist.
Install the tuikit command and create a new project:
curl -fsSL https://raw.githubusercontent.com/phranck/TUIkit/main/project-template/install.sh | bash
tuikit init MyApp
cd MyApp && swift runSee project-template/README.md for more options (SQLite, Swift Testing).
Add TUIkit to your Package.swift:
dependencies: [
.package(url: "https://github.com/phranck/TUIkit.git", exact: "0.6.0")
]Then add it to your target:
.target(
name: "YourApp",
dependencies: ["TUIkit"]
)Tip:
import TUIkitre-exports all sub-modules. For finer control you can import individual modules:TUIkitCore,TUIkitStyling,TUIkitView, orTUIkitImage.
TUIkit includes predefined palettes inspired by classic terminals:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.palette(SystemPalette(.green)) // Classic green terminal
}
}Available palettes (all via SystemPalette):
.green: Classic P1 phosphor CRT (default).amber: P3 phosphor monochrome.red: IBM 3279 plasma.violet: Retro sci-fi terminal.blue: VFD/LCD displays.white: DEC VT100/VT220 (P4 phosphor)
TUIkit includes comprehensive i18n support with 5 languages and type-safe string constants:
import TUIkit
struct MyView: View {
var body: some View {
VStack {
// Type-safe localized strings
Text(localized: LocalizationKey.Button.ok)
LocalizedString(LocalizationKey.Error.notFound)
// Switch language at runtime
Button("Deutsch") {
AppState.shared.setLanguage(.german)
}
}
}
}Supported languages: English, Deutsch, Français, Italiano, Español
For complete documentation, see Localization Guide in the DocC documentation.
- Modular package: 5 Swift modules + 1 C target (see Project Structure below)
- No singletons for state: All state flows through the Environment system
- Pure ANSI rendering: No ncurses or other C dependencies
- Linux compatible: Works on macOS and Linux (XDG paths supported)
- Value types: Views are structs, just like SwiftUI
Sources/
├── CSTBImage/ C bindings for stb_image (PNG/JPEG decoding)
├── TUIkitCore/ Primitives, key events, frame buffer, concurrency helpers
├── TUIkitStyling/ Color, theme palettes, border styles
├── TUIkitView/ View protocol, ViewBuilder, State, Environment, Renderable
├── TUIkitImage/ ASCII art converter, image loading (depends on CSTBImage)
├── TUIkit/ Main module: App, Views, Modifiers, Focus, StatusBar, Notification
│ ├── App/ App, Scene, WindowGroup
│ ├── Environment/ Environment keys, service configuration
│ ├── Focus/ Focus system and keyboard navigation
│ ├── Localization/ i18n service, type-safe keys, translation files (5 languages)
│ ├── Modifiers/ Border, Frame, Padding, Overlay, Lifecycle, KeyPress
│ ├── Notification/ Toast-style notification system
│ ├── Rendering/ Terminal, ANSIRenderer, ViewRenderer
│ ├── StatusBar/ Context-sensitive keyboard shortcuts
│ └── Views/ Text, Stacks, Button, TextField, Slider, List, Image, ...
└── TUIkitExample/ Example app (executable target)
Tests/
└── TUIkitTests/ 1172+ tests across 93 test files (including i18n consistency & localization tests)
- Swift 6.0+
- macOS 14+ or Linux
- Tests use Swift Testing (
@Test,#expect): run withswift test - All 1172 tests run in parallel
- The
Terminalclass handles raw mode and cursor control via POSIXtermios - See Known Limitations and Terminal Compatibility when validating real terminal behavior.
- Build a Real App tutorial
- Testing Guide
- Custom Component Guide
- Theming and Style Guide
- Keyboard and Focus Guide
- Performance Guide
- Troubleshooting
- Supported Platforms
- Terminal Input Policy
- Release Process
This repository has been published under the MIT license.