# `Events`

> 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.

Interface · `import type { Events } from '@holostep-configurators/runtime-client/contract';` · stable · since 2.0.0 · section 18. Events

Typed events. State events (those a commit causes) carry `cause`; input, camera, animation and
overlay events have no commit behind them and carry none. Payloads are frozen snapshots of their
commit; reads in a handler may be newer (`cause.seq < session.seq`). A payload may also predate
a write you have since called: never merge a whole snapshot over newer app state (the
[`setSceneModel`](Writer.setSceneModel.md) example merges each commit's `patch` from 'committed', never its whole model).
An equal write (one that
resolves `changed: false`) fires nothing, except 'history:changed': an equal undo or redo fires
it, because its history pointer moves (O9), and an equal write with `undo: 'rebase'` fires it
when the flags change (O15). Subscribe with [`session.on(name, handler, { signal })`](Session.on.md).

## Members

| Member | Kind | Summary |
| --- | --- | --- |
| <a id="committed"></a>[`committed`](Events.committed.md) | property | The commit feed: one entry per commit, after it is shown. |
| <a id="scene-model_changed"></a>[`scene-model:changed`](Events.scene-model_changed.md) | property | `model` carries no key material: merge its placement, `enabled` and group selections into your own document by `nodeId`; never save it as is. |
| <a id="assembly_changed"></a>[`assembly:changed`](Events.assembly_changed.md) | property | The connections changed in a commit: one event per commit whose connections differ from the previous commit's, whatever changed them (`attach`, `detach`, [`setSceneModel`](Writer.setSceneModel.md), [`applyPatch`](Writer.applyPatch.md), undo, redo, a restore, a reload,… |
| <a id="material_selected"></a>[`material:selected`](Events.material_selected.md) | property | A global-material GroupNode's selection changed in a commit: `material` (a MaterialNode `nodeId`) is now selected in `group`. |
| <a id="history_changed"></a>[`history:changed`](Events.history_changed.md) | property | The undo state changed: the same fields as [`session.history`](Session.history.md). |
| <a id="click"></a>[`click`](Events.click.md) | property | A click or tap on the canvas. |
| <a id="hover"></a>[`hover`](Events.hover.md) | property | The part under a mouse or pen pointer changed; `hit` is null when it leaves. |
| <a id="drag_start"></a>[`drag:start`](Events.drag_start.md) | property | `part` is the dragged unit (a model's root, or a collection item); `pose` is its world pose. |
| <a id="drag_move"></a>[`drag:move`](Events.drag_move.md) | property | The pointer moved during a drag; `pose` is the unit's world pose as drawn for that move, after `constrain` (the proposal `constrain` received is [`DragMove.pose`](DragMove.pose.md)). |
| <a id="drag_end"></a>[`drag:end`](Events.drag_end.md) | property | `pose` is the last constrained world pose. |
| <a id="camera_control-start"></a>[`camera:control-start`](Events.camera_control-start.md) | property | The shopper started a pointer or touch gesture: orbiting, panning or a two-finger pinch. |
| <a id="camera_control-end"></a>[`camera:control-end`](Events.camera_control-end.md) | property | The shopper's pointer or touch gesture ended (never after a wheel; see 'camera:control-start'). |
| <a id="camera_rest"></a>[`camera:rest`](Events.camera_rest.md) | property | The camera came to rest (after a move, damping or a gesture). |
| <a id="camera_changed"></a>[`camera:changed`](Events.camera_changed.md) | property | After a drawn frame that changed the camera; the state at subscription is the baseline. |
| <a id="anchors_moved"></a>[`anchors:moved`](Events.anchors_moved.md) | property | At most once per frame, after a drawn frame that moved an anchor or changed its `visible`. |
| <a id="hotspot_click"></a>[`hotspot:click`](Events.hotspot_click.md) | property | A hotspot badge was clicked, tapped, or pressed with Enter or Space (the button's `click` event); a pointer press counts only when released on the badge within the 'click' event's thresholds, so a sweep that starts on… |
| <a id="hotspot_hover"></a>[`hotspot:hover`](Events.hotspot_hover.md) | property | The badge under the pointer, else the badge with keyboard focus (`:focus-visible`), else null; it fires when that changes, so content you show on hover also shows on focus (WCAG 1.4.13). |
| <a id="animation_started"></a>[`animation:started`](Events.animation_started.md) | property | A clip that was neither playing nor paused started playing; a play that takes over a playing clip, or resumes a paused one, fires nothing. |
| <a id="animation_stopped"></a>[`animation:stopped`](Events.animation_stopped.md) | property | A playing or paused clip stopped before its end: by `stop`, `reset`, a `play` of an exclusive clip, a new asset version, or the removal of its node or item. |
| <a id="animation_finished"></a>[`animation:finished`](Events.animation_finished.md) | property | A clip reached the end of its play's direction (frame 0 for a `reverse` play), after its last play for `loop: n`; a `loop: true` clip never does. |
| <a id="ar_status"></a>[`ar:status`](Events.ar_status.md) | property | The AR launch state changed. |
| <a id="ar_modes"></a>[`ar:modes`](Events.ar_modes.md) | property | `info().ar.modes` or `fileModes` changed: 'webxr' joined once the probe answered after [`boot`](boot.md), a commit gave or took the product's public plain twin ('scene-viewer'), a document apply turned AR on or off, the… |
| <a id="xr_start"></a>[`xr:start`](Events.xr_start.md) | property · labs | Holostep's in-page AR or try-on showed its first picture: `experience` is 'place' (in-room AR) or 'try-on', `presenter` the viewer that shows it, named as [`ActivateARReport.mode`](ActivateARReport.mode.md) and `info().ar.modes` name it: 'webxr'… |
| <a id="xr_end"></a>[`xr:end`](Events.xr_end.md) | property · labs | That XR session ended, `durationMs` after the tap: 'user' (the shopper closed it), 'error', 'background' (the page was hidden), 'destroy', 'fallback' (the shopper went on to the native AR viewer or the 3D view),… |
| <a id="xr_cta"></a>[`xr:cta`](Events.xr_cta.md) | property · labs | A call to action in AR (the in-page AR's button, the Quick Look banner): `configuration` is the scene model at the tap, with no key material. |
| <a id="resize"></a>[`resize`](Events.resize.md) | property | The element was resized; the aspect follows at once. |
| <a id="document_applied"></a>[`document:applied`](Events.document_applied.md) | property | A document layer was applied; the same report [`applyDocument`](Session.applyDocument.md) resolves with. |
| <a id="problem"></a>[`problem`](Events.problem.md) | property | A Problem was recorded (also in [`info().problems`](InfoReport.problems.md)). |

## Declaration

```ts
export interface Events {
  'committed': {
    readonly cause: Cause;
    readonly label: string | null;
    readonly recorded: boolean;
    readonly patch: readonly JsonPatchOp[];
    readonly inverse: readonly JsonPatchOp[];
    readonly checkpoint: JsonValue | null;
  };
  'scene-model:changed': {
    readonly cause: Cause;
    readonly model: DeepReadonly<SceneModel>;
  };
  'assembly:changed': {
    readonly cause: Cause;
    readonly connections: readonly Connection[];
  };
  'material:selected': {
    readonly cause: Cause;
    readonly group: string;
    readonly material: string;
  };
  'history:changed': {
    readonly cause: Cause;
  } & Pick<History, 'canUndo' | 'canRedo' | 'undoLabel' | 'redoLabel' | 'depth'>;
  'click': {
    readonly at: ScreenPoint;
    readonly hit: Hit | null;
  };
  'hover': {
    readonly at: ScreenPoint;
    readonly hit: Hit | null;
  };
  'drag:start': {
    readonly part: Part<CommitOptions>;
    readonly pose: Pose;
    readonly pointerId: number;
  };
  'drag:move': {
    readonly part: Part<CommitOptions>;
    readonly pose: Pose;
    readonly at: ScreenPoint;
  };
  'drag:end': {
    readonly part: Part<CommitOptions>;
    readonly pose: Pose;
    readonly moved: boolean;
    readonly reason: 'released' | 'cancelled' | 'other';
    readonly cause: Cause | null;
    readonly op: OpId | null;
  };
  'camera:control-start': void;
  'camera:control-end': void;
  'camera:rest': {
    readonly state: CameraState;
  };
  'camera:changed': {
    readonly state: CameraState;
  };
  'anchors:moved': {
    readonly anchors: readonly AnchorPosition[];
  };
  'hotspot:click': {
    readonly hotspot: HotspotReference;
  };
  'hotspot:hover': {
    readonly hotspot: HotspotReference | null;
  };
  'animation:started': ClipRef;
  'animation:stopped': ClipRef;
  'animation:finished': ClipRef;
  'ar:status': {
    readonly status: 'disabled' | 'unsupported' | 'activating' | 'active' | 'error' | 'other';
    readonly place?: {
      readonly state: string;
      readonly hint: string;
    };
  };
  'ar:modes': {
    readonly modes: InfoReport['ar']['modes'];
  };
  'xr:start': {
    readonly presenter: 'webxr' | 'scene-viewer' | 'quick-look' | 'other';
    readonly experience: 'place' | 'try-on' | 'other';
  };
  'xr:end': {
    readonly reason: 'user' | 'error' | 'background' | 'destroy' | 'fallback' | 'other';
    readonly durationMs: number;
  };
  'xr:cta': {
    readonly action: 'add-to-cart' | 'back' | 'other';
    readonly configuration: DeepReadonly<SceneModel> | null;
  };
  'resize': {
    readonly width: number;
    readonly height: number;
  };
  'document:applied': ApplyReport;
  'problem': {
    readonly problem: Problem;
  };
}
```

## Generic-API test (spec 3.1)

| Rule | Result |
| --- | --- |
| 1. Neutral name | pass: `Events` names no product |
| 2. A precedent | not recorded: no ledger row (coverage.json) names this member or its owner |
| 3. Two apps, or labs | pass: 21 apps (fleet cross-check: app-04c2774145, app-0c773a4ee3, app-37356bf09f, app-378d190f1b, app-4762caacdc, app-4fd23bc869, app-822bb9d6aa, app-8675b3225c and 13 more) |
| 4. The cheaper fix first | not recorded per member (Appendix B decides it per need) |
