You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Integrate RmlUi into the client-side Lua runtime defined by #20.
Client packages may include RML, RCSS, fonts, images, and client scripts. Client scripts control the UI through a Lua-facing ui module.
The server has no UI API. It cannot open, close, mutate, inspect, focus, or directly invoke client UI. Server communication uses the networking primitives from #13:
net.shared is the recommended source for reactive server-owned UI state.
net.channel is used for transient UI actions, commands, and events.
Local ref values are used for client-only UI state.
The UI module is available only inside an active client package with the client.ui capability:
localui=require"ui"
RML and RCSS remain package resources. Lua controls documents, elements, models, and events, while the client integration owns RmlUi initialization, input forwarding, updating, and rendering.
The client waits for the shared value to become ready and reflects subsequent changes into the RmlUi data model.
The UI does not need to manually copy each update:
state:ready(function(shared)
-- The model is now ready to render initial state.end)
The server owns the shared value. The client only renders it. Writable shared state remains subject to the permissions and untrusted-input rules from #13.
Because channel messages are transient, a UI that needs recoverable state should use net.shared or define an explicit snapshot request protocol over a channel.
When a document, context, package, or package revision closes:
Focus is released.
Input capture is released.
Event handlers are removed.
A previous eligible context may regain focus.
Stale callbacks cannot receive input.
Hot Reload
UI follows the client package revision lifecycle from #20:
The new package revision downloads and verifies.
A new client runtime is initialized.
New UI contexts and documents are created.
The new runtime becomes active.
The old revision loses input ownership.
Old documents and contexts close.
The old runtime stops.
If UI initialization fails, the old UI remains active.
The new runtime reacquires fresh net.shared and net.channel handles. Shared state can become ready again; transient channel messages are not replayed automatically.
Resources
Supported package-owned resources include:
RML documents.
RCSS stylesheets.
Images.
Fonts.
Templates.
Localization files.
Embedded scripting inside RML is not supported. Client Lua scripts are the only script execution mechanism.
The UI must not allow arbitrary filesystem access or unrestricted cross-package resource loading.
Capabilities
The UI requires:
client
client.ui
Network permissions are separate:
network.channel.send
network.channel.receive
Access checks remain active in event callbacks, watchers, timers, coroutines, and async continuations.
Security and Authority
The UI is presentation code, not an authority boundary:
Form fields are client-controlled.
Button clicks are client-controlled.
UI models are client-controlled.
Client channel messages are untrusted.
The server validates all gameplay actions.
The server may send state and events through the existing networking API, but it never directly controls client documents or elements.
This proposal does not claim to protect a player from a malicious server that deliberately sends malicious client code.
Summary
Integrate RmlUi into the client-side Lua runtime defined by #20.
Client packages may include RML, RCSS, fonts, images, and client scripts. Client scripts control the UI through a Lua-facing
uimodule.The server has no UI API. It cannot open, close, mutate, inspect, focus, or directly invoke client UI. Server communication uses the networking primitives from #13:
net.sharedis the recommended source for reactive server-owned UI state.net.channelis used for transient UI actions, commands, and events.refvalues are used for client-only UI state.Related proposals:
Scope
The UI module is available only inside an active client package with the
client.uicapability:RML and RCSS remain package resources. Lua controls documents, elements, models, and events, while the client integration owns RmlUi initialization, input forwarding, updating, and rendering.
Contexts
A context is an independent UI surface:
Supported input modes should include:
A package may have multiple contexts, but each context belongs to its package runtime.
Lua does not manually call RmlUi's update or render loop.
Only the active package revision may own input or focus.
Documents
Convenience form:
Resources are package-relative. A package may not access another package's resources by default.
Documents and element handles become invalid after close. Invalid handles must fail clearly rather than silently affecting another document.
Elements
Lookup:
The first version should expose common element operations rather than mirror the entire native RmlUi API.
Events
Suggested event fields:
Suggested event methods:
Callbacks should follow the event semantics from #6, including cleanup, one-shot handlers, priorities, and package event-group ownership.
Initial event names:
The UI should not invoke Lua once per render frame unless the package explicitly subscribes to the client tick event.
Reactive Models
A UI model adapts Lua reactive values to RmlUi data binding. It must not replace
reffrom #13.Local model:
RML:
Models should support:
Model fields follow
refsemantics:Recommended Network State Pattern
net.sharedis the recommended API for server-owned reactive state:The client waits for the shared value to become ready and reflects subsequent changes into the RmlUi data model.
The UI does not need to manually copy each update:
The server owns the shared value. The client only renders it. Writable shared state remains subject to the permissions and untrusted-input rules from #13.
UI Actions and Events
Transient user actions use
net.channel:The server receives ordinary untrusted data and validates it. The UI layer does not create an RPC system or infer server methods from element IDs.
Server-to-client transient events may also use channels:
Because channel messages are transient, a UI that needs recoverable state should use
net.sharedor define an explicit snapshot request protocol over a channel.Input and Focus
Default UI behavior should not block gameplay:
Menus can explicitly capture input:
When a document, context, package, or package revision closes:
Hot Reload
UI follows the client package revision lifecycle from #20:
If UI initialization fails, the old UI remains active.
The new runtime reacquires fresh
net.sharedandnet.channelhandles. Shared state can become ready again; transient channel messages are not replayed automatically.Resources
Supported package-owned resources include:
Embedded scripting inside RML is not supported. Client Lua scripts are the only script execution mechanism.
The UI must not allow arbitrary filesystem access or unrestricted cross-package resource loading.
Capabilities
The UI requires:
Network permissions are separate:
Access checks remain active in event callbacks, watchers, timers, coroutines, and async continuations.
Security and Authority
The UI is presentation code, not an authority boundary:
The server may send state and events through the existing networking API, but it never directly controls client documents or elements.
This proposal does not claim to protect a player from a malicious server that deliberately sends malicious client code.
Non-Goals
Acceptance Criteria
client.ui.net.sharedis the recommended API for reactive server-owned UI state.net.channelis available for transient UI actions and events.refvalues can participate in UI models.Examples
Reactive Server State and UI Actions
The server owns
shops:state; the client renders it. The server validates thebuymessage received throughshops:actions.RML Data Binding
assets/shop.rml:The model updates when the shared value changes; the script does not need to manually rewrite the document text.
Local UI State
Local UI state is separate from server-owned state and is not authoritative.
Server-to-Client Events
Channels are transient. A UI that needs recoverable initial state should use
net.sharedor request a snapshot through a channel.HUD Without Input Capture
The HUD renders while gameplay continues to receive input.
Cleanup
Closing the context removes its documents, event handlers, focus, and input capture. Package reload performs the same cleanup automatically.