---
title: "Sounds, GAS, motion, and textures"
description: "Quartz UI 0.57.0-dev: Sounds, GAS, motion, and textures. Source-reviewed guidance, usage and limitations."
status: approved
visibility: public
sourceRevision: fe5b709ec900e282b50e58b819a25041945005f9
reviewedAt: 2026-09-24
---

# Sounds, GAS, motion, and textures

> **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](https://betterbuilt.games/docs/quartz-ui/evidence).

These integrations keep Unreal resources and gameplay ownership native. The browser receives semantic names, immutable values, or issued image URLs. Start with the exact-player shell from [setup](https://betterbuilt.games/docs/quartz-ui/first-ui).

## Semantic sound

Create a `UQuartzUISoundSet` Data Asset. Add an `FQuartzUISoundEntry` for `ui.confirm` with a soft sound reference; optionally preload small latency-critical cues. Set it as the project's Default Sound Set. The page uses the shipped transport:

```js
const result = await client.request('quartzui.sound.play', { sound: 'ui.confirm' });
// Inspect result.routed and optional reason; the UI action itself must not await audio.
```

`UQuartzUISoundSubsystem` belongs to one LocalPlayer. `PushSoundSet` adds an override; `RemoveSoundSet` removes the newest matching push. Resolution searches newest pushed sets then the default. Balance operations in the same feature lifetime. Each set permits 128 entries; admitted cues are bounded to 32 per second per player. Volume/pitch are clamped. Invalid tags, absent mappings, declined handlers, and rate limits have explicit outcomes.

For another audio backend, subclass `UQuartzUISoundHandler`: Initialize once, Handle Sound for each cue, Shutdown at subsystem teardown. Handler precedence is resolving set, project default, then built-in async-load/PlaySound2D. A listener on On Sound Requested is an alternative without a sound set; listeners also fire alongside mapped playback, so avoid double playback when using both. No browser-supplied asset paths are accepted. The npm-style `playSound2D` wrapper in the old guide is not shipped in this repository.

## Gameplay Ability System

Enable GameplayAbilities and restart the host. Add **QuartzUI GAS Binding** (`UQuartzUIGASBindingComponent`) to the local PlayerController, HUD, pawn, or valid owner chain. Leave Config unset for automatic discovery and Browser Ability Action Policy `Disabled` for observation. `QuartzUIGAS` loads only when its optional dependency is enabled; native consumers include its headers via a client module dependency.

```js
const stopAttributes = client.subscribeState('quartzui.gas.attributes', snapshot => {
  renderAttributes(snapshot); // Decode the generated FQuartzUIGASAttributeState shape.
});
```

The adapter snapshots context, attributes, tags, abilities, and status effects; matching events follow state updates. `UQuartzUIGASConfig` provides aliases, mappings, costs, failure labels, and action permissions. With automatic discovery disabled, mappings become the complete exposed allowlist. `UQuartzUIGASResolver` is the project seam for unusual ASC ownership; the exact-player guard still applies.

To permit a browser action, explicitly choose `ExplicitMappings` or `AllDiscovered`, then use the generated `quartzui.gas.activate` / `quartzui.gas.cancel` request shape. Do not infer request field names or treat UI affordability as authoritative. Unreal validates IDs, ownership, grants, rates, costs, cooldowns, and permission. No ASC/spec handles or UObject references cross the bridge.

The component owns retries, source replacement, and delegate cleanup. For custom feature ownership, `UQuartzUIGASBlueprintLibrary` creates a scope; attach that scope to the exact shell and detach on deactivation. Internal activate/cancel endpoint classes and observed-record structs are owned by that scope; do not instantiate an alternative endpoint for the reserved names.

## Camera-driven UI motion

Add **QuartzUI Motion** (`UQuartzUIMotionComponent`) to the local PlayerController. It samples in PostUpdateWork and publishes `quartzui.motion` to an existing presented shell at a bounded 1–60 Hz. The component does not create the shell. The snapshot includes `enabled`, `headingDegrees`, tilt, roll, offsets, shake, intensity, and revision.

Minimal use: call **Add Motion Impulse** with screen direction `(1,0)` and strength `0.25`, then consume the snapshot in your web CSS transform. Call **Set Motion Effects Enabled(false)** for a reduced-motion preference and also suppress web-side animation. Do not assume the component automatically consumes every presentation preference. EndPlay clears/publishes disabled state; the component owns its tick samples. Compass heading and visual shake are presentation data, not simulation input.

## Static Unreal textures in HTML

For a loaded, cook-reachable `UTexture2D`, use the logical view's `UQuartzUITextureResources`:

```cpp
const FString Url = View->GetTextureResources()->RegisterTexture(Texture);
// Empty: pending, unsupported, or failed. Republish when GetRevision changes.
```

Include `QuartzUIView.h` and `QuartzUITextureResources.h`; retain/load the texture through ordinary Unreal ownership before registration. Publish only a ready nonempty URL in your DTO. On the page, validate with `unrealTextureResource(value, document.baseURI)` from `texture-resources.mjs`, then assign the result to an image `src` if non-null.

This is one queued texture per tick, one-time GPU readback and PNG encoding, cached per UObject. It may spike the first frame. Bounds include 256 textures/view, longest output side 1024, 8 MiB encoded/image, and 128 MiB encoded/process. Streaming or pixel changes do not refresh an existing snapshot. `ReleaseAll` revokes URLs and permits re-registration; closing the view revokes all its URLs and releases references. Same-origin code given another view's URL can read it: the URL is a capability, not per-document authentication.

This API does not import live render targets, materials, virtual textures, or HDR-preserving frames into Chromium. It is not zero-copy.

## Bake authored textures instead

For a large immutable icon catalog, use `Scripts/texture_resources.py` from Unreal Editor Python. Supply explicit stable IDs, full Texture2D object paths, a project-owned output directory, and `unreal_exporter()`:

```python
from pathlib import Path
from texture_resources import bake, unreal_exporter
bake([{"id": "track-preview", "asset": "/Game/UI/T_Track.T_Track"}],
     Path(project_generated_directory) / "textures", unreal_exporter())
```

Put the plugin Scripts directory on Python's module path and define `project_generated_directory` in your host tooling. The editor must have Python support and exportable texture source. The tool validates the whole batch before replacing owned output, hashes/deduplicates PNGs, and preserves existing output on failure. It refuses unsafe paths and unowned output roots.

Bundle the manifest as compiled JS data, or otherwise stage it through a validated host rule: UAT may omit raw `.json` files. Use `textureResource(manifest, 'track-preview', baseUrl)` to resolve a same-origin file; missing IDs return null. The bake itself does not make the source asset cook-reachable or prove in-game alpha/color.

Sound guide (source: `Documentation/UISounds.md`), GAS guide (source: `Documentation/GAS.md`), motion source (source: `Source/QuartzUIRuntime/Public/QuartzUIMotionComponent.h`), texture guide (source: `Documentation/TextureResources.md`). Native/editor examples remain unexecuted in this scan.

Canonical HTML: https://betterbuilt.games/docs/quartz-ui/integrations
