Lua Scripting Integration¶
This page documents how ORCA integrates Lua scripting, how modules are loaded, and the conventions used by generated bindings.
Global Variables¶
When the engine starts it exposes several directory paths as Lua globals:
| Global | Description |
|---|---|
LIBDIR |
Directory containing compiled shared libraries (.so / .dll) |
SHAREDIR |
Directory containing shared Lua scripts and assets |
PLUGDIR |
Directory containing plugin files |
PROJECTDIR |
Path to the currently loaded project directory |
EXENAME |
Full path to the engine executable |
DATADIR |
Alias for PROJECTDIR (deprecated alias) |
SERVER |
Set to true when running in headless server mode |
These globals are set before any project Lua code runs. They can be used to build paths portably:
Module System¶
Built-in Modules¶
All built-in engine modules are pre-registered in package.preload by luaopen_orca before any project code runs. They are loaded lazily on first require:
local core = require "orca.core"
local geo = require "orca.geometry"
local fs = require "orca.filesystem"
local render = require "orca.renderer"
local sys = require "orca.system"
local json = require "orca.parsers.json"
local xml = require "orca.parsers.xml"
local l18n = require "orca.localization"
local back = require "orca.system"
The following modules are excluded from WebGL and server builds:
| Module | Reason excluded |
|---|---|
orca.network |
BSD sockets — not available in browser |
orca.editor |
Native desktop file-dialog features |
Short-hand orca.* Access¶
The orca table has a __index metamethod that automatically requires sub-modules on first access and caches them. This means:
The auto-require only works for modules with names of the form orca.<key>. Once loaded the result is cached directly in the orca table.
Plugin Module Loading (Native Builds)¶
On desktop builds, plugin shared libraries (.so / .dll) are placed in LIBDIR/lib*.so. The engine prepends LIBDIR/lib?.so to package.cpath so that require "orca.UIKit" finds and loads the plugin automatically:
Lua script plugins (.lua files) placed in SHAREDIR/plugins/ are loaded by load_plugins() at startup using dofile.
Plugin Module Loading (WebGL Builds)¶
In the WebGL / single-binary build there is no dynamic dlopen. Instead:
- The
webglMakefile target compiles all plugin sources directly into the WASM binary. build/webgl/plugins_luaopen.his auto-generated by scanning the compiled sources forluaopen_orca_*symbols.luaopen_orcaregisters these vialuaL_preloadalongside the built-in modules.
The result is transparent: require "orca.UIKit" works identically in both native and WebGL builds.
Generated Lua Bindings¶
The *_export.c files generated by cd tools && make wire every XML-declared struct, interface, and class into Lua. Understanding the generated binding pattern helps when debugging.
Struct Bindings¶
For each <struct name="Foo" export="Foo">:
luaX_pushFoo(L, ptr)— pushes a userdata wrappingFoo*luaX_checkFoo(L, idx)— checks and extractsFoo*from stack positionidx- A Lua metatable named
"Foo"is registered in the registry
Interface / Function Bindings¶
For each <interface name="Foo" prefix="FOO_" export="Foo">:
- A table
Foois created in the module's Lua table - Each
<method lua="true">becomes a function inFoo
Component / Class Bindings¶
For each <class name="Bar" export="Bar">:
Bar()is a constructor that callsOBJ_Create+OBJ_AddComponent(obj, ID_Bar)- Property access is via
__index/__newindexmetamethods backed byOBJ_FindShortProperty GetBar(obj)in C returns the typed component pointer from anObject*
Coroutines and Async¶
The engine exposes an orca.async function for fire-and-forget coroutines:
orca.async(function()
-- runs as a coroutine resumed by the event queue
local result = someLongOperation()
end)
Internally this posts a kMsgResumeCoroutine message to resume the coroutine on the next event loop tick. Unlike coroutine.wrap, orca.async coroutines are managed by the engine and resumed automatically.
Lua Path Setup¶
After the globals are set, the engine runs:
package.path = PLUGDIR.."/?.lua;"..SHAREDIR.."/?.lua;"..package.path
package.cpath = LIBDIR.."/lib?.so;"..package.cpath -- skipped on WebGL
This means any .lua file under PLUGDIR or SHAREDIR can be loaded with require. Project-local scripts can be placed in PROJECTDIR and required directly by path, or by adding PROJECTDIR to package.path in the project's entry-point script.
Lua State Lifecycle¶
| Stage | What happens |
|---|---|
| Engine init | luaopen_orca registers all built-in and plugin modules in package.preload |
| Globals setup | Directory paths (LIBDIR, SHAREDIR, …) pushed as globals |
| Path setup | package.path and package.cpath extended |
| Project load | RunProject(L, projectDir) locates and dofiles the entry point |
| Main loop | Lua while true do … end calls axPollEvent; ASYNCIFY yields to the browser on WebGL |
| Shutdown | Lua state closed; kMsgDestroy sent to all objects |
Gotcha — module preloading order: Modules in
package.preloadare not executed at registration time. Each module'sluaopen_*function runs on the firstrequirecall. If your module initialization has side effects that depend on another module (e.g. registering classes), make sure torequirethe dependency explicitly rather than relying on registration order.