5.11 Capture and export ​

Contract 2.0.0 · package sha256 a857eca95b35921109faf997094bb4192f12527d9d0fcd4be7e97f06425bad6e · generated from examples/section-5/5.11-capture-and-export.ts by services/onsite-scripter/scripts/build-contract-docs.mjs; edit the source, not this file.

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.

ts
import { HoloBusyError } from '@holostep-configurators/runtime-client';
import type { CameraView, Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
declare const showroomView: CameraView;
declare function uploadThumbnail(image: Blob, meta: { sceneHash: string; complete: boolean }): Promise<void>;
const spec = { view: showroomView, size: { width: 800, height: 800 }, pixelRatio: 1, background: 'transparent' } as const;
async function thumbnail(signal: AbortSignal) {
  try { return await session.capture(spec, { signal }); }
  catch (e) {
    if (!(e instanceof HoloBusyError)) throw e;          // a transaction holds the display
    await session.idle({ signal });                      // bounded by the signal
    return session.capture(spec, { signal });
  }
}
// A pick made just before 'Kosárba' may still be loading: wait for it, at most 5 s.
async function settle(ms: number): Promise<boolean> {
  try { await session.idle({ signal: AbortSignal.timeout(ms) }); return true; }
  catch (e) { if (e instanceof DOMException && e.name === 'AbortError') return false; throw e; }
}
// A product GLB that failed stays in the model, unloaded and without parts, and capture() still
// reports completed (6.4): send no picture then, so the shop shows its own fallback.
function productDrawn(): boolean {
  const model = session.getSceneModel();
  if (!model || session.find({ role: 'product' }).bounds() === null) return false;
  const inModel = new Set<string>();
  const walk = (nodes: NonNullable<typeof model>['root']): void => {
    for (const n of nodes) if (n.enabled) { inModel.add(n.nodeId); walk(n.children ?? []); }
  };
  walk(model.root);
  return !session.info().problems.some((p) => p.code === 'asset-failed' && p.asset === 'model'
    && p.node !== undefined && inModel.has(p.node) && !session.node(p.node).exists);
}
const fresh = await settle(5000);
if (productDrawn()) {
  const shot = await thumbnail(signal);
  await uploadThumbnail(shot.image, { sceneHash: shot.snapshot.sceneHash, complete: shot.completed && fresh });
}

Back to the examples · llms.txt