@ts3d-hoops/web-viewer-components API

@ts3d-hoops/web-viewer-components API

@ts3d-hoops/web-viewer-components

High-level web components and services for building HOOPS Web Viewer applications. This package provides ready-to-use UI components like model trees, toolbars, settings panels, and a complete service architecture for common viewer operations.

  • Built with Lit and TypeScript
  • Complete viewer UI components (trees, toolbars, panels)
  • Service-based architecture for viewer operations
  • Context management for component communication
  • Framework-agnostic web components

Installation

npm install @ts3d-hoops/web-viewer-components

This package depends on @ts3d-hoops/web-viewer and @ts3d-hoops/ui-kit, which will be installed automatically.

Quick start

Basic viewer with components

<hoops-web-viewer> doesn’t render its children into itself the way a native element with slots would — it has no <slot>s. Toolbar buttons, trees, and panels are placed as siblings of <hoops-web-viewer> and talk to it through shared Lit context instead. That context is provided by two small wrapper elements: <hoops-service-registry>, which registers the shared services those components use, and <hoops-web-viewer-context-manager>, which holds a reference to the active viewer and hands it to anything nested inside it. Both need to be present, in this order, around anything from this package you use:

<!doctype html>
<html>
  <head>
    <script type="module">
      import '@ts3d-hoops/web-viewer-components';
    </script>
  </head>
  <body>
    <hoops-service-registry>
      <hoops-web-viewer-context-manager>
        <hoops-web-viewer id="viewer" endpointUri="/models/sample.scs" style="width: 100%; height: 500px;"></hoops-web-viewer>

        <!-- Toolbar and panel components are siblings of the viewer, not children -->
        <hoops-toolbar-home></hoops-toolbar-home>
        <hoops-toolbar-camera></hoops-toolbar-camera>
        <hoops-toolbar-drawmode></hoops-toolbar-drawmode>
        <hoops-model-tree></hoops-model-tree>
      </hoops-web-viewer-context-manager>
    </hoops-service-registry>
  </body>
</html>

TypeScript setup

import '@ts3d-hoops/web-viewer-components';
import { WebViewerComponent } from '@ts3d-hoops/web-viewer-components';

// Configure the viewer
const viewer = document.querySelector('hoops-web-viewer') as WebViewerComponent;
viewer.endpointUri = '/models/microengine.scs';
viewer.enginePath = '/engine';

// Listen for viewer events — every entry in the old CallbackMap is re-dispatched
// as a same-named DOM CustomEvent prefixed with "hwv" (modelStructureReady -> hwvModelStructureReady).
// detail always includes `hwv`, the underlying WebViewer instance.
viewer.addEventListener('hwvModelStructureReady', (e) => {
  console.log('Model structure ready:', e.detail.hwv);
});
Note on attributes: properties like endpointUri and enginePath are declared as plain Lit reactive properties with no custom attribute name, so when set from HTML the attribute name is the lowercased property name with no separating hyphen — endpointuri, not endpoint-uri. Since HTML attribute names are case-insensitive in markup, writing endpointUri="..." (as shown above) or endpointuri="..." in your HTML source are exactly the same to the browser and to Lit. A hyphenated endpoint-uri is a different, unrecognized attribute and will silently do nothing — prefer setting these via the JS property (viewer.endpointUri = ...) if you want to avoid the ambiguity entirely.

Core components

Viewer component

  • hoops-web-viewer — The viewer’s rendering surface. Must be nested inside <hoops-web-viewer-context-manager>, which must in turn be nested inside <hoops-service-registry>, for any other component in this package to function.

Plumbing (required)

  • hoops-service-registry — Registers this package’s services (camera, selection, cutting, view, etc.) into the global service registry. Required as an ancestor of <hoops-web-viewer-context-manager>.
  • hoops-web-viewer-context-manager — Holds the active WebViewer instance and current UI state (draw mode, active operators) and provides it via Lit context to any component nested inside it, including <hoops-web-viewer> itself.

