Skip to main content

Augmented Reality

Dopple Visual allows 3D products to be viewed in augmented reality (AR) on a user’s device, directly within the web browser.

Before launching an AR experience, an AR scene needs to be generated by Dopple in the cloud, then presented to the user by one of two methods:

  1. Displaying a QR code for the user to scan, linking to the AR experience ideal for when the user is on a device that does not support augmented reality.
  2. Showing a Launch AR button for the user to click ideal for when a user is on an AR-supported device, such as a smartphone or tablet.

AR scene generation is often very time consuming and computationally heavy. For the best user experience, it is strongly recommended to keep track of when users make changes to their product’s configuration so that new AR scenes and QR codes only need to be generated for new configurations, and not repeated for existing configurations.

See the tracking configuration changes section below for more info.

Generating the AR scene

To create an AR scene of the current product configuration, use the create method available on Atlatl.ARScene, passing in the Visual instance as its only parameter.

const renderCanvas = document.getElementById('my-canvas')
const visual = new Atlatl.Visual(renderCanvas)

const createArScene = async () => {
const arScene = await Atlatl.ARScene.create(visual)

This will begin the process of converting the user’s scene (handled for you in the cloud by Dopple) into an AR scene that can be launched within their web browser. Once the AR scene has finished generating, a QR code linking to the AR experience or a button to launch the experience directly may then be displayed to the user.

Creating and displaying the QR code

To generate a QR code, an HTML <img> element needs to first be created in the DOM. This may be done either by adding an <img> tag to your HTML document, or using JavaScript (for example, document.createElement('img')).

<img id="qr-code-img" alt="QR code" />

This image’s src attribute will be populated by the base64 data returned by the generateQRCode method on the Atlatl.ARScene.

const createQrCode = async () => {

// Generate a new AR scene with the current product configuration
const arScene = await Atlatl.ARScene.create(visual)

// Generate a PNG image of the QR code onto the page
const qrCodeData = 'data:image/png;base64,' + arScene.generateQRCode()
document.getElementById('qr-code-img').setAttribute("src", qrCodeData)

Launching AR

To launch the AR experience directly, call the launchAR method on the Atlatl.ARScene after the AR scene has been generated.

const launchAr = async () => {

// Generate a new AR scene with the current product configuration
const arScene = await Atlatl.ARScene.create(visual)

// Launch the AR experience
if (confirm('Warning! You are about to leave this page. To continue to the AR experience, select "OK".')) {

The launchAr() function may then be triggered anytime after Dopple Visual has loaded, such as when the user clicks a <button> on the webpage.

<button id="launch-ar">Launch AR</button>
document.getElementById('launch-ar').addEventListener('click', () => {

On non-AR devices, such as a desktop computer, the AR experience will still be launched when launchAR is called. However, the user will be taken to an AR preview page without the ability to use their device for AR.

Detecting AR-supported devices

If the user is currently on a device that supports AR, it may be a desirable user experience to display only the Launch AR button and not the QR code (or vice versa if the user is on a non-AR device).

One method is to use a regular expression to check the user agent of the browser for known mobile devices, since these devices will typically have AR capabilities.

const isMobileDevice = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)

Then, if isMobileDevice returns true, the launch button or the QR code image may be shown or hidden accordingly.

if (isMobileDevice) {
// Hide the QR code (show only the Launch AR button)
document.getElementById('qr-code-img').style.display = 'none'
} else {
// Hide the Launch AR button (show only the QR code)
document.getElementById('launch-ar').style.display = 'none'

User agent detection can be unreliable. Depending on your unique needs for AR device detection, a more robust way of detecting a device’s AR capabilities may need to be built. See MDN’s browser detection using the user agent article for more information.

Showing a loader while AR generates

Since the AR scene creation process may take a few seconds, it is recommended to show a loading screen or indicator to the user while they wait.

A custom loading screen may be created by placing a loading message in the page’s HTML, then conditionally showing or hiding the message depending on the loading state of the AR scene.

<p id="ar-loading-screen">
Your AR experience is loading...
<span id="ar-loading-percent">0%</span>
<progress id="ar-progress-bar" max="100" value="0"></progress>
const renderCanvas = document.getElementById('my-canvas')
const visual = new Atlatl.Visual(renderCanvas)

const createArScene = async () => {
// Show the "loading" message as the AR scene generates
document.getElementById('ar-loader').style.display = ''

// Generate the AR scene
const arScene = await Atlatl.ARScene.create(visual,
onProgress(e) {
console.log(e.currentStep + '/' + e.totalSteps + ' (' + e.overallProgress * 100 + '%)')

// Hide the "loading" message once the AR scene has finished generating
document.getElementById('ar-loader').style.display = 'none'

Additionally, ARScene.create() also accepts an onProgress() callback function which gives access to the current step, total number of steps, and overall progress during the AR generation process.

const arScene = await Atlatl.ARScene.create(visual, {

// Get the current step, total number of steps, and overall progress of the AR scene generation
onProgress(e) {
console.log(e.overallProgress * 100 + '%')

Tracking configuration changes

As mentioned earlier, AR scene generation is usually a time consuming process. Depending on the complexity of the product and the scene, this could take upwards of 10 or 20 seconds. To help mitigate this, avoid calling Atlatl.ARScene.create() for repeat views of the same product configuration in AR.

One method is to wrap your Atlatl.ARScene.create() functionality in a conditional statement that first checks to see if the product configuration has been changed since the last time it was called.

// Default to true so that a new AR scene may be generated on the first try
let configHasChanged = true

// Generate the AR scene only if the product configuration is new
if (this.configHasChanged) {
const arScene = await Atlatl.ARScene.create(visual)

// Set back to false after AR scene creation to prevent repeat creations of an unchanged product
configHasChanged = false

Then, when the user makes an update to the product’s configuration, such as when using setValue() (see Updating the product using setValue()), the configHasChanged variable can be set back to true to allow your code to re-generate the AR scene with the updated configuration.

// Update the product's configuration when a button is clicked
document.getElementById('my-button').addEventListener('click', () => {
myProduct.setValue('some_property', 'some_value')

// Set to true to allow for a new AR scene to be generated
configHasChanged = true

This optimization also applies to products that do not have any configurable options. If your 3D product is static, you should still only call Atlatl.ARScene.create() once, then show or hide the same QR code or Launch AR button to users for any subsequent times after that.

Full code example

<html lang="en">
<meta charset="utf-8">
<title>My Page</title>
<!-- Link to the Visual Component's scripts -->
<script src="" defer></script>
<!-- Link to custom scripts -->
<script src="scripts.js" defer></script>
<!-- Canvas to render the 3D scene too -->
<canvas id="my-canvas"></canvas>
<button id="generate-qr">Generate QR Code</button>
<button id="launch-ar">Launch AR</button>
<img id="qrCodeOutput" alt="" />