# `IMaterialNode`

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

Type · `import type { IMaterialNode } from '@holostep-configurators/runtime-client/contract';` · stable · since 2.0.0 · section 21. Stored data (vendored; replaces @holo/interfaces)

Stored MaterialNode (format unchanged). A partial look; what it does to the GLB material
depends on how it is worn:
- selected ([`select(group, material)`](Writer.select.md), the scene model's choice): it lies over the GLB's
  material field by field, and the map slots it doesn't set keep the GLB's maps (spec section
  6.10, R1: the scene-model layer);
- worn by a rule (`{ materialNodeId }` in [`PartState.material`](PartState.material.md)) or a collection item's
  `material`: it replaces what the part wears, the GLB's maps included, as a [`Material`](Material.md) does
  ([`MaterialInput`](MaterialInput.md)).
There is no plain base-colour field: a colour-only finish (a priced RAL colour) is stored as a
`baseColorTextureUrl` of a flat image in that colour, which [`materialSpecFromNode`](materialSpecFromNode.md) reads with a
white `baseColor` so the image shows as stored. A colour kept outside the stored format (a
rule's `{ baseColor }`) is a look, never priced or saved.

Inherited from [`IConfiguratorNode`](IConfiguratorNode.md): [`_id`](IConfiguratorNode._id.md), [`type`](IConfiguratorNode.type.md), [`nodeId`](IConfiguratorNode.nodeId.md), [`label`](IConfiguratorNode.label.md), [`order`](IConfiguratorNode.order.md), [`enabled`](IConfiguratorNode.enabled.md), [`expanded`](IConfiguratorNode.expanded.md), [`createdAt`](IConfiguratorNode.createdAt.md), [`updatedAt`](IConfiguratorNode.updatedAt.md), [`children`](IConfiguratorNode.children.md), [`thumbnailUrl`](IConfiguratorNode.thumbnailUrl.md), [`attributes`](IConfiguratorNode.attributes.md).

## Declaration

```ts
export type IMaterialNode = IConfiguratorNode & {
  type: 'MaterialNode';
  sheenEnabled?: boolean;
  sheenIntensity?: number;
  sheenColor?: string;
  sheenRoughness?: number;
  specularEnabled?: boolean;
  specularIntensity?: number;
  specularColor?: string;
  ior?: number;
  clearcoatNormalScale?: number;
  emissiveColor?: string;
  emissiveIntensity?: number;
  optThumbnailUrl?: string;
  prices: IPrice[];
} & {
  [K in `${TextureChannel}TextureUrl` | `opt${Capitalize<TextureChannel>}TextureUrl`]?: string;
} & {
  [K in `${TextureChannel}TextureEnabled`]?: boolean;
};
```

## Generic-API test (spec 3.1)

| Rule | Result |
| --- | --- |
| 1. Neutral name | pass: `IMaterialNode` names no product |
| 2. A precedent | not recorded: no ledger row (coverage.json) names this member or its owner |
| 3. Two apps, or labs | not recorded: no ledger row names this member or its owner |
| 4. The cheaper fix first | not recorded per member (Appendix B decides it per need) |
