Using ORBITVU VIEWER as an ES module
ORBITVU VIEWER ships an ES module bundle (orbitvu.esm.js) you can import from a bundler or a module script tag, instead of loading the classic script.
Since VIEWER 3.10.19 every ORBITVU VIEWER package contains a second bundle next to the classic one:
orbitvu12/
orbitvu.js # classic bundle — loaded with a <script> tag
orbitvu.esm.js # ES module bundle — imported
viewer5.css # stylesheet — must be loaded separately by ES module consumers
version.xml
LICENSE.txtBoth bundles are built from the same source and render identically. The difference is how your page gets hold of them: orbitvu.js has to be loaded with a <script> tag before you can call it, while orbitvu.esm.js is imported — which is what you want if your site is built with Vite, webpack, Rollup, Next.js or any other bundler.
The ES module bundle is part of the downloadable VIEWER package, the same orbitvu12/ folder covered in Hosting 360° presentation on your own server. Presentations hosted on ORBITVU SUN keep using the generated embed code and need no changes.
The ES module bundle does not bring its own styles. Unlike the classic bundle — which loads viewer5.css for you from the VIEWER folder you pass to inject_orbitvu — orbitvu.esm.js has no folder argument and adds no stylesheet on its own. You have to load viewer5.css yourself, or the presentation renders unstyled.
mount_viewer
The module exports one function. Import the stylesheet next to it — viewer5.css is not part of the bundle, and without it the presentation renders unstyled:
import { mount_viewer } from './orbitvu12/orbitvu.esm.js';
import './orbitvu12/viewer5.css'; // required — see below
const viewer = mount_viewer(containerId, params);mount_viewer mounts a viewer into the element with the given id and returns the viewer instance. params is the same object of VIEWER parameters the classic bundle accepts, including width and height, which take the same values there as everywhere else — 'auto', a plain number, or a value with a unit.
Two things to keep in mind:
- The container element has to exist first.
mount_viewerlooks it up by id and fills it in; it does not create it. - Importing the module does not start anything by itself, so it is safe to import in a server-rendered build. Mounting needs a real DOM — call
mount_viewerfrom the browser only.
When you are done with a viewer — in a React useEffect cleanup, or a router teardown — call destroy() on the instance it returned:
viewer.destroy();Loading the stylesheet
viewer5.css is a separate file rather than something baked into the bundle, so that an injected <style> element cannot break a strict Content-Security-Policy setup. Importing orbitvu.esm.js therefore pulls in no styles, and you have three ways to supply them:
-
Import it next to the bundle — preferred, and the only one with no unstyled first paint:
import { mount_viewer } from '../vendor/orbitvu12/orbitvu.esm.js'; import '../vendor/orbitvu12/viewer5.css'; -
Link it from the host page:
<link rel="stylesheet" href="https://yourdomain.com/orbitvu12/viewer5.css" /> -
Pass viewer_base and let the VIEWER append the
<link>itself at mount time:mount_viewer('presentation1-container', { viewer_base: 'https://yourdomain.com/orbitvu12/', // … });Loading the stylesheet is all
viewer_basedoes — if you have already supplied it by one of the routes above, you do not need this parameter at all.
Basic example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Orbitvu presentation</title>
<link rel="stylesheet" href="https://yourdomain.com/orbitvu12/viewer5.css" />
</head>
<body>
<div id="presentation1-container"></div>
<script type="module">
import { mount_viewer } from 'https://yourdomain.com/orbitvu12/orbitvu.esm.js';
mount_viewer('presentation1-container', {
ovus_folder: 'https://yourdomain.com/presentations/presentation1/',
content2: 'yes',
width: '500',
height: '400'
});
</script>
</body>
</html>With a bundler
Copy the orbitvu12/ folder into your project (or serve it from your own static host) and import the bundle like any other module, so the VIEWER ends up in your own asset pipeline.
import { mount_viewer } from '../vendor/orbitvu12/orbitvu.esm.js';
import '../vendor/orbitvu12/viewer5.css';
export function showPresentation(containerId, presentationUrl) {
return mount_viewer(containerId, {
ovus_folder: presentationUrl,
content2: 'yes',
width: 'auto',
height: 'auto',
teaser: 'autorotate'
});
}Getting hold of the API
mount_viewer returns the viewer instance straight away, but the VIEWER API object is created later, once the presentation's configuration files have loaded — so reading it off the returned instance does not work. Pass viewer_api_init instead, and give it the function itself: a callback named by a string is looked up on the page's global scope, which cannot reach a function defined inside a module.
viewer_api_init fires early, before the first frame is requested. The API object is complete at that point, but the viewer is not drivable yet — rotate, zoom and pan do nothing until the frames are in. So use viewer_api_init to register your callbacks, and drive the viewer from the viewer_initialized event, which hands you the same API object once the presentation is ready:
import { mount_viewer } from '../vendor/orbitvu12/orbitvu.esm.js';
import '../vendor/orbitvu12/viewer5.css';
let viewerApi = null;
function onViewerReady(api) {
viewerApi = api;
api.setScene({ hangle: 10 }); // safe here — the viewer is loaded
}
const viewer = mount_viewer('presentation1-container', {
ovus_folder: '/presentations/presentation1/',
content2: 'yes',
width: 'auto',
height: '400px',
viewer_api_init: (api) => {
api.addCallback(onViewerReady, 'viewer_initialized');
}
});addCallback(callback, event_name) accepts a function reference too, so nothing in this flow needs a globally named function.
With partial_load enabled, viewer_initialized is deferred until the remaining frames have arrived. The earlier partially_initialized event is useful for progress UI, but the viewer still cannot be driven when it fires.
The API is only present in VIEWER editions that include it. viewer_api_init is never called in the My360 edition — see Licensing for the feature comparison.
Differences from the classic bundle
orbitvu.js | orbitvu.esm.js | |
|---|---|---|
| Loading | <script src="…/orbitvu.js"> | import |
| Entry point | inject_orbitvu(id, viewer_folder, '', params) | mount_viewer(id, params) |
| Stylesheet | loaded from the VIEWER folder argument | you import or link viewer5.css, or set viewer_base |
| Return value | nothing | the viewer instance |
inject_orbitvu is not part of the module bundle — when porting an embed to an import, replace it with mount_viewer, which takes no VIEWER folder argument and gets everything else from the same params object.