# `Overlays.hotspots.set`

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

Method of [`Overlays.hotspots`](Overlays.hotspots.md) · stable · since 2.0.0 · called as `session.overlays.hotspots.set`

```ts
set(badges: readonly HotspotBadge[]): void;
```

Replaces every badge (an empty array removes them). Sync; drawn from the next frame, or,
before the badge code has loaded (it loads at idle after the first complete frame), from the
first frame after it loads (spec section 6.3).
A badge it removes fires no 'hotspot:click' from the call on, while its button waits for that
frame or, during a hold, the reveal.
Badges match by `id`: a badge whose `id` survives keeps its `<button>`, so focus, hover and the
pressed state stay and only its label, position and order change; buttons follow array
order, so re-sending the whole list on every change is fine. When the focused badge is
removed, focus moves to the badge now at its index, else the new list's last badge, else to `el`:
when `el` has no `tabindex` attribute, the runtime sets `tabindex="-1"` for that focus and
removes it at `el`'s next `blur`, so focus never drops to `<body>` and `el` never joins the
tab order. A page-set negative `tabindex` on `el` takes every badge out of the tab order
([`BootOptions.el`](BootOptions.el.md)). A badge hidden off-screen or occluded keeps its place in the tab order and is
drawn while it has focus, clamped inside the element (spec section 5.9).
Errors: throws HoloInputError on invalid badges; a repeated `id` records 'hotspot-id-taken'.

## 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/13-Overlays.hotspots.set.ts`):

```ts
import type { Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
declare function openPanel(id: string): void;
session.overlays.hotspots.set([
  { id: 'cushions', at: { x: 0, y: 0.45, z: 0.2 }, label: 'Cushions' },
  { id: 'legs', at: { x: 0.9, y: 0.05, z: 0.4 }, label: 'Legs' },
]);
session.on('hotspot:click', ({ hotspot }) => openPanel(hotspot.id), { signal });
```

## Generic-API test (spec 3.1)

| Rule | Result |
| --- | --- |
| 1. Neutral name | pass: `set` names no product |
| 2. A precedent | pass (through its owner [`Overlays.hotspots`](Overlays.hotspots.md)): [Babylon.js SpriteManager](https://github.com/BabylonJS/Babylon.js/blob/master/packages/dev/core/src/Sprites/spriteManager.ts) (row `K50`); [model-viewer (ar, camera-orbit, auto-rotate)](https://modelviewer.dev/docs/) (row `K50`) |
| 3. Two apps, or labs | pass: 18 apps (ledger: app-ddfb017681, app-fc07850558, app-fc306ec3dc; fleet cross-check: app-37356bf09f, app-4fd23bc869, app-822bb9d6aa, app-8675b3225c, app-bcb7ef21da, app-c1384707fc, app-e3b47169bc, app-e61a0b42ad and 7 more) |
| 4. The cheaper fix first | decided per need in Appendix B: rows `K50` (through its owner [`Overlays.hotspots`](Overlays.hotspots.md)) at tier stable (a member only where no rule, data, asset or app code serves the need) |
