Zeichenwerk (German for "character works") is a modern, idiomatic Go library for building terminal user interfaces. It features a fluent builder API, a functional composition API, and an enhanced widget system.
package main
import . "github.com/tekugo/zeichenwerk"
func main() {
NewBuilder(TokyoNightTheme()).
Flex("main", false, "stretch", 0).
Flex("header", true, "center", 1).
Static("title", "My App").
End().
Grid("content", 2, 2, false).Rows(-1).Columns(20, -1).Hint(0, -1).
Cell(0, 0, 1, 1).List("menu", "Item 1", "Item 2", "Item 3").
Cell(1, 0, 1, 1).Button("action", "Click Me").
End().
End().
Run()
}Press q or Ctrl-Q to quit.
The compose sub-package offers a functional alternative to the builder. Each
widget is an Option — a plain function — that you nest directly:
package main
import (
z "github.com/tekugo/zeichenwerk"
. "github.com/tekugo/zeichenwerk/compose"
)
func main() {
UI(z.TokyoNightTheme(),
Flex("main", "", false, "stretch", 0,
Flex("header", "", true, "center", 1,
Static("title", "", "My App"),
),
Grid("content", "", []int{-1}, []int{20, -1}, false, Hint(0, -1),
Cell(0, 0, 1, 1, List("menu", "", []string{"Item 1", "Item 2", "Item 3"})),
Cell(1, 0, 1, 1, Button("action", "", "Click Me")),
),
),
).Run()
}Screens can be split into separate functions and composed with Include:
UI(z.TokyoNightTheme(),
Flex("root", "", false, "stretch", 0,
Include(header),
Include(content),
Include(footer),
),
).Run()
func header(theme *z.Theme) z.Widget {
return Build(theme, Static("title", "", "My App", Font("bold"), Fg("$cyan")))
}Where direct widget access is needed after construction — for example to wire
events, populate a tree, or start animations — retrieve the widget imperatively
with z.Find and call methods on it directly.
Zeichenwerk is designed for developers who want:
- A fluent, chainable builder API or a functional composition API
- Higher-level widgets than tcell
- More composable layouts than tview
- A traditional retained widget hierarchy rather than an event/message architecture
Compare to other Go TUI libraries:
| Library | Style |
|---|---|
| tcell | Low-level terminal primitives |
| tview | Traditional widget toolkit |
| bubbletea | Elm-style update loop |
| zeichenwerk | Builder + functional composition |
go get github.com/tekugo/zeichenwerk| Category | Widgets |
|---|---|
| Containers | Box, Flex, Grid, Form, Switcher, Tabs, Viewport |
| Interaction | Button, Checkbox, Combo, Input, Select, Typeahead |
| Navigation | Breadcrumb, Collapsible, List, Tree |
| Display | Bar Chart, Deck, Digits, Heatmap, Sparkline, Table, Text |
| Text | Editor, Rule, Static, Styled, Typewriter |
| Animation | CRT, Scanner, Spinner |
| Overlay | Commands palette, Dialog, and container-based popups |
| Other | Canvas, Terminal (ANSI/VT emulator) |
button.On("click", func(w Widget, event string, data ...any) bool {
// Handle click
return true
})theme := NewTheme()
theme.Set("button.primary", NewStyle("blue", "white", ""))
theme.Set("button#submit", NewStyle("green", "black", "bold"))Built-in themes:
TokyoNightTheme()— dark, blue/purple accentsGruvboxDarkTheme()/GruvboxLightTheme()— retro warm paletteNordTheme()— arctic blue-greyMidnightNeonTheme()— near-black with electric cyan/magentaLipstickTheme()— Charm-inspired fuchsia and indigo
- Tab/Shift+Tab: Move focus between widgets
- Arrow keys: Navigate within widgets (lists, tables)
- Enter/Space: Activate buttons, toggle checkboxes
- Click to focus widgets
- Hover states with visual feedback
UI (root)
├── Component (embedded)
│ ├── Bounds (x, y, width, height)
│ ├── Styles (CSS-like selectors)
│ ├── Events (handlers, bubbling)
│ └── Parent/Child hierarchy
├── Layers (popups/modals)
├── Event Loop (tcell integration)
├── Renderer (dirty-flag optimizations)
└── Focus Manager
Explore all widgets interactively with the builder-API demo:
go run ./cmd/demoOr the composition-API showcase:
go run ./cmd/compose- Tutorial (start here): doc/tutorial.md
- Package docs: doc.go
- Widget reference: doc/reference/overview.md
- Builder pattern: builder.go
- Composition API: compose/compose.go
- Theme system: theme.go
- Component base: component.go
Zeichenwerk ships with first-class support for AI agents and automated tooling that need to observe or interact with a running UI without a live terminal.
Dump(w io.Writer, root Widget) streams the full widget tree to any writer as
an indented, human- and LLM-readable text. One line per widget — type, ID,
class, content summary, screen bounds, and state flags ([FOCUSED], [HIDDEN],
[DISABLED]). Hidden containers are always included so every part of the UI is
readable regardless of what is currently visible on screen.
// Snapshot the entire UI (all layers) to stdout
ui.Dump(os.Stdout)
// Dump a subtree
zeichenwerk.Dump(os.Stdout, someContainer)
// Include per-widget style details (border, padding, margin, fg/bg)
ui.Dump(os.Stdout, zeichenwerk.DumpOptions{Style: true})Both demo binaries support -dump and -dump-verbose flags that lay out
the UI at a fixed 120×40 size, print the hierarchy, and exit — no terminal
required:
go run ./cmd/demo -dump
go run ./cmd/demo -dump-verbose
go run ./cmd/compose -dumpBuilt-in widgets produce concise inline summaries (button labels, input values,
checkbox state, active tab, etc.). Custom widgets can opt in by implementing the
Summarizer interface:
type Summarizer interface {
Summary() string
}AGENTS.md at the repository root is a machine-readable project guide kept up
to date for AI coding assistants. It covers architecture rules, the full widget
reference, selector format, event constants, and the builder checklist.
A Claude Code skill is bundled at .claude/skills/zeichenwerk/. When you open
this repository in Claude Code, the skill is loaded automatically — Claude gains
knowledge of all widget constructors, style keys, event constants, the selector
format, and both APIs without requiring additional context in the prompt. A
detailed widget reference is included in
.claude/skills/zeichenwerk/widgets.md.
Active development — Core API and widget set are stable. Test coverage is growing (bar chart, breadcrumb, button, checkbox, input, list, progress, select, switcher, table, tabs, text, viewport, and more are unit-tested). Some layout edge cases and advanced widgets are still being refined.
This project was developed with the support of AI coding assistants — specifically Claude (Anthropic), StepFun-3.5-Flash, and Qwen-3.5 — for coding support, documentation drafting, and test creation.
That said, all code was reviewed, tested, fine-tuned, and adjusted by me, and all significant design decisions were made by me. AI assistants are well-trained on GUI and web development patterns, but terminal UI is a niche where their experience is limited. The retained widget hierarchy, layout engine, scroll regions, ANSI terminal emulation, and theme system required substantial manual coding, debugging, and iteration that went well beyond what any assistant produced out of the box.
At the same time, without the heavy lifting in coding, specification work, and documentation that AI agents made possible, a spare-time project of this scope simply would not be feasible for a single developer.
MIT © Thomas Rustemeyer