Skip to content

Quick Start

Install

sh
npm install @optellix/xviewr-sdk

Licensing

Every viewer instance requires a valid license key. The key is an XVR1 ES256 token issued by Optellix. Pass it in viewer.licensing at construction. viewer.ready() will reject with a LicenseError if the key is missing or invalid.

ts
import { ViewerCore, LicenseError, LoaderPlugin, SelectionPlugin } from '@optellix/xviewr-sdk';

const container = document.getElementById('viewer') as HTMLElement;

const viewer = new ViewerCore(container, {
  viewer: {
    camera: {
      type: 'perspective',
      fov: 75,
      position: { x: 5, y: 5, z: 5 },
      target: { x: 0, y: 0, z: 0 },
    },
    licensing: {
      key: process.env.XVIEWR_LICENSE_KEY!,
    },
  },
  rendering: { antialias: true },
  plugins: [],
});

try {
  await viewer.ready();
  await viewer.loadPlugin(new LoaderPlugin());
  await viewer.loadPlugin(new SelectionPlugin());
} catch (err) {
  if (err instanceof LicenseError) {
    console.error('License invalid or expired:', err.message);
  }
  throw err;
}

The container element must be in the document and have a non-zero size before you construct the viewer. The renderer canvas is appended to it automatically.

Load a Model

ts
const loader = viewer.pluginManager.getPlugin('loader') as LoaderPlugin;

// Progress
viewer.eventBus.on('file:loading-progress', ({ progress }) => {
  setProgressBar(Math.round(progress * 100));
});

// Load GLB from URL
await loader.loadGlb('/models/assembly.glb');

// Or from a user-selected File
input.addEventListener('change', async () => {
  const file = input.files?.[0];
  if (file) await loader.loadFile(file);
});

The loaded model is added to viewer.root. After loading, the camera does not auto-fit — call CameraService.fitToScene() if you want that:

ts
import { CameraService } from '@optellix/xviewr-sdk';

const camera = viewer.getService<CameraService>('camera');
camera?.fitToScene();

Subscribe to Events

All events flow through viewer.eventBus. Handlers run synchronously on the emitting thread.

ts
viewer.eventBus.on('model:loaded', ({ model }) => {
  console.log('loaded', model.name);
});

viewer.eventBus.on('selection:changed', ({ selected }) => {
  console.log('selected objects:', selected.length);
});

Selection

SelectionPlugin is active after loading it with viewer.loadPlugin(new SelectionPlugin()). Click-to-select is on by default.

ts
const selection = viewer.pluginManager.getPlugin('selection') as SelectionPlugin;

// Programmatic select
selection.selectAll();
selection.focusOnSelection();
selection.clearSelection();

// Handle clicks yourself
viewer.renderer.domElement.addEventListener('click', (e) => {
  selection.clickToSelect(e.clientX, e.clientY);
});

Measurement

ts
import { MeasurementPlugin } from '@optellix/xviewr-sdk';

await viewer.loadPlugin(new MeasurementPlugin());
const measure = viewer.pluginManager.getPlugin('measurement') as MeasurementPlugin;

measure.enable();
measure.setMeasurementMode('distance');  // click two points to measure

viewer.eventBus.on('measurement:created', ({ measurement }) => {
  console.log(measurement.result);
});

// To stop measuring
measure.disable();

Available modes: distance, angle, area, multi-point, aabb, obb, volume, circle, arc.

Export a Screenshot

ts
import { CanvasExportPlugin } from '@optellix/xviewr-sdk';

await viewer.loadPlugin(new CanvasExportPlugin());
const exporter = viewer.pluginManager.getPlugin('canvas-export') as CanvasExportPlugin;

// Download a 1920x1080 PNG
await exporter.downloadImage({ width: 1920, height: 1080, format: 'png' });

// Or get a data URL
const url = await exporter.exportImage({ format: 'jpeg', quality: 0.92 });

Cleanup

Always dispose the viewer when the host component unmounts:

ts
await viewer.dispose();

dispose() unloads all plugins, shuts down services, disposes GPU resources, and removes the renderer canvas from the DOM. It is idempotent.

Next Steps

TopicReference
Full configuration optionstypes/configuration.md
All available pluginsoverview.md
All available servicesoverview.md
Loading chunked/LOD modelsplugins/LoaderPlugin.md
Custom measurement typesservices/MeasurementService.md
License inspection and feature gatingservices/LicenseService.md
Error typeserrors.md

XViewr SDK and xConvert CLI documentation.