globaltcad/swing-tree/agent-skills
Claude Code and agent skill by globaltcad/swing-tree
- community
Checking that the SKILL.md file is still in the repository.
Write Swing desktop UIs with the SwingTree library and its companion property library Sprouts. Use this skill whenever you are building, editing, reviewing, or debugging Java Swing GUI code that imports `swingtree.UI` or `sprouts.*` — declarative component trees, convergent/responsive/reactive layouts, the functional style API, SVG icons, animations, and MVI/MVL or MVVM view models.
Install
npx vskill@latest install globaltcad/swing-tree/agent-skillsSKILL.md
Writing SwingTree Applications
SwingTree is a Java library for building Swing desktop GUIs declaratively, the way Flutter / SwiftUI / Jetpack Compose / JetBrains' Kotlin UI DSL build theirs. You describe the component tree with method chaining + nesting, bind it to state with the Sprouts property library (Var/Val/Vars/Tuple), and paint it with a functional, immutable style API. There is no XML, no FXML, no separate template language — it is all plain Java, fully type-safe and debuggable.
This document gives you the intuition to write any SwingTree app: the builder, layout, properties & lenses, the two architecture patterns (MVI/MVL and classic MVVM), events, styling, animation, tables, icons & SVG, dialogs, and the non-obvious gotchas that bite people. Read it top to bottom once; thereafter use the cheat sheet at the end.
**One library-wide preference up front: SwingTree views are expected to be*convergent*** — usable whether the window is maximised on an ultrawide ortiled into a tall, 500-pixel strip. Users run tiling window managers, snapwindows to halves, and rotate monitors into portrait; a view that only worksat the size you developed it in is considered broken. §2c is the shortversion and the checklist; apply it to every view you write or review.
0. The one import and the mental model
A UI is a tree of components. Every node is built by a UI.xxx(..) factory that returns a builder (UIForPanel, UIForButton, UIForLabel, … all subtypes of UIForAnySwing). On a builder you:
- configure it with chained
withXyz(..)/isXyzIf(..)calls, - nest children with
.add(..), - bind it to
Var/Valproperties for reactivity, - style it with
.withStyle(it -> ...), - wire events with
.onXyz(..), - and finally unwrap it with
.get(JPanel.class)or hand it toUI.show(..).
Crucial idea: a builder is a recipe, not the component. It produces a real JComponent underneath. You can escape to the raw component with .peek(c -> ...) or unwrap with .get(Type.class) — but treat peek as a last resort (§12): reach for a SwingTree with*/is*If/on* method first.
The smallest complete program:
1. Growing the tree — factories, nesting, add
UI.show(component | builder | title, builder | Function<JFrame,Component>) opens a window. Inside it you compose nodes:
Rules of .add(..):
.add(childBuilder)— add with no constraint..add("growx, span 2", childBuilder)— first arg is a MigLayout add-constraint string..add(GROW.and(SPAN), childBuilder)— or a type-safe constraint (see §2)..add(a, b, c)— add several children at once (same constraint applies to each).
Common factories (each returns a builder)
| Factory | Component | |
|---|---|---|
panel(...), box(...) | JPanel / JBox (a transparent, insets-free panel — perfect for grouping) | |
label(text), html("<h1>..</h1>") | JLabel (html(..) renders HTML) | |
button(text), toggleButton(text), checkBox(text), radioButton(text) | buttons | |
textField(text), textArea(text), passwordField(), numericTextField(var) | text inputs | |
comboBox(...), slider(Axis, min, max), spinner(...), progressBar(...) | value pickers | |
separator(), scrollPane(), scrollPanels(), splitPane(Axis), tabbedPane() | structure | |
table(Var<TableData>), table(), tree(Var<N>, conf), trees(Var<Tuple<N>>, conf), list(...), menu(...), menuItem(...), splitButton(text) | data / menus (bind a TableData value — see §10; a tree binds one nested value, a forest a tuple of them — see §10) | |
icon(path), icon(w,h,path) | JIcon (supports SVG, see §10) |
box(...) vs panel(...): a JBox is non-opaque with zero default insets — use it for invisible structural grouping; use panel when you want a real surface to style. Never call `setOpaque(..)` yourself on a styled component — the style engine owns opacity and will fight you.
Wrapping a custom / third-party component
UI.of(jcomponent) wraps any JComponent so the declaration keeps flowing. UI.of(this) is the standard way to start a View extends JPanel (see §5).
2. Layout — MigLayout, type-safe constants, and convergence
SwingTree's default layout manager is MigLayout; §2a and §2b are the two ways to drive it. §2c onwards is about making the result work at any window size, which SwingTree treats as the default expectation rather than a nice-to-have.
2a. String constraints (most common, terse)
The container constraint goes in the factory; per-child constraints go as the first add(..) arg:
Memorize these MigLayout keywords:
- Container:
fill,fillx,filly,wrap N(N columns),insets T L B R/ins N,gap,debug(draws guide borders — great for diagnosing layout). - Per-child:
grow,growx,growy,push,pushx,pushy,span/span N,wrap,align center/left/right,top/bottom,width 60px::,w 180!,h 90!. 60px::means "min 60, no max";180!means "exactly 180".
withLayout("fill, wrap 2") sets the container constraint after the fact, and withLayout(layout, colConstraints, rowConstraints) gives full control, e.g. .withLayout("fill, wrap 2", "[grow 60][grow 40]").
Full keyword reference: http://www.miglayout.com/
2b. Type-safe constants (refactor-safe, composable)
import static swingtree.UI.* exposes constants that compose with .and(..):
Container constants: FILL, FILL_X, FILL_Y, WRAP(n), INS(n) / INS(t,l,b,r), GAP_REL(n), FLOW_X, DEBUG. Per-child constants: GROW, GROW_X, GROW_Y, PUSH, PUSH_X, PUSH_Y, SPAN, SPAN(n), WRAP, SHRINK, CENTER, LEFT, RIGHT, TOP, BOTTOM, ALIGN_CENTER, ALIGN_LEFT, ALIGN_X_CENTER, ALIGN_Y_TOP, GAP_LEFT(n), …
String constraints and constants are interchangeable — pick whichever reads clearer locally. (Examples in this codebase mix both freely.)
The geometry enums (UI.Axis, UI.Placement, and friends)
Wherever Swing wants an int constant, SwingTree wants one of these. They are the vocabulary the whole API shares, so learn them once:
- `UI.Axis` —
HORIZONTAL,VERTICAL,LINE,PAGE. Which way a thing
runs: slider(Axis), progressBar(Axis, ..), separator(Axis), splitPane(Axis), toolBar(Axis), scrollPanels(Axis, ..), Layout.box(Axis), withBoxLayout(Axis). LINE and PAGE follow the container's ComponentOrientation, but only a BoxLayout acts on that difference; every other component calls Axis.resolve() and so reads LINE as HORIZONTAL and PAGE as VERTICAL.
- `UI.Placement` —
UNDEFINED, the four corners (TOP_LEFT…), the middle
of the four sides (TOP, LEFT, BOTTOM, RIGHT) and CENTER. One named point of a rectangle: img.placement(..), text.placement(..), SvgIcon.withPreferredPlacement(..), label(text, Placement), withAlignment(..), withTextPosition(..), fontAlignment(..). Careful: Placement.TOP is the middle of the top edge, so aligning a label with it also centres the label horizontally. Use Placement.TOP_LEFT to pin both axes.
- `UI.Side` (
TOP/LEFT/BOTTOM/RIGHT) picks an edge to dock to, e.g.
tabbedPane(Side.LEFT). `UI.Edge` picks an edge to draw on (borderAt(Edge.TOP, 1, color)), `UI.Corner` picks a corner to round (borderRadiusAt(Corner.TOP_LEFT, w, h), plus Corner.EVERY).
- `UI.Span` names the direction a gradient travels — either side to side
(LEFT_TO_RIGHT, TOP_TO_BOTTOM, …) or corner to corner (TOP_LEFT_TO_BOTTOM_RIGHT, …).
- `UI.ComponentArea` (
ALL,EXTERIOR,BORDER,INTERIOR,BODY) names
a region of the box model and `UI.ComponentBoundary` (OUTER_TO_EXTERIOR … CENTER_TO_CONTENT) names the line between two regions. clipTo(..) and parentFilter(f -> f.area(..)) take an area; gradient(g -> g.boundary(..)) takes a boundary.
Each of these carries small helper methods so you rarely have to write a switch over them yourself — Axis.perpendicular(), Side.opposite(), Placement.opposite(), Span.reversed(), Cursor.resizeAt(Side), Active.decide(boolean), FontStyle.withBold(boolean).
2c. Convergence — a SwingTree view is expected to survive any window shape
This is a strong preference of the library, not an optional polish step. Write convergent views by default; treat "it only works maximised on a landscape monitor" as a bug.
Desktop windows are not a fixed size any more. Users run tiling window managers (i3, sway, Hyprland, yabai, AeroSpace, FancyZones), snap windows to halves and thirds, put four windows across an ultrawide, rotate a monitor into portrait, and drag your app onto a smaller second screen. A view that assumes ~1400×900 is broken for a large fraction of real users.
Convergent ≠ merely responsive. Responsive means nothing overlaps; convergent means nothing is lost — the layout rearranges, the content re-prioritises, and the primary action stays reachable at every size.
The default recipe (start every page like this)
Four mechanisms, in the order you should reach for them
| Gear | Mechanism | Use when | Costs | |
|---|---|---|---|---|
| 0 | "wmin 0" + withMinSize(0,0) | always — a prerequisite for all of the others | nothing | |
| 1 | withFlowLayout() + AUTO_SPAN (§2d) | the same regions want a different number of columns | no state at all | |
| 2 | Var<Layout> reflow (§2e) | the same widgets want a genuinely different arrangement (a toolbar folding into rows) | one property; nothing is rebuilt | |
| 3 | form-factor state + view swap (§2f) | the two shapes want different component trees (split pane ⇄ scrolling column) | rebuilds — loses focus/caret/scroll | |
| 4 | isVisibleIf + shorter bound labels (below) | content, not layout, must re-prioritise | nothing |
Most views need gear 0 + gear 1. Escalate only when the shape of the problem demands it — gear 3 is the only one that destroys component state.
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingdocs/agent-skills/SKILL.md
Popularity
- Repository stars
- 55
- Repository forks
- 4
- 7-day trend score
- 20
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/globaltcad/swing-tree/agent-skills)