Update V8 Version
openinterpreter/openinterpreter
Bumps the pinned v8 and rusty_v8 versions in Codex, validates the release-candidate path with the v8-canary check, and traces failures to upstream build changes.
Build Rust TUI apps with SuperLightTUI v0.23 (immediate-mode terminal UI).
$ npx skills add subinium/SuperLightTUI --skill slt -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install subinium/SuperLightTUI slt --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/subinium/SuperLightTUI.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/slt .claude/skills/slt && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "slt" agent skill from https://github.com/subinium/SuperLightTUI/tree/main/.agents/skills/slt into .claude/skills/slt/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "slt", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/subinium/SuperLightTUI/tree/main/.agents/skills/sltType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add subinium/SuperLightTUI --skill slt -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install subinium/SuperLightTUI slt --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/subinium/SuperLightTUI.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/slt .agents/skills/slt && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "slt" agent skill from https://github.com/subinium/SuperLightTUI/tree/main/.agents/skills/slt into .agents/skills/slt/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "slt", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add subinium/SuperLightTUI --skill slt -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install subinium/SuperLightTUI slt --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/subinium/SuperLightTUI.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/slt .cursor/skills/slt && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "slt" agent skill from https://github.com/subinium/SuperLightTUI/tree/main/.agents/skills/slt into .cursor/skills/slt/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "slt", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/subinium/SuperLightTUI.git --path .agents/skills/slt--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add subinium/SuperLightTUI --skill slt -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install subinium/SuperLightTUI slt --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/subinium/SuperLightTUI.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/slt .gemini/skills/slt && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "slt" agent skill from https://github.com/subinium/SuperLightTUI/tree/main/.agents/skills/slt into .gemini/skills/slt/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "slt", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install subinium/SuperLightTUI sltInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add subinium/SuperLightTUI --skill slt -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/subinium/SuperLightTUI.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/slt .github/skills/slt && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "slt" agent skill from https://github.com/subinium/SuperLightTUI/tree/main/.agents/skills/slt into .github/skills/slt/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "slt", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add subinium/SuperLightTUI --skill slt -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install subinium/SuperLightTUI slt --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/subinium/SuperLightTUI.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/slt .opencode/skills/slt && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "slt" agent skill from https://github.com/subinium/SuperLightTUI/tree/main/.agents/skills/slt into .opencode/skills/slt/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "slt", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
sltBuild Rust TUI apps with SuperLightTUI v0.23 (immediate-mode terminal UI).
Slt is an agent skill from subinium/SuperLightTUI. Build Rust TUI apps with SuperLightTUI v0.23 (immediate-mode terminal UI). Use this skill when the user asks to create, modify, or debug terminal UI code in this repo, or asks "how do I X in SLT / TUI / terminal", or types Korean triggers like "터미널 UI", "TUI 만들어줘", "SLT로", "ratatui 대신". Read REFERENCES.md for feature flags and doc pointers; grep src/context/ and src/widgets/ before inventing any API.
Its SKILL.md is about 5.1k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `REFERENCES.md`).
It works with Rust. The repository describes itself as: 🦀 An immediate-mode Rust TUI framework with flexbox layout and Tailwind-style chaining API. The licence is MIT.
6 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 15fd63a. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
cargoghbashFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use gh, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Slt loads about 5.1k tokens when it runs. Until then it costs about 103 tokens; SKILL.md has 1,521 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from subinium/SuperLightTUI at commit 15fd63a, republished under its MIT licence (© subinium). 1,521 words, ~5,071 tokens.
.claude/skills/slt/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.SLT is immediate-mode. Your app is one closure: slt::run(|ui: &mut Context| { ... }). The closure runs every frame. State lives in plain Rust variables outside the closure — no App trait, no Model/View/Update, no retained tree. SLT handles flexbox layout, ANSI diff, and stdout flush.
Response.rect reflects the previous frame because layout runs after the closure returns. Frame 1 returns a zero Rect. Guard measurement-dependent logic with if ui.tick() > 0 { ... }. See docs/PREVIOUS_FRAME_GUIDE.md.
For larger apps write components as functions: fn render_card(ui: &mut Context, data: &Card). Share read-mostly state with ui.provide(value, |ui| ...) + ui.use_context::<T>() instead of threading &theme through every helper.
These are non-negotiable in v0.20+. When generating new code, every public widget must match all 5.
Builder for optional config. Methods on Context return a builder when ≥1 option exists. Builders chain &mut self -> &mut Self, render on Drop, expose .show() to capture a *Response.
ui.gauge(0.6).label("60%").width(24).color(Color::Cyan); // good
let r = ui.breadcrumb(&segs).separator(" › ").show(); // capture responseRemoved in v0.20: gauge_w, gauge_colored, line_gauge_with, breadcrumb_sep, LineGaugeOpts, HighlightRange::single, label_owned. Do not write these — AI training data may suggest them.
Floats are f64. Public surface never takes/returns f32. 0.5 is f64 natively, so ui.gauge(0.5) just works.
≤3 positional args. When 4+ args appear, use an opts struct (<Widget>Opts) or a builder.
GutterOpts::line_numbers(total, viewport) // Opts struct
ui.scrollable_with_gutter(&mut scroll, opts, |ui, abs| { ... });Stateful widgets take &mut <Widget>State. Never &mut String, &mut Vec<T>, &mut usize. Trivial-value exceptions: slider(&mut f64), checkbox(&mut bool), toggle(&mut bool).
ui.text_input(&mut TextInputState); // not &mut String
ui.tabs(&mut TabsState); // not &mut usizeResponses. Single-rect widgets return Response. Compound widgets return <Widget>Response: Deref<Target = Response> with #[must_use]. Never tuples.
if ui.button("Save").clicked { ... } // Response
if let Some(i) = ui.breadcrumb(&segs).show().clicked_segment { ... } // BreadcrumbResponseReturn-type pattern. Methods on Context return one of two types — picking the wrong one is the most common AI-generated compile error.
&mut Self — chainable mutators of the last rendered element. Use for: text, link, styled, separator, timer_display, and the style chain (bold, dim, italic, fg, bg, wrap, truncate, align, text_center, m, mx, w, h, grow, spacer, with_if, with).Response — interaction result of an independently-rendered widget. Use for every stateful interactive widget (button, checkbox, toggle, table, tabs, select, radio, multi_select, text_input, list, tree, file_picker, slider, calendar, command_palette, rich_log).col / row / modal → Response. line / line_wrap / screen → &mut Self (these continue an inline-text chain).ui.button("Save").bold(); // ❌ Response has no .bold() — compile error
if ui.button("Save").clicked { … } // ✅ Response field
ui.text("Saved").bold().fg(green); // ✅ &mut Self chain on display elementMethod names encode their category. When picking a name, match the category shape of nearby methods.
| Category | Shape | Examples |
|---|---|---|
| Verbs (actions, side effects) | <verb> or <verb>_<object> | quit, notify, register_focusable, focus_by_name, consume_event, set_ratio |
| Nouns (getters, no side effects) | <noun> or <noun>_<modifier> | theme, width, events, focused_name, state.cursor. Never get_X. |
| Adjectives (Layer 2 builder modifiers) | short, ≤2 syllables | bordered, bg, fg, p, m, w, h, gap, grow, fill, bold, dim |
| Constructors | Type::default() / Type::new(args) / Type::with_X(arg) | TextInputState::default(), SplitPaneState::new(0.5), TextInputState::with_placeholder("…") |
Allowed universal abbreviations: bg fg id idx len min max pos pct w h x y r g b a.
Forbidden: ctx btn lbl dbg cfg req res srv db in public API. Closure params over &mut Context are always ui, never ctx.
| Layer | Object | Examples |
|---|---|---|
| 1 — Context | &mut Context (the ui parameter) | ui.text(...), ui.button(...), ui.row(...), ui.theme(), ui.use_state(...) |
| 2 — ContainerBuilder | returned by ui.container(), ui.bordered(...) | chained adjectives: `.p(2).bg(c).gap(1).col( |
| 3 — Widget | impl Widget for MyType { type Response; fn ui(...) } | custom widget extension point |
| 4 — State | pub struct <Widget>State in src/widgets/*.rs | TextInputState, TableState, ScrollState |
| 5 — Response | Response or <Widget>Response: Deref<Response> | Response { clicked, hovered, changed, focused, rect, right_clicked, gained_focus, lost_focus } |
When a method belongs to two layers (ui.bordered(B) shortcut vs ui.container().border(B) explicit), prefer the explicit form in skill output.
When unsure about a widget signature, find its family and match.
// Stateful interactive widgets — &mut <Widget>State, returns Response
ui.list(&mut ListState); ui.tabs(&mut TabsState);
ui.table(&mut TableState); ui.tree(&mut TreeState);
ui.select(&mut SelectState); ui.radio(&mut RadioState);
ui.multi_select(&mut MultiSelectState);
ui.file_picker(&mut FilePickerState); ui.calendar(&mut CalendarState);
ui.text_input(&mut TextInputState); ui.textarea(&mut TextareaState, rows); // textarea takes rows
ui.rich_log(&mut RichLogState); ui.command_palette(&mut CommandPaletteState);
ui.toast(&mut ToastState); ui.spinner(&SpinnerState); // spinner is &, not &mut
// Trivial-value siblings — exception to Rule 4
ui.button("Save"); // Response
ui.checkbox("Done", &mut done); // Response
ui.toggle("Enabled", &mut on); // Response
ui.slider("Vol", &mut value, 0.0..=100.0); // Response
// Builder widgets — chain optional config, render on Drop
ui.gauge(0.6).label("60%").width(24).color(Color::Cyan);
ui.line_gauge(0.6).filled('━').empty('─').width(24).label("60%");
let r = ui.breadcrumb(&segs).separator(" › ").color(Color::Cyan).show();
// Compound responses — Deref<Response> + extra fields
let r = ui.gauge(cpu).label("CPU").show(); // GaugeResponse { ratio: f64 }
let r = ui.breadcrumb(&segs).show(); // BreadcrumbResponse { clicked_segment: Option<usize> }
let r = ui.split_pane(&mut split, l, r); // SplitPaneResponse { ratio: f64 }
let r = ui.scrollable_with_gutter(&mut scroll, opts, body); // GutterResponse { current_highlight: Option<usize> }Hooks must be called in the same order every frame unless they are id-keyed.
| Hook | Key | Safe in if/match? | Use when |
|---|---|---|---|
ui.use_state(|| init) | call order | No | Top-level state, no conditional placement |
ui.use_state_named("id", || init) | &'static str | Yes | Conditional/branching state with compile-time id and initializer |
ui.use_state_named_default::<T>("id") | &'static str | Yes | Same, using T::default() |
ui.use_state_keyed("id-{i}", || init) | runtime String | Yes | Per-row state in a list (key from data) |
ui.use_state_keyed_default("id-{i}") | runtime String | Yes | Same, T: Default shortcut |
ui.use_memo(&deps, |d| compute(d)) | call order + deps | No | Cached compute, deps change → recompute |
ui.use_effect(|d| { ... }, &deps) | call order + deps | No | Side effect on deps change |
// WRONG — order-based hook in conditional drifts call order between frames
if expanded { let count = ui.use_state(|| 0); }
// RIGHT — id-keyed variant is safe inside conditionals
if expanded { let count = ui.use_state_named_default::<i32>("sidebar.count"); }
// Per-list-item runtime keys
for i in 0..items.len() {
let count = ui.use_state_keyed_default::<i32>(format!("counter-{i}"));
}provide / use_context)Stop threading &theme, &tick, &mut toasts through every render fn. provide injects a typed value scoped to a closure; nested code reads it back with use_context.
struct AppCtx { theme: slt::Theme, tick: u64, user: &'static str }
slt::run(|ui| {
let ctx = AppCtx { theme: *ui.theme(), tick: ui.tick(), user: "subin" };
ui.provide(ctx, |ui| {
render_header(ui);
render_card(ui);
});
});
fn render_card(ui: &mut slt::Context) {
let ctx = ui.use_context::<AppCtx>(); // panics if missing
// let maybe = ui.try_use_context::<AppCtx>(); // returns Option<&T>
ui.text(format!("hi {} (tick {})", ctx.user, ctx.tick));
}Reserve explicit parameters for writes (&mut MyDocState). Bound is T: 'static — use &'static str for literals, String for runtime values.
with_if / with)with_if(cond, modifier) and with(modifier) collapse conditional branches into a single chain. Available on text and ContainerBuilder. Beware: text uses &mut self -> &mut Self, ContainerBuilder uses consuming Self -> Self.
// text — closure receives &mut Self
ui.text("Status").with_if(is_error, |t| { t.bold().fg(Color::Red); });
// ContainerBuilder — closure receives Self by value
ui.container().with_if(is_focused, |c| c.bg(theme.surface_hover)).col(|ui| ...);When to use which pattern:
fn render_card(ui: &mut Context, data: &CardData)): 90% of cases. Use for screens, sections, reusable layouts. Cheaper to write, no trait bounds, easier to test. Built-in widgets follow this shape internally (impl Context direct methods).impl Widget: when the component (a) has its own state struct that the caller owns, and (b) you want ui.widget(&mut w) ergonomics matching built-ins. Required for third-party crates that export widgets through trait-bound APIs.struct Label<'a> { text: &'a str }
impl<'a> slt::Widget for Label<'a> {
type Response = slt::Response;
fn ui(&mut self, ui: &mut slt::Context) -> Self::Response {
ui.register_focusable();
ui.text(self.text).bold();
slt::Response::default()
}
}
let mut label = Label { text: "hello" };
ui.widget(&mut label); // or call `label.ui(ui)` with `Widget` in scopeFor mouse hit-testing use ui.interaction(rect). For keyboard use register_focusable() + available_key_presses().
examples/ for the closest pattern (see Reference Examples below). Start from that file if it fits.src/context/widgets_* and src/widgets/* for the actual signature before writing ui.foo(...). Do NOT invent APIs.Cargo.toml features minimal — see REFERENCES.md.Core — every commit:
cargo fmt -- --check
cargo check --all-features
cargo clippy --all-features -- -D warnings
cargo test --all-features
cargo check --examples --all-featuresExtended — before PR or release:
typos
bash scripts/api_audit.sh --strict
cargo check -p superlighttui --no-default-features
cargo check -p slt-wasm --target wasm32-unknown-unknown
cargo hack check -p superlighttui --each-feature --no-dev-deps
cargo audit
cargo deny checkAGENTS.md has the full 8-step checklist. Short version:
Cargo.toml, update CHANGELOG.mdrelease/vX.Y.Z, single atomic commit, pushgh pr create, wait for CI greenrelease.yml greengh release view, crates.io, docs.rsRed flags that mean STOP: "Probably fine", "Just a docs change", "CI will catch it", "I'll tag now and fix later". Run the gate locally first.
src/context/ and src/widgets/ first.gauge_w, gauge_colored, line_gauge_with, breadcrumb_sep, LineGaugeOpts, HighlightRange::single, label_owned are GONE in v0.20. Use the builder forms.Response.rect on frame 1. Zero Rect. Guard with ui.tick() > 0.use_state() inside if/match/for. Use use_state_named (&'static str id) or use_state_keyed (runtime String)..show() on builders that return a response. Drop renders and discards the response. Capture with let r = ui.gauge(...).show();.'static on deferred raw draw. Use draw_with for owned data, or draw_precomputed when the closure must borrow local data and fixed source dimensions are acceptable.ui.* helpers. Prefer ui.key(), ui.key_code(), ui.key_mod(). For modal-aware shortcuts use ui.raw_key_*.Color::Rgb(...) instead of ui.theme() — themes can't swap.RichLogState::new() for unbounded. New caps at 10000; use RichLogState::new_unbounded() if you really want unlimited.tb.render(...) call.q, Esc, and Ctrl-Q.unsafe blocks. #![forbid(unsafe_code)]. Hard compile error.| Domain | Reference file | Key shape |
|---|---|---|
| Hello / minimal | examples/hello.rs (21 lines) | slt::run, bordered.title.col, quit triple |
| Counter (state in closure) | examples/counter.rs | move-closure state pattern |
| Inline mode | examples/inline.rs (23 lines) | run_inline(rows, ...) |
| Tabbed tour | examples/cookbook_tour.rs | TabsState + child pub fn render(ui, &mut DemoState) |
| Form / validators | examples/cookbook_login.rs | TextInputState::with_placeholder, masked password, validation |
| Searchable+sortable table | examples/cookbook_table.rs | TableState::set_filter, toggle_sort, consume_key |
| Modal + Toast | examples/cookbook_modal_toast.rs | ButtonVariant::Danger, raw_key_code(Esc) for modal-aware quit |
| Modal focus trap | examples/v020_modal_trap.rs | ModalOptions { tab_trap: true } |
| File picker | examples/cookbook_file_picker.rs | FilePickerState::selected_file() |
| Dashboard (chart+sparkline) | examples/cookbook_dashboard.rs | ui.chart(|c| c.line(...).color()), rolling VecDeque<f64> |
| Animation primitives | examples/anim.rs | Tween/Spring/Keyframes/Sequence/Stagger |
use_state_keyed | examples/v020_use_state_keyed.rs | per-row counter via format!("counter-{i}") |
use_effect | examples/v020_use_effect.rs | three dep shapes (&(), &i32, &bool) |
provide/use_context | tests/context_provider.rs (100 lines), examples/demo_website.rs:139-152 | injection + try_use_context |
| Theme subtree | examples/v020_theme_subtree.rs | container().theme(theme) per-subtree override |
| Theme density | examples/v020_spacing_scale.rs | Theme::compact() / comfortable() / spacious() |
| Gauge builder | examples/v020_gauge.rs:104-107 | ui.gauge(value).label(...).width(24) |
| Line gauge | examples/v020_gauge.rs:74-92 | ui.line_gauge(0.45).filled('#').empty('.').width(24) |
| Breadcrumb response | examples/v020_breadcrumb_response.rs:72-77 | ui.breadcrumb(&segs).separator(" › ").show() |
| Scrollable + gutter | examples/v020_gutter_highlights.rs:150-165 | GutterOpts::line_numbers, HighlightRange::line |
| Split pane | examples/v020_split_pane.rs | split_pane, vsplit_pane, drag handle |
| WidthSpec variants | examples/v020_widthspec.rs | Constraints::default().w_pct(50), .w_ratio(1,3), .w_minmax(10,30) |
| Named focus | examples/v020_named_focus.rs:187 | register_focusable_named + focus_by_name |
| Keymap help overlay | examples/v020_keymap_help.rs | WidgetKeyHelp, publish_keymap, keymap_help_overlay |
| DX shortcuts | examples/v020_dx_shortcuts.rs | on_hover, animate_bool, fill(), Rect::center_in |
| Static log / scrollback | examples/v020_static_log.rs | slt::run_static, ui.static_log(...) |
| Async demo | examples/async_demo.rs | slt::run_async with tokio |
| All-in-one showcase | examples/v020_showcase.rs (277 lines) | every major v0.20 feature |
| Test utilities | tests/v020_test_utils_demo.rs | record_frames, sequence().tick().key().type_string() |
use slt::{TestBackend, EventBuilder};
#[test]
fn my_widget_renders() {
let mut tb = TestBackend::new(80, 24);
tb.render(|ui| { ui.text("hello"); });
tb.assert_contains("hello");
}
// Multi-frame with events (warm prev-frame hit map first)
#[test]
fn click_triggers() {
let mut tb = TestBackend::new(40, 10);
tb.render(|ui| { ui.button("Save"); }); // warm frame
tb.run_with_events(vec![EventBuilder::mouse_down(2, 0)], // event frame
|ui| { if ui.button("Save").clicked { /* assert */ } });
}
// Sequence builder (most readable)
tb.sequence().tick(5).key(KeyCode::Tab, KeyModifiers::NONE).type_string("hello", &mut state.value).run();See tests/v020_test_utils_demo.rs for record_frames, assert_not_contains, assert_style_at.
| Area | Primary files |
|---|---|
| Public API | src/lib.rs (re-exports) |
| Run loop / backend | src/terminal.rs, src/lib.rs (run, run_with, run_inline, run_async, run_static, frame, frame_owned) |
| Context core | src/context/{core,runtime,container,helpers,state}.rs |
| Widget impls | src/context/widgets_display/*, widgets_interactive/*, widgets_input/*, widgets_viz.rs |
| Layer 4 state types | src/widgets/*.rs |
| Compound responses | src/widgets/responses.rs (BreadcrumbResponse, GaugeResponse, SplitPaneResponse, GutterResponse) |
| Layout kernels | src/layout/{tree,flexbox,collect,render,command}.rs |
| Style / theme | src/style/{color,theme}.rs, src/style.rs |
| Animation | src/anim.rs |
| Charts | src/chart.rs, src/chart/*.rs, src/context/widgets_viz.rs |
| Testing helpers | src/test_utils.rs |
| Skill references | REFERENCES.md (feature flags, doc pointers) |
cat to terminal)© subinium, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in .agents/skills/slt of subinium/SuperLightTUI.
Open the folder on GitHubat commit 15fd63a
Slt next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Slt this skillsubinium/SuperLightTUI | 192 | — | ~5.1k | Automated safety check: Pass | MIT | |
| Update V8 Versionopeninterpreter/openinterpreter | 69k | 2 repos | ~845 | Automated safety check: Pass | Apache-2.0 | |
| Firecrawl Page Scrape Integrationfirecrawl/firecrawl | 190k | 1 repos | ~944 | Automated safety check: Pass | ISC | |
| Migrate Core Code to Submodulestinyhumansai/openhuman | 42k | — | ~2.6k | Automated safety check: Pass | GPL-3.0 | |
| Rust TDD Workflowrtk-ai/rtk | 83k | — | ~753 | Automated safety check: Notes | Apache-2.0 | |
| OpenLogi macOS Permissions TriageAprilNEA/OpenLogi | 23k | — | ~2.5k | Automated safety check: Notes | Apache-2.0 |
openinterpreter/openinterpreter
Bumps the pinned v8 and rusty_v8 versions in Codex, validates the release-candidate path with the v8-canary check, and traces failures to upstream build changes.
firecrawl/firecrawl
Adds Firecrawl's /scrape endpoint to application code to pull markdown, HTML, links, screenshots or structured data from a single known URL.
tinyhumansai/openhuman
Plans and carries out moving non-host-specific code and its tests from the OpenHuman core into vendored tiny submodule libraries, then releases the submodule and re-pins the host.
rtk-ai/rtk
Enforces red-green-refactor for Rust work, with idiomatic test patterns, a naming convention and a pre-commit gate of cargo fmt, clippy and test.
AprilNEA/OpenLogi
Decides whether an OpenLogi device problem on macOS is a privacy-permission (TCC) problem, using agent log lines, and says which identity needs which grant.
farm-fe/farm
Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook.
subinium/SuperLightTUI
Build Rust TUI apps with SuperLightTUI v0.20 (immediate-mode terminal UI).
subinium/SuperLightTUI
Migrate Rust TUIs from ratatui (or cursive, Python textual) to SuperLightTUI v0.23.
subinium/SuperLightTUI
Migrate Rust TUIs from ratatui (or cursive, Python textual) to SuperLightTUI v0.20.
Works with
Build Rust TUI apps with SuperLightTUI v0.23 (immediate-mode terminal UI). Slt is an agent skill from subinium/SuperLightTUI.23 (immediate-mode terminal UI).
Slt fits situations like: the user asks to create; debug terminal UI code in this repo; asks how do I X in SLT / TUI / terminal; types Korean triggers like 터미널 UI.
Run `npx skills add subinium/SuperLightTUI --skill slt -a claude-code`. Or copy the skill folder (.agents/skills/slt in subinium/SuperLightTUI) into .claude/skills/slt in your project. Claude Code loads it when a task matches its description.
Run `npx skills add subinium/SuperLightTUI --skill slt -a codex`. Or copy the skill folder (.agents/skills/slt in subinium/SuperLightTUI) into .agents/skills/slt in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add subinium/SuperLightTUI --skill slt -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/slt, .gemini/skills/slt, .github/skills/slt and .opencode/skills/slt in your project.
Going by SKILL.md and its folder, Slt needs the command-line tools its instructions call (cargo, gh and bash).
SKILL.md contains no URLs. Its commands use gh, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Slt is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.1k tokens (SKILL.md is roughly 20k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Slt: Update V8 Version (openinterpreter/openinterpreter, 69k stars), Firecrawl Page Scrape Integration (firecrawl/firecrawl, 190k stars), Migrate Core Code to Submodules (tinyhumansai/openhuman, 42k stars) and Rust TDD Workflow (rtk-ai/rtk, 83k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
subinium (a GitHub user) maintains it in subinium/SuperLightTUI, which has 192 GitHub stars. The repository holds 4 skills in this directory. The repository was last updated on September 9, 2026.
Source: subinium/SuperLightTUI on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.