Quartz UI ↗
Browse docs
On this page
Private preview · 0.57.0-devView Markdown

Providers and typed contracts

0.57.0-dev · beta source documentation. Native, Blueprint, Editor and rendering examples are source-reviewed, not executed in Unreal during this scan. See validation and limits.

Use a provider when a screen needs a persistent gameplay model, such as inventory or player vitals. Use an explicit project contract when you want individually declared state/event DTOs and request/result endpoints. Both send copied values, never live Unreal objects, to one exact player's view.

Create a provider in Blueprint

  1. Derive a Blueprint from UQuartzUIProvider; set Provider Id to inventory.
  2. Add supported state variables such as integer Count. Add an Event Dispatcher only for information that is transient. Public callable functions become validated browser operations.
  3. Implement Provider Bound to resolve sources belonging to the passed player, install subscriptions, initialize all values, and return success. Implement Provider Unbound to remove those subscriptions, including partially installed ones.
  4. With Auto Update Interval zero, call Mark Provider Dirty after changing state. Use a positive bounded interval only when polling is necessary. Refresh Provider requests an immediate active-state comparison.
  5. Create a QuartzUI Provider Set, add this exact Blueprint class, set Activation to OnShellReady, and register the set in the app's RegisteredProviderSets.
  6. Save, generate the app contract, rebuild the frontend and manifest, then start the shell.

Minimal frontend consumption:

const unsubscribe = client.subscribeState('provider.inventory', snapshot => {
  // Verify generated casing: Count is illustrative until your contract is generated.
  if (Number.isInteger(snapshot.Count)) countElement.textContent = String(snapshot.Count);
});

The set's class membership determines the contract even when Activation is Manual. Registering a class does not instantiate it. OnShellReady is the activation policy name; automatic instances actually bind during shell startup before document Ready, with initial publication controlled by the readiness barrier. Distinct classes cannot share a Provider Id. The closure permits 32 exact classes; a registered base class does not authorize a subclass.

Native provider example

Put this in a game header, with the generated include last. The normal host module must already support Unreal reflection. This example publishes local demo data; replace it with subscriptions to your game model.

#pragma once
#include "CoreMinimal.h"
#include "QuartzUIProvider.h"
#include "InventoryUIProvider.generated.h"

UCLASS()
class UInventoryUIProvider : public UQuartzUIProvider
{
    GENERATED_BODY()
public:
    UInventoryUIProvider() { ProviderId = TEXT("inventory"); AutoUpdateIntervalSeconds = 0.0f; }
    UPROPERTY(BlueprintReadOnly, Category="UI")
    int32 Count = 3;
    // Native-only helper; does not expose authority to the browser.
    void SetCountFromGame(int32 NewCount) { Count = NewCount; MarkProviderDirty(); }
protected:
    virtual bool ProviderBound_Implementation(ULocalPlayer* Player, UQuartzUIView* View) override
    { return Player != nullptr && View != nullptr; }
    virtual void ProviderUnbound_Implementation() override {}
};

Ordinary supported reflected properties become state; dynamic delegates become typed events; eligible public functions become actions or requests. Avoid casually exposing admin/helper functions. QuartzUIIgnore excludes a member; QuartzUIName sets its web name, and QuartzUITypeName sets the generated type name. Do not reflect actors, components, object/class references, interfaces, delegates as ordinary state, sets, or unsupported map keys into DTOs.

Own a temporary provider lifetime

For a menu/feature that loads temporarily, use a Manual set:

const FQuartzUIProviderSetHandle Handle = FQuartzUI::BindProviderSet(Player, ProviderSet);
// Store Handle in the feature owner; release once that same owner deactivates.
FQuartzUI::ReleaseProviderSet(Player, Handle);

Validate the returned handle before treating the binding as active. Alternatively add UQuartzUIProviderBindingComponent to a PlayerController, HUD, pawn, or supported owner chain. Select its set/classes; empty selection means the app's complete registered closure. Activate/Deactivate/Retry and failure events expose startup ordering. Component destruction releases providers without closing the retained shell.

The optional Game Feature action described upstream belongs to a separate plugin absent from this checkout. Use manual/component lifetimes here, or supply and verify that sibling integration separately.

Declare explicit DTOs and endpoints

Create data-only USTRUCT types, then a UQuartzUIProjectContractAsset. Its States, Events, and Actions entries specify name and payload struct; Requests additionally specify a result struct. Register the fragment in the app's RegisteredProjectContracts array. Names are unique across all message kinds and cannot use quartzui.*.

For example, declare request inventory.inspect with a payload containing an item ID string and result containing a display-name string. Create a UQuartzUITypedEndpoint Blueprint subclass with Endpoint Name inventory.inspect. Bind it using Bind Typed UI Endpoint for the exact player. In Handle Request, read the supplied typed payload, check gameplay authority and item existence, create the declared result as an Instanced Struct, and call Complete Success on the request token. On failure call Complete Failure with a stable project code and bounded message.

// Only after the host declares and binds this exact request and its DTO fields.
const result = await client.request('inventory.inspect', { itemId: selectedId });

Field names above are a project design example, not a built-in endpoint. A request token completes once, with the exact declared result type. Retain asynchronous UObject tokens with a GC-visible reference and return to the game thread before touching Unreal objects. Navigation, timeout, endpoint removal, and teardown cancel pending work. The bridge caps pending requests at 32 per view and timeout at 50 ms–30 s. Client timeout/disposal cannot undo gameplay already performed.

Actions use Handle Action and an empty acknowledgment. Unbind by name when the owner stops accepting calls. EndpointUnbound runs after pending requests are canceled. Do not hold tokens across travel and assume they remain live.

UQuartzUIBindingScope is an advanced lifetime owner for explicit endpoints, subscriptions, initial state, and asynchronous cancellation tokens. Subclass it, set a stable Provider Id, add endpoints while detached, implement Begin Binding / Publish Initial State / End Binding, then AttachToShell(Player) or AttachToView(View). Call Detach() on feature teardown. The initial baseline must succeed before transient events are admitted. Use CreateCancellationToken() and check IsCurrent() before completing work from an old generation.

Provider subclasses already own this transaction through their reflection runtime: override Provider Bound/Unbound, not the generic scope hooks. Internal provider event relays, schemas, codecs, and binding records are implementation tools, not extra objects game code should create.

Regenerate after schema changes

Supported DTOs include finite numbers (integers within JavaScript's exact range), bools, strings/names/resolved text, explicitly mapped enums, nested structs, arrays, and string/name-keyed maps. The simple struct payload path bounds depth to 12, fields to 128, and container entries to 256. See the exact codecs for their own additional constraints.

Generate with QuartzUIContract -App=<id>, build the frontend against that file, rewrite manifest fingerprints, save/recook app assets, and run generation with -Check in CI. Cooked contract metadata preserves names and enum/optional-field metadata that cooked Unreal would otherwise strip. C++ layout changes require a full rebuild and restart; Live Coding is not a schema migration.

Native examples are source-reviewed only. Provider guide and source (source: Documentation/Providers.md), contract guide (source: Documentation/ProjectContracts.md), binding scope (source: Source/QuartzUIRuntime/Public/QuartzUIBindingScope.h).