Trees and navigation

  • hoops-model-tree — Hierarchical model structure tree
  • hoops-layer-tree — CAD layer management tree
  • hoops-view-tree — Saved views and configurations tree
  • hoops-types-tree — Object type filtering tree
  • hoops-markup-tree — Markup and annotation tree

Toolbar buttons

  • hoops-toolbar-home — Home/fit view button
  • hoops-toolbar-camera — Camera controls and projections
  • hoops-toolbar-camera-operator — Switches between built-in camera operators (Navigate, Turntable, WalkMode)
  • hoops-toolbar-drawmode — Rendering mode toggle (shaded, wireframe, etc.)
  • hoops-toolbar-layers — Layer visibility controls
  • hoops-toolbar-views — View management
  • hoops-toolbar-model-tree — Model tree toggle
  • hoops-toolbar-properties — Properties panel toggle
  • hoops-toolbar-snapshot — Screenshot capture
  • hoops-toolbar-explode — Model explode controls
  • hoops-toolbar-redlines — Markup and redlining tools
  • hoops-toolbar-tools — Additional viewer tools
  • hoops-toolbar-settings — Settings panel toggle
  • hoops-toolbar-cad-configuration — CAD configuration controls

Panels and dialogs

  • hoops-settings-panel — Viewer settings and preferences
  • hoops-tools-panel — Tool collection panel
  • hoops-context-menu — Right-click context menu
  • hoops-info-button — Information display button
  • hoops-cad-configuration-list — CAD configuration selection

Service architecture

The package includes a comprehensive service system for viewer operations:

Available services

  • CameraService — Camera manipulation and animation
  • SelectionService — Object selection and highlighting
  • CuttingService — Cutting plane management
  • ExplodeService — Model explosion controls
  • RedlineService — Markup and annotation tools
  • RenderOptionsService — Rendering and visual settings
  • ViewService — View management and navigation
  • PmiService — PMI (Product Manufacturing Information) handling
  • SheetService — Drawing sheet management
  • SpaceMouseService — 3D mouse integration
  • WalkOperatorService — Walk-through navigation

Using services

import {
  CameraService,
  SelectionService,
  serviceRegistry,
} from '@ts3d-hoops/web-viewer-components/services';

// Get services from the registry
const cameraService = serviceRegistry.get(CameraService);
const selectionService = serviceRegistry.get(SelectionService);

// Use camera service
await cameraService.fitView();
await cameraService.setProjection('orthographic');

// Use selection service
const selectedNodes = await selectionService.getSelection();
await selectionService.selectByNodeId([nodeId]);

Advanced examples

Complete viewer application

import '@ts3d-hoops/web-viewer-components';

const container = document.getElementById('app')!;
container.innerHTML = `
  <hoops-service-registry>
    <hoops-web-viewer-context-manager style="display: flex; width: 100vw; height: 100vh;">
      <hoops-web-viewer
        endpointUri="/models/assembly.scs"
        enginePath="/engine"
        style="flex: 1;">
      </hoops-web-viewer>

      <!-- Toolbar -->
      <div style="display: flex; gap: 4px;">
        <hoops-toolbar-home></hoops-toolbar-home>
        <hoops-toolbar-camera></hoops-toolbar-camera>
        <hoops-toolbar-drawmode></hoops-toolbar-drawmode>
        <hoops-toolbar-explode></hoops-toolbar-explode>
        <hoops-toolbar-snapshot></hoops-toolbar-snapshot>
        <hoops-toolbar-settings></hoops-toolbar-settings>
      </div>

      <!-- Left sidebar -->
      <div style="width: 300px; display: flex; flex-direction: column;">
        <hoops-model-tree style="flex: 1;"></hoops-model-tree>
        <hoops-layer-tree style="flex: 1;"></hoops-layer-tree>
      </div>

      <!-- Right panel -->
      <div style="width: 250px;">
        <hoops-settings-panel></hoops-settings-panel>
      </div>
    </hoops-web-viewer-context-manager>
  </hoops-service-registry>
`;
All of the elements above need to be actual descendants of the same <hoops-web-viewer-context-manager> to share its context — they are laid out with ordinary CSS (flexbox, in this example), not slots.

