Custom Interfaces
Build an interface scene from components, wire buttons and inputs to server actions, drive it from an interface script, and share it via the cloud library.
9 min read
What a custom interface is#
A custom interface is a scene you design in the GUI Editor and open from a server script: a shop window, a quest log, a bank, a scoreboard, a tab panel. The scene holds the layout and styling; the server owns all of the behavior. You name the nodes the server needs to address, mark the widgets that should report back, and write the handling in a small C# interface script that the editor generates for you.
This page walks through the full loop: create, build, wire, script, test, and share.
Creating an interface#
- Open the GUI Editor and, in the main menu, browse to the library folder you want the new interface filed under.
- Click + Game Screen for an overlay window (600 x 400 canvas) or + Tab Interface for a side-tab panel (256 x 308 canvas). Tab interfaces are explained on Tabs.
- In the Create New Interface dialog, type a Name and confirm the Interface Type, then click Create. The Chatbox type is shown as Coming Soon and cannot be selected.
The interface opens in a new tab with an empty root control. Its file is written on the first Ctrl+S to assets/interface/screens/<name>.tscn (or screens/tabs/<name>.tscn for a tab), filed into the library folder you were browsing.
Building the layout#
Adding components#
The Components panel along the bottom lists component types in three categories. Click a type, choose a configuration card, then double-click the card or click + Add Component. The new node is added as a child of the selected node (or the root).
| Category | Type | Choices |
|---|---|---|
| Layout | Panel | Panel, Image |
| Layout | Container | Vertical, Horizontal, Grid, ScrollContainer |
| Content | Label | Regular, Rich Text, Input |
| Content | Button | Text, Toggle, Dropdown |
| Misc | Misc | Dropdown, ProgressBar, ItemSlot, ItemGrid, ModelViewer, NodeSpawner, Tooltip |
For any other Godot control, press the + button in the Scene Tree header (or right-click a node and choose Add Child Node) to open the Add Node dialog, which offers the full list: Control, Container, CenterContainer, HBoxContainer, VBoxContainer, GridContainer, HSplitContainer, VSplitContainer, MarginContainer, PanelContainer, ScrollContainer, TabContainer, AspectRatioContainer, HFlowContainer, VFlowContainer, Button, LinkButton, OptionButton, MenuButton, CheckBox, CheckButton, ColorPickerButton, TextureButton, Label, LineEdit, TextEdit, RichTextLabel, CodeEdit, Panel, ColorRect, TextureRect, NinePatchRect, ProgressBar, HSlider, VSlider, HScrollBar, VScrollBar, SpinBox, ItemList, Tree, GraphEdit, TabBar and SubViewportContainer.
Moving and arranging nodes#
The toolbar's V, G and R buttons (keys V, G, R) switch between select, move and rotate. Snap is on by default with a 5 px grid; Grid shows the grid lines; the spin box sets the snap size from 1 to 50 px. Pick lets you choose among stacked nodes under the cursor, and Lock (L) freezes the selected node against accidental drags. Arrow keys nudge the selection by 1 px, or by one snap step with Shift.
Right-click a node in the canvas or the Scene Tree for the context menu:
| Item | Shortcut |
|---|---|
| Add Child Node | — |
| Cut / Copy / Paste Inside / Paste as Sibling | Ctrl+X / Ctrl+C / Ctrl+V / Ctrl+Shift+V |
| Duplicate | Ctrl+D |
| Rename | F2 |
| Move Up / Move Down | — |
| Bring to Front / Send to Back | Ctrl+Shift+] / Ctrl+Shift+[ |
| Align (Left, Center, Right, Top, Middle, Bottom, Distribute Horizontally, Distribute Vertically, Center in Parent) | — |
| Delete | Delete |
| Save as Template | — |
Ctrl+] and Ctrl+[ raise and lower a node one step. Ctrl+Z and Ctrl+Y undo and redo.
The Properties panel#
Selecting a node shows collapsible sections on the right. Which ones appear depends on the node:
| Section | Applies to | Contents |
|---|---|---|
| Node Info | All | Name (locked on the root) and type. |
| Interface Root | The root only | Always Show bounds, Close on Esc. |
| Display | All | Visible, Opacity, Tooltip, Mouse (Stop / Pass / Ignore), Clip. |
| Layout | All | Anchor preset picker; non-root nodes also get an Advanced (Anchors & Offsets) editor. |
| Transform | Non-root | Position, Size, Min Size. |
| Style | Styled nodes | Background, border, corner radius, font color and per-state styles. |
| Label, Rich Text, Line Edit, Text Edit, Button, Toggle, Panel, Image, Slider, Progress Bar | Matching node types | Type-specific content and presets. |
| Container, Child Sizing | Containers and their children | Layout direction, gap, padding, scroll, background; size flags for children. |
| Interaction Options | Interactive nodes | Server wiring, described below. |
| Item Slot, Node Spawner, Tooltip, Model Viewer | The matching widgets | Widget settings, described below. |
The root's Layout anchor preset decides where the whole window docks on the player's screen. Drag the root in the Resizable view mode to set an offset from that anchor.
Wiring widgets to the server#
Interactive nodes get an Interaction Options section. There are two wiring styles.
Buttons, panels, labels, images and item slots: context options#
These nodes carry a list of options, each with a Label and an action_id. Click + Add Option to add a row — it only adds one on a button; on a panel, label, image or item slot you can edit and remove the options already there but not add new ones. Use ^ to move an option up and x to remove it. The first option is what a left-click sends; a right-click shows all options as a menu. Use this for "Buy", "Examine", "Withdraw 10" style actions on an item slot, or a single "Close" action on a button.
Toggles, dropdowns, text inputs and sliders: direct actions#
CheckBox, CheckButton, OptionButton, LineEdit, TextEdit, HSlider, VSlider and SpinBox send one action directly:
| Field | Meaning |
|---|---|
| Action ID | The string your script receives, for example submit_chat. |
| Trigger | Only the triggers that fit the node are offered: toggled for toggles, text_submitted or text_changed for text inputs, value_changed for sliders and spin boxes. A dropdown has no Trigger field — it always sends on item_selected. |
| Debounce (ms) | Text inputs with text_changed only: wait this long after typing stops before sending (default 300). |
| Data Source | Optional. |
The node's current value travels with the action: the text for inputs, true/false for toggles, the number for sliders. A dropdown instead lists its options as Label / Data pairs under + Add Option and sends the selected option's data.
Testing without the server#
Click Preview on the toolbar. A sacrificial copy of the interface takes input, item slots fill with sample items, spawners show three clones of their template, and a log in the top-left corner prints each action the client would send, such as action: buy (pressed). Edits are paused until you toggle Preview off; saving or switching tabs also ends it.
The interface script#
Click Script on the tab bar. The editor creates server/scripts/interfaces/<Name>Script.cs if it does not exist and opens it in the Script Editor. The stub implements IInterfaceScript:
public class ShopWindowScript : IInterfaceScript
{
public string[] InterfaceNames => new[] { "shop_window" };
public async Task OnOpen(ScriptPlayer player, int interfaceId)
{
// Example: await player.SetInterfaceText(interfaceId, "Title", "Hello!");
}
public async Task OnAction(ScriptPlayer player, int interfaceId, string actionId, string actionData)
{
switch (actionId)
{
case "buy":
// BuyButton (Button) - trigger: pressed
break;
}
}
public async Task OnClose(ScriptPlayer player, int interfaceId) { }
}
One case is generated per action ID found in the scene at the time. Tab interfaces can also implement OnLogin(ScriptPlayer player, int interfaceId), called at login for interfaces of type tab.
Open the interface from any script or module with await player.OpenInterface("shop_window"). Pass a mode as the second argument, OpenInterface("hud", 3), for a walkable interface that stays open while the player moves. Close it with CloseInterface.
Calls available on ScriptPlayer to drive the open interface:
| Call | Effect |
|---|---|
SetInterfaceText(id, node, text) | Set a label, button or input's text. |
SetInterfaceVisible(id, node, visible) | Show or hide a node. |
SetInterfaceTransform(id, node, x, y) | Move a node. |
SetInterfaceTexture(id, node, spriteName) | Swap an image. |
SetInterfaceValue(id, node, value) | Set a progress bar, slider, spin box or dropdown value. |
SetInterfaceEnabled(id, node, enabled) | Enable or disable a control. |
SetInterfaceItem(id, node, itemId, amount) | Fill one item slot. |
SetInterfaceItems(id, container, items) | Fill an item grid in one call; slots are numbered from 0 in tree order. |
SpawnInterfaceNode(id, node, amount) | Append copies of a spawner's template. |
SetInterfaceModel(id, node, kind, refId, animation) | Show an NPC, NPC head or item in a Model Viewer. |
Nodes are addressed by name or by path relative to the root. See NPC, object and interaction scripts and the script API reference.
Widgets#
| Widget | Settings | Runtime |
|---|---|---|
| Item Slot | Slot Size 32, 48 or 64 px; Background, Quantity and Tooltip toggles. | Filled by SetInterfaceItem; its context options fire when clicked. |
| Item Grid | A grid of item slots named Slot0, Slot1, and so on. | Filled by SetInterfaceItems. |
| Node Spawner | Layout Horizontal, Vertical or Grid, with Columns for grids. The first child is the template and is hidden in game. | SpawnInterfaceNode appends clones; chat logs and lists. |
| Tooltip | Title, subtitle and description labels. | Place it as a child of the node to describe; hidden until hovered. |
| Model Viewer | Kind npc, npc_head or item; Ref ID; Animation (default idle). | The server can override with SetInterfaceModel. |
| Progress Bar | Value and range. | Updated with SetInterfaceValue. |
Templates#
Right-click any node and choose Save as Template to store its subtree as assets/interface/screens/templates/<name>.tscn. A Templates category then appears at the top of the Components panel. Select a template and click + Add Detached for an editable copy, or + Add Linked to keep it tied to the template file with its children locked; a linked instance shows a Linked Template section with Detach from Template. Delete Template removes the file.
Sharing through the cloud library#
Finished interfaces and templates can be published for other creators, and installed from them.
- Click Library in the top bar and stay on the Store view.
- Open the 2D category, then GUI Interfaces (complete screens) or GUI Templates (reusable parts).
- Click Share an Interface... or Share a Template.... Sign in if prompted.
- Choose the scene from the dropdown, set the name it will have in the library, and click Share.
The upload bundles the scene with any project images it references. To use someone else's, open a card and click Add to Project; the scene is installed into the matching folder of your project and appears in the GUI Editor's library, or in its template list for templates. An install that would overwrite an existing file is cancelled rather than renamed. Your own uploads are listed under Creations. See Cloud library.
With AI (MCP)#
define_interface authors a screen headlessly from a node tree (panels, labels, buttons, containers, item slots and grids, progress bars, spawners, checkboxes, line edits and textures, with action_id and context_options on nodes). It files the scene by type into the same folders the editor uses, assigns or preserves the interface ID, and updates both copies of interface_database.json. Call get_interface first when changing an existing screen, because define_interface replaces the whole scene. list_interfaces and delete_interface round out the set. The running client sees a new scene after the next Dev Test or Play Local. See MCP tools reference.
