# `MaterialSpec.variant`

> 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 [`MaterialSpec`](MaterialSpec.md) · inherited by [`MaterialInput`](MaterialInput.md) · labs, `@experimental` · since 2.0.0

```ts
variant?: string;
```

A KHR_materials_variants variant of the GLB the mesh comes from ([`AssetManifest.variants`](AssetManifest.variants.md)): the
base this rule's fields merge over is that variant's material for the mesh instead of the one
it wears, so `{ variant: 'Walnut', roughness: 0.35 }` shows the GLB's walnut, glossier. A mesh
the variant maps no material to keeps its own, as the glTF extension reverts it. A name the
mesh's model doesn't declare records 'unsupported-spec' with `path` 'patch.material.variant'
(a [`find(q).set`](PartActions.set.md) or [`node(id).set`](PartActions.set.md); 'scene.rules[i].set.material.variant' for a rule [`apply`](Writer.apply.md)
lists), naming the meshes and the names it declares, and the fields lay over what the mesh
wears. The variant's material loads on first use: the mesh shows its own until it lands, and
[`idle()`](Session.idle.md) waits for it. Experimental: check [`supports('spec.material.variant')`](Session.supports.md) before writing
it, and keep the mesh's own material where it answers false.
Only in a rule's material over a GLB's mesh: a whole material ([`materials.create`](Materials.create.md), [`apply`](Writer.apply.md)'s
`materials`) has no GLB under it and rejects it (HoloInputError 'invalid-input'). Null in a
rule removes it. The stored format has no field for it ([`materialNodeFromSpec`](materialNodeFromSpec.md) lists it in
`unstorable`). The fake checks the name against [`FakeModel.variants`](testing.FakeModel.variants.md) (`fakeModelFromGlb` fills
it from the file), else [`FakeModel.manifest.variants`](AssetManifest.variants.md).

**Default:** undefined (the material the mesh wears)

## 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/08-MaterialSpec.variant.ts`):

```ts
import type { Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
// the GLB's own walnut on the doors, a little glossier; reset with null
const doors = session.find({ node: 'cab', slot: 'Front' });
if (session.supports('spec.material.variant')) {
  const r = await doors.set({ material: { variant: 'Walnut', roughness: 0.35 } });
  for (const p of r.problems) console.warn(p.code, p.message); // a name the GLB lacks
}
```

## Generic-API test (spec 3.1)

| Rule | Result |
| --- | --- |
| 1. Neutral name | pass: `variant` names no product |
| 2. A precedent | pass (through its owner [`MaterialSpec`](MaterialSpec.md)): [glTF 2.0 metallic-roughness material](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#metallic-roughness-material) (row `K10`); [glTF KHR_materials_sheen](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen) (row `K10`); [glTF KHR_materials_transmission](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_transmission) (row `K10`); [glTF KHR_materials_unlit](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_unlit) (row `K10`) |
| 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: app-04c2774145, app-0c773a4ee3, app-37356bf09f, app-378d190f1b, app-4762caacdc, app-4f16d2f6da, app-4fd23bc869, app-510d750508, app-59c5b5751e, app-822bb9d6aa, app-8675b3225c, app-b362a81c85, app-b4ae2fce25, app-bcb7ef21da, app-c1384707fc, app-ceb4eccc72, app-ddfb017681, app-e3b47169bc, app-e61a0b42ad, app-e9a33606d2, app-f07e9033d9, app-f3598fad77, app-f9a32142f1, app-fb16dd1985, app-fc07850558, app-fc306ec3dc, app-fd09090420, configurator-template |
| 4. The cheaper fix first | decided per need in Appendix B: rows `K10` (through its owner [`MaterialSpec`](MaterialSpec.md)) at tier stable (a member only where no rule, data, asset or app code serves the need) |