Custom service integration

import {
  serviceRegistry,
  CameraService,
  SelectionService,
} from '@ts3d-hoops/web-viewer-components/services';

class MyCustomService {
  constructor(
    private cameraService: CameraService,
    private selectionService: SelectionService,
  ) {}

  async focusOnSelected() {
    const selection = await this.selectionService.getSelection();
    if (selection.length > 0) {
      await this.cameraService.fitNodes(selection);
    }
  }
}

// Register custom service
const cameraService = serviceRegistry.get(CameraService);
const selectionService = serviceRegistry.get(SelectionService);
const myService = new MyCustomService(cameraService, selectionService);

Event handling

Every viewer event is a DOM CustomEvent named hwv + the callback name in PascalCase (so the old CallbackMap‘s modelStructureReady becomes hwvModelStructureReady, sceneReady becomes hwvSceneReady, selectionArray becomes hwvSelectionArray, and so on for every entry in the map). detail always includes hwv (the WebViewer instance) plus whatever arguments that callback used to take — for example hwvCamera‘s detail is { hwv, camera }, and hwvSelectionArray‘s is { hwv, selectionEvents, removed }.

// Listen for tree selection changes
const modelTree = document.querySelector('hoops-model-tree')!;
modelTree.addEventListener('selectionChange', (e) => {
  console.log('Model tree selection:', e.detail);
});

// Listen for viewer state changes
const viewer = document.querySelector('hoops-web-viewer')!;
viewer.addEventListener('hwvSceneReady', (e) => {
  console.log('Viewer is active and can be interacted with:', e.detail.hwv);
});

viewer.addEventListener('hwvModelStructureReady', (e) => {
  console.log('Model structure loaded successfully');
});

viewer.addEventListener('hwvSelectionArray', (e) => {
  console.log('Viewer selection changed:', e.detail.selectionEvents);
});

Modular imports

Import only the components you need:

// Individual components
import '@ts3d-hoops/web-viewer-components/hoops-web-viewer';
import '@ts3d-hoops/web-viewer-components/hoops-model-tree/hoops-model-tree';

// Specific services
import { CameraService, SelectionService } from '@ts3d-hoops/web-viewer-components/services';

// Everything (not recommended for production)
import '@ts3d-hoops/web-viewer-components';
Check the exports map in the package’s package.json for the granular entry points available in your installed version — not every component currently has its own subpath export, in which case the whole-package import above is the only option.

Context management

Components use Lit Context for communication. In practice you don’t construct this yourself — you place a <hoops-web-viewer-context-manager> element in your markup (see Quick start, above) and it provides context to everything nested inside it:

import { WebViewerContextManager } from '@ts3d-hoops/web-viewer-components';

Styling and theming

Components inherit theming from @ts3d-hoops/ui-kit and can be styled with CSS custom properties:

hoops-web-viewer {
  --hoops-neutral-foreground: #ffffff;
  --hoops-accent-foreground: #0078d4;
  --hoops-body-font: 'Segoe UI', system-ui, sans-serif;
}

hoops-model-tree {
  border: 1px solid #ccc;
  border-radius: 4px;
}

Storybook documentation

This package includes Storybook for component documentation and testing:

# Run Storybook locally (if you have the source)
npm run storybook

TypeScript

Full TypeScript definitions are included for all components and services:

import type {
  WebViewerComponent,
  HoopsModelTreeElement,
  CameraService,
} from '@ts3d-hoops/web-viewer-components';

Browser support

  • Modern browsers with web component support
  • ES2020+ environments
  • WebGL-capable devices
  • Works with all major bundlers (Vite, Webpack, Rollup, esbuild)

Framework integration

React

