widget
SkillDev toolsBPX widget construction and inspection skill. Use for widget-init/read/parent-class/add/remove/write workflows.
Available today. Use it from your connected AI after setup.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the widget skill
What this skill tells your AI
The instructions your AI receives, as published by wilddogjp/openbpx in skills/bpx-widget/SKILL.md and read by ahel’s review.
PREREQUISITE: Read bpx-shared.
Usage
bpx blueprint widget-read <file.uasset> [--export <n>]
bpx blueprint widget-init <out.uasset> --template <minimum> [--engine <auto|ue5.6>] [--asset-name <Name>] [--package-path </Game/...>] [--parent-class </Script/Module.ClassName>] [--force] [--dry-run] [--backup]
bpx blueprint widget-parent-class <file.uasset> --class </Script/Module.ClassName> [--export <n>] [--dry-run] [--backup]
bpx blueprint widget-add <file.uasset> --parent <path|name|root> --type <image|textblock|richtextblock|progressbar|slider|spacer|scrollbar|editabletext|editabletextbox|multilineeditabletextbox|spinbox|comboboxstring|checkbox|userwidget|button|border|retainerbox|invalidationbox|menuanchor|namedslot|sizebox|scalebox|backgroundblur|safezone|windowtitlebararea|canvaspanel|overlay|verticalbox|horizontalbox|stackbox|scrollbox|wrapbox|gridpanel|uniformgridpanel|widgetswitcher|listview|tileview|treeview> --name <Widget_N> [--class </Game/...> when --type userwidget] [--export <n>] [--dry-run] [--backup]
bpx blueprint widget-remove <file.uasset> --widget <path|name> [--export <n>] [--dry-run] [--backup]
bpx blueprint widget-write <file.uasset> --widget <path|name> --property <text|visibility|render-opacity|brush-image|progressbar-percent|progressbar-fill-color|slider-value|slider-min-value|slider-max-value|slider-step-size|slider-orientation|spacer-size|scrollbar-thickness|scrollbar-orientation|checkbox-checked-state|checkbox-is-checked|editabletext-hint-text|editabletext-is-read-only|editabletext-is-password|editabletext-minimum-desired-width|editabletext-justification|editabletextbox-hint-text|editabletextbox-is-read-only|editabletextbox-is-password|editabletextbox-minimum-desired-width|editabletextbox-justification|multilineeditabletextbox-hint-text|multilineeditabletextbox-is-read-only|multilineeditabletextbox-justification|spinbox-value|spinbox-min-value|spinbox-max-value|spinbox-delta|comboboxstring-selected-option|comboboxstring-options|is-focusable|button-is-focusable|checkbox-is-focusable|slider-is-focusable|scrollbox-is-focusable|comboboxstring-is-focusable|listview-entry-widget-class|listview-orientation|listview-selection-mode|listview-consume-mouse-wheel|listview-is-focusable|listview-return-focus-to-selection|listview-clear-scroll-velocity-on-selection|listview-scroll-into-view-alignment|listview-wheel-scroll-multiplier|listview-enable-scroll-animation|listview-allow-overscroll|listview-enable-right-click-scrolling|listview-enable-touch-scrolling|listview-is-pointer-scrolling-enabled|listview-is-gamepad-scrolling-enabled|listview-horizontal-entry-spacing|listview-vertical-entry-spacing|listview-scrollbar-padding|tileview-entry-width|tileview-entry-height|tileview-scrollbar-disabled-visibility|tileview-entry-size-includes-entry-spacing|scrollbox-orientation|scrollbox-scrollbar-visibility|scrollbox-consume-mouse-wheel|sizebox-width-override|sizebox-width|sizebox-height-override|sizebox-height|sizebox-min-desired-width|sizebox-min-desired-height|sizebox-max-desired-width|sizebox-max-desired-height|sizebox-min-aspect-ratio|sizebox-max-aspect-ratio|scalebox-stretch|scalebox-stretch-direction|scalebox-user-specified-scale|scalebox-ignore-inherited-scale|wrapbox-wrap-size|wrapbox-explicit-wrap-size|wrapbox-inner-slot-padding|wrapbox-orientation|widgetswitcher-active-widget-index|retainerbox-retain-render|retainerbox-render-on-invalidation|retainerbox-render-on-phase|retainerbox-phase|retainerbox-phase-count|backgroundblur-strength|backgroundblur-apply-alpha-to-blur|safezone-pad-left|safezone-pad-right|safezone-pad-top|safezone-pad-bottom|invalidationbox-can-cache|uniformgridpanel-min-desired-slot-width|uniformgridpanel-min-desired-slot-height|uniformgridpanel-slot-padding|text-color-and-opacity|text-color|text-font|text-font-family|text-typeface|text-font-size|text-justification|text-auto-wrap-text|text-wrap-text-at|text-line-height-percentage|text-shadow-offset|text-shadow-color-and-opacity|text-outline-size|text-outline-color|button-normal-image|button-hovered-image|button-pressed-image|button-disabled-image|button-normal-tint|button-hovered-tint|button-pressed-tint|button-disabled-tint|button-normal-image-size|button-hovered-image-size|button-pressed-image-size|button-disabled-image-size|button-normal-draw-as|button-hovered-draw-as|button-pressed-draw-as|button-disabled-draw-as|menu-anchor-placement|button-background-color|button-color-and-opacity|border-padding|border-brush-color|border-content-color-and-opacity|border-horizontal-alignment|border-vertical-alignment|grid-row-fill|grid-column-fill|richtext-style-set|richtext-decorator-classes|richtext-override-default-style|richtext-default-font|richtext-default-font-family|richtext-default-typeface|richtext-default-font-size|richtext-default-color-and-opacity|richtext-default-shadow-offset|richtext-default-shadow-color-and-opacity|richtext-default-outline-size|richtext-default-outline-color|richtext-auto-wrap-text|richtext-wrap-text-at|richtext-line-height-percentage|richtext-justification|slot-padding|slot-size|slot-horizontal-alignment|slot-vertical-alignment|slot-row|slot-column|slot-row-span|slot-column-span|slot-layer|slot-nudge|layout-position|layout-size|layout-anchors|layout-alignment|layout-data> --value <value> [--export <n>] [--dry-run] [--backup]
Behavior
widget-read: reads WidgetBlueprint / WidgetTree hierarchy as normalized JSON, plus logical widget aggregation and high-level widget/slot summaries.widget-init: clones a validated empty WidgetBlueprint template into a new output asset and rewrites package/object identity; this is the default starting point for unspecified new-widget requests.widget-parent-class: rewrites the compiled/Script/...parent class on a rootless WidgetBlueprint before widgets are added.widget-add: creates a root container/content widget or inserts a bare child widget under supported panel/content parents.widget-remove: removes one non-root leaf widget from the logical WidgetTree and related WidgetBlueprint metadata.widget-write: updates one logical widget across designer/generated trees.- Do not repurpose or mutate an existing WidgetBlueprint unless the user explicitly identifies that asset as the edit target.
- Pair multi-step widget edits with
bpx validate <file.uasset>when you want a structural safety pass after a write chain.
[!CAUTION] This skill is write-heavy. Confirm intent and run
--dry-runfirst.
Supported Widgets
- Rootless start:
widget-init --template minimum, optionally followed bywidget-parent-classorwidget-init --parent-classwhile the asset still has no root widget. - Root / parent containers:
CanvasPanel,Overlay,VerticalBox,HorizontalBox,StackBox,ScrollBox,WrapBox,GridPanel,UniformGridPanel,WidgetSwitcher,ListView,TileView,TreeView,Button,CheckBox,Border,RetainerBox,InvalidationBox,MenuAnchor,NamedSlot,SizeBox,ScaleBox,BackgroundBlur,SafeZone, andWindowTitleBarArea. - Child widgets:
Image,TextBlock,RichTextBlock,ProgressBar,Slider,Spacer,ScrollBar,EditableText,EditableTextBox,MultiLineEditableTextBox,SpinBox,ComboBoxString,ListView,TileView,TreeView,CheckBox, anduserwidget. widget-add --type userwidgetexpects a WidgetBlueprint asset path like/Game/UI/WBP_Statusand instantiates the referencedWidgetBlueprintGeneratedClassas a child widget.- Parent-class rewrites currently accept compiled
/Script/...classes, including project/plugin module classes such as/Script/LyraGame.LyraActivatableWidget.
Supported Writes
- Universal reads/writes:
text,visibility,render-opacity,brush-image. - Basic widgets:
progressbar-percent,progressbar-fill-color,slider-value,slider-min-value,slider-max-value,slider-step-size,slider-orientation,spacer-size,scrollbar-thickness,scrollbar-orientation,checkbox-checked-state,checkbox-is-checked,editabletext-hint-text,editabletext-is-read-only,editabletext-is-password,editabletext-minimum-desired-width,editabletext-justification,editabletextbox-hint-text,editabletextbox-is-read-only,editabletextbox-is-password,editabletextbox-minimum-desired-width,editabletextbox-justification,multilineeditabletextbox-hint-text,multilineeditabletextbox-is-read-only,multilineeditabletextbox-justification,spinbox-value,spinbox-min-value,spinbox-max-value,spinbox-delta,comboboxstring-selected-option,comboboxstring-options,is-focusable,button-is-focusable,checkbox-is-focusable,slider-is-focusable,scrollbox-is-focusable,comboboxstring-is-focusable,listview-entry-widget-class,listview-orientation,listview-selection-mode,listview-consume-mouse-wheel,listview-is-focusable,listview-return-focus-to-selection,listview-clear-scroll-velocity-on-selection,listview-scroll-into-view-alignment,listview-wheel-scroll-multiplier,listview-enable-scroll-animation,listview-allow-overscroll,listview-enable-right-click-scrolling,listview-enable-touch-scrolling,listview-is-pointer-scrolling-enabled,listview-is-gamepad-scrolling-enabled,listview-horizontal-entry-spacing,listview-vertical-entry-spacing,listview-scrollbar-padding,tileview-entry-width,tileview-entry-height,tileview-scrollbar-disabled-visibility,tileview-entry-size-includes-entry-spacing,scrollbox-orientation,scrollbox-scrollbar-visibility,scrollbox-consume-mouse-wheel,sizebox-width-override,sizebox-width,sizebox-height-override,sizebox-height,sizebox-min-desired-width,sizebox-min-desired-height,sizebox-max-desired-width,sizebox-max-desired-height,sizebox-min-aspect-ratio,sizebox-max-aspect-ratio,scalebox-stretch,scalebox-stretch-direction,scalebox-user-specified-scale,scalebox-ignore-inherited-scale,wrapbox-wrap-size,wrapbox-explicit-wrap-size,wrapbox-inner-slot-padding,wrapbox-orientation,widgetswitcher-active-widget-index,retainerbox-retain-render,retainerbox-render-on-invalidation,retainerbox-render-on-phase,retainerbox-phase,retainerbox-phase-count,backgroundblur-strength,backgroundblur-apply-alpha-to-blur,safezone-pad-left,safezone-pad-right,safezone-pad-top,safezone-pad-bottom,invalidationbox-can-cache,uniformgridpanel-min-desired-slot-width,uniformgridpanel-min-desired-slot-height,uniformgridpanel-slot-padding. EditableText: generictextpluseditabletext-hint-text,editabletext-is-read-only,editabletext-is-password,editabletext-minimum-desired-width,editabletext-justification.EditableTextBox: generictextpluseditabletextbox-hint-text,editabletextbox-is-read-only,editabletextbox-is-password,editabletextbox-minimum-desired-width,editabletextbox-justification.MultiLineEditableTextBox: generictextplusmultilineeditabletextbox-hint-text,multilineeditabletextbox-is-read-only,multilineeditabletextbox-justification.SpinBox:spinbox-value,spinbox-min-value,spinbox-max-value,spinbox-delta.ComboBoxString:comboboxstring-selected-option,comboboxstring-options,comboboxstring-is-focusable.TextBlock:text-color(-and-opacity),text-font,text-font-family,text-typeface,text-font-size,text-justification,text-auto-wrap-text,text-wrap-text-at,text-line-height-percentage,text-shadow-offset,text-shadow-color-and-opacity,text-outline-size,text-outline-color.Button: per-state brush image/tint/size/draw-as writes plusbutton-background-color,button-color-and-opacity, andbutton-is-focusable.Border:border-padding,border-brush-color,border-content-color-and-opacity,border-horizontal-alignment,border-vertical-alignment.GridPanel:grid-row-fill,grid-column-fill.RichTextBlock:richtext-style-set,richtext-decorator-classes,richtext-override-default-style,richtext-default-font,richtext-default-font-family,richtext-default-typeface,richtext-default-font-size,richtext-default-color-and-opacity,richtext-default-shadow-offset,richtext-default-shadow-color-and-opacity,richtext-default-outline-size,richtext-default-outline-color,richtext-auto-wrap-text,richtext-wrap-text-at,richtext-line-height-percentage,richtext-justification.- Slot/layout writes:
slot-padding,slot-size,slot-horizontal-alignment,slot-vertical-alignment,slot-row,slot-column,slot-row-span,slot-column-span,slot-layer,slot-nudge,layout-position,layout-size,layout-anchors,layout-alignment,layout-data.
Known Gaps
widget-moveandwidget-cloneare not implemented.widget-removeis intentionally narrow: non-root leaf widgets only.- Broader
RichTextBlockstyling such as strike brushes, transform policy, and material-backed font overrides is not implemented yet. - CommonUI-specific widget/property writers are not implemented yet.
widget-parent-classis intentionally narrow: rootless WidgetBlueprints only, and compiled/Script/...parent classes only.
Recommended Workflow
- If the user asks to create a widget without explicitly naming an existing
.uassetto edit, treat it as a new-widget request and start frombpx blueprint widget-init ... --template minimum. - Do not choose an existing WidgetBlueprint as a base asset unless the user explicitly asks to modify that specific widget.
- Start a new widget with
bpx blueprint widget-init ... --template minimumso BPX clones a validated empty WidgetBlueprint. If the widget should inherit a compiled project/plugin class, set it before adding the root widget with--parent-class /Script/...orwidget-parent-class --class /Script/.... - Run widget-building commands sequentially on the same asset. Do not parallelize
widget-init,widget-parent-class, repeatedwidget-add/widget-remove, orwidget-writesteps. - Add exactly one root container with
widget-add --parent root. The common choices arecanvaspanel,overlay,verticalbox,horizontalbox,scrollbox,sizebox,border, orbuttondepending on layout intent. - Add child widgets under that parent with
widget-add --parent <panel>and keep names unique. Use--type userwidget --class /Game/.../WBP_Namewhen the user wants to compose with another WidgetBlueprint. - For nested multi-child layouts, build the tree in exact order and switch to full widget paths as soon as siblings exist. A proven sequence is
root -> CanvasPanel -> Image1 -> Image2 -> Overlay -> Image3. - After each nested
widget-add, re-runwidget-readand confirm the new logical path exists before continuing. This catches regressions like a missing second child underCanvasPanelorOverlayearly. - Fill in appearance after structure. Common writes are
layout-data,slot-*,brush-image,text,text-color,text-font-family,text-font-size,text-auto-wrap-text,progressbar-percent,slider-value,checkbox-is-checked,sizebox-width, andscrollbox-orientation. - Use
widget-removeonly for non-root leaf cleanup after confirming the exact path withwidget-read. - Keep the order stable: later widget commands depend on the export/name/import state produced by earlier ones.
- Re-check the tree with
widget-read; usevalidatewhen you want an extra safety pass after a multi-step edit chain. - Treat
testdata/golden/ue5.6/operations/widget_add_image_nested_overlayas the ground-truth fixture for nestedCanvasPanel -> Overlay -> Imagebehavior. If a fresh asset differs or opens badly in UE, compare against that operation first. --package-pathis a directory like/Game/UI, not a full asset path like/Game/UI/WBP_Login. When the destination is already under a UEContentdirectory, keep--package-path/--asset-namealigned with that filesystem location.brush-imageexpects a UE package path like/Game/UI/T_Icon, not a filesystem path likeC:\Textures\Icon.png.- If your shell rewrites
/Game/...arguments (for example Git Bash/MSYS), disable path conversion for those arguments first.
Worked Recipe
export MSYS_NO_PATHCONV=1
bpx blueprint widget-init ./Content/WBP_Status.uasset --template minimum --asset-name WBP_Status --package-path /Game
bpx blueprint widget-add ./Content/WBP_Status.uasset --parent root --type canvaspanel --name Canvas_Root
bpx blueprint widget-add ./Content/WBP_Status.uasset --parent Canvas_Root --type image --name Image_Circle
bpx blueprint widget-add ./Content/WBP_Status.uasset --parent Canvas_Root --type image --name Image_Square
bpx blueprint widget-add ./Content/WBP_Status.uasset --parent Canvas_Root --type textblock --name Text_Label
bpx blueprint widget-write ./Content/WBP_Status.uasset --widget Canvas_Root/Image_Circle --property brush-image --value /Game/Textures/Circle
bpx blueprint widget-write ./Content/WBP_Status.uasset --widget Canvas_Root/Image_Square --property brush-image --value /Game/Textures/Square
bpx blueprint widget-write ./Content/WBP_Status.uasset --widget Canvas_Root/Text_Label --property text --value "Hello World"
bpx blueprint widget-read ./Content/WBP_Status.uasset
bpx validate ./Content/WBP_Status.uasset
export MSYS_NO_PATHCONV=1
bpx blueprint widget-init ./Content/WBP_MenuRoot.uasset --template minimum --asset-name WBP_MenuRoot --package-path /Game/UI --parent-class /Script/LyraGame.LyraActivatableWidget
bpx blueprint widget-add ./Content/WBP_MenuRoot.uasset --parent root --type overlay --name Overlay_1
bpx blueprint widget-add ./Content/WBP_MenuRoot.uasset --parent Overlay_1 --type userwidget --class /Game/UI/WBP_Status --name WBP_Status_1
bpx blueprint widget-write ./Content/WBP_MenuRoot.uasset --widget Overlay_1/WBP_Status_1 --property slot-horizontal-alignment --value fill
bpx blueprint widget-read ./Content/WBP_MenuRoot.uasset
bpx validate ./Content/WBP_MenuRoot.uasset
export MSYS_NO_PATHCONV=1
bpx blueprint widget-init ./Content/WBP_NestedStatus.uasset --template minimum --asset-name WBP_NestedStatus --package-path /Game
bpx blueprint widget-add ./Content/WBP_NestedStatus.uasset --parent root --type canvaspanel --name CanvasPanel_1
bpx blueprint widget-add ./Content/WBP_NestedStatus.uasset --parent CanvasPanel_1 --type image --name Image_1
bpx blueprint widget-add ./Content/WBP_NestedStatus.uasset --parent CanvasPanel_1 --type image --name Image_2
bpx blueprint widget-add ./Content/WBP_NestedStatus.uasset --parent CanvasPanel_1 --type overlay --name Overlay_1
bpx blueprint widget-add ./Content/WBP_NestedStatus.uasset --parent CanvasPanel_1/Overlay_1 --type image --name Image_3
bpx blueprint widget-read ./Content/WBP_NestedStatus.uasset
bpx validate ./Content/WBP_NestedStatus.uasset
- The first recipe is the preferred happy-path for "new widget + CanvasPanel + Image x2 + TextBlock x1".
- The second recipe shows the safe parent-class-first flow for project/plugin widget bases plus child
userwidgetcomposition. - When the request is simply "make a widget" and no existing target asset is named, use this
widget-init-first flow instead of editing a pre-existing WidgetBlueprint. - The third recipe is the regression-sensitive nested path that should yield
CanvasPanel_1,CanvasPanel_1/Image_1,CanvasPanel_1/Image_2,CanvasPanel_1/Overlay_1, andCanvasPanel_1/Overlay_1/Image_3inwidget-read. - Do not insert manual
name addsteps in the normal widget workflow.widget-addandwidget-write --property brush-imageare expected to manage required names/imports themselves. - If a freshly built
widget-initasset still reports missing NameMap/import-add names, treat that as a stale binary/build mismatch and updatebpxinstead of patching NameMap by hand. - Use full widget paths like
Canvas_Root/Image_Circleonce the tree has more than one child; that avoids ambiguous selectors and keeps later writes aligned with the intended widget. - In the nested recipe, use the full path
CanvasPanel_1/Overlay_1for the final add. Do not rely on bareOverlay_1once siblings already exist underCanvasPanel_1. - If a nested asset passes BPX
validatebut still behaves differently in UE, diff it againstwidget_add_image_nested_overlaybefore hand-editing NameMap, imports, or GeneratedClass data.
Code-Aligned Caveats
- On a normal
widget-init->widget-addflow, you should not need manualname addbefore inserting widgets. - If
widget-addon a fresh widget reports missing NameMap/import-add names, suspect a stalebpxbinary rather than treating manual NameMap surgery as standard workflow. - Nested multi-child panels can appear in
WidgetVariableNameToGuidMapwithout appearing inGeneratedVariablesorPropertyGuids.widget_add_image_nested_overlayis the reference case:Overlay_1is real and valid there even though it does not become a generated class field. widget-parent-classis only safe before a root widget exists. Once the WidgetBlueprint has a root/widget tree, change the structure instead of trying to reparent the class in place.widget-add --type userwidgetexpects a WidgetBlueprint asset path like/Game/UI/WBP_Status, not a generated-class path like/Game/UI/WBP_Status_C.widget-removeis conservative by design: it supports only non-root leaf widgets and only compacts orphan export/import/name entries when the remaining references validate cleanly.- BPX structural
validateis necessary but not sufficient for UE-openability on newly generated nested widgets. If the editor still crashes or refuses to open, compare bothwidget-readoutput and the binary delta against the UE-authored nested fixture before widening BPX special-cases.
High-Signal Examples
bpx blueprint widget-init ./Content/WBP_Login.uasset --template minimum --asset-name WBP_Login --package-path /Game/UI
bpx blueprint widget-add ./Content/WBP_Login.uasset --parent root --type canvaspanel --name Canvas_Root
bpx blueprint widget-add ./Content/WBP_Login.uasset --parent Canvas_Root --type image --name Image_Logo
bpx blueprint widget-write ./Content/WBP_Login.uasset --widget Canvas_Root/Image_Logo --property brush-image --value /Game/UI/T_Logo
Signals
- GitHub stars
- 100
- Forks
- 8
- Last commit
- Jun 2026
Advanced
- Item type
- skill
- Key
bpx-widget- Source
- github.com/wilddogjp/openbpx