PartState.outline ​

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 PartState · stable · since 2.0.0

ts
outline?: {
  color: ColorValue;
  widthPx?: number;
} | null;

A screen-space outline around the parts, for hover and selection. To outline the product as a whole, as 1.x's highlight did (it resolved the hovered mesh to its model root), write it from your 'hover' handler on the hovered part's model root (node(hit.part.node)), or for a collection part on its collection's root (or its item, part(key), when each item is a product), and only when that changes: 'hover' fires whenever the part under the pointer changes, and each outline write is a look commit (a feed entry and a 'committed' event). Null when the hover ends; the same write on the selected product. Look only: the parts keep their colour, and it is never saved or exported; a capture includes it. It follows skinned and animated parts and holds across a level-of-detail swap. It is never drawn into the shadow map or the ambient-occlusion pass, and never counts for picking or bounds. It is cleared when its part leaves the scene (a scene write removes or disables its model, or its item is removed), so it doesn't come back with it. On a group part it outlines every mesh below. Reset it with null.

Default: unchanged

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/06-PartState.outline.ts):

ts
import type { CommitOptions, Part, Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
const look = { color: '#2f80ed', widthPx: 2 } as const;
// The product a part belongs to: its model's root, else its collection's root.
const productOf = (p: Part<CommitOptions>): Part<CommitOptions> =>
  p.node !== null ? session.node(p.node)
    : p.collection !== null ? session.collection(p.collection).root : p;
let hovered: Part<CommitOptions> | null = null;
let hoveredId: string | null = null;
session.on('hover', ({ hit }) => {
  const next = hit ? productOf(hit.part) : null;
  const id = next ? `${next.node ?? next.collection}/${next.id}` : null;
  if (id === hoveredId) return;                    // 'hover' fires per part: write per product
  void hovered?.set({ outline: null });
  hovered = next;
  hoveredId = id;
  void hovered?.set({ outline: look });
}, { signal });
// A selection outline is the same write on the selected product, reset with null when the
// selection moves; a model that leaves the scene takes its outline with it.

Generic-API test (spec 3.1) ​

Rule Result
1. Neutral name pass: outline names no product
2. A precedent pass: Babylon.js HighlightLayer (row G38); Babylon.js OutlineRenderer (row G38); Unity LineRenderer (row K49); Babylon.js EdgesRenderer (row K49)
3. Two apps, or labs pass: 9 apps (ledger: app-378d190f1b, app-4f16d2f6da, app-510d750508, app-822bb9d6aa, app-b4ae2fce25, app-ceb4eccc72, app-ddfb017681, app-fc07850558 and 1 more; fleet cross-check: app-4f16d2f6da, app-510d750508, app-822bb9d6aa, app-ceb4eccc72)
4. The cheaper fix first decided per need in Appendix B: rows G38, K49 at tier stable (a member only where no rule, data, asset or app code serves the need)