Skip to content

Editor plugin API

The Editor, ui and overlay APIs editor plugins use (the plugins guide). Generated from editor/definitions/editor_api.lua.

Field Type
id string The plugin’s folder name
name string
version string
dir string The plugin’s folder (absolute)
Field Type
id string Unique within the plugin (the action id becomes plugin..)
label string Shown in menus and the command palette
run fun() Runs the command
menu? string Where it goes: “Tools”, “Tools/Align” (a submenu), “Edit”, … (none: the palette only)
shortcut? string “Primary+Shift+L” (Primary = Cmd on macOS, Ctrl elsewhere), “Alt+F3”, …
scope? "global"|"scene" “scene”: not while typing code (default “global”)
enabled? fun(): boolean Greyed out / skipped when false
checked? fun(): boolean A toggle’s check mark
Field Type
id string Unique within the plugin
title? string The window’s title (default: id)
dock? "right"|"left"|"bottom"|"center"|"float" Where it docks the first time (as a tab)
open? boolean Shown at start (default true)
draw fun(ui: EditorUI) Draws it, every frame - keep it cheap
Field Type
name string
path string Project-relative scene file
root Node The scene’s root node
Field Type
name string
path string The project folder (absolute)
Field Type
fn fun(paths: string[]) Called with the chosen paths (empty: cancelled)
title? string
exts? string[] Extensions without dots ({“png”, “jpg”})
folders? boolean Choose folders
multiple? boolean Allow several

Reads a text file in the project (relative paths) or the plugin’s folder.

local text, err = Editor.fs.read("data/items.json")
  • path string

Returns string? text, string? err

Writes a text file in the project or the plugin’s folder (its folders are made).

Editor.fs.write("data/notes.txt", "Hello")
  • path string
  • text string

Returns boolean ok

Whether a file or folder exists (false outside the project and the plugin’s folder).

if not Editor.fs.exists("levels") then Editor.fs.mkdir("levels") end
  • path string

Returns boolean

The names in a folder, sorted; folders end with “/”.

for _, name in ipairs(Editor.fs.list("scripts")) do print(name) end
  • path string A folder

Returns string[] names Folders end with “/”

Makes a folder (and its parents) in the project or the plugin’s folder.

Editor.fs.mkdir("generated/levels")
  • path string

Returns boolean ok

Field Type
plugin EditorPluginInfo
fs EditorFS

Logs to the plugin’s log (Settings > Plugins) and the console (print does too).

  • ... any

Logs a warning to the plugin’s log and the console.

Editor.warn("No player in this scene")
  • ... any

Logs an error to the plugin’s log and the console.

Editor.error("Could not read data/items.json")
  • ... any

Adds a command: menus, the command palette, the keymap.

Editor.add_command{id = "align_left", label = "Align Left", menu = "Tools/Align", run = align_left}
  • spec EditorCommand

Adds a dockable panel drawn with the ui widgets.

  • spec EditorPanel

Shows (in front) or hides one of the plugin’s panels.

  • id string
  • open? boolean Default true

Adds a section to the Inspector.

  • spec EditorInspector

Draws over the viewport (world space) with draggable handles.

  • spec EditorOverlay

Imports a new file type (dropped or from Import Assets).

  • spec EditorImporter

Calls fn on an editor event.

  • event EditorEvent
  • fn function

The selected nodes.

Returns Node[]

Selects nodes (nil: nothing).

  • nodes Node|Node[]|nil

The scene being edited (nil: none).

Returns EditorScene?

The open project: its name and folder.

local project = Editor.project(); print(project.name, project.path)

Returns EditorProject

Changes to the scene inside fn are one undo step. Always use it for scene changes.

Editor.edit("Align left", function() n.position = Vec2(0, n.position.y) end)
  • label string The undo step’s name
  • fn fun()

Creates a node (inside Editor.edit).

  • type string “Node”, “TextureNode”, “CameraNode”, …
  • parent? Node Default: the scene’s root
  • name? string Default: the type (made unique)

Returns Node

Deletes a node (inside Editor.edit).

  • node Node

Project files (project-relative paths), optionally in a folder / with an extension.

  • folder? string
  • ext? string “.png”, “.scene.json”, …

Returns string[]

A message in the console.

  • text string

Asks yes / no.

  • text string
  • fn fun(yes: boolean)

Asks for text.

  • text string
  • default? string
  • fn fun(value: string?) nil: cancelled

The system’s file dialog.

  • spec EditorPickFile

Runs a program (permission “process” in plugin.json); fn gets its result.

  • cmd string
  • args? string[]
  • fn fun(ok: boolean, output: string, exit_code: integer)

Fetches a URL (permission “network” in plugin.json).

  • url string
  • fn fun(ok: boolean, body: string)
