# `ActivateAROptions.ui`

> Contract 2.0.0 · package sha256 `a857eca95b35921109faf997094bb4192f12527d9d0fcd4be7e97f06425bad6e` · generated from `configurator-runtime.d.ts` by `services/onsite-scripter/scripts/build-contract-docs.mjs`; edit the source, not this file.

Property of [`ActivateAROptions`](ActivateAROptions.md) · labs, `@experimental` · since 2.0.0

```ts
ui?: 'default' | 'headless';
```

'default' shows Holostep's AR screens; 'headless' lets the page draw its own: Holostep's
in-page AR then shows only the camera and the product (no coaching icons, buttons, arrow or
sheets) and tells its state through `place` on 'ar:status'. The page closes it with [`endAR()`](Session.endAR.md)
(the shopper's back gesture and Escape still close it). A fault that would ask the shopper
(the camera or motion refused, the device too hot) ends the session ('xr:end' 'error'), with
`place` saying why. Where the in-page camera route doesn't apply, a headless call opens the
native AR viewer (on Android's WebXR route too), or, in an in-app browser where none can open,
resolves `{ launched: false, reason: 'unsupported' }` with no sheet. Pair it with
[`overlayRoot`](ActivateAROptions.overlayRoot.md) for your controls. Check [`supports('activateAR.ui.headless')`](Session.supports.md) first; where it
answers false a headless call opens the native AR viewer.

**Default:** 'default'

## Example

Imports: values (`has`, `validate`, the `Holo*Error` classes, the pure helpers) from `@holostep-configurators/runtime-client`, types from `@holostep-configurators/runtime-client/contract`, `/math` and `/testing` names from those entries; `boot` from the runtime module the root's `loadRuntimeAtFloor` resolves to. A type your page defines is your app's: declare it there, never import it from the package.

Compiled under the contract's strict settings (`examples/declaration/16-ActivateAROptions.ui.ts`):

```ts
import type { Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
declare const controls: HTMLElement;
declare const line: HTMLElement;
declare function closeButton(onClick: () => void): void;
const words: Record<string, string> = {
  'point-at-floor': 'Point your phone at the floor',
  'hold-still': 'Hold still',
  'camera-denied': 'Allow the camera to see this in your room',
};
session.on('ar:status', ({ status, place }) => {
  // an id you don't know: show nothing for it (both fields are open sets)
  if (place) line.textContent = words[place.hint] ?? '';
  if (status === 'error') line.textContent = words[place?.hint ?? ''] ?? 'AR did not start.';
}, { signal });
closeButton(() => session.endAR?.());
const headless = session.supports('activateAR.ui.headless');
await session.activateAR(headless ? { ui: 'headless', overlayRoot: controls } : {});
```

## Generic-API test (spec 3.1)

| Rule | Result |
| --- | --- |
| 1. Neutral name | pass: `ui` names no product |
| 2. A precedent | pass: [model-viewer canActivateAR and activateAR()](https://modelviewer.dev/docs/index.html#entrydocs-augmentedreality-methods-activateAR) (row `G66`); [XRSession.end()](https://developer.mozilla.org/en-US/docs/Web/API/XRSession/end) (row `G66`); [Navigator.share() (resolves when the share UI closes)](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share) (row `G66`) |
| 3. Two apps, or labs | labs (`@experimental` at a stable path, reached through `has()` or `supports()`): it graduates when a second app uses it; apps today: configurator-template, tryon-template |
| 4. The cheaper fix first | decided per need in Appendix B: rows `G66` at tier labs (a member only where no rule, data, asset or app code serves the need) |
