Choose an approach#
For a small setting, consider a settings menu API. To add a card or action to an existing menu, start with extending the standard UI. A custom window can use Helper to create a frame, table, rows and widgets, then display it. Python and a network service are not required.
Register Lua#
Declare the Lua file in your extension's ui.xml, as shown below. Wait until Helper and the game UI are ready before opening the window. Loading a Lua file does not mean the world and every menu already exist.
<addon name="wiki_panel">
<environment type="menus">
<file name="ui/wiki_panel.lua" />
</environment>
</addon>Build the window#
The ui/wiki_panel.lua example registers its menu once. A separate event opens the panel after UI readiness. It creates a frame on layer 3, adds a table and text, binds a Close button and displays the frame. Check internal callbacks and layer usage against the current game UI.
The MD raise_lua_event fragment belongs inside an existing actions block. Your mod supplies the trigger, such as a working button or event. The example does not install a hotkey automatically.
local menu = { name = "WikiExamplePanel" }
menu.onViewCreated = function() end
menu.onRowChanged = function() end
menu.onSelectElement = function() end
function menu.onCloseElement()
if menu.shown then
Helper.clearFrame(menu, 3)
menu.shown = false
end
end
Menus = Menus or {}
table.insert(Menus, menu)
Helper.registerMenu(menu)
local function showPanel()
if menu.shown then return end
local width = Helper.scaleX(480)
local height = Helper.scaleY(150)
local frame = Helper.createFrameHandle(menu, {
layer = 3,
x = (Helper.viewWidth - width) / 2,
y = (Helper.viewHeight - height) / 2,
width = width, height = height,
standardButtons = {},
startAnimation = false,
playerControls = true,
})
local t = frame:addTable(1, { tabOrder = 1, width = width })
local title = t:addRow(false, {})
title[1]:createText("Hello, X4!", { fontsize = 14 })
local row = t:addRow(true, {})
row[1]:createButton({ height = 28 }):setText("Close")
row[1].handlers.onClick = menu.onCloseElement
menu.shown = true
frame:display()
end
RegisterEvent("Wiki.ShowPanel", function()
showPanel()
end)<raise_lua_event name="'Wiki.ShowPanel'" />Verify the lifecycle#
Repeated opening must not accumulate callbacks. Test the Close button, Escape/controller behavior, menu changes and save loading. A table with insufficient height can disappear entirely. Do not clear another menu's frame or alter global player control just to display text. This template illustrates Helper forms and has not been separately tested in game across X4 versions.