Panel¶
A nine-sliced frame containing other elements. Use it for callouts, boxed asides or anything that needs a border around a group of content.
{
"Type": "Panel",
"TexturePath": "Assets/PeacefulEnd.Parchment/panelFrame2",
"TextureSourceRectangle": { "X": 0, "Y": 0, "Width": 24, "Height": 24 },
"Sizing": "Fill",
"Alignment": "Center",
"Scale": 4,
"Children": [
{ "Type": "Paragraph", "Text": "Pitch on level ground.", "Alignment": "Center" }
]
}
Children stack inside the panel exactly as they do on a page, and the panel is as tall as they need unless you set Height.
Panel fields¶
| Property | Type | Default | Description |
|---|---|---|---|
Children optional |
list of elements |
empty list | The panel's contents, stacked top to bottom. Panels can contain panels. |
Background optional |
list of elements |
— | Elements drawn behind Children, placed at their own Position inside the panel rather than stacked. These never change the panel's size. |
Foreground optional |
list of elements |
— | Elements drawn over Children, placed the same way. |
Padding optional |
int |
0 |
Extra space between the frame's inner edge and the children, in unscaled sprite pixels × Scale. 0 means flush against the inside of the border. You don't need to account for the border's thickness yourself. |
Sizing optional |
sizing mode |
Fill |
How wide the panel is. ShrinkToFit hugs the widest child. |
Width optional |
int? |
— | The content width in unscaled sprite pixels × Scale. The border and padding are added around it. Required when Sizing is Fixed. |
Height optional |
int? |
— | The content height in unscaled sprite pixels × Scale. When omitted, the panel is as tall as its children need. When set, it's exactly this tall and children that would stack past it are dropped. Independent of Sizing, which only controls width. |
Background and Foreground¶
A panel takes its own placed layers, working the same way a page's Background and Foreground do. Children stack, while these two sit wherever their Position puts them:
{
"Type": "Panel",
"TexturePath": "{{ModId}}/panelFrame2",
"TextureSourceRectangle": { "X": 0, "Y": 0, "Width": 24, "Height": 24 },
"Scale": 4,
"Padding": 4,
"Background": [
{
"Type": "Image",
"TexturePath": "{{ModId}}/watermark",
"TextureSourceRectangle": { "X": 0, "Y": 0, "Width": 32, "Height": 32 },
"Alignment": "Center",
"VerticalAlignment": "Middle"
}
],
"Children": [
{ "Type": "Paragraph", "Text": "Pitch on level ground.", "Alignment": "Center" }
],
"Foreground": [
{
"Type": "Image",
"TexturePath": "{{ModId}}/seal",
"TextureSourceRectangle": { "X": 0, "Y": 0, "Width": 16, "Height": 16 },
"Alignment": "Right",
"VerticalAlignment": "Bottom"
}
]
}
Draw order is Background, then Children, then Foreground.
Both layers are anchored to the panel's content area, the same rectangle the children occupy, so the border and Padding inset them exactly as they inset a child. Alignment and VerticalAlignment anchor the element within that area first and Position is then an offset from that anchor, matching how a page's layers behave.
A placed layer can't size the panel
A ShrinkToFit panel hugs its widest child, and a panel without Height is as tall as its children need. Neither layer contributes, since the panel has to know its own size before it can place anything inside it. A background wider than the panel is simply clipped by nothing (it draws past the frame). Size the panel with Width and Height when the layer is what matters.
A panel with no Children reserves no space
A panel whose only content is placed measures no height at all, so whatever stacks after it draws over the top. The layers themselves are fine: they draw where you put them and the cursor reaches them normally.
Give the panel a Height when it should hold space open for itself. Parchment logs a trace message when it spots this, so check your SMAPI log with trace output on if a panel isn't pushing the next element down.
Placed elements are only reachable by the cursor when they have something to offer, such as a Description, DisplayName or an Action. Purely decorative art in either layer passes the cursor through to the children beneath it, which holds regardless of whether the panel itself is in a page's stacked Elements or in one of its layers.
The panel itself is reachable in the stacked list whatever it holds, so a panel with no tooltip of its own still claims the cursor over its own padding. Set IgnoreCursor on it to hand that back to whatever is drawn beneath, without affecting the children.
Sprite fields¶
TexturePath is optional. A panel without one is an invisible container, which is a fine way to group and indent content.
The texture must nine-slice: the border is a third of the shorter side, and the middle stretches. For a 24×24 frame that's 8-pixel corners and an 8×8 middle. Keep the visible border inside those corners and the middle flat, or the stretch will smear whatever detail crosses the boundary (see Preparing your art).
SpriteEffects is ignored. A nine-sliced frame has no meaningful flip.
| Property | Type | Default | Description |
|---|---|---|---|
TexturePath optional |
string |
— | The asset name of the sprite sheet, such as Assets/PeacefulEnd.Parchment/panelFrame2 or a vanilla path like LooseSprites/Cursors. This is a game asset name, not a file path in your content pack. Load your PNG into the game's content with a Content Patcher Load patch first. See Loading your art. |
TextureSourceRectangle optional |
Rectangle |
the whole texture | The area of the sprite sheet to draw. Almost always needed: without it, the whole sheet is used, which for a multi-sprite sheet means a much larger element than you expect. |
HoverTextureSourceRectangle optional |
Rectangle? |
— | An alternate source rectangle drawn while the cursor is over the element. Must be the same size as TextureSourceRectangle. The element's layout is measured from the normal rectangle, so a differently-sized hover sprite will overhang its own bounds. For a moving hover state on an Image, use HoverFrames instead. |
TintColor optional |
color |
white | A color multiplied into the sprite. Multiplying means it can only darken: red on grey art gives red, red on blue art gives near-black. Best on neutral or greyscale art. |
SpriteEffects optional |
None | FlipHorizontally | FlipVertically |
None |
Mirrors the sprite within its own bounds. It does not move the element. If flipping appears to shift the art sideways, the sprite has uneven transparent padding inside its source rectangle. Combine with a comma: "FlipHorizontally, FlipVertically". Ignored by Panel and Button, which are nine-sliced. |
Common fields¶
Scale on a Panel is the sprite scale, and it drives the border's thickness: a 24×24 frame at Scale: 4 has a 32-pixel border. To thicken the frame without inflating the panel, raise Scale and lower Padding.
| Property | Type | Default | Description |
|---|---|---|---|
Type required |
element type |
— | Which kind of element this is. Determines every other field below. |
Id optional |
string |
— | An optional identifier for this element. Not used for navigation, purely for your own reference. |
Alignment optional |
Left | Center | Right |
Left |
Where the element sits within its container's width. Only has an effect when the element is narrower than the space available (see Layout). In a placed list it anchors the element and Position is measured from there. |
VerticalAlignment optional |
Top | Center | Bottom |
Top |
Where the element sits within its container's height. Only used in Background, Foreground, Underlay and Overlay, since a stacked element takes its vertical position from the elements above it (see Placed elements). Setting it on a stacked element logs an error and does nothing. |
Scale optional |
number |
1 |
The element's scale. Its meaning depends on the element type: sprite scale for Image, Panel, Banner, Button and Divider. Font scale for Title, Heading and Paragraph. See Units and scale. |
SpacingAfter optional |
int |
8 |
The gap between this element and the next one, in unscaled sprite pixels × Scale. Not applied after the last visible element, so a trailing gap can't appear at the bottom of a page or panel. |
MarginLeft optional |
int |
0 |
Space reserved to the element's left, in unscaled sprite pixels × Scale. This narrows the width the element measures against, so text wraps at the indented width rather than overflowing. |
MarginRight optional |
int |
0 |
Space reserved to the element's right, in unscaled sprite pixels × Scale. |
Position optional |
Point |
{ X: 0, Y: 0 } |
The element's position, in screen pixels. Only used in Background, Foreground, Underlay and Overlay, where elements are placed rather than stacked. Measured from wherever Alignment and VerticalAlignment anchor the element, so under the default Left and Top it's a plain coordinate (see Placed elements). Unlike every other spacing field this is not multiplied by Scale. Changing an element's scale resizes it in place rather than moving it. |
Condition optional |
string |
— | A game state query. When it evaluates false the element is hidden, and elements below it close the gap. Re-checked several times a second while the book is open. Understands tokens. |
Lifetime optional |
number |
— | Seconds the element stays up once shown. Setting it makes the element a timed one: hidden until a ShowElement action names it, so an Id is required. |
FadeAfter optional |
number |
— | Seconds before it starts fading, reaching nothing at the end of Lifetime. Needs Lifetime, and must be below it. |
IgnoreCursor optional |
bool |
false |
Lets the cursor pass straight through the element to whatever sits beneath it, so it can't be hovered or clicked. Its children and its own Background and Foreground are still reachable (see Passing the cursor through). |
Action optional |
string |
— | A trigger action run when the element is clicked. When set, the element becomes interactive: any element type can have one, not just Button. Understands tokens. |
Actions optional |
list of string |
— | Trigger actions run in order when the element is clicked. Combined with Action rather than replacing it, so an element with both runs Action first. Understands tokens. |
Sound optional |
string |
bigSelect |
The cue played when the element is clicked. Only used when Action or Actions is set, and played once however many actions run. Set to null for a silent click. |
HoverAction optional |
string |
— | A trigger action run when the cursor moves onto the element. Runs on entry, not while the cursor rests there. Sound doesn't apply. Understands tokens. |
HoverActions optional |
list of string |
— | Trigger actions run in order when the cursor moves onto the element. Combined with HoverAction rather than replacing it, so an element with both runs HoverAction first. Understands tokens. |
DisplayName optional |
string |
— | The bold title of the element's hover tooltip. Works in every list, including a page's Background and Foreground. Can carry tokens. |
Description optional |
string |
— | The body of the element's hover tooltip. Works in every list, including a page's Background and Foreground, where setting it is also what makes an otherwise decorative element reachable by the cursor. Ignored when IgnoreCursor is set, which logs a warning. Can carry tokens. |
Tags optional |
list of string |
— | Free-form markers other mods can read off whatever the cursor is over, such as Lookup Anything support. Tagging an element also makes it reachable by the cursor, since a tag is only useful on something that can be hovered. Ignored when IgnoreCursor is set. See Tags. |
ParseTokenizableStrings optional |
bool |
true |
Whether the game's [Token] tokenizable strings are resolved in this element's Text, DisplayName, Description, Condition and actions. Set it to false where a square bracket is meant as the character itself. |
Children are measured against the panel, not the page
A narrow panel's children wrap at the panel's inner width, and their Alignment is resolved within the panel. A centred heading inside a left-aligned narrow panel centres within the panel, which is correct, if briefly surprising.