5.5 KiB
Runtime protocol
The runtime protocol is the stable boundary between Lua and Dart.
RuntimeEvent -> Lua -> GameDiff / RuntimeCommand -> Flame
RuntimeEvent
Dart sends white-listed events to Lua. Events represent input, lifecycle, command/resource outcomes, and host/runtime notifications.
Lua should treat events as data and return explicit state changes.
GameDiff
A GameDiff describes desired changes to the runtime render tree.
Typical operations include creating, updating, and removing runtime nodes. Dart validates node fields before applying them to Flame components.
RuntimeNode
Runtime nodes are generic render descriptions. They are not Flame objects.
Supported node concepts include:
- Containers/panels.
- Text.
- Sprites/images.
- Buttons.
- List views.
- Particles.
- Spine nodes.
Lua may compose higher-level widgets, but those widgets must normalize into supported runtime nodes.
Color and alpha
RuntimeNode.color supports #RRGGBB and #AARRGGBB. When the alpha channel is present in the color, it is multiplied with RuntimeNode.alpha and any runtime animation alpha.
Final opacity = color alpha × node alpha × runtime animation alpha
#RRGGBB colors behave as fully opaque colors. #00000000 is fully transparent.
Text shadow
Text-capable nodes may use flat shadow fields:
textShadowColor:#RRGGBBor#AARRGGBBshadow color.textShadowOffsetX/textShadowOffsetY: shadow offset in runtime pixels.textShadowBlur: non-negative blur radius.
The shadow color alpha is multiplied by RuntimeNode.alpha and any runtime animation alpha.
Image regions and nine-slice
Image-capable nodes (image, sprite, and image-backed button) may draw only part of an asset.
For manual atlas regions, set source fields in image pixels:
sourceX/sourceY: top-left source position inside the loaded image.sourceWidth/sourceHeight: source region size.
For TexturePacker JSON atlases, declare atlas on an image resource and set frame on the node. Image-backed buttons may also use pressedFrame and disabledFrame. The runtime supports TexturePacker JSON Hash and JSON Array frames formats with non-rotated frames. rotated: true frames are rejected.
When frame/source fields are omitted, the full image is used.
Image-capable nodes may also use nine-slice scaling with source-pixel insets:
sliceLeft/sliceTop/sliceRight/sliceBottom.
Nine-slice keeps corners unscaled, stretches edges on one axis, and stretches the center on both axes. Insets are clamped to the selected source region and destination size.
Runtime network API
Lua may use runtime-owned async networking without blocking script execution:
runtime.http_request({ id?, method?, url, headers?, body?, timeout? })runtime.ws_connect({ id?, url, protocols? })runtime.ws_send(id, message)runtime.ws_close(id)
HTTP requests support http and https URLs. WebSocket connections support ws and wss URLs.
Network results are delivered back to Lua through on_event(event):
network_http: HTTP request completed or failed.event.dataincludesid,url,method,ok, and eitherstatus/headers/bodyorerror.network_ws_open: WebSocket connection opened.network_ws_message: WebSocket message received.network_ws_error: WebSocket connection or stream error.network_ws_close: WebSocket connection closed.
Runtime host bridge
Flutter host apps may register a RuntimeHostBridge when creating LuaGameWidget or FlameLuaGame.
Lua-to-Flutter calls:
runtime.host_call({ id?, method, data? }): async request. Result is delivered to Lua ashost_call_resultwithid,method,ok, and eitherresultorerror.runtime.host_notify({ method, data? }): fire-and-forget notification to Flutter host code.
Flutter-to-Lua calls:
FlameLuaGame.notifyLua(method, data?): emits ahost_notifyevent into Lua.FlameLuaGame.callLua(method, data?, timeout?): emits ahost_callevent into Lua and waits for Lua to callruntime.host_respond({ id, result?, error? }).
Host bridge payloads must be JSON-like values: null, bool, number, string, list, or string-keyed map. Unsupported Dart objects are converted to strings.
RuntimeCommand
Runtime commands request generic side effects owned by Dart/Flame.
Examples:
move_pathmove_tofade_toscale_torotate_toremove_nodesequenceparalleldelaytoastplay_soundplay_bgmpause_bgmresume_bgmstop_bgmpreload_resourcesevict_resourcescancel_commandsplay_spine_animationcopy_text
Commands must remain generic. Do not add commands like roll_ludo_dice or move_airplane_piece; those belong in Lua game logic.
Validation expectations
- Unknown protocol fields should not become implicit behavior.
- Required fields should fail clearly when absent.
- Helper-only aliases must be normalized before Dart protocol validation.
- Runtime code should not silently convert invalid game state into fake success.
Where to change protocol code
lib/runtime/models/ Data models
lib/runtime/protocol/ Protocol validation
lib/runtime/commands/ Command validation/execution
lib/runtime/rendering/ Runtime node to Flame component mapping
assets/runtime/lua/ Lua helper constructors/aliases
When protocol changes affect Lua authoring, update:
tool/lua_runtime_defs_common.lua
Then run:
dart run tool/generate_lua_runtime_defs.dart