TextureSpec ​

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.

Interface · import type { TextureSpec } from '@holostep-configurators/runtime-client/contract'; · stable · since 2.0.0 · section 8. Materials and textures

At most one of url and image. With neither, inside a partial MaterialSpec, the spec changes only placement and sampling (uv, scale, offset, rotationDeg, sizeM, wrap, sampling) of the texture the slot shows now, whether it comes from the GLB, the scene model or an earlier rule. It never pins the image, so a later select() or undo changes the image and keeps your placement. On a slot that shows no texture it does nothing. With url or image it is a new texture, placed by its own fields: every field it omits (uv, scale, offset, rotationDeg, sizeM, wrap, sampling, colorSpace, enabled) takes its default below, never the value of the texture it covers (its texCoord, KHR_texture_transform or a stored …TextureEnabled: false), and only a URL-less spec above it lays fields over it, while the GLB's own image keeps its authored placement. Successive writes to one rule merge first (spec section 6.10, R10), so a scale an earlier write to that rule gave stays. Every texture, url, optimizedUrl and image alike, is sampled with the glTF convention: row 0 of the image is v = 0, never flipped.

Members ​

Member Kind Summary
url? property png, jpg, webp, avif, ktx2, hdr.
image? property A canvas or bitmap, copied at the call.
optimizedUrl? property The optimized twin the runtime prefers when present (stored opt…TextureUrl).
enabled? property false keeps the URL but shows no map (stored …TextureEnabled: false).
uv? property UV channel (glTF's TEXCOORD_n).
scale? property Repeats per UV unit (KHR_texture_transform).
offset? property In UV units.
rotationDeg? property Degrees, about the UV origin.
sizeM? property Physical size one image covers, metres.
wrap? property One mode, or [u, v].
sampling? property How the image is filtered when drawn smaller or larger than its pixels: 'pixel' for pixel art and data maps, a lower anisotropy to save GPU time on a slot seen face-on.
colorSpace? property How the image's values decode.

Declaration ​

ts
export interface TextureSpec {
  url?: string;
  image?: HTMLCanvasElement | OffscreenCanvas | ImageBitmap | ImageRef;
  optimizedUrl?: string;
  enabled?: boolean;
  uv?: 0 | 1 | 2 | 3;
  scale?: number | Point2;
  offset?: Point2;
  rotationDeg?: number;
  sizeM?: number | Point2;
  wrap?: Wrap | readonly [
    Wrap,
    Wrap
  ];
  sampling?: TextureSampling;
  colorSpace?: 'srgb' | 'linear';
}

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-TextureSpec.ts):

ts
import type { Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
declare const fabricGroup: string;
// Tile whatever fabric the shopper picks: no url, so only the placement is written.
await session.find({ slot: 'fabric' }).set({ material: { maps: {
  baseColor: { scale: 16 }, normal: { scale: 16 }, roughness: { scale: 16 },
} } });
// the image changes; the tiling stays
await session.select(fabricGroup, 'linen', { actor: 'shopper' });

Generic-API test (spec 3.1) ​

Rule Result
1. Neutral name pass: TextureSpec names no product
2. A precedent pass: glTF KHR_texture_transform (row G34)
3. Two apps, or labs pass: 4 apps (ledger: app-0c773a4ee3, app-f3598fad77; fleet cross-check: app-59c5b5751e, app-e61a0b42ad, app-f3598fad77)
4. The cheaper fix first decided per need in Appendix B: rows G34 at tier stable (a member only where no rule, data, asset or app code serves the need)