Skip to content

Talking to Godot

Nari is made with Godot, and plugins can use almost all of it from Lua: create nodes, call Nari’s own functions and listen to its signals.

Global names that Lua doesn’t know are looked up in this order:

  1. Nari’s autoloads: Main, MediaPlayer, ThemeEngine, SettingsManager, InputGlyphs, Soundboard, Plugins
  2. Godot singletons: Engine, OS, Time, Input, DisplayServer, ResourceLoader…
  3. Nari’s classes: NariButton, NariLabel, Dialog, SettingItem, Page, LyricsParser, LyricsProvider, Visualizers, Log…
  4. Godot classes: Label, Control, HBoxContainer, TextureRect, Timer…

Nari APIs lists the most useful autoload functions.

local label = Label.new() -- create
label.text = "Hello" -- set a property
nari.log(label.text) -- read a property
label:add_theme_font_size_override("font_size", 48) -- call a method, with : or .
MediaPlayer.playback_changed:connect(function(state) end) -- connect a signal
  • Properties read and write like table fields.
  • Methods are called with object:method(...) or object.method(...).
  • Signals are fields with :connect(handler), which returns a function that disconnects it, and :emit(...).
  • Constants and enums are fields too: ThemeEngine.Colors.AccentBg, InputGlyphs.Glyph.A, Visualizers.SCOPE, Main.Pages.NowPlaying.
  • Classes: Class.new(...) creates an instance. Nari’s classes also have their static functions (Dialog.menu("Title"), SettingItem.toggle(...)) and constants. Godot’s classes have their integer constants (Control.PRESET_FULL_RECT) and static methods (FileAccess.file_exists(path)).
  • Using a freed object raises a Lua error. Two objects are == when they’re the same object.
Godot Lua
null nil
bool, int, float boolean, integer, number
String, StringName, NodePath string
Array, Packed*Array table (a list starting at 1)
Dictionary table
Vector2, Vector2i, Color, Rect2 table with x/y, r/g/b/a, position/size
Callable function
Object object
anything else an opaque value you can pass back to Godot

Make the table types with Vector2(x, y), Vector2i(x, y), Color(r, g, b, a) or Color("#ff8800"), and Rect2(x, y, width, height). A Lua function passed to Godot becomes a Callable, so it can be a signal handler or the action of a settings entry.

Lists or dictionaries? A Lua table with only keys 1..n (or an empty table) becomes an Array, anything else a Dictionary. Dictionaries that came from Godot stay dictionaries, even when empty. Use Dictionary() for an empty one, and Dictionary({ ... }) to mark any table as one.

Some Nari functions are coroutines: MediaPlayer:get_tracks(), get_song, get_album and others. From Lua they return a pending state. Use nari.await to get the result:

nari.await(MediaPlayer:get_tracks(), function(tracks)
nari.log(#tracks .. " songs in the library")
end)

nari.await also takes plain values and calls the handler right away, so it’s safe to use whenever you’re not sure whether a function is async.