Rendering and spatial UI
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.
Choose the presentation path before tuning raster size. Each browser has a rendering cost; a browser per unit marker is usually the wrong architecture. None of these APIs changes gameplay authority.
| Path | Ownership and purpose | Current boundary |
|---|---|---|
| UMG/Slate screen UI | widget presents one logical view | Raster follows actual Slate geometry/DPI |
| Direct world surface | static mesh samples stable browser texture | Passive; Win64 D3D11/D3D12 capability gate |
| Compatibility spatial widget | UWidgetComponent presents browser through its render target | Passive; extra world-widget composition |
| DOM projected markers | one page renders bounded position snapshots | Browser cadence adds latency |
| Retained HTML projection | native render view positions HTML atlas pixels | Experimental; fixed-cell atlas and limited interaction |
Scene backdrop
For a transparent screen-space browser, mark a panel:
<aside data-quartzui-backdrop="frost"
style="backdrop-filter:blur(24px);border-radius:18px;background:#15203344">
<h2>Inventory</h2>
</aside>
The native observer maps its geometry to the exact local player's viewport and filters the post-tonemap scene before browser composition. SetSceneBackdropEnabled(false) disables it per widget. A standalone Slate host must supply its owning LocalPlayer. No scene capture or CPU readback is needed for this effect.
Bounds: eight rounded rectangles, blur 0–64 CSS pixels, screen-space SDR. DOM-behind-DOM blur stays normal CSS. Separate browser views cannot blur each other. Arbitrary filter chains, transformed clipping, HDR/stereo, world-space blur, and a fully qualified split-screen rendering matrix are not established. Hiding retained panels must remove their regions; the shipped observer tests cover hidden ancestors and in-flight updates.
A passive panel in the world
Add QuartzUI Direct World Surface (UQuartzUIWorldSurfaceComponent) to an actor. Its defaults supply an engine plane and pass-through material. Set Raster Size, then call InitializeApp(AppAsset, LocalPlayer) for normal project contracts/providers. A custom material needs a Texture2D parameter whose name matches Texture Parameter Name (default SlateUI).
The mesh transform controls physical size; raster pixels control sharpness. The default engine plane is 100×100 units before scale. Match aspect ratios explicitly. AttachToView(View) instead borrows an existing unpresented view; InitializeStandalone(Definition) supplies only the core contract. Use exactly one path.
UQuartzUISurfaceTexture is a stable facade over Epic's existing browser texture. Do not recreate it every frame. The component owns heartbeat, resizing, binding generations, visibility suspension, and teardown. ReleaseQuartzUI releases its presentation/session; owned versus borrowed view behavior follows the initialization path. Auto-suspension normally begins when hidden or not recently rendered, with lower-frequency visibility polling. Providers are refreshed when revealed.
Transparent browser output is premultiplied alpha. Prefer a matching AlphaComposite material; inspect UV orientation and gamma on target hardware. Sizes are capped by both axis and project memory budgets; avoid continuously resizing with distance.
The transfer is reported as BackendManaged, not zero-copy. The facade adds no second full-size copy, but Epic's backend may copy/synchronize. D3D12 historical host evidence is recorded upstream; D3D11 remains runtime-unvalidated there due to a stock host/device failure. This scan ran neither RHI. Input rays, mesh-UV hit mapping, keyboard/IME, and multi-user focus are not implemented by the direct surface.
Compatibility spatial widget
Use UQuartzUIWidgetComponent only when the standard UWidgetComponent path is needed. Initialize with the same app/view/standalone choice. World space uses authored world geometry and draw size; screen space projects the anchor to a player widget layer. It disables hardware interaction and hit testing. Suspend it explicitly when pooling/hiding it and release its browser on owner teardown. Budget the browser raster and the additional UWidgetComponent render target separately.
Project world points into one DOM
FQuartzUISpatialProjection and UQuartzUISpatialBlueprintLibrary::ProjectWorldLocations accept the exact PlayerController, a bounded point array, and FQuartzUISpatialProjectionSettings. They return one FQuartzUISpatialProjectionResult per input index, including invalid/behind-camera entries. Use projection success/on-screen flags before displaying records.
Minimal Blueprint flow: after camera updates, Project World Locations → pair results with your stable IDs → publish a compact struct snapshot → update keyed web elements. Choose physical pixels or DPI-converted viewport/widget coordinates once; do not divide by DPI twice. Separate high-frequency positions from ordinary inventory data. FlushOutboundMessagesNow can reduce one native tick delay but cannot make asynchronous Chromium paint synchronous.
Experimental retained HTML projection
FQuartzUIHtmlProjection accepts Player, owning View, a permitted page URL, atlas dimensions, cell pixels, and an interactive flag. Its separate document needs its own normal contract handshake. Create it once in a native owner; call Update after pose updates with copied FQuartzUIHtmlAnchor values; destroy it before the player/view lifetime ends.
Minimal recipe: a 2×1 atlas with 64×64 cells paints normal/hover artwork; add one anchor with a stable Key, world Position, and cell indices 0/1. For passive nameplates set bInteractive=false. PublishContent sends retained projection.content only when artwork metadata changes; world positions belong in Update, not repeated browser messages. SetCallbacks receives validated activation/hover keys for the interactive path.
Limits: at most 128 anchors; uniform bounded cells; no world occlusion, general DOM partitioning, differently sized cells, or full input per cell. Browser Ready and frame ID do not prove a particular content revision is painted. The host must manage allocation/repaint consistency; never reuse a live cell for another identity without a strategy. This prototype is an opt-in advanced page, not a general production replacement for the shell.
Measure what the user sees
Use stat QuartzUI for plugin counters, Unreal Insights/GPU profiling for composition, and Chromium tools for page cost. Surface estimates are not full GPU/process memory. The development FrameProbe measures composed-backbuffer timing and optional frame capture, not monitor scanout. Historical benchmark figures in the original docs are not promises for this revision or hardware.
Rendering guide (source: Documentation/Rendering.md), direct surfaces (source: Documentation/DirectWorldSurfaces.md), projection (source: Documentation/HtmlProjectionPrototype.md). All rendering recipes require host/RHI validation; none were rendered during this scan.