Kite is a modern, DOM-like terminal UI framework for Go. It brings web-inspired development paradigmsβsuch as a logical DOM tree, CSS-style flexbox layout, standard event propagation, and scrollingβto the terminal environment.
- π³ Logical DOM Tree: Core entities like
Document,Element, andTextNodewith strict lifecycle hooks. - π¨ Style Engine: CSS-like styling using an
Optional[T]pattern for sparse definitions. - π Layout Engine: High-performance, LayoutNG-inspired engine responsible for computing geometry.
- ποΈ 60FPS Pipeline: Orchestrated 6-phase pipeline (Sync -> Style -> Layout -> Paint -> Commit).
- π±οΈ Advanced Events: Support for capture, target, and bubble phases, plus synthetic event management.
- π§ Spatial & Caret Navigation: Unified cell-by-cell caret navigation within cursor-navigable elements combined with spatial boundary-crossing focus jumps.
- π§ͺ Headless Testing: Simulate user input and assert on DOM state or visual regression (golden files).
- β¨ Animations: Imperative property interpolation and tweening system for smooth transitions.
- π οΈ Developer Tools: Web-based DOM inspector, in-terminal X-Ray mode, and performance profiler.
- βοΈ Reactive Primitives: Lightweight Virtual DOM (VDOM) for declarative, type-safe API (via
extras/kitex). - π¦ Global State Management: Lightweight, thread-safe external state store with selector-based re-rendering (via
extras/kites). βοΈ Stack Navigation: Type-safe stack-based navigation (push/pop) with automated focus isolation (viaextras/flight).- π Async Fetching & Cache: Ergonomic data fetching and caching with background refetches and mutations (via
extras/wind). - π Idiomatic Promises: Chainable async primitive with main-thread safety guarantees (via
promise). - π Component Playground: Interactive component development sandbox with live knobs and action logs (via
extras/stage).
Kite is built with a clean separation of concerns, divided into specialized packages that form the rendering pipeline:
dom: The logical node tree representing the user interface. It implements strict lifecycle hooks, identity registration, semantic state, and a top-layer overlay API for out-of-flow elements.style: CSS-like styling engine using anOptional[T]pattern. It supports a four-layer cascade (inherited values, element-type defaults, author styles, and UA intrinsic styles) and a high-performance Media Queries matching system for responsive design.layout: The high-performance engine responsible for computing geometry, returning immutable fragment trees.paint&backend: The drawing layer and terminal decoupling, allowing for varied output backends.render: The visual bridge mirroring the DOM to the layout engine, carrying lifecycle dirty-flags.engine: The central nervous system orchestrating the pipeline at 60FPS while managing the task scheduler.event: Advanced event dispatcher supporting capture, target, and bubble phases.animation: Imperative property interpolation and tweening system for smooth transitions.
- Go 1.26.1 or higher.
go get github.com/masterkeysrd/kiteKite provides a declarative, type-safe API for constructing UI trees.
package main
import (
"github.com/masterkeysrd/kite/element"
"github.com/masterkeysrd/kite/style"
"github.com/masterkeysrd/kite/event"
)
func main() {
// Build a UI tree declaratively
ui := element.Box(
element.Box(
"Welcome to Kite!",
).Style(style.Style{
Padding: style.Some(style.Edges(1, 0)),
Bold: style.Some(true),
}),
element.UL(
element.LI("High Performance"),
element.LI("Flexbox & Grid Layouts"),
),
element.Button("Click Me").OnEvent(event.EventClick, func(e event.Event) {
// Handle click
}),
)
// In a real application, you would mount this to the engine:
// eng.Mount(ui)
_ = ui
}Kite provides a headless testing environment via the testenv package. This allows you to simulate user input and assert on the DOM state without a physical terminal.
func TestMyApp(t *testing.T) {
env := testenv.Default(80, 24)
defer env.Close()
env.Mount(element.Input("").WithID("my-input"))
env.Flush()
env.Type("hello")
env.Flush()
input := env.GetNodeByID("my-input").(*element.InputElement)
if input.Value() != "hello" {
t.Errorf("expected 'hello', got %q", input.Value())
}
// Visual Regression Testing (Golden Files)
env.MatchGolden(t, "input-state")
}Kite includes a unified developer tools package that provides a web-based DOM inspector, an in-terminal X-Ray mode, and a performance profiler.
import "github.com/masterkeysrd/kite/devtools"
// ... after creating your engine
insp, _ := devtools.Install(eng, devtools.Options{
InspectorAddr: "127.0.0.1:8080",
})Open the inspector window in your browser to debug your application's logical tree, computed styles, and layout box model in real-time. It features a live DOM tree, style layer inspection, and a visual box model representation.
Toggle colored bounding boxes directly on your running application for immediate layout debugging.
- Red: Margin Box
- Green: Padding Box
- Blue: Content Box
Analyze execution durations for the rendering pipeline phases and asynchronous background jobs with interactive flamecharts and Chrome Trace export.
extras/stage is an interactive component development sandbox inspired by Storybook. It lets you build, tweak, and preview Kitex components in complete isolation β without running your main application.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π SCENES β β
β βββββββββββββββββ β Component Canvas (70%) β
β Button / Default β β
β Button / Primary β βββββββββββββββββββββββ β
β Text Input / Basic β β rendered scene β β
β Status Badges / β¦ β βββββββββββββββββββββββ β
βββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββ€
β π οΈ CONTROLS β π ACTION LOG β
β Label Submit Form β 12:01:05 Button clicked! β
β Disabled [ ] β 12:01:07 Button clicked! β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ-β
Register interactive knobs in your scene's Render function via the *stage.Context:
| Method | Control type | Description |
|---|---|---|
c.Text(name, default) |
Text input | Free-form string value |
c.Bool(name, default) |
Toggle button | true / false |
c.Select(name, options, default) |
Cycle button | Cycles through a fixed list of options |
Use c.Log(msg) to append entries to the Action Log panel at the bottom right.
package main
import (
"github.com/masterkeysrd/kite/event"
"github.com/masterkeysrd/kite/extras/kitex"
"github.com/masterkeysrd/kite/extras/stage"
)
func main() {
stg := stage.New()
stg.Register("Button", []stage.Scene{
{
Name: "Default",
Render: func(c *stage.Context) kitex.Node {
label := c.Text("Label", "Click Me")
disabled := c.Bool("Disabled", false)
return kitex.Button(kitex.ButtonProps{
Disabled: disabled,
OnClick: func(e event.Event) {
c.Log("Button clicked!")
},
}, kitex.Text(label))
},
},
})
stg.Run()
}Run it:
go run ./examples/stageSee the full working example in examples/stage/.
| Key | Action |
|---|---|
β / β |
Navigate between scenes |
Tab |
Move focus to the controls panel inputs |
Ctrl+C |
Quit |
F12 |
Toggle web-inspector devtools |
Kite is engineered for speed, leveraging a batch-coalesced rendering pipeline and incremental DOM updates to maintain smooth, lag-free terminal interactions even under massive layouts.
We run a realistic benchmark (BenchmarkEngine_RealisticApp_1000Nodes) that mounts a complex UI structure containing a header, sidebar, and a scrollable content area with over 1,200 nested nodes (styled with borders, colors, padding, and Flexbox layouts). On every iteration, we mutate a dynamic text node to trigger dirtiness and force the engine through a complete frame execution (Sync β Style Cascade β Layout Reflow β FrameBuffer Paint).
| Benchmark | Latency / Frame | Frame Rate (FPS) | Memory / Frame | Allocations / Frame |
|---|---|---|---|---|
| Realistic App (1,200+ Nodes) | ~0.84 ms |
~1,190 FPS | 0.97 MB |
7,123 |
To run the benchmark yourself:
go test -bench=BenchmarkEngine_RealisticApp -benchmem ./engineFor more detailed information, please refer to the following guides in the docs/ directory:
Contributions are welcome! Please check our Developing Guide to get started.