Choosing a package
| Package | Use | Target |
|---|---|---|
com.link1345.gua | The UPM package for Unity projects, including automatic startup, UI collection, actions, and screenshots | Unity 6000.5+ |
Gua.Runtime | Shared runtime API for implementing another engine adapter | net10.0 / netstandard2.1 |
Gua.Testing.Unity | Build, launch, and connect to the Unity Editor or Player from external .NET tests | net10.0 / netstandard2.1 |
Gua.Testing | Engine-neutral testing API for locators, assertions, remote connections, and screenshots | Engine-neutral |
Gua.Testing.Snapshots | Compare semantic UI/World JSON baselines | net10.0 / netstandard2.1 |
Gua.Testing.Visual | Add PNG baseline comparison and diff artifacts to any Gua context, including Unity | net10.0 / netstandard2.1 |
Gua.Testing.Recording | Record and replay semantic actions against any Gua context, including Unity | net10.0 / netstandard2.1 |
Unity public types
| Type | Contract |
|---|---|
GuaUnityRuntime | Automatically started MonoBehaviour; exposes EnsureStarted() and manual RunFrame() |
GuaId | Optional stable Value for uGUI/TMP GameObjects |
GuaScreen | Optional logical screen Value; otherwise active scene name/path |
IGuaUnityControlAdapter | TryDescribe/TryApply extension point for custom uGUI-like controls |
GuaUnityAdapterRegistry | Add control adapters with Register(adapter) |
GuaUnityKeyEvent | Maps protocol keys and modifier bits to Unity Events |
Gua.Runtime surface
Normal Unity projects do not need to call this layer directly because the UPM package manages it. When building a custom engine adapter, GuaRuntime creates and owns the native runtime and destroys its bridge and handle in Dispose(). Its primary API includes StartInspectorBridge/StopInspectorBridge, SetAdapterVersion, BeginFrame/EndFrame, RegisterNode, TryConsumeAction/EmitActionResult, TryConsumeScreenshotRequest/CompleteScreenshot, AddLog, GetUiTreeJson, and GetVersionJson.
Test-host API
| Member | Meaning |
|---|---|
UnityPlayerBuilder.Build | Batch-build a selected Windows, Linux, or macOS desktop Mono Player for one scene |
LoadPlayer | Start a headless Player |
LoadRenderedPlayer | Start a rendered Player |
LoadEditor | Start a scene through the StartPlayMode editor command |
BuildAndLoadPlayer | Build and launch in one call |
Context / RemoteContext | Shared IGuaContext / WebSocket implementation |
CaptureScreenshot | Wait for an on-demand PNG after the current frame sequence |
CreateDiagnosticsSession | Add Unity log and process metadata to shared artifacts |
UI mapping
| Role | UI Toolkit | uGUI / TMP | Actions |
|---|---|---|---|
| button | Button | Button / Button with TMP label | click, focus |
| checkbox | Toggle | Toggle | click, focus, set_checked |
| textbox | TextField | InputField / TMP_InputField | focus, set_value, press_key |
| slider | Slider / SliderInt | Slider | focus, set_value |
| combobox | DropdownField | Dropdown / TMP_Dropdown | focus, select |
| list / listitem | ListView and all itemsSource entries | No standard mapping | focus, select, scroll |
| tablist / tab | TabView / Tab | No standard mapping | select |
| scrollarea | ScrollView | ScrollRect | scroll |
| text / panel | Label / fallback | Text, TMP_Text / fallback | Observe only |
Each frame collects role, label, text/value, visible, enabled, focused, checkbox checked state, ListView item selected state, slider range, parentId, and bounds. Virtualized offscreen ListView entries still get nodes, but unrealized entries have visible: false and zero bounds.
Actions and completion
The adapter consumes only actions declared by the target role. It emits the original requestId after synchronous Unity listeners return; it does not wait for coroutines, async void, or next-frame work. Invalid numbers, choices, and keys return invalid_value; unavailable combinations return unsupported. Exceptions are logged to both Gua and the Unity Console and become failed results.
press_key modifier bits are 1=Shift, 2=Alt, 4=Control, and 8=Command. Enter, Esc, and Arrow* aliases are normalized to Unity KeyCode names. A global key request is routed to the focused textbox.
Engine-neutral specification
version_v1includes an optionaladapterVersionsmap. Unity reports the loaded native runtime version as{"unity":"<runtime version>"}.godotPluginVersionremains for compatibility and is null outside Godot.- Adapter bounds use physical viewport pixels with a top-left origin and positive right/down axes; NaN and Infinity are not allowed.
GuaWebSocketContext, the remote tree, and captured screenshots are available fromGua.Testing.- The C ABI includes
gua_runtime_set_adapter_version(runtime, adapter, version); existing exports remain available. - A screenshot consumed before a session reset completes as
stale_session, preventing an old image from appearing in the new session.
Lifecycle and ownership
BeforeSceneLoad creates two persistent GameObjects: a bootstrap driver and the runtime. Driver LateUpdate() runs begin → collect → end → dispatch actions → service screenshot requests. Destruction stops the bridge and disposes the native handle. The UPM artifact bundles Gua.Core.dll, Gua.Runtime.dll and dependencies, gua.dll, and gua_runtime.dll.
Usage notes
- For screens that need external integer-slider changes, use
Sliderfor now.SliderIntstate can still be observed. - Toggle clicks are delivered as value changes. Custom behavior should listen for value/change events as well as pointer events.
- When registering a custom Control, implement the role's actions in
TryApply. Observation-only controls can use a role without interactive actions. - Parallel Unity test hosts use dynamic ports. Avoid running an unrelated process that pins the same port range.
Observe and physics API
The engine integration can register typed Observe values on published UI/World owners. External Gua.Testing.GuaWebSocketContext uses GetObserveSnapshotJson/SubscribeObservations when observe_v1 is advertised. Engine registration examples · Managed and remote examples.
Physics queries use an explicitly authorized Testing/Debug provider; Debug observation alone is insufficient. External tests call GetSpatialInfo/QuerySpatialBatch. GodotPhysics3D/Jolt and Unity PhysX setup documents bounds and invalidation. Built-in browser WebMCP privileged physics queries are unsupported. Query semantics and limits.