Field Type
id string Unique within the plugin
title? string The section’s header (default: id)
type? string Only for this node type (“TextureNode”, …; default: every node)
draw fun(ui: EditorUI, node: Node) Draws the section, every frame the node is selected
Field Type
zoom number The viewport’s zoom
mouse Vec2 The mouse in world space
Field Type
id string Unique within the plugin
title? string The undo step’s name for handle drags (default: id)
draw fun(g: EditorOverlayDraw, view: EditorOverlayView) Draws over the viewport, every frame
Field Type
ext string “.tsx”: the extension it imports
import fun(name: string, data: string): table<string, string>?, string? Returns {[“project/path”] = contents} (or nil, “why”)

World-space drawing in an overlay’s draw. Colours: “#rrggbb” / “#rrggbbaa”.

EditorOverlayDraw.line(a, b, color, width)

Section titled “EditorOverlayDraw.line(a, b, color, width)”

Draws a line between two world positions.

g.line(Vec2(0, 0), Vec2(100, 0), "#ff8800", 2)
  • a Vec2
  • b Vec2
  • color? string
  • width? number Pixels

EditorOverlayDraw.circle(center, radius, color, filled)

Section titled “EditorOverlayDraw.circle(center, radius, color, filled)”

Draws a circle (outline, or filled) in world units.

g.circle(Vec2(320, 180), 48, "#00ff0080")
  • center Vec2
  • radius number World units
  • color? string
  • filled? boolean

EditorOverlayDraw.rect(min, max, color, filled)

Section titled “EditorOverlayDraw.rect(min, max, color, filled)”

Draws a rectangle between two world corners (outline, or filled).

g.rect(Vec2(0, 0), Vec2(64, 32), "#ffffff40", true)
  • min Vec2
  • max Vec2
  • color? string
  • filled? boolean

Draws a label at a world position.

g.text(Vec2(320, 150), "Spawn point", "#ffffff")
  • pos Vec2
  • text string
  • color? string

A draggable point. While dragged: true and where it is now (change the scene right away - the drag is one undo step).

  • id string Unique within the overlay
  • pos Vec2
  • color? string

Returns boolean moved, Vec2 pos

A line of text.

ui.text("Enemies: " .. count)
  • text string

A line of dimmed (secondary) text.

ui.dim("Select a node to edit it")
  • text string Dimmed

A horizontal line, with an optional label.

ui.separator("Options")
  • label? string

Puts the next widget on the same line as the last one.

if ui.button("OK") then ok() end; ui.same_line(); if ui.button("Cancel") then cancel() end

A little vertical space.

ui.spacing()

The next widget’s width.

  • w number

A button; true on the frame it is clicked.

if ui.button("Rebuild") then rebuild() end
  • label string

Returns boolean clicked

A selectable row (lists); true when clicked.

if ui.selectable(name, name == current) then current = name end
  • label string
  • selected? boolean

Returns boolean clicked

A check box; returns whether it changed and the new value.

local changed; changed, opts.snap = ui.checkbox("Snap", opts.snap)
  • label string
  • value boolean

Returns boolean changed, boolean value

A one-line text field; returns whether it changed and the text.

local changed; changed, self.filter = ui.input("Filter", self.filter)
  • label string
  • text string

Returns boolean changed, string text

A slider between min and max; returns whether it changed and the value.

local changed; changed, opts.size = ui.slider("Size", opts.size, 8, 128)
  • label string
  • value number
  • min number
  • max number

Returns boolean changed, number value

A number edited by dragging (or typing); returns whether it changed and the value.

local changed; changed, opts.speed = ui.drag("Speed", opts.speed, 0.5)
  • label string
  • value number
  • speed? number

Returns boolean changed, number value

A drop-down list; returns whether it changed and the chosen 1-based index.

local changed; changed, opts.mode = ui.combo("Mode", opts.mode, {"Grid", "Free"})
  • label string
  • index integer 1-based
  • items string[]

Returns boolean changed, integer index

A collapsible tree item; true while open (then call ui.tree_pop()).

if ui.tree_node("Details") then ui.text("..."); ui.tree_pop() end
  • label string

Returns boolean open Call ui.tree_pop() when open

Ends an open ui.tree_node.

ui.tree_pop()

A tooltip for the last widget.

  • text string

Starts a table with a number of columns; true while visible (then call ui.end_table()).

if ui.begin_table("nodes", 2) then ui.text("Name"); ui.next_cell(); ui.text("Type"); ui.end_table() end
  • id string
  • columns integer

Returns boolean visible Call ui.end_table() when visible

Moves to the next table cell (wrapping to the next row).

ui.next_cell()

Ends a table started with ui.begin_table.

ui.end_table()