Teaches coding agents how to build TUIs with TamboUI correctly: API-level selection, render-thread discipline, display-width safety, CSS-aware element authoring, and JFR conventions.
76
95%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Process steps in order, do not skip ahead. The end state is a ToolkitApp where each pane has a stable id, the app starts with focus on the user's chosen pane (not the first-registered one), Tab cycles between panes, and the focused pane carries a visible border color the audience can spot from across a room. See rules/focusable-needs-id.md for why ids are mandatory, and rules/projector-safe-colors.md for the border color choice.
ListElement, an input textInput(...), sometimes a sidebar list"chat", "trace", "prompt" — short, lowercase, no spacesToolkitApp class, declare one constant per pane: private static final String CHAT_ID = "chat"; (Java) or companion object { const val CHAT_ID = "chat" } (Kotlin).id(CHAT_ID)) and the focus-set site (setFocus(CHAT_ID)) — typos are silent (no compile error, focus just lands on the wrong pane).id(...) and .focusable() on Each Pane.id(CONSTANT).focusable() to its builder chainrules/focusable-needs-id.md — .focusable() without .id(...) is dropped from the chain and the pane silently never receives eventsrender() — see rules/persistent-stateful-elements.mdonStart()onStart() on the ToolkitApp and call runner()?.focusManager()?.setFocus(<PREFERRED_ID>)render() traversal order, not a user-meaningful defaultPROMPT_ID) so the first keystroke goes where the user expectsrender(), look up the current focused id once: val focused = runner()?.focusManager()?.focusedId()focused == ITS_ID — focused → a projector-safe saturated color, unfocused → a dimmer-but-still-visible neutralfun paneBorder(id: String) =
if (runner()?.focusManager()?.focusedId() == id) Color.GREEN else Color.WHITEpanel("CHAT", chatList).rounded().borderColor(paneBorder(CHAT_ID)) — recompute each render so it tracks focus changesrules/projector-safe-colors.md — do not use Color.GRAY for the unfocused border on a demo build, it disappears against light projector backgrounds.focusable() without .id(...) — see rules/focusable-needs-id.mdmouseCapture(true) enabled (see rules/enable-mouse-capture-when-scrollable.md), clicking inside a pane should move focus to it — Toolkit handles this automatically once panes are in the focus chainmouseCapture left at its false default — add the configure() overriderules
skills