MiliUI IntelliSense
VS Code/Lua Language Server support for MiliUI.
The extension contains editor-only LuaLS declarations for the public MiliUI API.
It does not install or modify the MiliUI game runtime.
Setup
Open either the external_lua_file folder itself or any parent workspace that
contains:
external_lua_file/
└─ MiliUI/
└─ init.lua
The extension detects MiliUI and enables its declaration library for the matching
workspace. When that setup changes the LuaLS library configuration, MiliUI
automatically restarts Lua Language Server so the declarations are picked up
immediately.
If the workspace already has .luarc.json or .luarc.jsonc, the extension
preserves existing workspace.library entries (for example Miliastra typings)
and adds the MiliUI library there because LuaLS gives that config file precedence
over VS Code's normal Lua settings.
You can also run these commands from the Command Palette:
MiliUI: Enable IntelliSense for Workspace
MiliUI: Disable IntelliSense for Workspace
MiliUI: Diagnose IntelliSense
The extension never changes the runtime under external_lua_file/MiliUI.
It updates only LuaLS editor configuration. Existing library entries are retained.
MiliUI: Diagnose IntelliSense opens a report showing the resolved
declaration-library path, whether VS Code settings / .luarc include it,
and the size of the project's real MiliUI/init.lua compared with the
Lua Language Server preload limit.
Large MiliUI runtime files and missing completions
LuaLS normally skips Lua files larger than workspace.preloadFileSize
(default 500 KB) when preloading workspace files. A beautified/formatted
MiliUI bundle can be larger than that even though the compact production
bundle works. If VS Code finds MiliUI/init.lua but UI.* methods don't
autocomplete after restarting, this is worth checking.
When the detected runtime exceeds the configured limit, MiliUI IntelliSense
shows one warning per runtime per VS Code session, and the diagnostic
report shows the file size and configured limit. This is a potential
workspace-loading cause, not a guarantee that every missing completion is
caused by file size.
Recommended: use the compact/production MiliUI bundle. If you need the
larger formatted file, increase LuaLS's limit (e.g. to 2048 KB), then
restart Lua Language Server:
// .vscode/settings.json — when there is no .luarc config
{
"Lua.workspace.preloadFileSize": 2048
}
When using .luarc.json or .luarc.jsonc, put
"workspace.preloadFileSize": 2048 in that file instead, without
the Lua. prefix; .luarc takes priority over VS Code Lua settings.
Increasing the limit can increase LuaLS memory usage. The extension
never changes the setting or your MiliUI/init.lua automatically.
MiliUI normally restarts Lua Language Server automatically when its library path
is first added or changed. If hover/signature information still looks stale:
Ctrl+Shift+P
→ Lua: Restart Language Server
Beginner-friendly help across all components
The hover library explains parameters and return values across the MiliUI
API, including Buttons, layout helpers, scrolling, animation, native controls,
Pages, and data lists. Each function's argument list uses its real LuaLS type.
You do not need to memorize its settings: hover the function or press
Ctrl+Space inside a component's { ... } table to explore them.
Note: internal CoreAPI helper types also appear for accurate editor
hints. For a new game, start with the documented UI.* functions.
Native Miliastra controls use the engine's own API.
Discovering table arguments before typing braces
MiliUI IntelliSense now suggests Insert settings table { ... } when the
next function argument expects a Lua settings table. You do not need to know
what a custom MiliUI type name means before using it.
For example, after the comma in:
UI.Navigation.Reset(MAIN_PAGE, )
press Ctrl+Space. Choose Insert options settings table { ... } to
insert a valid example with a slide transition and duration. Move the cursor
inside the braces and press Ctrl+Space again to see available property
names and their explanations from Lua Language Server.
The same suggestion is generated from the installed MiliUI declarations for
other functions that accept typed settings tables, including Buttons, Pages,
and more. Unknown required IDs and project-specific settings are not
invented: the snippet leaves those tables empty for you to fill in.
options? means the argument can be left out. The MiliUI.*Options or
MiliUI.*Props name tells the editor which settings the table accepts;
you do not need to memorize those names.
Finding function parameters in hover help
Hover over a function such as UI.Pages.GetOpenPages to see what it does,
what values to pass, and what it returns. The hostId parameter is the Host
name from UI.Hosts.Attach, such as "Menu".
local pageIds = UI.Pages.GetOpenPages("Menu")
print(#pageIds) -- How many Pages are open in this Host?
After typing a function name and (, VS Code also shows its argument names.
For property suggestions inside UI.Button(parent, { ... }), put the cursor
inside the braces and press Ctrl+Space. Hover over an option for a plain
explanation and example. The full API details remain available in the
public MiliUI reference.
The extension provides this documentation to the editor only; it does not
change your game's runtime.
Reading MiliUI hover help
Hover over a UI.Button, UI.Row, or a property such as grow in VS Code
to see what it does, when to use it, and a small example where useful.
These are editor hints; the extension does not change your game.
A few layout ideas to know:
- Row: puts items next to each other, left to right.
- Column: stacks items top to bottom.
- gap: space between items.
gap = 12 means 12 UI units apart.
- padding: empty space inside a container, around its contents.
- grow: gives an item some leftover space. In a Row, it means extra width;
in a Column, it means extra height.
- align: places items across their Row/Column (Row: up/down; Column: left/right).
- justify: positions items along the Row/Column (start, center, end, or between).
- fitContent: lets a control choose a size based on its own text and children.
- responsive: changes layout automatically when the available parent space changes.
Reading the Lua examples
The examples use ordinary Lua variables. You do not need to know web development to use them.
local column = ... means create something and save it under the name column, so you can use it on later lines.
parent means an existing UI container where you want to put something. In your own script, use the actual container you already created.
UI.Column(parent, { ... }) creates a Column inside that parent. The values inside { } are its settings.
UI.Button(column, { ... }) creates a Button inside that Column. That is why the example passes column instead of parent.
fillWidth = true turns that setting on. fillWidth = false turns it off.
'Play' is text. Numbers such as 56 are sizes or other numeric settings, depending on the property.
Example:
local column = UI.Column(parent, {
width = 300,
gap = 8,
})
local playButton = UI.Button(column, {
label = { text = 'Play' },
fillWidth = true,
})
local settingsButton = UI.Button(column, {
label = { text = 'Settings' },
fillWidth = true,
})
This creates a Column 300 UI units wide, then creates two Buttons inside that Column. Each Button uses the available width of the Column.
Reading method calls and callbacks
Once an element has been created, you can call a method on it using a colon (:):
local button = UI.Button(parent, { label = { text = 'Play' } })
button:SetEnabled(false)
button is the name you gave the new Button. button:SetEnabled(false) tells that Button to stop accepting input. The : means you are calling a function that belongs to that particular Button.
Some methods return a value that you can save in a variable:
local currentValue = slider:GetValue()
Here, slider is an existing Slider. currentValue receives the Slider's current number.
A callback is a function you give MiliUI to run later, such as when the player clicks a Button:
local button = UI.Button(parent, {
label = { text = 'Play' },
onClick = function()
print('Button clicked')
end,
})
function() starts the code to run on a click, and end finishes that function. You do not have to run it yourself; MiliUI runs it after the click.
Other Lua terms you may encounter:
true / false: a setting is on or off.
nil: no value was supplied, or there is currently no matching item.
return: gives a result back from a function.
{ ... }: a table, used as a group of settings or a list of items.
- Index: an item's position in a Lua list. The first position is
1, not 0.
Example: controller focus indicator
local button = UI.Button(parent, {
label = { text = 'Play' },
controllerFocusIndicator = {
placement = 'inside-right',
gap = 8,
size = 20,
animation = false,
},
})
The controller focus indicator shows which Button is selected by a controller. 'inside-right' places it inside the right edge; 'right' places it outside the edge. gap changes its distance from the Button, size sets its width and height, and animation = false keeps it still.
If a hover also shows a comment beginning with --, that text may come from your own Lua script, not the MiliUI documentation.
local row = UI.Row(parent, { width = 500, height = 60, gap = 10 })
local backButton = UI.Button(row, {
label = { text = "Back" },
width = 120,
})
local continueButton = UI.Button(row, {
label = { text = "Continue" },
grow = 1, -- Takes the extra width left after Back and the 10-unit gap.
})
Both Buttons are inside a 500-unit-wide Row. The first requests 120 units,
the gap takes 10, and the second receives the available leftover width.
If you instead give two children grow = 1 and grow = 2, the
extra space is divided in a 1:2 ratio. grow = 0 does not request extra space.
Example: change layout when space becomes narrow
local controls = UI.Row(parent, {
gap = 12,
responsive = {
{ when = { maxWidth = 600 }, props = { direction = "vertical", gap = 8 } },
},
})
This normally puts children side by side, but stacks them above/below
each other when the available parent width is 600 UI units or less.
local list = UI.ScrollColumn(parent, {
width = 420,
height = 300,
gap = 8,
autoScrollOnControllerFocus = true,
})
UI.Button(list.column, {
label = { text = "Map One" },
controllerFocusIndicator = { placement = "right" },
})
When the controller selects a Button, the list scrolls to make it visible.
The focus indicator may extend beyond the list horizontally but still disappears
when the selected row scrolls off the top or bottom.
Terms found in hover descriptions
- UI units: coordinates/sizes in Miliastra's UI system; not necessarily physical screen pixels.
- native: functionality provided directly by Miliastra, rather than by MiliUI.
- Text Mapping ID: the name/key of a translated string in your project's text table.
- Host: one attached Client UI root; several pages can share the same Host.
- Session: values remembered while the same Lua session is alive, not saved to disk.
- 1-based index: Lua counts the first item as 1, not 0.
If an API shows unknown after installing the extension, try MiliUI:
Enable IntelliSense for Workspace, then Lua: Restart Language Server.
The editor library includes a type-only module for require("MiliUI/init"),
so you should not need to add ---@type MiliUI to every user script.
If a hover explanation still seems unclear, include the property name and
what you expected it to do when reporting it.