okami.mom/ultraviolet

git clone https://git.nkp.pet/okami.mom/ultraviolet

Ayman Bagabasdocs: update README and tutorial5027f0c

upstream
5.0 KiB161 linesraw

Ultraviolet

<img width="400" alt="Charm Ultraviolet" src="https://github.com/user-attachments/assets/3484e4b0-3741-4e8c-bebf-9ea51f5bb49c" /> <p> <a href="https://pkg.go.dev/github.com/charmbracelet/ultraviolet?tab=doc"><img src="https://godoc.org/github.com/charmbracelet/ultraviolet?status.svg" alt="GoDoc"></a> <a href="https://github.com/charmbracelet/ultraviolet/actions"><img src="https://github.com/charmbracelet/ultraviolet/actions/workflows/build.yml/badge.svg" alt="Build Status"></a> </p>

Ultraviolet is a set of primitives for building terminal user interfaces in Go. It provides cell-based rendering, cross-platform input handling, and a diffing renderer inspired by ncurses—without the need for terminfo or termcap databases.

Ultraviolet powers Bubble Tea v2 and Lip Gloss v2. It replaces the ad-hoc terminal primitives from earlier versions with a cohesive, imperative API that can also be used standalone.

Install

go get github.com/charmbracelet/ultraviolet@latest

Quick Start

package main

import (
	"log"

	uv "github.com/charmbracelet/ultraviolet"
	"github.com/charmbracelet/ultraviolet/screen"
)

func main() {
	t := uv.DefaultTerminal()
	scr := t.Screen()

	scr.EnterAltScreen()

	if err := t.Start(); err != nil {
		log.Fatalf("failed to start terminal: %v", err)
	}
	defer t.Stop()

	ctx := screen.NewContext(scr)
	text := "Hello, World!"
	textWidth := scr.StringWidth(text)

	display := func() {
		screen.Clear(scr)
		bounds := scr.Bounds()
		x := (bounds.Dx() - textWidth) / 2
		y := bounds.Dy() / 2
		ctx.DrawString(text, x, y)
		scr.Render()
		scr.Flush()
	}

	for ev := range t.Events() {
		switch ev := ev.(type) {
		case uv.WindowSizeEvent:
			scr.Resize(ev.Width, ev.Height)
			display()
		case uv.KeyPressEvent:
			if ev.MatchString("q", "ctrl+c") {
				return
			}
		}
	}
}

Architecture

Ultraviolet is organized as a set of layered primitives:

  • Terminal — manages the application lifecycle: raw mode, input event loop, start/stop. Create one with DefaultTerminal() or NewTerminal(console, opts).

  • TerminalScreen — the screen state manager. Handles rendering, alternate screen buffer, cursor, mouse modes, keyboard enhancements, bracketed paste, window title, and more. Access it via terminal.Screen().

  • Screen — a minimal interface (Bounds, CellAt, SetCell, WidthMethod) implemented by TerminalScreen, Buffer, Window, and ScreenBuffer. Write code against Screen to stay decoupled from the terminal.

  • Buffer / Window — off-screen cell buffers. Buffer is a flat grid of cells. Window adds parent/child relationships and shared-buffer views. Both implement Screen and Drawable.

  • screen package — drawing helpers that operate on any Screen: a Context for styled text rendering (Print, DrawString, etc.) and utility functions like Clear, Fill, Clone.

  • layout package — a constraint-based layout solver built on the Cassowary algorithm. Partition screen space with Len, Min, Max, Percent, Ratio, and Fill constraints.

Features

  • Cell-based diffing renderer — only redraws what changed. Optimizes cursor movement, uses ECH/REP/ICH/DCH when available, and supports scroll optimizations. Minimal bandwidth, critical for SSH.

  • Universal input — unified keyboard and mouse event handling across platforms. Supports legacy encodings, Kitty keyboard protocol, SGR mouse, and Windows Console input.

  • Inline and fullscreen — works in both alternate screen (fullscreen) and inline mode. Inline TUIs preserve terminal context and scrollback.

  • Cross-platform — first-class support for Unix (termios + ANSI) and Windows (Console API). Consistent behavior across terminal emulators.

  • Suspend/resume — Stop() and Start() can be called repeatedly for suspend/resume cycles, shelling out to editors, or process suspension via uv.Suspend().

Examples

See the examples/ directory for core examples and examples/advanced/ for more complex demos.

Tutorial

See TUTORIAL.md for a step-by-step guide to building your first Ultraviolet application.

[!NOTE] Ultraviolet is in active development. The API may change.

Feedback

We'd love to hear your thoughts on this project. Feel free to drop us a note!

License

MIT


Part of Charm.

<a href="https://charm.sh/"><img alt="The Charm logo" width="400" src="https://stuff.charm.sh/charm-banner-next.jpg" /></a>

Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة

1# Ultraviolet
2
3<img width="400" alt="Charm Ultraviolet" src="https://github.com/user-attachments/assets/3484e4b0-3741-4e8c-bebf-9ea51f5bb49c" />
4
5<p>
6    <a href="https://pkg.go.dev/github.com/charmbracelet/ultraviolet?tab=doc"><img src="https://godoc.org/github.com/charmbracelet/ultraviolet?status.svg" alt="GoDoc"></a>
7    <a href="https://github.com/charmbracelet/ultraviolet/actions"><img src="https://github.com/charmbracelet/ultraviolet/actions/workflows/build.yml/badge.svg" alt="Build Status"></a>
8</p>
9
10Ultraviolet is a set of primitives for building terminal user interfaces in Go.
11It provides cell-based rendering, cross-platform input handling, and a diffing
12renderer inspired by [ncurses](https://invisible-island.net/ncurses/)—without
13the need for `terminfo` or `termcap` databases.
14
15Ultraviolet powers [Bubble Tea v2][bbt] and [Lip Gloss v2][lg]. It replaces the
16ad-hoc terminal primitives from earlier versions with a cohesive, imperative API
17that can also be used standalone.
18
19[bbt]: https://github.com/charmbracelet/bubbletea
20[lg]: https://github.com/charmbracelet/lipgloss
21
22## Install
23
24```bash
25go get github.com/charmbracelet/ultraviolet@latest
26```
27
28## Quick Start
29
30```go
31package main
32
33import (
34	"log"
35
36	uv "github.com/charmbracelet/ultraviolet"
37	"github.com/charmbracelet/ultraviolet/screen"
38)
39
40func main() {
41	t := uv.DefaultTerminal()
42	scr := t.Screen()
43
44	scr.EnterAltScreen()
45
46	if err := t.Start(); err != nil {
47		log.Fatalf("failed to start terminal: %v", err)
48	}
49	defer t.Stop()
50
51	ctx := screen.NewContext(scr)
52	text := "Hello, World!"
53	textWidth := scr.StringWidth(text)
54
55	display := func() {
56		screen.Clear(scr)
57		bounds := scr.Bounds()
58		x := (bounds.Dx() - textWidth) / 2
59		y := bounds.Dy() / 2
60		ctx.DrawString(text, x, y)
61		scr.Render()
62		scr.Flush()
63	}
64
65	for ev := range t.Events() {
66		switch ev := ev.(type) {
67		case uv.WindowSizeEvent:
68			scr.Resize(ev.Width, ev.Height)
69			display()
70		case uv.KeyPressEvent:
71			if ev.MatchString("q", "ctrl+c") {
72				return
73			}
74		}
75	}
76}
77```
78
79## Architecture
80
81Ultraviolet is organized as a set of layered primitives:
82
83- **Terminal** — manages the application lifecycle: raw mode, input event loop,
84  start/stop. Create one with `DefaultTerminal()` or `NewTerminal(console, opts)`.
85
86- **TerminalScreen** — the screen state manager. Handles rendering, alternate
87  screen buffer, cursor, mouse modes, keyboard enhancements, bracketed paste,
88  window title, and more. Access it via `terminal.Screen()`.
89
90- **Screen** — a minimal interface (`Bounds`, `CellAt`, `SetCell`,
91  `WidthMethod`) implemented by `TerminalScreen`, `Buffer`, `Window`, and
92  `ScreenBuffer`. Write code against `Screen` to stay decoupled from the
93  terminal.
94
95- **Buffer / Window** — off-screen cell buffers. `Buffer` is a flat grid of
96  cells. `Window` adds parent/child relationships and shared-buffer views.
97  Both implement `Screen` and `Drawable`.
98
99- **screen package** — drawing helpers that operate on any `Screen`: a
100  `Context` for styled text rendering (`Print`, `DrawString`, etc.) and
101  utility functions like `Clear`, `Fill`, `Clone`.
102
103- **layout package** — a constraint-based layout solver built on the
104  [Cassowary algorithm][casso]. Partition screen space with `Len`, `Min`,
105  `Max`, `Percent`, `Ratio`, and `Fill` constraints.
106
107[casso]: https://en.wikipedia.org/wiki/Cassowary_(software)
108
109## Features
110
111- **Cell-based diffing renderer** — only redraws what changed. Optimizes
112  cursor movement, uses ECH/REP/ICH/DCH when available, and supports scroll
113  optimizations. Minimal bandwidth, critical for SSH.
114
115- **Universal input** — unified keyboard and mouse event handling across
116  platforms. Supports legacy encodings, Kitty keyboard protocol, SGR mouse,
117  and Windows Console input.
118
119- **Inline and fullscreen** — works in both alternate screen (fullscreen) and
120  inline mode. Inline TUIs preserve terminal context and scrollback.
121
122- **Cross-platform** — first-class support for Unix (termios + ANSI) and
123  Windows (Console API). Consistent behavior across terminal emulators.
124
125- **Suspend/resume** — `Stop()` and `Start()` can be called repeatedly for
126  suspend/resume cycles, shelling out to editors, or process suspension
127  via `uv.Suspend()`.
128
129## Examples
130
131See the [`examples/`](./examples/) directory for core examples and
132[`examples/advanced/`](./examples/advanced/) for more complex demos.
133
134## Tutorial
135
136See [TUTORIAL.md](./TUTORIAL.md) for a step-by-step guide to building your
137first Ultraviolet application.
138
139> [!NOTE]
140> Ultraviolet is in active development. The API may change.
141
142## Feedback
143
144We'd love to hear your thoughts on this project. Feel free to drop us a note!
145
146- [Twitter](https://twitter.com/charmcli)
147- [Discord](https://charm.land/discord)
148- [Slack](https://charm.land/slack)
149- [The Fediverse](https://mastodon.social/@charmcli)
150
151## License
152
153[MIT](./LICENSE)
154
155---
156
157Part of [Charm](https://charm.land).
158
159<a href="https://charm.sh/"><img alt="The Charm logo" width="400" src="https://stuff.charm.sh/charm-banner-next.jpg" /></a>
160
161Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة