# `Labs.decal`

> 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 [`Labs`](Labs.md) · labs · since 2.0.0 · called as `session.labs.decal`

```ts
decal(target: Query, spec: DecalSpec, options: {
  owner: Collection;
  signal?: AbortSignal;
}): Promise<Part<C>>;
```

A decal on the matched surfaces, owned by `owner`: an item of that collection under a key the
runtime makes, so its part has the owner's [`role`](Part.role.md) and [`collection`](Part.collection.md). Resolves with its part.
`owner.dispose()` removes it, and so does a later `set()` on the owner, as it removes `load()`
items its spec doesn't list, so give decals a collection of their own. Each piece of it moves
and hides with the part it lands on, and draws only while that part draws. Captures, exports
and the runtime's AR copy take it as any part of its role: an export, and [`activateAR`](Session.activateAR.md)'s own
USDZ and WebXR copy, carry it as a mesh (its projected geometry, wearing its image as the
base-colour map over [`material`](Part.material.md)) whenever their query matches its part, as the default role
'product' does for a 'product' owner (spec section 5.15). Rejects HoloAssetError when the
image fails, and AbortError, starting nothing, when `owner` is disposed. An asset load: not allowed inside [`beforeCommit`](Session.beforeCommit.md).
A commit that fails inside the runtime after it resolved drops it, as [`Collection.load`](Collection.load.md)'s does.

**Default:** options.signal undefined

## Options

Through [`Session`](Session.md):

| Option | Type | Default | What it does |
| --- | --- | --- | --- |
| `owner` | `Collection` | — |  |
| `signal` | `AbortSignal` | — |  |

Through [`Tx`](Tx.md):

| Option | Type | Default | What it does |
| --- | --- | --- | --- |
| `owner` | `Collection` | — |  |
| `signal` | `AbortSignal` | — |  |

## Abort (`signal`)

This call is neither a write, a registration, a wait nor a creator (`SignalOption.signal`, [the kinds of call](../read-this-first.md#conventions)).

> Cancels this call; the member's JSDoc says what an abort does.

## 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/20-Labs.decal.ts`):

```ts
import type { Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
declare const logo: HTMLCanvasElement;                     // the shopper's uploaded logo
// the logos' own collection: a later set() on it removes them
const logos = session.collection('logos', { role: 'product', signal });
await session.labs.decal(
  { node: 'cabinet', name: 'fascia' },
  { image: { image: logo }, at: { x: 0, y: 0.6, z: 0.3 }, size: { x: 0.3, y: 0.15 } },
  { owner: logos, signal },
);
// a new logo is a new decal: clear the owner, then call decal() again
await logos.set({ items: [] });
```

## Generic-API test (spec 3.1)

| Rule | Result |
| --- | --- |
| 1. Neutral name | pass: `decal` names no product |
| 2. A precedent | pass: [Babylon.js MeshBuilder.CreateDecal](https://github.com/BabylonJS/Babylon.js/blob/master/packages/dev/core/src/Meshes/Builders/decalBuilder.ts) (row `G24`); [Unity Projector](https://docs.unity3d.com/ScriptReference/Projector.html) (row `G24`) |
| 3. Two apps, or labs | labs: it graduates when a second app uses it; apps today: app-bcb7ef21da |
| 4. The cheaper fix first | decided per need in Appendix B: rows `G24`, `K52` at tier labs (a member only where no rule, data, asset or app code serves the need) |
