ImGui
BeamNG World Editor ImGui Windows
Editor extensions live in `lua/ge/extensions/editor/` and use the `editor` API alongside ImGui.
Creating an Editor Tool Window
Editor extensions live in lua/ge/extensions/editor/ and use the editor API alongside ImGui.
Minimal Editor Extension
local M = {}
local logTag = 'editor_myTool'
local im = ui_imgui
local toolWindowName = "editor_myTool_window"
local function onEditorGui()
if not editor.isWindowVisible(toolWindowName) then return end
if editor.beginWindow(toolWindowName, "My Tool") then
im.Text("Tool content here")
if im.Button("Do Something") then
log('I', logTag, "Button clicked")
end
end
editor.endWindow()
end
local function onWindowMenuItem()
editor.showWindow(toolWindowName)
end
local function onEditorInitialized()
editor.registerWindow(toolWindowName, im.ImVec2(400, 300))
editor.addWindowMenuItem("My Tool", onWindowMenuItem)
log('I', logTag, "My Tool initialized")
end
local function onActivate()
log('I', logTag, "My Tool activated")
end
M.onEditorGui = onEditorGui
M.onEditorInitialized = onEditorInitialized
M.onWindowMenuItem = onWindowMenuItem
M.onActivate = onActivate
return MKey Differences from Regular ImGui
| Feature | Regular Extension | Editor Extension |
|---|---|---|
| Render hook | onUpdate() | onEditorGui() |
| Window begin | im.Begin("Name") | editor.beginWindow(name, title) |
| Window end | im.End() | editor.endWindow() |
| Registration | N/A | editor.registerWindow() |
| Menu entry | N/A | editor.addWindowMenuItem() |
| Visibility | Manual flag | editor.isWindowVisible() |
| Show/Hide | Manual | editor.showWindow() / editor.hideWindow() |
Editor Window with Menu Bar
local function onEditorGui()
if not editor.isWindowVisible(toolWindowName) then return end
if editor.beginWindow(toolWindowName, "My Tool", im.WindowFlags_MenuBar) then
if im.BeginMenuBar() then
if im.BeginMenu("File") then
if im.MenuItem1("Load") then loadData() end
if im.MenuItem1("Save") then saveData() end
im.EndMenu()
end
im.EndMenuBar()
end
-- Window content
im.Text("Content")
end
editor.endWindow()
endEditor Helper: Object Selection
-- Select a scene object
editor.selectObjectById(objectId)
-- Get current selection
local selection = editor.selection
if selection and selection.object and #selection.object > 0 then
local selectedObj = scenetree.findObjectById(selection.object[1])
end
-- Show notification
editor.showNotification("Operation complete!")Editor Helper: Icon Buttons
-- Editor provides icon buttons (only available in editor context)
if editor.uiIconImageButton then
editor.uiIconImageButton(editor.icons.save, im.ImVec2(24, 24))
editor.uiIconImageButton(editor.icons.delete, im.ImVec2(24, 24))
endPeriodic Updates in Editor
local lastUpdateTime = 0
local UPDATE_INTERVAL = 5 -- seconds
function M.onEditorUpdate()
-- Called every frame when editor is active
if os.time() - lastUpdateTime > UPDATE_INTERVAL then
lastUpdateTime = os.time()
-- Do periodic work (refresh lists, validate data, etc.)
end
endEditor Preferences
-- Read editor preferences
if editor and editor.getPreference then
local dpiAware = editor.getPreference("ui.general.dpiAware")
local lineThickness = editor.getPreference("gizmos.general.lineThicknessScale")
endDebug Drawing in Editor
-- Draw debug shapes in the 3D viewport
function M.onEditorUpdate()
if pendingPlacement then
local hit = cameraMouseRayCast(true)
if hit then
local pos = vec3(worldEditorCppApi.snapPositionToGrid(hit.pos))
local lineWidth = editor.getPreference("gizmos.general.lineThicknessScale") * 4
-- Draw crosshair at cursor position
debugDrawer:drawLineInstance(pos - vec3(2,0,0), pos + vec3(2,0,0), lineWidth, ColorF(1,0,0,1))
debugDrawer:drawLineInstance(pos - vec3(0,2,0), pos + vec3(0,2,0), lineWidth, ColorF(0,1,0,1))
debugDrawer:drawLineInstance(pos - vec3(0,0,2), pos + vec3(0,0,2), lineWidth, ColorF(0,0,1,1))
end
end
endCreating Objects from Editor
-- Create a BeamNGTrigger
local obj = worldEditorCppApi.createObject("BeamNGTrigger")
if obj then
obj:setName("myTriggerName")
obj:registerObject("")
obj:setPosition(hitPosition)
-- Add to appropriate parent group
local parent = scenetree.MissionGroup
parent:addObject(obj)
-- Select it
editor.selectObjectById(obj:getID())
end