Skip to content

Commit a73ce3a

Browse files
vchelaruclaude
andcommitted
Add gum-skills/ folder with 5 consumer-facing AI skills (#2700)
Establishes a permanent home for external-facing AI skills that consumers drop into their project's .claude/skills/ to work *with* Gum (distinct from the engine-internal .claude/skills/ set for working *on* Gum). Fulfills the folder the published docs/ai/ai-skills.md already links to. Adds README.md plus five skills: gum-overview (file types, Forms vs raw visuals, the three usage modes, project wiring, the content-copy rule), gumcli (edit->validate->verify recipes), gum-file-format (enum->int tables for Units/Origins/ChildrenLayout, qualified InstanceName.Property variables, instance parenting, and the silent-failure landmines), gum-forms-controls (controls vs raw visuals, composition via AddChild, the state/category system), and gum-layout (units, Anchor/Dock, stacking). Content is grounded in source (enum values, GumService init, package IDs, Anchor/Dock/AddChild APIs) and validated by a fresh-agent dry-run whose findings drove a round of fixes; the file-format skill's example passes gumcli check and renders. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 39d8926 commit a73ce3a

6 files changed

Lines changed: 581 additions & 0 deletions

File tree

gum-skills/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# gum-skills
2+
3+
Skills for developers building game UI **with** Gum.
4+
5+
Drop the subfolders you want into your project's `.claude/skills/` (or your
6+
user-global `~/.claude/skills/`) to give an AI assistant such as Claude Code
7+
durable, concept-level context on Gum — file formats, layout, Forms controls,
8+
and the `gumcli` command-line tool. A skill loads automatically when its
9+
`description` matches what you are doing, so the assistant stops guessing at
10+
Gum's conventions and starts following them.
11+
12+
These are **3rd-party skills**: they describe how to *use* Gum from a game
13+
project. Skills for working *on* Gum itself live in the repo's own
14+
`/.claude/skills/` folder and are not meant for distribution — do not add
15+
engine-internal material here.
16+
17+
## Getting started
18+
19+
Copy `gum-overview` first — it is the single entry point the other skills
20+
assume — then add the topical skills that match your work:
21+
22+
| Skill | Use it for |
23+
|-------|-----------|
24+
| `gum-overview` | What Gum is, project file types, usage modes, project wiring. **Start here.** |
25+
| `gumcli` | Scaffolding, code generation, validation, and screenshots from the command line. |
26+
| `gum-file-format` | Reading and safely hand-editing `.gumx`/`.gusx`/`.gucx`/`.gutx` XML. |
27+
| `gum-forms-controls` | Buttons, text boxes, lists, panels, and the state/category styling system. |
28+
| `gum-layout` | Positioning and sizing — units, anchor/dock, stacking. |
29+
30+
A good default set is `gum-overview` + `gumcli` + whichever of `gum-layout`,
31+
`gum-forms-controls`, and `gum-file-format` your task touches.
32+
33+
These skills pair with two other AI aids Gum ships: the **MCP documentation
34+
server** (live, authoritative doc lookups) and **`gumcli`** (act on a project
35+
and verify the result). See <https://docs.flatredball.com/gum/ai> for the full
36+
picture.
37+
38+
## Authoring a new skill
39+
40+
Each skill is a folder containing a single `SKILL.md`. The file starts with
41+
YAML frontmatter and uses `##` sections for the body:
42+
43+
```markdown
44+
---
45+
name: gum-example
46+
description: One line telling the assistant WHEN this skill is relevant. Triggers: distinctive words, file types, symbols.
47+
---
48+
49+
# Title
50+
51+
## Section
52+
Concise, high-signal guidance. Link to the docs for depth.
53+
```
54+
55+
Guidelines:
56+
57+
- **`description` is a trigger, not a summary.** Keep it to one line. Lead with
58+
the topic, then list the distinctive words, file extensions, or symbols that
59+
should activate it. It is loaded on every session, so keep it short.
60+
- **Link to the docs; don't restate them.** Point at
61+
<https://docs.flatredball.com/gum> for anything that lives there. A skill is a
62+
map and a list of gotchas, not a copy of the manual.
63+
- **Keep it short and self-contained.** The reader does not have Gum's source
64+
tree — favor concrete rules and small examples over "see this class."
65+
- **Add a `references/` subfolder** only when a skill needs bulky supporting
66+
material (long tables, extended examples) that would bloat `SKILL.md`.
67+
68+
When a skill becomes broadly useful, propose adding it here by opening an issue
69+
or PR on the [Gum repository](https://github.com/vchelaru/Gum).
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
---
2+
name: gum-file-format
3+
description: Reading and safely hand-editing Gum's XML files — enum-to-int mappings for Units/Origins/ChildrenLayout, qualified InstanceName.Property variables, and why hand-edited files silently break. Triggers: editing .gusx/.gucx/.gutx by hand, WidthUnits/XOrigin values, gumcli check errors.
4+
---
5+
6+
# Gum File Format
7+
8+
Gum projects are XML, serialized with .NET's `XmlSerializer`. Prefer editing
9+
them with the Gum tool or `gumcli`; when you must read or hand-edit, this skill
10+
covers the structure and the traps. **Always run `gumcli check` after a hand
11+
edit** — several failure modes below are silent otherwise (see **gumcli**).
12+
13+
## File → root element
14+
15+
| Extension | Root element |
16+
|-----------|--------------|
17+
| `.gumx` (project) | `<GumProjectSave>` — lists element references, loaded first |
18+
| `.gusx` (screen) | `<ScreenSave>` |
19+
| `.gucx` (component) | `<ComponentSave>` |
20+
| `.gutx` (standard element) | `<StandardElementSave>` |
21+
| `.behx` (behavior) | `<BehaviorSave>` |
22+
23+
## Element structure
24+
25+
Every file needs the complete root tag **with both XML-schema namespaces**
26+
the `xsi:`/`xsd:` prefixes used on every `<Value>` are undefined without them.
27+
The element has a `<Name>`, an optional `<BaseType>` (what it inherits from,
28+
e.g. `Container`), one or more `<State>`s (the first is `Default`), and a list
29+
of `<Instance>`s (child objects). A state holds `<Variable>` entries. This is a
30+
complete, valid screen (it passes `gumcli check`):
31+
32+
```xml
33+
<?xml version="1.0" encoding="utf-8"?>
34+
<ScreenSave xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
35+
<Name>MainMenu</Name>
36+
<State>
37+
<Name>Default</Name>
38+
<Variable Type="ChildrenLayout" Name="MenuStack.ChildrenLayout"><Value xsi:type="xsd:int">1</Value></Variable>
39+
<Variable Type="string" Name="Title.Parent"><Value xsi:type="xsd:string">MenuStack</Value></Variable>
40+
<Variable Type="string" Name="Title.Text"><Value xsi:type="xsd:string">Main Menu</Value></Variable>
41+
</State>
42+
<Instance><Name>MenuStack</Name><BaseType>Container</BaseType></Instance>
43+
<Instance><Name>Title</Name><BaseType>Text</BaseType></Instance>
44+
</ScreenSave>
45+
```
46+
47+
**`<Name>`** is the element's name — path-qualified for an element in a
48+
subfolder (`Elements/Divider`), otherwise bare (`MainMenu`). It must match the
49+
reference to it in the `.gumx`.
50+
51+
**Qualified variable names.** A variable named `MenuStack.ChildrenLayout` sets
52+
the `ChildrenLayout` of the instance named `MenuStack`. No dot means an
53+
element-level value. The name before the dot must match an `<Instance>`'s
54+
`<Name>`.
55+
56+
**Parenting instances.** Instances are siblings by default — all direct children
57+
of the element root. To nest one inside another, give the child a `Parent`
58+
variable whose value is the parent instance's name (`Title.Parent = MenuStack`
59+
above puts `Title` inside `MenuStack`, so the container's stacking layout
60+
arranges it). Without it, a stacking container has nothing to lay out.
61+
62+
## Landmine: enum values are stored as integers
63+
64+
For an enum-typed variable, the `Type` attribute holds the enum name but the
65+
`<Value>` holds its **underlying int** (`xsi:type="xsd:int"`), not the name.
66+
`WidthUnits` = `2` means `RelativeToParent`. You must know the mappings to read
67+
or write these correctly:
68+
69+
### WidthUnits / HeightUnits — `DimensionUnitType`
70+
71+
| Int | Name | Int | Name |
72+
|----|------|----|------|
73+
| 0 | Absolute | 6 | MaintainFileAspectRatio |
74+
| 1 | PercentageOfParent | 7 | Ratio |
75+
| 2 | RelativeToParent | 8 | AbsoluteMultipliedByFontScale |
76+
| 3 | PercentageOfSourceFile | 9 | ScreenPixel |
77+
| 4 | RelativeToChildren | 10 | RelativeToMaxParentOrChildren |
78+
| 5 | PercentageOfOtherDimension | | |
79+
80+
### XUnits / YUnits — `PositionUnitType`
81+
82+
One shared enum; some values apply to the X axis, some to Y. **This is not the
83+
`GeneralUnitType` enum you use in C# code** — on disk `XUnits`/`YUnits` are
84+
`PositionUnitType`. Do not copy int values between the two.
85+
86+
| Int | Name | Axis | Int | Name | Axis |
87+
|----|------|:----:|----|------|:----:|
88+
| 0 | PixelsFromLeft | X | 5 | PixelsFromBottom | Y |
89+
| 1 | PixelsFromTop | Y | 6 | PixelsFromCenterX | X |
90+
| 2 | PercentageWidth | X | 7 | PixelsFromCenterY | Y |
91+
| 3 | PercentageHeight | Y | 8 | PixelsFromCenterYInverted | Y |
92+
| 4 | PixelsFromRight | X | 9 | PixelsFromBaseline | Y |
93+
94+
### XOrigin, and Text `HorizontalAlignment``HorizontalAlignment`
95+
96+
`0` = Left, `1` = Center, `2` = Right.
97+
98+
### YOrigin, and Text `VerticalAlignment``VerticalAlignment`
99+
100+
`0` = Top, `1` = Center, `2` = Bottom, `3` = TextBaseline.
101+
102+
### ChildrenLayout (on a container) — `Type="ChildrenLayout"`
103+
104+
`0` = Regular, `1` = TopToBottomStack, `2` = LeftToRightStack,
105+
`3` = AutoGridHorizontal, `4` = AutoGridVertical.
106+
107+
## Landmine: two on-disk variable shapes exist
108+
109+
Gum has written variables two ways over time — a compact **attribute form**
110+
(current tool output) and an expanded **element form** (older files). Both load:
111+
112+
```xml
113+
<!-- attribute form -->
114+
<Variable Type="DimensionUnitType" Name="WidthUnits"><Value xsi:type="xsd:int">0</Value></Variable>
115+
<!-- element form -->
116+
<Variable><Type>DimensionUnitType</Type><Name>WidthUnits</Name><Value xsi:type="xsd:int">0</Value><SetsValue>true</SetsValue></Variable>
117+
```
118+
119+
Do not hand-craft variables from scratch by guessing the shape. Copy the shape
120+
of an existing variable in the same file, or better, let the tool/`gumcli`
121+
write them and edit values only.
122+
123+
## Landmine: wrong element names are dropped silently
124+
125+
`XmlSerializer` ignores XML elements it does not recognize — it does not error.
126+
So `<States>` instead of `<State>`, or `<InstanceSave>` instead of `<Instance>`,
127+
loads as an **empty** element with no warning, and your UI is silently missing
128+
content. `gumcli check` is built to catch exactly this. Run it after every hand
129+
edit.
130+
131+
## Bottom line
132+
133+
Read these files freely; the tables above let you understand and sanity-check
134+
them. But to *write* them, prefer the Gum tool or `gumcli`, and validate with
135+
`gumcli check` before trusting the result. Data-model reference:
136+
<https://docs.flatredball.com/gum/gum-tool/gum-elements>.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
name: gum-forms-controls
3+
description: Gum Forms controls (Button, Label, TextBox, CheckBox, ListBox, StackPanel…) vs raw visuals, and the state/category styling system. Triggers: adding a button/textbox/list, WPF-style properties not working, IsVisible, styling a control, DefaultVisuals.
4+
---
5+
6+
# Gum Forms Controls
7+
8+
Forms controls are interactive UI classes whose names mirror WPF (`Button`,
9+
`CheckBox`, `TextBox`, …), but they are laid out and rendered by **Gum**, not
10+
WPF. Reach for a Forms control for anything the player clicks, types in, or
11+
scrolls. For non-interactive HUD/decoration, use raw visuals instead (see
12+
below). Docs: <https://docs.flatredball.com/gum/code/controls>.
13+
14+
## Common controls
15+
16+
`Button`, `ToggleButton`, `RadioButton`, `CheckBox`, `Label`, `TextBox`,
17+
`PasswordBox`, `ComboBox`, `ListBox`, `Slider`, `ScrollBar`, `ScrollViewer`,
18+
`StackPanel`, `Panel`, `Menu`, `Window`, `Splitter`.
19+
20+
## Using a control in code
21+
22+
```csharp
23+
using Gum.Forms.Controls;
24+
25+
var button = new Button();
26+
button.Text = "Play";
27+
button.AddToRoot(); // adds it to the screen
28+
button.Click += (_, _) => StartGame();
29+
```
30+
31+
Text-bearing controls share this shape — `new Label()`, `new TextBox()`, etc.
32+
all expose `.Text`. Set position/size with Gum's unit system (see
33+
**gum-layout**), not WPF layout.
34+
35+
## Composing controls (parenting in code)
36+
37+
`AddToRoot()` attaches a control to the screen. To nest one control inside
38+
another — buttons inside a panel, anything inside a container — call `AddChild`
39+
on the parent. There is **no** `.Children.Add(...)` on a Forms control.
40+
41+
```csharp
42+
var menu = new StackPanel(); // stacks its children; vertical by default
43+
menu.Spacing = 8; // gap between children (StackPanel.Spacing)
44+
menu.AddToRoot();
45+
46+
var play = new Button { Text = "Play" };
47+
var quit = new Button { Text = "Quit" };
48+
menu.AddChild(play); // parents the control under the panel
49+
menu.AddChild(quit);
50+
```
51+
52+
`AddChild(child)` sets the child's visual parent; the parent's layout then
53+
positions it — a `StackPanel` stacks them, and any container with
54+
`ChildrenLayout` set arranges them. `RemoveChild` undoes it. `StackPanel`
55+
defaults to `Orientation.Vertical`; set `Orientation = Orientation.Horizontal`
56+
for a row.
57+
58+
## Forms vs raw visuals
59+
60+
| Need | Use |
61+
|------|-----|
62+
| Player interaction (click/type/scroll) | A Forms control |
63+
| Static text | `TextRuntime` |
64+
| Solid color block | `ColoredRectangleRuntime` |
65+
| Image | `SpriteRuntime` |
66+
| Scalable panel/border | `NineSliceRuntime` |
67+
| Plain layout container | `ContainerRuntime` |
68+
69+
Raw visuals: <https://docs.flatredball.com/gum/code/standard-visuals>.
70+
71+
## Landmine: WPF conventions do not carry over
72+
73+
The names match WPF; the property model does not. On a Forms control:
74+
75+
- **No** `Margin`, `Padding`, or WPF-style `HorizontalAlignment`/`VerticalAlignment`.
76+
Position and size come from Gum units (`X`, `XUnits`, `Width`, `WidthUnits`, …).
77+
- **No** `Background`, `Foreground`, or `BorderBrush`. Color and appearance come
78+
from **states** (below), not brush properties.
79+
- **No** `Visibility` enum. Use the `IsVisible` bool.
80+
- **No** WPF `Auto` sizing. A `Button` with `Width = 128` is 128 px wide
81+
regardless of its text unless `WidthUnits = RelativeToChildren`. See
82+
**gum-layout**.
83+
84+
For a fuller WPF-to-Gum translation:
85+
<https://docs.flatredball.com/gum/code/about/for-wpf-users>.
86+
87+
## The state / category system (how styling works)
88+
89+
Appearance is driven by named **states** grouped into a **category** on the
90+
control's visual, not by per-property setters. A `Button`'s visual, for example,
91+
carries a category with `Enabled`, `Highlighted`, `Pushed`, `Focused`, and
92+
`Disabled` states; the control switches between them automatically as the player
93+
interacts. Each state sets a batch of variables (colors, sizes) at once.
94+
95+
To recognize this in code: applying a state name changes the look; the control
96+
does this for you on hover/press/focus. To *customize* appearance you edit the
97+
states (in the tool, or via the styling APIs) or swap in a different visual —
98+
you do **not** look for a `Color` property on the control. Don't panic when you
99+
see categories and states; they are Gum's equivalent of a style sheet. Styling
100+
guide: <https://docs.flatredball.com/gum/code/styling>.
101+
102+
## Default visuals
103+
104+
A newly-constructed control (`new Button()`) gets a built-in default visual so
105+
it renders without any project. Replacing or restyling that visual is the
106+
styling story above. If a control looks unstyled or blank, its visual — not the
107+
control class — is what to inspect.

0 commit comments

Comments
 (0)