Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

271 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸͺ Kite

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.

✨ Features

  • 🌳 Logical DOM Tree: Core entities like Document, Element, and TextNode with 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 (via extras/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).

πŸ— Architecture Overview

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 an Optional[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.

πŸš€ Getting Started

Prerequisites

  • Go 1.26.1 or higher.

Installation

go get github.com/masterkeysrd/kite

Usage Example

Kite 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
}

πŸ§ͺ Headless Testing

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")
}

πŸ›  Developer Tools

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",
})

Web-Based DOM Inspector

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.

Terminal X-Ray Mode

Toggle colored bounding boxes directly on your running application for immediate layout debugging.

  • Red: Margin Box
  • Green: Padding Box
  • Blue: Content Box

Performance Profiler

Analyze execution durations for the rendering pipeline phases and asynchronous background jobs with interactive flamecharts and Chrome Trace export.

🎭 Stage – Component Playground

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.

Layout

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  πŸ“– 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!              β”‚
└───────────────────────────────────────────────────────────────────-β”˜

Controls

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.

Usage

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/stage

See the full working example in examples/stage/.

Hotkeys

Key Action
↑ / ↓ Navigate between scenes
Tab Move focus to the controls panel inputs
Ctrl+C Quit
F12 Toggle web-inspector devtools

⚑ Performance & Benchmarks

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).

Results (Tested on Apple M1 Max)

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 ./engine

πŸ“– Documentation & Guides

For more detailed information, please refer to the following guides in the docs/ directory:

🀝 Contributing

Contributions are welcome! Please check our Developing Guide to get started.

About

TUI Engine based on the DOM Architecture

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages