ultraviolet v1.0.1
Ultraviolet
Crystal port of Charm's Ultraviolet terminal UI library. The upstream Go implementation is vendored at vendor/ultraviolet/ for behavioral reference.
Vendored Go source: 6b8d4ba. The Crystal port currently tracks behavior through 7cc6674; the remaining delta is tracked in the vendor-update plan. See parity plan.
Installation
Add to shard.yml:
dependencies:
ultraviolet:
github: dsisnero/ultraviolet
Then:
shards install
Quick Start
require "ultraviolet"
env = ENV.map { |key, value| "#{key}=#{value}" }
term = Ultraviolet::Terminal.new(STDIN, STDOUT, env)
term.start
term.enter_alt_screen
"Hello, World!".each_char_with_index do |char, idx|
term.set_cell(idx, 0, Ultraviolet::Cell.new(char.to_s, 1))
end
term.display
See examples/helloworld.cr for a complete interactive application.
Features
Terminal Screen & Input
- Full-window and inline rendering modes (
TerminalScreen) - Raw terminal mode with signal handling (
Terminal) - Event-driven input: keyboard, mouse, paste, focus/blur, resize (
EventDecoder) - Kitty keyboard protocol, modifyOtherKeys, Win32 input, bracketed paste
- Legacy key encoding support via
LegacyKeyEncoding
High-Performance Renderer
The TerminalRenderer minimizes terminal output using cell-based diffing and ANSI optimizations:
- REP (repeat character), ECH (erase character), ICH/DCH (insert/delete character)
- SD/SU (scroll down/up), IL/DL (insert/delete line)
- CHA/HPA/VPA (cursor positioning), CHT/CBT (tab movement)
- Color profile downsampling (TrueColor → 256 → 16 → ASCII)
- Backspace/tab optimization for cursor movement
- Per-terminal capability detection
Cell-Based Buffer System
The Buffer / RenderBuffer / ScreenBuffer hierarchy provides:
- Cell-level read/write with wide character support (emoji, CJK)
- Touch tracking for efficient dirty-region rendering
- Clone, fill, clear area operations
- Insert/delete line/cell with bounds checking
ANSI Styled Strings
StyledString renders ANSI-escaped text with:
- SGR attribute parsing (bold, faint, italic, blink, reverse, conceal, strikethrough)
- TrueColor / 256 / 16 color foreground, background, underline
- Hyperlink (OSC 8) parsing
- Text wrapping, truncation with tail, placement functions
Screen Window System
Window provides nested, resizable viewports:
- Parent-child hierarchy with relative positioning
- MoveTo, MoveBy, Resize, Clone, CloneArea
- Custom width methods for CJK/emoji/grapheme support
Layout System
Layout functions for constraint-based positioning:
Percent,Fixed,RatioconstraintsSplitVertical,SplitHorizontal- 9 rect placement helpers: Center, TopLeft, TopRight, BottomLeft, etc.
Cross-Platform Console I/O
Console provides a unified interface across platforms:
- Unix: TTY detection, raw/restore terminal state,
Winsizequeries - Windows:
WinConconsole handle wrapper - Environment variable access via
Environ
Poll-Based Event Reading
Platform-optimized poll readers in poll.cr:
- BSD/macOS:
kqueueReadervia Kqueue - Linux:
epollReadervia Epoll - Windows:
conReadervia Windows Console API - Fallback:
fallbackReaderfor non-TTY file descriptors
Border Drawing
Border provides configurable box-drawing:
- Built-in styles: Normal, Rounded, Double, Thick, Hidden, Block, Markdown, ASCII
- Style/Link application without mutating base border
Drawrenders border into anyScreenregion
Module Overview
| Module | Go Source | Crystal Source |
|---|---|---|
| Terminal | terminal.go | terminal.cr |
| TerminalScreen | terminal_screen.go | terminal_screen.cr |
| TerminalRenderer | terminal_renderer.go | terminal_renderer.cr |
| TerminalReader | terminal_reader.go | terminal_reader.cr |
| EventScanner | terminal_reader.go (eventScanner) | event_scanner.cr |
| EventDecoder | decoder.go | decoder.cr |
| Buffer | buffer.go | buffer.cr |
| Cell/Style | cell.go | cell.cr, style.cr |
| StyledString | styled.go | styled.cr |
| Console | console.go | console.cr |
| Border | border.go | border.cr |
| Window | window.go | window.cr |
| Layout | layout/layout.go | layout.cr |
| Poll | poll*.go | poll*.cr |
| Winch | winch.go | winch.cr |
| TabStops | tabstop.go | tabstop.cr |
| Options | terminal.go (Options) | options.cr |
| Key types | key.go, key_table.go | key.cr, key_table.cr |
| Mouse | mouse.go | mouse.cr |
| Event types | event.go | event.cr |
| TTY | tty*.go | tty.cr, tty_state.cr |
Documentation
- Resuming work — start here in a new session
- Architecture — repository layout and runtime layers
- Development — setup, porting workflow, and parity checks
- Coding Guidelines — behavior, style, and dependency rules
- Testing — spec layout and how to port Go tests
- PR Workflow — branch, gates, and review checklist
- Parity Plan — feature status, resume point, and remaining work
- Vendor Update 6b8d4ba — porting checklist for the latest upstream delta
- Conformance Assessment — decision on the optional Go conformance harness
- Tutorial — building a terminal application with Ultraviolet
- API Reference — Go-to-Crystal type mapping
- Porting Map — source-to-source checklist
- Examples — runnable Crystal examples
- Parity Manifests — Go-vs-Crystal tracking
- Port Audit — per-symbol audit notes
- Unchecked Items — remaining missing ports
Development
Setup
make install
Quality Gates
make format-check
make lint
make test
See docs/development.md for the porting workflow, parity scripts, and how to update the vendored Go source.
Contributing
- Fork it (https://github.com/dsisnero/ultraviolet/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Port from Go source of truth, matching behavior exactly
- Write Crystal specs matching Go test expectations
- Run quality gates:
make format-check && make lint && make test - Run the parity checks described in docs/development.md
- Commit and push
- Create a Pull Request using docs/pr-workflow.md
License
MIT — see LICENSE.
Contributors
- Dom — creator and maintainer
ultraviolet
- 0
- 1
- 2
- 3
- 6
- 12 days ago
- February 3, 2026
MIT License
Tue, 20 Oct 2026 04:52:52 GMT