Entity GUI Library - Modder's Guide
This guide explains how to use Entity GUI Library to create custom entity GUIs for your Factorio mod.
Why Use This Library?
Creating custom entity GUIs requires handling:
- Frame creation and styling
- Titlebar with drag handle and close button
- Entity preview widget
- Status display
- GUI lifecycle (open/close events)
- E key to close
This library handles all of that, letting you focus on your custom content.
Quick Start
1. Add Dependency
In your info.json:
{
"dependencies": ["entity-gui-lib >= 0.1.1"]
}
2. Create Your Remote Interface
In your control.lua, define callbacks for building your GUI:
remote.add_interface("my_mod", {
build_inserter_gui = function(container, entity, player)
-- Add your custom GUI elements here
container.add{
type = "label",
caption = "Custom inserter interface",
style = "caption_label",
}
container.add{
type = "button",
name = "my_mod_rotate_button",
caption = "Rotate",
}
end,
close_inserter_gui = function(entity, player)
-- Optional: called when GUI closes
end,
})
3. Register Your Entity
local function register_guis()
remote.call("entity_gui_lib", "register", {
mod_name = "my_mod", -- Your remote interface name
entity_type = "inserter", -- Or entity_name for specific entities
title = "Custom Inserter", -- Optional custom title
on_build = "build_inserter_gui", -- Your callback name
on_close = "close_inserter_gui", -- Optional
})
end
script.on_init(register_guis)
script.on_load(register_guis)
4. Handle GUI Events
script.on_event(defines.events.on_gui_click, function(event)
if event.element.name == "my_mod_rotate_button" then
local entity = remote.call("entity_gui_lib", "get_entity", event.player_index)
if entity and entity.valid then
entity.rotate()
end
end
end)
That's it! The library handles the frame, titlebar, preview, status, and E key closing.
Advanced Features
Auto-Refresh for Live Data
For progress bars, energy levels, or other dynamic content:
remote.add_interface("my_mod", {
build_drill_gui = function(container, entity, player)
container.add{
type = "progressbar",
name = "my_progress",
value = entity.mining_progress or 0,
}
end,
update_drill_gui = function(content, entity, player)
-- Called every update_interval ticks
for _, child in pairs(content.children) do
if child.name == "my_progress" then
child.value = entity.mining_progress or 0
end
end
end,
})
remote.call("entity_gui_lib", "register", {
mod_name = "my_mod",
entity_type = "mining-drill",
on_build = "build_drill_gui",
on_update = "update_drill_gui",
update_interval = 10, -- Every 10 ticks (~6 times/sec)
})
Tabbed Interfaces
build_my_gui = function(container, entity, player)
local _, tabs = remote.call("entity_gui_lib", "create_tabs", container, {
{name = "main", caption = "Main"},
{name = "settings", caption = "Settings"},
})
-- Add content to tabs
tabs.main.add{type = "label", caption = "Main content"}
tabs.settings.add{type = "label", caption = "Settings content"}
end,
Confirmation Dialogs
-- In your remote interface
show_confirm = function(player_index, entity)
remote.call("entity_gui_lib", "show_confirmation", player_index, {
mod_name = "my_mod",
title = "Confirm Action",
message = "Are you sure?",
on_confirm = "do_action",
on_cancel = "cancel_action",
data = {entity = entity},
})
end,
do_action = function(player, data)
-- User clicked confirm
end,
cancel_action = function(player, data)
-- User clicked cancel
end,
Custom Preview Size
remote.call("entity_gui_lib", "register", {
mod_name = "my_mod",
entity_type = "accumulator",
on_build = "build_gui",
preview_size = 200, -- Default is 148
})
Priority System
If multiple mods register for the same entity, highest priority wins:
remote.call("entity_gui_lib", "register", {
mod_name = "my_mod",
entity_type = "inserter",
on_build = "build_gui",
priority = 100, -- Higher than default 0
})
-- Check existing registrations
local existing = remote.call("entity_gui_lib", "get_registrations", "inserter")
for _, reg in ipairs(existing) do
log(reg.mod_name .. " has priority " .. reg.priority)
end
API Reference
Registration Config
| Field |
Type |
Required |
Description |
mod_name |
string |
Yes |
Your remote interface name |
entity_name |
string |
One required |
Specific entity name |
entity_type |
string |
|
Entity type (e.g., "inserter") |
title |
LocalisedString |
No |
Custom title |
on_build |
string |
Yes |
Build callback name |
on_close |
string |
No |
Close callback name |
on_update |
string |
No |
Update callback name |
update_interval |
number |
No |
Ticks between updates (default: 10) |
priority |
number |
No |
Conflict resolution (default: 0) |
preview_size |
number |
No |
Preview size in pixels (default: 148) |
Remote Functions
-- Register/unregister
remote.call("entity_gui_lib", "register", config)
remote.call("entity_gui_lib", "unregister", "entity-type", "mod_name")
-- Get GUI info
remote.call("entity_gui_lib", "get_content", player_index)
remote.call("entity_gui_lib", "get_entity", player_index)
remote.call("entity_gui_lib", "get_registrations", "entity-type")
-- Actions
remote.call("entity_gui_lib", "refresh", player_index)
remote.call("entity_gui_lib", "close", player_index)
-- Helpers
remote.call("entity_gui_lib", "create_tabs", container, tabs)
remote.call("entity_gui_lib", "show_confirmation", player_index, config)
remote.call("entity_gui_lib", "create_slider", container, config)
remote.call("entity_gui_lib", "create_number_input", container, config)
remote.call("entity_gui_lib", "create_dropdown", container, config)
remote.call("entity_gui_lib", "create_toggle_group", container, config)
remote.call("entity_gui_lib", "create_inventory_display", container, config)
remote.call("entity_gui_lib", "create_item_selector", container, config)
remote.call("entity_gui_lib", "create_recipe_selector", container, config)
remote.call("entity_gui_lib", "create_elem_button", container, config)
remote.call("entity_gui_lib", "create_signal_selector", container, config)
remote.call("entity_gui_lib", "create_color_picker", container, config)
-- Debug
remote.call("entity_gui_lib", "set_debug_mode", true)
Tips
- Name your elements uniquely - Prefix with your mod name to avoid conflicts
- Use debug mode - Enable to see registrations in the log file
- Check the example mod - Located in
examples/entity-gui-lib-example
- Entity must have vanilla GUI - Library can only replace existing GUIs
- Avoid reserved tab names - Don't use names like "items", "style", "parent" etc. as tab names since they conflict with LuaGuiElement properties
Questions?
Post here. I'll do my best to answer.