en un clic
preferred imgui layout patterns
npx skills add https://github.com/meow-sci/ksa-mod-experiments --skill imgui-designCopiez et collez cette commande dans Claude Code pour installer le skill
preferred imgui layout patterns
npx skills add https://github.com/meow-sci/ksa-mod-experiments --skill imgui-designCopiez et collez cette commande dans Claude Code pour installer le skill
| name | imgui-design |
| description | preferred imgui layout patterns |
These patterns are extracted from the KSA mod codebase and represent the preferred style for building ImGui UIs in submods.
Every submod's RenderContent() wraps its body with SubmodUI.BeginContentArea / EndContentArea from MeowSci.KsaAbstractions. This applies a consistent WindowPadding = float2(20f, 20f) and extra bottom padding. Always call this — never render content directly.
SubmodUI.BeginContentArea("##my_content");
// ... content ...
SubmodUI.EndContentArea();
All layout tables use NoPadOuterX so content stretches edge-to-edge with the window border (the window padding from BeginContentArea handles outer inset).
Apply CellPadding = float2(6f, 6f) before every layout table and pop after:
ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, new float2(6f, 6f));
if (ImGui.BeginTable("##id", columns, flags))
{
// ...
ImGui.EndTable();
}
ImGui.PopStyleVar(); // CellPadding
Use for pairs of label+widget side by side (e.g. Columns/Rows, Spacing/Scale):
var flags = ImGuiTableFlags.SizingStretchSame | ImGuiTableFlags.NoPadOuterX;
if (ImGui.BeginTable("##params", 4, flags))
{
ImGui.TableNextRow();
ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.Text("Label A");
ImGui.TableNextColumn(); ImGui.SetNextItemWidth(-1); ImGui.DragFloat("##a", ref valA, ...);
ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.Text("Label B");
ImGui.TableNextColumn(); ImGui.SetNextItemWidth(-1); ImGui.DragFloat("##b", ref valB, ...);
ImGui.EndTable();
}
Use for rows where the label gets ¼ width and the widget gets ¾, matching the 4-column table's visual alignment:
var flags = ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.NoPadOuterX;
if (ImGui.BeginTable("##select", 2, flags))
{
ImGui.TableSetupColumn("##lbl", ImGuiTableColumnFlags.WidthStretch, 1f);
ImGui.TableSetupColumn("##widget", ImGuiTableColumnFlags.WidthStretch, 3f);
ImGui.TableNextRow();
ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.Text("Label");
ImGui.TableNextColumn(); ImGui.SetNextItemWidth(-1); /* widget */
ImGui.EndTable();
}
Use when rows need a label, a fill widget, and a fixed-width button group (e.g. con-man layout):
var flags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoPadOuterX;
if (ImGui.BeginTable("##form", 3, flags))
{
ImGui.TableSetupColumn("##lbl", ImGuiTableColumnFlags.WidthFixed, labelW);
ImGui.TableSetupColumn("##widget", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("##btns", ImGuiTableColumnFlags.WidthFixed, btnColW);
// ...
ImGui.EndTable();
}
Always call ImGui.AlignTextToFramePadding() immediately before any label text that sits in the same row as a widget, to vertically center it.
Use ImGui.Spacing() between logical groups. Use ImGui.SeparatorText("label") for named section dividers (e.g. between a creation form and a list of items).
(?) to the label when a tooltip is needed, then call ImGui.SetItemTooltip(...) immediately after.ImGuiTreeNodeFlags.DefaultOpen for primary/important sections.if (!ImGui.CollapsingHeader("My Section (?)", ImGuiTreeNodeFlags.DefaultOpen))
return;
ImGui.SetItemTooltip("Explanation of this section.");
When rendering a list of items where each has its own CollapsingHeader, put the content inside a bordered child window. The CollapsingHeader renders flush to the window edges (ignoring WindowPadding), so the child must be manually expanded to match and its cursor pulled left:
if (!ImGui.CollapsingHeader($"Item: {name}##id"))
return;
var wpadX = ImGui.GetStyle().WindowPadding.X;
float childW = ImGui.GetContentRegionAvail().X + wpadX * 2;
ImGui.SetCursorPosX(ImGui.GetCursorPosX() - wpadX);
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new float2(20f, 10f)); // inner padding
ImGui.BeginChild($"child_{id}", new float2(childW, 0),
ImGuiChildFlags.Borders | ImGuiChildFlags.AutoResizeY | ImGuiChildFlags.AlwaysUseWindowPadding,
ImGuiWindowFlags.NoScrollbar);
ImGui.PopStyleVar(); // WindowPadding
// ... content ...
ImGui.Spacing();
ImGui.EndChild();
The WindowPadding push/pop must happen before BeginChild — ImGui captures it at Begin time.
" Apply ", " Delete ", " Create ", " Off ", " Rows ", etc.ImGui.PushStyleColor(ImGuiCol.Button, ImGui.GetColorU32(KSAColor.Xkcd.Scarlet));
ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetColorU32(KSAColor.Xkcd.PaleGrey));
if (ImGui.Button($" Destroy ##{id}"))
DoDestroy();
ImGui.PopStyleColor();
ImGui.PopStyleColor();
ImGui.SameLine(0, 8).ImGui.SameLine(0, 12) then ImGui.AlignTextToFramePadding() before the text.All combo dropdowns that may have many items follow this pattern:
if (ImGui.BeginCombo("##id", preview))
{
if (ImGui.IsWindowAppearing())
{
ImGui.SetKeyboardFocusHere();
_filter.Clear();
}
_filter.Draw("##filter", -1f);
for (int i = 0; i < items.Length; i++)
{
if (!_filter.PassFilter(items[i])) continue;
bool sel = _selectedIndex == i;
if (ImGui.Selectable(items[i], sel))
_selectedIndex = i;
if (sel) ImGui.SetItemDefaultFocus();
}
ImGui.EndCombo();
}
ImGui.TextColored(new float4(1f, 0.3f, 0.3f, 1f), message)ImGui.TextColored(new float4(0.4f, 1f, 0.4f, 1f), message)ImGui.TextDisabled(message)if (!string.IsNullOrEmpty(_message)) and add ImGui.Spacing() before.Wrap unavailable controls with the standard ImGui disable guard:
if (!canAct) ImGui.BeginDisabled();
if (ImGui.Button(" Act ##id")) DoAct();
if (!canAct) ImGui.EndDisabled();
ImGui is an immediate mode UI library. KSA uses ImGui for UI
details about the ksa game code and behavior
how to use fd cli tool
how to use ripgrep `rg` cli tool
how to use genhttp effectively for http server
details about the rpc mechanism in unladen swallow