import '@ts3d-hoops/web-viewer-components';

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'hoops-service-registry': any;
      'hoops-web-viewer-context-manager': any;
      'hoops-web-viewer': any;
      'hoops-model-tree': any;
    }
  }
}

function ViewerApp() {
  return (
    <hoops-service-registry>
      <hoops-web-viewer-context-manager>
        <hoops-web-viewer endpointUri="/models/sample.scs" />
        <hoops-model-tree />
      </hoops-web-viewer-context-manager>
    </hoops-service-registry>
  );
}

Vue

<template>
  <hoops-service-registry>
    <hoops-web-viewer-context-manager>
      <hoops-web-viewer :endpointUri="modelUri" />
      <hoops-model-tree />
    </hoops-web-viewer-context-manager>
  </hoops-service-registry>
</template>

<script setup>
import '@ts3d-hoops/web-viewer-components';
const modelUri = '/models/sample.scs';
</script>

Related packages

  • @ts3d-hoops/web-viewer — Core HOOPS Web Viewer library
  • @ts3d-hoops/web-viewer-components-react — React wrappers for these components
  • @ts3d-hoops/ui-kit — Base UI component library
  • @ts3d-hoops/streamcache — Low-level streaming client

License

Commercial license. For evaluation or production licensing, contact Tech Soft 3D.

Classes

Interfaces

Type Aliases

Variables

wvc.ActiveToolOperatorPosition

const

ActiveToolOperatorPosition: 1
wvc.CameraOperatorPosition

const

CameraOperatorPosition: 0
wvc.contextManagerContext

const

contextManagerContext: object
wvc.LogLevelNames

const

LogLevelNames: readonly [“debug”, “info”, “warn”, “error”]

Built-in log level names. These are the standard levels recognized by the log service, but the service also accepts arbitrary string values for custom levels.

wvc.OrbitFallbackModeValues

const

OrbitFallbackModeValues: readonly [“Camera Target”, “Model Center”, “Orbit Target”]
wvc.PointSizeUnitValues

const

PointSizeUnitValues: readonly [“Screen Pixels”, “CSS Pixels”, “World”, “Proportion Of Screen Width”, “Proportion Of Screen Height”, “Proportion Of Bounding Diagonal”]
wvc.ProjectionValues

const

ProjectionValues: readonly [“Perspective”, “Orthographic”]
wvc.redlineModes

const

redlineModes: readonly [RedlineCircle, RedlineText, RedlineRectangle, RedlinePolyline]
wvc.ServiceNames

const

ServiceNames: readonly [“BcfService”, “CameraService”, “CuttingService”, “ExplodeService”, “FilterService”, “SheetService”, “IFCRelationshipsService”, “MeasurementService”, “NoteTextService”, “PmiService”, “RedlineService”, “RenderOptionsService”, “SelectionService”, “SpaceMouseService”, “ViewService”, “FloorplanService”, “WalkOperatorService”, “MaterialService”, “LogService”]

The following types are used to define the structure of services in the web viewer components. They include a list of service names, a type for service names, and an interface for services. The ServiceRegistry type maps service names to their respective service instances. This allows for easy registration, retrieval, and management of services within the application.

The ServiceNames constant defines the available service names, which can be extended as needed. The ServiceName type is a union of the defined service names and allows for string literals, providing flexibility in service naming while ensuring type safety.

This concept is named loose completion in typescript, you can learn more about it here: https://www.totaltypescript.com/tips/create-autocomplete-helper-which-allows-for-arbitrary-values

wvc.serviceRegistry

const

serviceRegistry: ServiceRegistry

Service Registry for managing services in the application. This registry allows for registering, unregistering, and retrieving services by their names. It also provides utility functions to check for service existence and clear all services.

wvc.WalkModeNames

const

WalkModeNames: readonly [“Mouse”, “Keyboard”]
wvc.WalkSpeedUnitNames

const

WalkSpeedUnitNames: string[]
wvc.webViewerContext

const

webViewerContext: object
wvc.webViewerStateContext

const

webViewerStateContext: object

Functions