Production-grade declarative TUI framework for Rust — ink philosophy, Rust strengths.
Fork of iocraft ·
Internal crate: iocraft
CometixTUI is a maintained fork of iocraft that brings Claude Code's ink fork design patterns into Rust: React-like hooks, declarative composition, fullscreen selection/scroll/search, retained rendering, and terminal-native capabilities — while preserving Rust's type safety and zero-cost abstractions.
The internal crate name remains iocraft for upstream compatibility.
CometixTUI adds 59,600+ lines across 104 source files and 114 examples, organized into the following capability areas.
Declarative focus management ported from ink's useFocus / useFocusManager:
use_focus/use_focus_managerhooks — auto-registration with RAII cleanup,is_focused/focus()/blur()APIFocusScopecomponent — focus boundary withtrap_keysfor nested groups (Tab/Shift+Tab cycling)- UI-order tracking — focus order follows the render tree, not registration order
- CC Ink focus parity — focus-stack restoration,
view_tab_indextraversal,focus_restoresemantics
Full event propagation with bubble semantics, matching ink's event model:
SharedEventState+stop_propagation()— depth-first poll order = bubble order; any component can consume events- Ctrl+C dispatched to components — framework delivers Ctrl+C as a normal
KeyEventbefore default exit;stop_propagation()suppresses quit (enables confirmation dialogs, save-before-exit) - Bracketed paste —
TerminalEvent::Paste(String)for multi-character paste as a single atomic event use_keybindinghook — declarative keyboard bindings with modifier-aware parser ("ctrl+shift+s")use_input/use_input_event— CC Ink-style input callbacks with propagation-aware variants- View-level event handlers — mouse, focus, key, paste capture/bubble handlers with CC Ink
event_type/bubbles/cancelable/defaultPreventedmetadata
Terminal rendering engine extended with CC Ink's retained screen-buffer architecture:
- Post-render
StyleOverlay— cursor inversion, search highlighting, selection rendering applied after the component tree draws, so components don't need awareness of overlays - CSI K attribute bleed fix — full SGR reset before erase-to-EOL; single row-end exit path (fixes kitty rendering)
- Grapheme-cluster width measurement — per-cluster calculation matching npm
string-width(accurate for CJK, ZWJ emoji, VS16) CellWidthtracking —Normal/Wide/WidthTailenum for correct CJK/emoji alignment- ANSI helpers module (
ansi.rs) — semantic functions replacing raw escape writes; tmux truecolor auto-clamp (RGB→ANSI-256); OSC 8 hyperlink detection with CC Ink terminal allowlist - Retained screen primitives — per-cell canvas diffing, damage regions, clear/blit helpers, soft-wrap metadata, noSelect metadata, packed canvas snapshot/output-queue
- Bidi-aware styled-run writes — right-to-left text support in canvas rendering
- Frame throttling — configurable max FPS with event coalescing (default 60fps)
Robust terminal lifecycle management ported from CC Ink's terminal layer:
- Suspend/resume (SIGCONT) — self-healing redraw after Ctrl+Z; raw mode + keyboard enhancement auto-restore
- Panic recovery — panic hook restores terminal state (raw mode, alternate screen) before printing the panic message
- Kitty keyboard protocol —
SystemContext::set_keyboard_enhancement_flagsfor disambiguating escape codes - Terminal title —
use_terminal_titlehook; writes only when the title changes (OSC 0,SetConsoleTitleWfallback on legacy Windows conhost) - Dual cursor mode —
CursorDeclaration { visible }: ink model (overlay cursor, physical hidden for IME only) or ratatui model (native terminal cursor) - Inline diff safety — bounded diff planning scans, terminal height-aware main-screen layout
- Fullscreen patch planners — DECSTBM scroll-hint patch planning/serialization, cursor anchor/park patch planning, stateful retained-canvas frame planners
- Raw input backend — opt-in raw-stdin frontend bridge, async-reader bridge, terminal-side mode sequence helpers, scoped session event stream with tmux-compatible
modifyOtherKeys - Terminal input tokenizer — raw terminal byte normalization, tokenization, key/response/paste/mouse parsing, incomplete-sequence flush timing
New components ported from or inspired by CC Ink:
| Component | Description |
|---|---|
TextInput |
Extended with cursor_color, cursor_background_color, physical_cursor props for cross-theme visibility |
Checkbox |
Toggle component with customizable indicators |
StaticOutput |
ink's <Static> — render-once content that exits the render loop |
ErrorBoundary |
catch_unwind wrapper with silent panic hook for graceful error UI |
ErrorOverview |
Structured error display component |
ScrollBox |
CC Ink-style fullscreen scroll containers with virtual scroll, fast-path retained scroll blits |
ScrollView |
Enhanced with scroll-drain helpers, viewport child culling/cache planning, sticky follow-scroll |
AlternateScreen |
Dynamic alternate-screen mounting |
Button |
CC Ink-style tabIndex defaults, actions/state |
Link |
OSC 8 hyperlink component with supports_hyperlinks() detection |
Ansi / RawAnsi |
Pre-wrapped ANSI screen-buffer rendering with opt-in line parse caching |
Spacer / Newline |
Layout primitives |
NoSelect |
Gutter metadata for selection-aware rendering |
CachedSubtree |
Explicit clean-subtree retained canvas blits |
OffscreenFreeze |
Terminal viewport visibility tracking with opt-in subtree freeze |
Memo |
Transparent memoization wrapper for retained layout nodes |
Fragment |
Enhanced with topmost hit-testing |
NotificationProvider |
CC-style toast notification viewport |
KeybindingProvider |
Action-based keybinding contexts with chord support |
New hooks matching CC Ink's hook API:
| Hook | Description |
|---|---|
use_focus / use_focus_manager |
Declarative focus with RAII lifecycle |
use_keybinding |
Modifier-aware key binding declarations |
use_input / use_input_event |
CC Ink-style input callbacks |
use_selection |
Fullscreen text selection with copy-on-select, drag autoscroll |
use_screen_overlays |
Selection/search/current overlay ordering |
use_search_highlight |
Rendered-screen search with current-match overlays |
use_terminal_events |
Extended with propagation-aware variant |
use_terminal_size |
Terminal size context syncing |
use_terminal_focus |
Terminal focus reporting |
use_terminal_title |
Declarative terminal title |
use_terminal_notification |
Side-band terminal notifications/progress |
use_terminal_viewport |
Viewport visibility tracking for offscreen subtree freezing |
use_stdin |
Stdin/raw-mode status |
use_app |
App lifecycle exit handles |
use_interval / use_animation_frame |
Timer hooks for animation |
use_declared_cursor |
Custom cursor declarations for IME/accessibility |
use_keybinding_registry |
Action-based keybinding contexts with chord sequences |
CC Ink's fullscreen capabilities ported to Rust:
- Terminal text selection — mouse drag selection with word/line granularity
- Copy-on-select — selection clipboard integration with toast notifications
- Selection drag autoscroll — automatic scrolling when dragging past viewport edges
- Search/highlight overlays — rendered-screen search with current-match tracking and overlay painting
- Selection/search overlay ordering — CC Ink-style multi-layer overlay composition
- DECSTBM scroll hints — fullscreen terminal scroll optimization
- Retained rendering — node-cache metadata, generation-stamped IDs, logical-key tree reconciliation, dirty-tree invalidation, blit/clear planning, sibling contamination planning, escaping absolute-descendant repair
- Taffy 0.12.1 (upstream: 0.5.2) — flexbox + grid + layout-cache soundness fix
- CSS Grid DSL —
grid_template_areas,grid_template_columns/rowswith CSS string parsing - CC Ink style shorthands — additional layout style properties matching ink's API surface
- Border text labels — dashed/per-edge border styling, opaque overlays, absolute overlay clamping
- Context fallback bug —
ContextStacknow uses TypeId indexing; borrowed inner context returnsNoneinstead of falling through to outer context of the same type - CSI K rendering order — character written before erase-to-EOL so the last cell retains its style
- Full-width ANSI row fix — prevents erasing last cell in full-width rows
- Opt-in retained optimization mode — retained render with opt-in canvas diff planning
- Canvas diff planning — bounded diff iteration, terminal diff patch optimization
- Frame profiling — opt-in render diff scan timings, mock-terminal benchmark collection, renderer workload profiling, debug repaint visualization
- Duplicate repaint skip — preflight scan deduplication
use iocraft::prelude::*;
fn main() {
element! {
View(
border_style: BorderStyle::Round,
border_color: Color::Blue,
) {
Text(content: "Hello from CometixTUI!")
}
}
.print();
}114 examples are available in the examples/ directory, covering focus management, event propagation, forms, fullscreen apps, selection, search, scroll containers, retained rendering, terminal capabilities, and more.
Two diagnostic variables, each a comma-separated list of tokens, read once per process. Neither is needed for normal use; unknown tokens are ignored.
| Variable | Token | Effect |
|---|---|---|
IOCRAFT_DISABLE |
push-wake |
Poll every component every frame instead of only the woken paths |
retained-blit |
Re-draw memo-retained subtrees instead of blitting them from the previous canvas | |
damage-skip |
Diff every row instead of only the rows a canvas write marked | |
measure-memo |
Run every measure function Taffy asks for instead of answering repeat probes from the node's memo | |
IOCRAFT_DEBUG |
settle |
Print each component whose render-phase state write re-ran the update |
cells |
Count changed cells per frame for the render profile | |
layout |
Print per-frame layout statistics to stderr: measure functions run, probes answered, dirty nodes before layout, cache invalidations by entry point | |
wake |
Print, for every component the poll pass finds changed, which hook slots reported Ready: the writers behind each frame | |
frame-log=PATH |
Append one line per frame describing the canvas and the repaint to PATH | |
layout-dump=PATH |
Append every frame's layout tree to PATH |
IOCRAFT_DISABLE tokens are kill-switches for optimizations that are on by default; use them to bisect a rendering artifact back to the pass that introduced it. IOCRAFT_DEBUG tokens cost per frame and are off by default.
IOCRAFT_DISABLE=push-wake,retained-blit cargo run --example fullscreen
IOCRAFT_DEBUG=settle,frame-log=/tmp/frames.log cargo run --example fullscreen- origin:
Haleclipse/CometixTUI(this fork) - upstream:
ccbrown/iocraft(original)
This fork is maintained independently. Changes are not submitted as PRs to upstream.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Built on iocraft by ccbrown. Design informed by ink (and Claude Code Source) and ratatui.